Skip to content

Commit

Permalink
Memfault Firmware SDK 1.9.2 (Build 8056)
Browse files Browse the repository at this point in the history
  • Loading branch information
Memfault Inc committed May 29, 2024
1 parent 130dc3a commit 9d3ca21
Show file tree
Hide file tree
Showing 23 changed files with 286 additions and 18 deletions.
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,59 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.9.2] - 2024-05-29

### :chart_with_upwards_trend: Improvements

- ESP-IDF:

- Fix CLI command, `memfault_ota_check`, to return 0 to the console component
when an update is available.

- Add the temperature metric `cpu_temp` which is measured using an internal
temperature sensor that many ESP32 boards have built-in. This metric is
collected by default with the Kconfig `CONFIG_MEMFAULT_METRICS_CPU_TEMP=y`.

- Enable recording vprintf data into the Memfault log buffer through a vprintf
hook. Users can call `memfault_esp_port_vprintf_log_hook()` from their
vprintf handler so they can use both their vprintf handler and record logs
into Memfault's log buffer. To use this feature, set
`CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK=n`.

- Fix a case where `esp_http_client_cleanup()` was not called in certain
scenarios (for example, if the access point is connected, but there is no
outside internet access), which resulted in a memory leak. Thanks to
@mykmelez for providing the fix in
[#71](https://github.com/memfault/memfault-firmware-sdk/pull/71) 🎉!

- Zephyr:

- Fix a bug in `memfault_zephyr_port_post_data_return_size()` where a positive
value could be returned in the event of a failure instead of a negative
value. This would result in `mflt post_chunks` returning a successful post
message even though there was a failure such as a DNS lookup failure.

- Add the temperature metric `cpu_temp` which is measured using an internal
temperature sensor that some Zephyr boards have. Similar to ESP-IDF, this
metric is collected by default with the Kconfig
`CONFIG_MEMFAULT_METRICS_CPU_TEMP=y`, but the board must have the device
tree node `die-temp0` for this option to be used.

- Add an example for collecting thread stack usage metrics when the thread
handles are not accessible in the desired scope. Users can leverage the
Zephyr routine `k_thread_foreach()` to register a callback that will be
called with each thread's `k_thread` handle. In the callback, users can read
the stack usage via the handle and set their metrics.

### :boom: Breaking Changes

- Zephyr:

- Change the error return value for
`memfault_zephyr_port_http_upload_sdk_data()` to a negative value instead
of 1. This change aligns with the error return value for the other Zephyr
HTTP client APIs, and simplifies logic in the HTTP client.

## [1.9.1] - 2024-05-21

### :chart_with_upwards_trend: Improvements
Expand Down
6 changes: 3 additions & 3 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
BUILD ID: 7915
GIT COMMIT: 435dc7c1d8
VERSION: 1.9.1
BUILD ID: 8056
GIT COMMIT: 398b8ca5a7
VERSION: 1.9.2
4 changes: 2 additions & 2 deletions components/include/memfault/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ typedef struct {
uint8_t patch;
} sMfltSdkVersion;

#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 9, .patch = 1 }
#define MEMFAULT_SDK_VERSION_STR "1.9.1"
#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 9, .patch = 2 }
#define MEMFAULT_SDK_VERSION_STR "1.9.2"

#ifdef __cplusplus
}
Expand Down
32 changes: 32 additions & 0 deletions examples/esp32/apps/memfault_demo_app/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,12 +388,44 @@ void esp_heap_trace_alloc_hook(void *ptr, size_t size, uint32_t caps) {
}
#endif

#if !defined(CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK)
// Demonstrate a custom vprintf hook that prefixes all log messages with
// "[IDF]", before invoking the Memfault log hook, and then printing to stdout.
static int prv_vprintf_hook(const char *fmt, va_list args) {
char *fmt_annotated;
int rv = asprintf(&fmt_annotated, "[IDF] %s", fmt);
if ((rv < 0) || (fmt_annotated == NULL)) {
return -1;
}

#if defined(CONFIG_MEMFAULT)
(void)memfault_esp_port_vprintf_log_hook(fmt_annotated, args);
#endif

rv = vprintf(fmt_annotated, args);

free(fmt_annotated);

return rv;
}

#endif

// This task started by cpu_start.c::start_cpu0_default().
void app_main() {
#if defined(CONFIG_MEMFAULT)
#if !defined(CONFIG_MEMFAULT_AUTOMATIC_INIT)
memfault_boot();
#endif

#if !defined(CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK)
esp_log_set_vprintf(prv_vprintf_hook);
ESP_LOGD("main", "debug log 🕵️");
ESP_LOGI("main", "info log 🐢");
ESP_LOGW("main", "warning log ⚠️");
ESP_LOGE("main", "error log 🔥");
#endif

memfault_device_info_dump();

g_unaligned_buffer = &s_my_buf[1];
Expand Down
2 changes: 2 additions & 0 deletions examples/zephyr/qemu/qemu-app/boards/nucleo_f756zg.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_ADC=y
CONFIG_SENSOR=y
16 changes: 16 additions & 0 deletions examples/zephyr/qemu/qemu-app/boards/nucleo_f756zg.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/ {
aliases {
die-temp0 = &die_temp;
};
};

&die_temp {
status = "okay";
};

&adc1 {
pinctrl-0 = <&adc1_in0_pa0>;
pinctrl-names = "default";
st,adc-prescaler = <4>;
status = "okay";
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ MEMFAULT_METRICS_KEY_DEFINE(MainStack_MinBytesFree, kMemfaultMetricType_Unsigned
// This example metric demonstrates a permille integer with a range of 0-1000 to be translated into
// a percentage 0.0-100.0%
MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(main_thread_cpu_time_permille, kMemfaultMetricType_Unsigned, 10)
MEMFAULT_METRICS_KEY_DEFINE(shell_uart_stack_free_bytes, kMemfaultMetricType_Unsigned)
24 changes: 24 additions & 0 deletions examples/zephyr/qemu/qemu-app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,35 @@ static int prv_run_example_memory_metrics(const struct shell *shell, size_t argc
SHELL_CMD_REGISTER(memory_metrics, NULL, "Collects runtime memory metrics from application",
prv_run_example_memory_metrics);

//! Callback to collect stack usage for specific threads
static void prv_collect_thread_stack_usage_cb(const struct k_thread *thread, void *user_data) {
// table mapping thread names to metric IDs
static const struct {
const char *name;
MemfaultMetricId id;
} threads[] = {
{ "shell_uart", MEMFAULT_METRICS_KEY(shell_uart_stack_free_bytes) },
};

// scan for a matching thread name
for (size_t i = 0; i < ARRAY_SIZE(threads); i++) {
if (strncmp(thread->name, threads[i].name, CONFIG_THREAD_MAX_NAME_LEN) == 0) {
// get the stack usage and record in the matching metric id
size_t stack_free_bytes;
k_thread_stack_space_get(thread, &stack_free_bytes);
memfault_metrics_heartbeat_set_unsigned(threads[i].id, stack_free_bytes);
}
}
}

// Override function to collect the app metric MainStack_MinBytesFree
// and print current metric values
void memfault_metrics_heartbeat_collect_data(void) {
prv_collect_main_thread_stack_free();
prv_collect_main_thread_run_stats();

k_thread_foreach(prv_collect_thread_stack_usage_cb, NULL);

memfault_metrics_heartbeat_debug_print();
}

Expand Down
1 change: 1 addition & 0 deletions examples/zephyr/qemu/qemu-app/west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ manifest:
name-allowlist:
- cmsis
- picolibc
- hal_stm32

- name: memfault-firmware-sdk
path: modules/lib/memfault-firmware-sdk
Expand Down
4 changes: 4 additions & 0 deletions examples/zephyr/stm32l4_disco/apps/memfault_demo_app/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ CONFIG_MEMFAULT_LOGGING_RAM_SIZE=512

CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_HEAP_MEM_POOL_SIZE=1024

# Currently not supported on older Zephyr, so explicitly disable until this
# sample is updated
CONFIG_MEMFAULT_METRICS_CPU_TEMP=n
7 changes: 7 additions & 0 deletions ports/esp_idf/memfault/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ endif
Collects the core metric for connectivity_connected_time based on
WiFi connection state.

config MEMFAULT_METRICS_CPU_TEMP
bool "Enable collection of a temperature metric"
default y
depends on !IDF_TARGET_ESP32
help
Collects a Memfault metric for the CPU die temperature.

config MEMFAULT_ESP_HEAP_METRICS
bool "Collect basic heap metrics"
default y
Expand Down
14 changes: 9 additions & 5 deletions ports/esp_idf/memfault/common/memfault_platform_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,7 @@ void memfault_unlock(void) {
xSemaphoreGiveRecursive(s_memfault_lock);
}

#if defined(CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK)
// The esp32 uses vprintf() for dumping to console. The libc implementation used requires a lot of
// stack space. We therefore prevent this function from being inlined so the log_buf allocation
// does not wind up in that path.
__attribute__((noinline)) static int prv_copy_log_to_mflt_buffer(const char *fmt, va_list args) {
int memfault_esp_port_vprintf_log_hook(const char *fmt, va_list args) {
// copy result into memfault log buffer collected as part of a coredump
char log_buf[80];
const size_t available_space = sizeof(log_buf);
Expand All @@ -145,6 +141,14 @@ __attribute__((noinline)) static int prv_copy_log_to_mflt_buffer(const char *fmt
return rv;
}

#if defined(CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK)
// The esp32 uses vprintf() for dumping to console. The libc implementation used requires a lot of
// stack space. We therefore prevent this function from being inlined so the log_buf allocation
// in `memfault_esp_port_vprintf_log_hook()` does not wind up in that path.
__attribute__((noinline)) static int prv_copy_log_to_mflt_buffer(const char *fmt, va_list args) {
return memfault_esp_port_vprintf_log_hook(fmt, args);
}

static int prv_memfault_log_wrapper(const char *fmt, va_list args) {
prv_copy_log_to_mflt_buffer(fmt, args);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ static int prv_memfault_ota(sMemfaultOtaUserCtx *ctx) {
MEMFAULT_LOG_ERROR("OTA update failed, rv=%d", rv);
}

return rv;
// Should return 0 on success. Change update available rv to 0
return (rv == 1) ? 0 : rv;
}

static int prv_memfault_ota_perform(int argc, char **argv) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,7 @@ sMfltHttpClient *memfault_platform_http_client_create(void) {

int memfault_platform_http_client_destroy(sMfltHttpClient *_client) {
esp_http_client_handle_t client = (esp_http_client_handle_t)_client;
esp_err_t err = esp_http_client_close(client);
if (err == ESP_OK) {
err = esp_http_client_cleanup(client);
}
esp_err_t err = esp_http_client_cleanup(client);
if (err == ESP_OK) {
return 0;
}
Expand Down
49 changes: 49 additions & 0 deletions ports/esp_idf/memfault/common/memfault_platform_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "esp_timer.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "memfault/core/debug_log.h"
#include "memfault/core/math.h"
#include "memfault/core/reboot_tracking.h"
#include "memfault/esp_port/metrics.h"
Expand All @@ -39,6 +40,11 @@
#include "memfault/ports/mbedtls/metrics.h"
#endif // CONFIG_MEMFAULT_MBEDTLS_METRICS

#if defined(CONFIG_MEMFAULT_METRICS_CPU_TEMP)
#include "driver/temperature_sensor.h"
#include "soc/clk_tree_defs.h"
#endif // CONFIG_MEMFAULT_METRICS_CPU_TEMP

#if defined(CONFIG_MEMFAULT_ESP_WIFI_METRICS)

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
Expand Down Expand Up @@ -209,6 +215,45 @@ bool memfault_platform_metrics_timer_boot(uint32_t period_sec,
return true;
}

#if defined(CONFIG_MEMFAULT_METRICS_CPU_TEMP)
static void prv_collect_temperature_metric(void) {
// See documentation here:
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/temp_sensor.html
static temperature_sensor_handle_t temp_handle = NULL;
temperature_sensor_config_t temp_sensor = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
esp_err_t err;

do {
if (!temp_handle) {
err = temperature_sensor_install(&temp_sensor, &temp_handle);
if (err != ESP_OK) {
MEMFAULT_LOG_ERROR("Failed to install temperature sensor: %d", err);
break;
}
}
// Enable temperature sensor
err = temperature_sensor_enable(temp_handle);
if (err != ESP_OK) {
MEMFAULT_LOG_ERROR("Failed to enable temperature sensor: %d", err);
break;
}
// Get converted sensor data
float tsens_out;
err = temperature_sensor_get_celsius(temp_handle, &tsens_out);
if (err != ESP_OK) {
MEMFAULT_LOG_ERROR("Failed to get temperature sensor data: %d", err);
break;
} else {
MEMFAULT_LOG_INFO("Temperature: %.02fC", tsens_out);
MEMFAULT_METRIC_SET_SIGNED(cpu_temp, (int32_t)(tsens_out * 10.0f));
}
} while (0);

// Disable the temperature sensor if it is not needed and save the power
(void)temperature_sensor_disable(temp_handle);
}
#endif // CONFIG_MEMFAULT_METRICS_CPU_TEMP

void memfault_metrics_heartbeat_collect_sdk_data(void) {
#if defined(CONFIG_MEMFAULT_LWIP_METRICS)
memfault_lwip_heartbeat_collect_data();
Expand All @@ -233,6 +278,10 @@ void memfault_metrics_heartbeat_collect_sdk_data(void) {
#if defined(CONFIG_MEMFAULT_ESP_HEAP_METRICS)
prv_record_heap_metrics();
#endif // CONFIG_MEMFAULT_ESP_HEAP_METRICS

#if defined(CONFIG_MEMFAULT_METRICS_CPU_TEMP)
prv_collect_temperature_metric();
#endif // CONFIG_MEMFAULT_METRICS_CPU_TEMP
}

#if defined(CONFIG_MEMFAULT_PLATFORM_METRICS_CONNECTIVITY_BOOT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ MEMFAULT_METRICS_KEY_DEFINE(wifi_disconnect_count, kMemfaultMetricType_Unsigned)
MEMFAULT_METRICS_STRING_KEY_DEFINE(wifi_ap_oui, sizeof("00:00:00") - 1)
#endif // CONFIG_MEMFAULT_ESP_WIFI_METRICS

#if defined(CONFIG_MEMFAULT_METRICS_CPU_TEMP)
// One decimal place of precision
MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(cpu_temp, kMemfaultMetricType_Signed, 10)
#endif // CONFIG_MEMFAULT_METRICS_CPU_TEMP

#if defined(CONFIG_MEMFAULT_USER_CONFIG_SILENT_FAIL)

#if __has_include("memfault_metrics_heartbeat_config.def")
Expand Down
15 changes: 15 additions & 0 deletions ports/esp_idf/memfault/include/memfault/esp_port/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! Copyright (c) Memfault, Inc.
//! See License.txt for details

#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>

Expand Down Expand Up @@ -40,6 +41,20 @@ bool memfault_esp_port_data_available(void);
//! @return true if the buffer was filled, false otherwise
bool memfault_esp_port_get_chunk(void *buf, size_t *buf_len);

//! Record vprintf log lines into the Memfault log buffer.
//!
//! Normally installed with esp_log_set_vprintf() as part of the Memfault
//! integration memfault_boot() function, this function is exposed if the
//! esp_log_set_vprintf() call is disabled with
//! CONFIG_MEMFAULT_LOG_USE_VPRINTF_HOOK=n, and the user still wants to record
//! logs into the Memfault logging system.
//!
//! @param[in] fmt Format string
//! @param[in] args Variable argument list
//!
//! @return 0 on success, non-zero error code on failure
int memfault_esp_port_vprintf_log_hook(const char *fmt, va_list args);

//! Initializes the Memfault system, and should be called one time by the application during boot.
void memfault_boot(void);

Expand Down
8 changes: 8 additions & 0 deletions ports/zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,14 @@ config MEMFAULT_FS_BYTES_FREE_VFS_PATH
The path to the virtual filesystem mount point to collect free space
metrics for, omitting the leading '/'.

config MEMFAULT_METRICS_CPU_TEMP
bool "Enable collection of CPU temperature metrics"
default y
depends on ADC && SENSOR && ("$(dt_alias_enabled,die-temp0)" != "")
help
Memfault CPU temperature metric component. Requires a `die-temp0`
device tree node.

config MEMFAULT_METRICS_SYNC_SUCCESS
bool "Enable collection of sync success metrics"
default y
Expand Down
Loading

0 comments on commit 9d3ca21

Please sign in to comment.