Skip to content

Commit 987283b

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.2.5 (Build 3530)
1 parent 2808ab2 commit 987283b

16 files changed

+323
-12
lines changed

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Memfault Firmware SDK Changelog
22

3+
## 1.2.5 - Sept 18, 2023
4+
5+
### :chart_with_upwards_trend: Improvements
6+
7+
- Add MQTT transport to esp32 example app
8+
39
## 1.2.4 - Sept 12, 2023
410

511
### :chart_with_upwards_trend: Improvements

VERSION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
BUILD ID: 3479
2-
GIT COMMIT: 2ae56da92
1+
BUILD ID: 3530
2+
GIT COMMIT: 9d31ca353

components/include/memfault/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ typedef struct {
1919
uint8_t patch;
2020
} sMfltSdkVersion;
2121

22-
#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 2, .patch = 4 }
23-
#define MEMFAULT_SDK_VERSION_STR "1.2.4"
22+
#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 2, .patch = 5 }
23+
#define MEMFAULT_SDK_VERSION_STR "1.2.5"
2424

2525
#ifdef __cplusplus
2626
}

examples/esp32/apps/memfault_demo_app/CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,28 @@ include(${memfault_firmare_sdk_dir}/ports/esp_idf/memfault.cmake)
2424
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
2525
project(${PROJECT_NAME})
2626

27+
# Check for invalid partition table configurations
28+
if (
29+
CONFIG_APP_MEMFAULT_TRANSPORT_HTTP AND
30+
NOT CONFIG_PARTITION_TABLE_CUSTOM_FILENAME STREQUAL "partitions_example.csv"
31+
)
32+
message(WARNING "Data transport is HTTP but using partition table ${CONFIG_PARTITION_TABLE_CUSTOM_FILENAME}")
33+
set(INVALID_PARTITION_TABLE true)
34+
elseif(
35+
CONFIG_APP_MEMFAULT_TRANSPORT_MQTT AND
36+
NOT CONFIG_PARTITION_TABLE_CUSTOM_FILENAME STREQUAL "partitions_example_mqtt.csv"
37+
)
38+
message(WARNING "Data transport is MQTT but using partition table ${CONFIG_PARTITION_TABLE_CUSTOM_FILENAME}")
39+
set(INVALID_PARTITION_TABLE true)
40+
endif()
41+
42+
if (INVALID_PARTITION_TABLE)
43+
message(FATAL_ERROR
44+
"Invalid partition table configuration, check CONFIG_APP_MEMFAULT_TRANSPORT configs.\
45+
If this error occurs repeatedly run `idf.py fullclean && rm sdkconfig`"
46+
)
47+
endif()
48+
2749
# Add the Memfault Build ID so each build can have a unique version.
2850
set(IDF_PROJECT_EXECUTABLE ${PROJECT_NAME}.elf)
2951
add_custom_command(TARGET ${IDF_PROJECT_EXECUTABLE}

examples/esp32/apps/memfault_demo_app/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,35 @@ This Demo App is based on the console example from ESP-IDF, which can be found
44
here relative to the ESP-IDF SDK root folder:
55

66
- `examples/system/console/advanced/`
7+
8+
## Configuring for MQTT
9+
10+
This application includes an option to send Memfault data over MQTT. This option requires a few extra pieces to set up.
11+
You can either follow the steps outlined here or use your own MQTT setup.
12+
13+
### Broker Setup
14+
15+
1. Install a local installtion of Cedalo by following the [installation guide](https://docs.cedalo.com/management-center/installation/)
16+
2. Login to Cedalo at <http://localhost:8088>
17+
3. Create a new client login for the device
18+
- Ensure device client has the "client" role to allow publishing data
19+
4. Create a new client login for the Python service
20+
- Ensure Python service client has "client" role to allow subscribing to data
21+
22+
### Service Setup
23+
24+
1. Modify the script found in Docs->Best Practices->MQTT with Memfault with the the following:
25+
1. The service client login information previously created
26+
2. Connection info for your local broker
27+
3. Map of Memfault projects to project keys
28+
2. Start the service by running `python mqtt.py`
29+
30+
### Device Setup
31+
32+
1. Make the following modifications to `main/app_memfault_transport_mqtt.c`:
33+
1. Update `MEMFAULT_PROJECT` macro with your project's name
34+
2. Update `s_mqtt_config` with your setup's IP address, and MQTT client username and password
35+
2. Clean your existing build with `idf.py fullclean && rm sdkconfig`
36+
3. Set your target: `idf.py set-target <esp32_platform_name>`
37+
4. Build your image: `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.mqtt" build`
38+
5. Flash to your device using `idf.py flash`

examples/esp32/apps/memfault_demo_app/main/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ list(APPEND
77
memfault/memfault_platform_device_info.c
88
)
99

10+
if (CONFIG_APP_MEMFAULT_TRANSPORT_HTTP)
11+
list(APPEND COMPONENT_SRCS app_memfault_transport_http.c)
12+
elseif(CONFIG_APP_MEMFAULT_TRANSPORT_MQTT)
13+
list(APPEND COMPONENT_SRCS app_memfault_transport_mqtt.c)
14+
endif()
15+
1016
# the 'cmd_wifi.c' implementation is different for ESP-IDF v5+
1117
if("${IDF_VERSION_MAJOR}" VERSION_GREATER_EQUAL 5)
1218
list(APPEND

examples/esp32/apps/memfault_demo_app/main/Kconfig.projbuild

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ config MEMFAULT_APP_WIFI_AUTOJOIN
2828
help
2929
Automatically join if credentials are configured.
3030

31+
choice APP_MEMFAULT_TRANSPORT
32+
prompt "Protocol to send chunks over"
33+
default APP_MEMFAULT_TRANSPORT_HTTP
34+
35+
config APP_MEMFAULT_TRANSPORT_HTTP
36+
bool "HTTP"
37+
config APP_MEMFAULT_TRANSPORT_MQTT
38+
bool "MQTT"
39+
select MQTT_PROTOCOL_5
40+
endchoice
41+
42+
config MEMFAULT_APP_SOFTWARE_TYPE
43+
string "Software version for the application"
44+
default "esp32-main-mqtt" if APP_MEMFAULT_TRANSPORT_MQTT
45+
default "esp32-main"
46+
3147
# These LED settings are taken from ESP-IDF:
3248
# examples/get-started/blink/main/blink_example_main.c
3349

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
6+
#pragma once
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
//! Initializes any components needed for configured transport
13+
//!
14+
//! Transport is selected via CONFIG_APP_MEMFAULT_TRANSPORT choices
15+
void app_memfault_transport_init(void);
16+
17+
//! Sends all available Memfault chunks over configured transport
18+
//!
19+
//! Transport is selected via CONFIG_APP_MEMFAULT_TRANSPORT choices
20+
//!
21+
//! @return 0 on success or non-zero on error
22+
int app_memfault_transport_send_chunks(void);
23+
24+
#ifdef __cplusplus
25+
}
26+
#endif
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
6+
#include "app_memfault_transport.h"
7+
#include "memfault/esp_port/http_client.h"
8+
9+
void app_memfault_transport_init(void) {}
10+
11+
int app_memfault_transport_send_chunks(void) {
12+
return memfault_esp_port_http_client_post_data();
13+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
6+
#include <stddef.h>
7+
#include <stdint.h>
8+
9+
#include "app_memfault_transport.h"
10+
#include "esp_log.h"
11+
#include "memfault/components.h"
12+
#include "mqtt_client.h"
13+
14+
// TODO: Fill in with device's Memfault project
15+
#define MEMFAULT_PROJECT "my_project"
16+
17+
static const char *TAG = "app_memfault_transport_mqtt";
18+
19+
// TODO: Fill in with broker connection configuration
20+
static esp_mqtt_client_config_t s_mqtt_config = {
21+
.broker.address.uri = "mqtt://192.168.50.88",
22+
.credentials.username = "test",
23+
.credentials.authentication.password = "test1234",
24+
.session.protocol_ver = MQTT_PROTOCOL_V_5,
25+
};
26+
static SemaphoreHandle_t s_mqtt_connected = NULL;
27+
28+
static esp_mqtt_client_handle_t s_mqtt_client = NULL;
29+
static esp_mqtt5_publish_property_config_t s_publish_property = {
30+
.topic_alias = 1,
31+
};
32+
static char s_topic_string[128] = {0};
33+
34+
static uint8_t s_chunk_data[1024] = {0};
35+
36+
static void mqtt_event_handler(MEMFAULT_UNUSED void *handler_args,
37+
MEMFAULT_UNUSED esp_event_base_t base,
38+
MEMFAULT_UNUSED int32_t event_id, void *event_data) {
39+
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;
40+
41+
switch (event->event_id) {
42+
case MQTT_EVENT_CONNECTED:
43+
ESP_LOGI(TAG, "Connected to MQTT broker");
44+
xSemaphoreGive(s_mqtt_connected);
45+
break;
46+
default:
47+
ESP_LOGE(TAG, "Unknown MQTT event received[%d]", event->event_id);
48+
break;
49+
}
50+
}
51+
52+
static void prv_close_client(void) {
53+
int rv = esp_mqtt_client_disconnect(s_mqtt_client);
54+
if (rv) {
55+
ESP_LOGW(TAG, "Failed to disconnect[%d]", rv);
56+
}
57+
58+
rv = esp_mqtt_client_destroy(s_mqtt_client);
59+
if (rv) {
60+
ESP_LOGW(TAG, "Failed to destroy client[%d]", rv);
61+
}
62+
memfault_metrics_heartbeat_timer_stop(MEMFAULT_METRICS_KEY(mqtt_conn_uptime));
63+
64+
s_mqtt_client = NULL;
65+
}
66+
67+
static int prv_create_client(void) {
68+
if (s_mqtt_client) {
69+
return 0;
70+
}
71+
72+
s_mqtt_client = esp_mqtt_client_init(&s_mqtt_config);
73+
if (s_mqtt_client == NULL) {
74+
ESP_LOGE(TAG, "MQTT client failed to initialize");
75+
return -1;
76+
}
77+
78+
int rv =
79+
esp_mqtt_client_register_event(s_mqtt_client, MQTT_EVENT_CONNECTED, mqtt_event_handler, NULL);
80+
if (rv) {
81+
ESP_LOGE(TAG, "MQTT event handler registration failed[%d]", rv);
82+
}
83+
84+
rv = esp_mqtt_client_start(s_mqtt_client);
85+
if (rv) {
86+
ESP_LOGE(TAG, "MQTT client start failed[%d]", rv);
87+
return -1;
88+
}
89+
90+
// Wait for successful connection
91+
rv = xSemaphoreTake(s_mqtt_connected, (1000 * 10) / portTICK_PERIOD_MS);
92+
if (rv != pdTRUE) {
93+
ESP_LOGE(TAG, "MQTT client failed to connect[%d]", rv);
94+
memfault_metrics_heartbeat_timer_start(MEMFAULT_METRICS_KEY(mqtt_conn_downtime));
95+
prv_close_client();
96+
return -1;
97+
}
98+
99+
// Update connection metrics when connected
100+
memfault_metrics_heartbeat_timer_stop(MEMFAULT_METRICS_KEY(mqtt_conn_downtime));
101+
memfault_metrics_heartbeat_timer_start(MEMFAULT_METRICS_KEY(mqtt_conn_uptime));
102+
103+
// Set topic alias before publishing
104+
rv = esp_mqtt5_client_set_publish_property(s_mqtt_client, &s_publish_property);
105+
if (rv != 0) {
106+
ESP_LOGW(TAG, "MQTT client could not set publish property [%d]", rv);
107+
}
108+
return 0;
109+
}
110+
111+
static const char *prv_get_device_serial(void) {
112+
sMemfaultDeviceInfo info = {0};
113+
memfault_platform_get_device_info(&info);
114+
return info.device_serial;
115+
}
116+
117+
void prv_build_topic_string(void) {
118+
// String already built
119+
if (strlen(s_topic_string) > 0) {
120+
return;
121+
}
122+
123+
const char *device_serial = prv_get_device_serial();
124+
snprintf(s_topic_string, MEMFAULT_ARRAY_SIZE(s_topic_string),
125+
"memfault/" MEMFAULT_PROJECT "/%s/chunks", device_serial);
126+
}
127+
128+
void app_memfault_transport_init(void) {
129+
#if MEMFAULT_FREERTOS_PORT_USE_STATIC_ALLOCATION != 0
130+
static StaticSemaphore_t s_mqtt_connected;
131+
s_mqtt_connected = xSemaphoreCreateBinaryStatic(&s_mqtt_connected);
132+
#else
133+
s_mqtt_connected = xSemaphoreCreateBinary();
134+
#endif
135+
}
136+
137+
int app_memfault_transport_send_chunks(void) {
138+
int rv = prv_create_client();
139+
140+
if (rv) {
141+
return rv;
142+
}
143+
144+
prv_build_topic_string();
145+
146+
ESP_LOGD(TAG, "Checking for packetizer data");
147+
while (memfault_packetizer_data_available()) {
148+
size_t chunk_size = MEMFAULT_ARRAY_SIZE(s_chunk_data);
149+
bool chunk_filled = memfault_packetizer_get_chunk(s_chunk_data, &chunk_size);
150+
151+
if (!chunk_filled) {
152+
ESP_LOGW(TAG, "No chunk data produced");
153+
break;
154+
}
155+
156+
rv = esp_mqtt_client_publish(s_mqtt_client, s_topic_string, (char *)s_chunk_data, chunk_size, 1,
157+
0);
158+
if (rv < 0) {
159+
ESP_LOGE(TAG, "MQTT failed to publish[%d]", rv);
160+
memfault_packetizer_abort();
161+
break;
162+
}
163+
164+
memfault_metrics_heartbeat_add(MEMFAULT_METRICS_KEY(mqtt_publish_bytes), chunk_size);
165+
memfault_metrics_heartbeat_add(MEMFAULT_METRICS_KEY(mqtt_publish_count), 1);
166+
ESP_LOGD(TAG, "chunk[%d], len[%zu] published to %s", rv, chunk_size, s_topic_string);
167+
}
168+
169+
prv_close_client();
170+
return rv;
171+
}

0 commit comments

Comments
 (0)