From 0bd360fec3b5bf3af0286a1bba3e1faa8c7b8b1b Mon Sep 17 00:00:00 2001 From: Memfault Inc Date: Mon, 25 Nov 2024 22:03:47 +0000 Subject: [PATCH] Memfault Firmware SDK 1.18.0 (Build 11548) --- CHANGELOG.md | 37 +++- VERSION | 6 +- components/include/memfault/default_config.h | 12 + .../memfault/metrics/heartbeat_config.def | 4 + components/include/memfault/version.h | 4 +- components/metrics/src/memfault_metrics.c | 3 + components/panics/src/memfault_coredump.c | 14 ++ .../src/memfault_fault_handling_xtensa.c | 27 ++- examples/zephyr/qemu/README.md | 2 +- examples/zephyr/qemu/qemu-app/west.yml | 2 +- ports/esp_idf/memfault/Kconfig | 11 + .../memfault/common/memfault_fault_handler.c | 205 ++++++++++-------- .../config/memfault_esp_idf_port_config.h | 2 + scripts/mflt-build-id/README.md | 6 + scripts/mflt-build-id/pyproject.toml | 4 + .../src/mflt_build_id/__init__.py | 8 + tests/src/test_memfault_heartbeat_metrics.cpp | 4 +- .../test_memfault_heartbeat_metrics_debug.cpp | 4 + ...st_memfault_heartbeat_metrics_nocustom.cpp | 2 +- .../test_memfault_session_metrics_debug.cpp | 4 + 20 files changed, 253 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faa9f89d5..ec6046b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,31 @@ 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.18.0] - 2024-11-25 + +### 📈 Added + +- General: + + - Add a new built-in metric, `uptime_s`, which reports the total uptime of the + device in seconds. This metrics is enabled by default, and can be disabled + with `#define MEMFAULT_METRICS_UPTIME_ENABLE 0` in + `memfault_platform_config.h`. + +- Zephyr: + + - Update the [QEMU sample app](examples/zephyr/qemu) to use newly-released + Zephyr v4.0.0 🥳. + +- ESP-IDF: + + - Added support for dual-core coredumps on ESP32 and ESP32-S3. This feature is + enabled by default and can be disabled with the Kconfig option + `CONFIG_MEMFAULT_COREDUMP_CPU_COUNT=1`. Note: not all fault conditions will + cause both CPU cores to be captured in the coredump. The SDK will always + capture the core that triggered the fault, and if the non-faulting core is + available for capture, it will be included as well. + ## [1.17.0] - 2024-11-14 ### 📈 Added @@ -43,16 +68,16 @@ and this project adheres to # Before: mflt> test_log Raw log! - 2024-11-14T17:01:12Z|4284 I Info log! - 2024-11-14T17:01:12Z|4284 W Warning log! - 2024-11-14T17:01:12Z|4284 E Error log! + MFLT:[INFO] Info log! + MFLT:[WARN] Warning log! + MFLT:[ERRO] Error log! # After: mflt> test_log Raw log! - MFLT:[INFO] Info log! - MFLT:[WARN] Warning log! - MFLT:[ERRO] Error log! + 2024-11-14T17:01:12Z|4284 I Info log! + 2024-11-14T17:01:12Z|4284 W Warning log! + 2024-11-14T17:01:12Z|4284 E Error log! ``` - ESP-IDF: diff --git a/VERSION b/VERSION index 37fc29d83..4eed2fd7a 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ -BUILD ID: 11353 -GIT COMMIT: 767ed66f9e -VERSION: 1.17.0 +BUILD ID: 11548 +GIT COMMIT: 045729d525 +VERSION: 1.18.0 diff --git a/components/include/memfault/default_config.h b/components/include/memfault/default_config.h index 16517b41c..e1ebeecc2 100644 --- a/components/include/memfault/default_config.h +++ b/components/include/memfault/default_config.h @@ -84,6 +84,13 @@ extern "C" { #define MEMFAULT_COREDUMP_INCLUDE_BUILD_ID 1 #endif +//! Some architectures will support multiple cores. This is used by the +//! architecture-specific coredump handling code to determine how many +//! register sets to save. +#ifndef MEMFAULT_COREDUMP_CPU_COUNT + #define MEMFAULT_COREDUMP_CPU_COUNT 1 +#endif + //! Controls the truncation of the Build Id that is encoded in events //! //! The full Build Id hash is 20 bytes, but is truncated by default to save space. The @@ -347,6 +354,11 @@ extern "C" { #define MEMFAULT_METRICS_LOGS_ENABLE 1 #endif +//! Enable built in uptime metric tracking +#ifndef MEMFAULT_METRICS_UPTIME_ENABLE + #define MEMFAULT_METRICS_UPTIME_ENABLE 1 +#endif + //! Disable Metrics Sessions at compile time. This saves a small amount of //! memory but prevents the use of Metrics Sessions. #ifndef MEMFAULT_METRICS_SESSIONS_ENABLED diff --git a/components/include/memfault/metrics/heartbeat_config.def b/components/include/memfault/metrics/heartbeat_config.def index ef0a52be8..52725437d 100644 --- a/components/include/memfault/metrics/heartbeat_config.def +++ b/components/include/memfault/metrics/heartbeat_config.def @@ -42,3 +42,7 @@ MEMFAULT_METRICS_KEY_DEFINE_WITH_SCALE_VALUE(battery_soc_pct, kMemfaultMetricTyp MEMFAULT_METRICS_KEY_DEFINE(MemfaultSDKMetric_log_dropped_lines, kMemfaultMetricType_Unsigned) MEMFAULT_METRICS_KEY_DEFINE(MemfaultSDKMetric_log_recorded_lines, kMemfaultMetricType_Unsigned) #endif + +#if MEMFAULT_METRICS_UPTIME_ENABLE +MEMFAULT_METRICS_KEY_DEFINE(uptime_s, kMemfaultMetricType_Unsigned) +#endif diff --git a/components/include/memfault/version.h b/components/include/memfault/version.h index d1081ca36..50b66198a 100644 --- a/components/include/memfault/version.h +++ b/components/include/memfault/version.h @@ -20,8 +20,8 @@ typedef struct { } sMfltSdkVersion; #define MEMFAULT_SDK_VERSION \ - { .major = 1, .minor = 17, .patch = 0 } -#define MEMFAULT_SDK_VERSION_STR "1.17.0" + { .major = 1, .minor = 18, .patch = 0 } +#define MEMFAULT_SDK_VERSION_STR "1.18.0" #ifdef __cplusplus } diff --git a/components/metrics/src/memfault_metrics.c b/components/metrics/src/memfault_metrics.c index 06fba7e40..6324340be 100644 --- a/components/metrics/src/memfault_metrics.c +++ b/components/metrics/src/memfault_metrics.c @@ -555,6 +555,9 @@ static void prv_collect_builtin_data(void) { #if MEMFAULT_METRICS_LOGS_ENABLE prv_memfault_collect_log_metrics(); #endif +#if MEMFAULT_METRICS_UPTIME_ENABLE + MEMFAULT_METRIC_SET_UNSIGNED(uptime_s, memfault_platform_get_time_since_boot_ms() / 1000); +#endif } // Returns NULL if not a timer type or out of bounds index. diff --git a/components/panics/src/memfault_coredump.c b/components/panics/src/memfault_coredump.c index 23fc93218..4ce84b023 100644 --- a/components/panics/src/memfault_coredump.c +++ b/components/panics/src/memfault_coredump.c @@ -477,10 +477,24 @@ static bool prv_write_coredump_sections(const sMemfaultCoredumpSaveInfo *save_in const void *regs = save_info->regs; const size_t regs_size = save_info->regs_size; if (regs != NULL) { +#if MEMFAULT_COREDUMP_CPU_COUNT == 1 if (!prv_write_non_memory_block(kMfltCoredumpBlockType_CurrentRegisters, regs, regs_size, &write_ctx)) { return false; } +#else + // If we have multiple CPUs, we need to save the registers for each CPU. + // save_info->regs is an array of CPU0, CPU1, etc. registers. + for (size_t i = 0; i < MEMFAULT_COREDUMP_CPU_COUNT; i++) { + const size_t cpu_regs_size = regs_size / MEMFAULT_COREDUMP_CPU_COUNT; + const uint32_t *cpu_regs = (const uint32_t *)((const uintptr_t)regs + (i * cpu_regs_size)); + + if (!prv_write_non_memory_block(kMfltCoredumpBlockType_CurrentRegisters, cpu_regs, + cpu_regs_size, &write_ctx)) { + return false; + } + } +#endif } if (!prv_write_device_info_blocks(&write_ctx)) { diff --git a/components/panics/src/memfault_fault_handling_xtensa.c b/components/panics/src/memfault_fault_handling_xtensa.c index b5eae7f1a..a4b4d7d9f 100644 --- a/components/panics/src/memfault_fault_handling_xtensa.c +++ b/components/panics/src/memfault_fault_handling_xtensa.c @@ -99,15 +99,34 @@ MEMFAULT_NO_OPT void memfault_fault_handling_assert(void *pc, void *lr) { #error "Unsupported Xtensa platform. Please visit https://mflt.io/contact-support" #endif // !defined(ESP_PLATFORM) && defined(__ZEPHYR__) + #if MEMFAULT_COREDUMP_CPU_COUNT > 1 + #if defined(__ZEPHYR__) + #error "Dual-core support not yet implemented for Zephyr Xtensa" + #else + #include "esp_cpu.h" + + #endif + +static int prv_get_current_cpu_id(void) { + return esp_cpu_get_core_id(); +} + #endif // MEMFAULT_COREDUMP_CPU_COUNT == 1 + void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRebootReason reason) { + #if MEMFAULT_COREDUMP_CPU_COUNT == 1 + const sMfltRegState *current_cpu_regs = regs; + #else + const int cpu_id = prv_get_current_cpu_id(); + const sMfltRegState *current_cpu_regs = ®s[cpu_id]; + #endif if (s_crash_reason == kMfltRebootReason_Unknown) { // skip LR saving here. - prv_fault_handling_assert((void *)regs->pc, (void *)0, reason); + prv_fault_handling_assert((void *)current_cpu_regs->pc, (void *)0, reason); } sMemfaultCoredumpSaveInfo save_info = { .regs = regs, - .regs_size = sizeof(*regs), + .regs_size = sizeof(*regs) * MEMFAULT_COREDUMP_CPU_COUNT, .trace_reason = s_crash_reason, }; @@ -122,7 +141,7 @@ void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRebootReason rea // For the windowed ABI, a1 always holds the current "sp": // https://github.com/espressif/esp-idf/blob/v4.0/components/freertos/readme_xtensa.txt#L421-L428 const uint32_t windowed_abi_spill_size = 64; - const uint32_t sp_prior_to_exception = regs->a[1] - windowed_abi_spill_size; + const uint32_t sp_prior_to_exception = current_cpu_regs->a[1] - windowed_abi_spill_size; sCoredumpCrashInfo info = { .stack_address = (void *)sp_prior_to_exception, @@ -139,7 +158,7 @@ void memfault_fault_handler(const sMfltRegState *regs, eMemfaultRebootReason rea size_t memfault_coredump_storage_compute_size_required(void) { // actual values don't matter since we are just computing the size - sMfltRegState core_regs = { 0 }; + sMfltRegState core_regs[MEMFAULT_COREDUMP_CPU_COUNT] = { 0 }; sMemfaultCoredumpSaveInfo save_info = { .regs = &core_regs, .regs_size = sizeof(core_regs), diff --git a/examples/zephyr/qemu/README.md b/examples/zephyr/qemu/README.md index abb28d315..c8a3fdbba 100644 --- a/examples/zephyr/qemu/README.md +++ b/examples/zephyr/qemu/README.md @@ -22,7 +22,7 @@ the following commands to test the application: ❯ west build qemu-app ❯ west build --target run -*** Booting Zephyr OS build zephyr-v3.2.0 *** +*** Booting Zephyr OS build zephyr-v4.0.0 *** [00:00:00.000,000] mflt: GNU Build ID: 4ffb5879ed5923582035133086015bbf65504364 [00:00:00.000,000] main: 👋 Memfault Demo App! Board qemu_cortex_m3 diff --git a/examples/zephyr/qemu/qemu-app/west.yml b/examples/zephyr/qemu/qemu-app/west.yml index b75ede41e..ec0485028 100644 --- a/examples/zephyr/qemu/qemu-app/west.yml +++ b/examples/zephyr/qemu/qemu-app/west.yml @@ -13,7 +13,7 @@ manifest: projects: - name: zephyr remote: zephyrproject-rtos - revision: v3.7.0 + revision: v4.0.0 import: # Limit the Zephyr modules to the required set name-allowlist: diff --git a/ports/esp_idf/memfault/Kconfig b/ports/esp_idf/memfault/Kconfig index 337b77de3..4b690f5a4 100644 --- a/ports/esp_idf/memfault/Kconfig +++ b/ports/esp_idf/memfault/Kconfig @@ -103,6 +103,17 @@ endif 'memfault_platform_coredump_storage_get_info()' function to return the threshold value set here as the size of the partition.. + config MEMFAULT_COREDUMP_CPU_COUNT + int "Number of CPU cores to include in coredumps" + default SOC_CPU_CORES_NUM + # Symbolic values in the range are not supported by + # confgen.py/esp-idf-kconfig until later versions (esp-idf 5+). Hard + # code to a max of 2. + range 1 2 + help + The number of CPU cores to include in coredumps. By default, all + cores are included. + config MEMFAULT_AUTOMATIC_INIT bool "[DEPRECATED] Automatically initialize the SDK when the system is booted" default n diff --git a/ports/esp_idf/memfault/common/memfault_fault_handler.c b/ports/esp_idf/memfault/common/memfault_fault_handler.c index 972be858e..e37da756f 100644 --- a/ports/esp_idf/memfault/common/memfault_fault_handler.c +++ b/ports/esp_idf/memfault/common/memfault_fault_handler.c @@ -3,9 +3,10 @@ //! Copyright (c) Memfault, Inc. //! See LICENSE for details //! -//! Hooks +//! Fault handler hook into ESP-IDF's fault handling system. #include +#include #include "esp_idf_version.h" // keep the esp_idf_version.h include above for version-specific support @@ -75,75 +76,20 @@ void memfault_fault_handling_assert_extra(void *pc, void *lr, sMemfaultAssertInf abort(); } -//! Invoked when a panic is detected in the esp-idf when coredumps are enabled -//! -//! @note This requires the following sdkconfig options: -//! CONFIG_ESP32_ENABLE_COREDUMP=y -//! CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y -//! -//! @note This is a drop in replacement for the pre-existing flash coredump handler. -//! The default implementation is replaced by leveraging GCCs --wrap feature -//! https://github.com/espressif/esp-idf/blob/v4.0/components/esp32/panic.c#L620 -//! -//! @note The signature changed in esp-idf v5.3.0, back ported to v5.1.4 + v5.2.2. -#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 2)) || \ - ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 4)) && \ - (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0))) -void __wrap_esp_core_dump_write(panic_info_t *info) { -#else // ESP_IDF_VERSION -void __wrap_esp_core_dump_to_flash(panic_info_t *info) { -#endif // ESP_IDF_VERSION +//! Convert the esp-idf arch-specific frame info into the Memfault format +static sMfltRegState prv_esp_frame_info_to_memfault(const void *frame) { #ifdef __XTENSA__ - XtExcFrame *fp = (void *)info->frame; -#elif __riscv - RvExcFrame *fp = (void *)info->frame; -#endif // __XTENSA__ + const XtExcFrame *fp = frame; - eMemfaultRebootReason reason; - - /* - * To better classify the exception, we need panic_info_t - */ - switch (info->exception) { - case PANIC_EXCEPTION_DEBUG: - reason = kMfltRebootReason_DebuggerHalted; - break; - case PANIC_EXCEPTION_IWDT: - reason = kMfltRebootReason_SoftwareWatchdog; - break; - default: - // Default to HardFault until other reasons are handled - reason = kMfltRebootReason_HardFault; - break; - } - -#ifdef __XTENSA__ // Clear "EXCM" bit so we don't have to correct PS.OWB to get a good unwind This will also be // more reflective of the state of the register prior to the "panicHandler" being invoked const uint32_t corrected_ps = fp->ps & ~(PS_EXCM_MASK); - sMfltRegState regs = { + sMfltRegState reg = { .collection_type = (uint32_t)kMemfaultEsp32RegCollectionType_ActiveWindow, .pc = fp->pc, .ps = corrected_ps, - .a = { - fp->a0, - fp->a1, - fp->a2, - fp->a3, - fp->a4, - fp->a5, - fp->a6, - fp->a7, - fp->a8, - fp->a9, - fp->a10, - fp->a11, - fp->a12, - fp->a13, - fp->a14, - fp->a15, - }, + .sar = fp->sar, // the below registers are not available on the esp32s2; leave them zeroed // in the coredump @@ -156,36 +102,20 @@ void __wrap_esp_core_dump_to_flash(panic_info_t *info) { .excvaddr = fp->excvaddr, }; - // If enabled, check if exception was triggered by stackoverflow type - #if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) - /* - * See Xtensa ISA Debug Cause Register section: - * https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf#_OPENTOPIC_TOC_PROCESSING_d61e48262 - */ - // Mask to select bits indicating a data breakpoint/watchpoint - #define DBREAK_EXCEPTION_MASK (1 << 2) - - #define _WATCHPOINT_VAL_SHIFT (8) - #define _WATCHPOINT_VAL_MASK (0xF << _WATCHPOINT_VAL_SHIFT) - // Extracts DBNUM bits to determine watchpoint that triggered exception - #define WATCHPOINT_VAL_GET(reg) ((reg & _WATCHPOINT_VAL_MASK) >> _WATCHPOINT_VAL_SHIFT) - // Watchpoint to detect stack overflow - #define END_OF_STACK_WATCHPOINT_VAL (SOC_CPU_WATCHPOINTS_NUM - 1) + // Bulk copy the general registers. This saves a substantial amount of code + // size compared to copying each register individually (~500 bytes). + MEMFAULT_STATIC_ASSERT( + sizeof(reg.a) == offsetof(XtExcFrame, a15) + sizeof(fp->a15) - offsetof(XtExcFrame, a0), + "register size mismatch"); + memcpy(®.a, &fp->a0, sizeof(reg.a)); - if (info->exception == PANIC_EXCEPTION_DEBUG) { - // Read debugcause register into debug_cause local var - int debug_cause; - asm("rsr.debugcause %0" : "=r"(debug_cause)); + return reg; - // Check that DBREAK bit is set and that stack overflow watchpoint was the source - if ((debug_cause & DBREAK_EXCEPTION_MASK) && - (WATCHPOINT_VAL_GET(debug_cause) == END_OF_STACK_WATCHPOINT_VAL)) { - reason = kMfltRebootReason_StackOverflow; - } - } - #endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) #elif __riscv - sMfltRegState regs = { + + const RvExcFrame *fp = frame; + + return (sMfltRegState){ .mepc = fp->mepc, .ra = fp->ra, .sp = fp->sp, @@ -231,8 +161,105 @@ void __wrap_esp_core_dump_to_flash(panic_info_t *info) { .mhartid = fp->mhartid, }; #endif // __XTENSA__ +} + +//! Invoked when a panic is detected in the esp-idf when coredumps are enabled +//! +//! @note This requires the following sdkconfig options: +//! CONFIG_ESP32_ENABLE_COREDUMP=y +//! CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +//! +//! @note This is a drop in replacement for the pre-existing flash coredump handler. +//! The default implementation is replaced by leveraging GCCs --wrap feature +//! https://github.com/espressif/esp-idf/blob/v4.0/components/esp32/panic.c#L620 +//! +//! @note The signature changed in esp-idf v5.3.0, back ported to v5.1.4 + v5.2.2. +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 2)) || \ + ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 4)) && \ + (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0))) +void __wrap_esp_core_dump_write(panic_info_t *info) { +#else // ESP_IDF_VERSION +void __wrap_esp_core_dump_to_flash(panic_info_t *info) { +#endif // ESP_IDF_VERSION + eMemfaultRebootReason reason; + + /* + * To better classify the exception, we need panic_info_t + */ + switch (info->exception) { + case PANIC_EXCEPTION_DEBUG: + reason = kMfltRebootReason_DebuggerHalted; + break; + case PANIC_EXCEPTION_IWDT: + reason = kMfltRebootReason_SoftwareWatchdog; + break; + default: + // Default to HardFault until other reasons are handled + reason = kMfltRebootReason_HardFault; + break; + } + + sMfltRegState regs[MEMFAULT_COREDUMP_CPU_COUNT] = { 0 }; + +#ifdef __XTENSA__ + // We can get core_id from info->core or esp_cpu_get_core_id(). + int core_id = info->core; + + regs[core_id] = prv_esp_frame_info_to_memfault(info->frame); + + #if MEMFAULT_COREDUMP_CPU_COUNT == 2 + #if !(CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3) + #error "Dual core support unavailable for this platform, please contact Memfault support" + #endif + // If available, the other core's registers are in the ESP-IDF global g_exc_frames. We only + // support dual-core SOCs currently. + int other_core_id = core_id ^ 1; + if (g_exc_frames[other_core_id] != NULL) { + regs[other_core_id] = prv_esp_frame_info_to_memfault(g_exc_frames[other_core_id]); + } else { + // If the other core's frame is not available, we can't collect a coredump + // for it. Mark it with the correct format for loading into Memfault, but + // leave all other data blank. + regs[other_core_id] = (sMfltRegState){ + .collection_type = (uint32_t)kMemfaultEsp32RegCollectionType_ActiveWindow, + }; + } + + #endif // MEMFAULT_COREDUMP_CPU_COUNT == 2 + + // If enabled, check if exception was triggered by stackoverflow type + #if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) + /* + * See Xtensa ISA Debug Cause Register section: + * https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf#_OPENTOPIC_TOC_PROCESSING_d61e48262 + */ + // Mask to select bits indicating a data breakpoint/watchpoint + #define DBREAK_EXCEPTION_MASK (1 << 2) + + #define _WATCHPOINT_VAL_SHIFT (8) + #define _WATCHPOINT_VAL_MASK (0xF << _WATCHPOINT_VAL_SHIFT) + // Extracts DBNUM bits to determine watchpoint that triggered exception + #define WATCHPOINT_VAL_GET(reg) ((reg & _WATCHPOINT_VAL_MASK) >> _WATCHPOINT_VAL_SHIFT) + // Watchpoint to detect stack overflow + #define END_OF_STACK_WATCHPOINT_VAL (SOC_CPU_WATCHPOINTS_NUM - 1) + + if (info->exception == PANIC_EXCEPTION_DEBUG) { + // Read debugcause register into debug_cause local var + int debug_cause; + asm("rsr.debugcause %0" : "=r"(debug_cause)); + + // Check that DBREAK bit is set and that stack overflow watchpoint was the source + if ((debug_cause & DBREAK_EXCEPTION_MASK) && + (WATCHPOINT_VAL_GET(debug_cause) == END_OF_STACK_WATCHPOINT_VAL)) { + reason = kMfltRebootReason_StackOverflow; + } + } + #endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) +#elif __riscv + regs[0] = prv_esp_frame_info_to_memfault(info->frame); +#endif // __XTENSA__ - memfault_fault_handler(®s, reason); + memfault_fault_handler(regs, reason); } // Ensure the substituted function signature matches the original function diff --git a/ports/esp_idf/memfault/config/memfault_esp_idf_port_config.h b/ports/esp_idf/memfault/config/memfault_esp_idf_port_config.h index 0fd9d8a56..28f57ec6b 100644 --- a/ports/esp_idf/memfault/config/memfault_esp_idf_port_config.h +++ b/ports/esp_idf/memfault/config/memfault_esp_idf_port_config.h @@ -89,6 +89,8 @@ extern "C" { #define MEMFAULT_METRICS_LOGS_ENABLE 0 #endif +#define MEMFAULT_COREDUMP_CPU_COUNT CONFIG_MEMFAULT_COREDUMP_CPU_COUNT + // Pick up any user configuration overrides. This should be kept at the bottom // of this file #if CONFIG_MEMFAULT_USER_CONFIG_SILENT_FAIL diff --git a/scripts/mflt-build-id/README.md b/scripts/mflt-build-id/README.md index eb9755664..5c8a0842a 100644 --- a/scripts/mflt-build-id/README.md +++ b/scripts/mflt-build-id/README.md @@ -48,6 +48,12 @@ options: ## Changes +### [1.1.1] - 2024-11-14 + +- Fix `mflt_build_id` script to be installed correctly again (regression in + 1.1.0) +- Add an alternate name `mflt-build-id` for the `mflt_build_id` script + ### [1.1.0] - 2024-11-07 - Remove support for Python 3.6 + 3.7 diff --git a/scripts/mflt-build-id/pyproject.toml b/scripts/mflt-build-id/pyproject.toml index c7e7fba1a..c39039908 100644 --- a/scripts/mflt-build-id/pyproject.toml +++ b/scripts/mflt-build-id/pyproject.toml @@ -6,6 +6,10 @@ dependencies = [ ] requires-python = ">=3.8,<4.0" +[project.scripts] +mflt_build_id = 'mflt_build_id:main' +mflt-build-id = 'mflt_build_id:main' + [tool.uv] dev-dependencies = [ "pytest >=6", diff --git a/scripts/mflt-build-id/src/mflt_build_id/__init__.py b/scripts/mflt-build-id/src/mflt_build_id/__init__.py index 1d38dbb65..1b9b95c9b 100644 --- a/scripts/mflt-build-id/src/mflt_build_id/__init__.py +++ b/scripts/mflt-build-id/src/mflt_build_id/__init__.py @@ -32,6 +32,7 @@ import argparse import hashlib +import importlib.metadata import struct import zlib from collections import defaultdict @@ -482,6 +483,13 @@ def main() -> None: parser.add_argument("--dump", nargs="?", const=7, type=int) parser.add_argument("--crc", action="store") parser.add_argument("--sha1", action="store") + # get version from importlib.metadata + try: + version = importlib.metadata.version("mflt-build-id") + except importlib.metadata.PackageNotFoundError: + # script is being used without installation, provide a fall back version + version = "0.0.0" + parser.add_argument("--version", action="version", version=f"%(prog)s {version}") args = parser.parse_args() diff --git a/tests/src/test_memfault_heartbeat_metrics.cpp b/tests/src/test_memfault_heartbeat_metrics.cpp index b2a65df58..de7fd7678 100644 --- a/tests/src/test_memfault_heartbeat_metrics.cpp +++ b/tests/src/test_memfault_heartbeat_metrics.cpp @@ -101,10 +101,12 @@ TEST_GROUP(MemfaultHeartbeatMetrics){ const size_t num_scale_value_metrics = 1; // 2 log metrics const size_t num_log_metrics = 2; + // 1 uptime metric + const size_t num_uptime_metrics = 1; // We should test all the types of available metrics so if this // fails it means there's a new type we aren't yet covering - LONGS_EQUAL(kMemfaultMetricType_NumTypes + num_memfault_sdk_metrics + num_scale_value_metrics + num_log_metrics, + LONGS_EQUAL(kMemfaultMetricType_NumTypes + num_memfault_sdk_metrics + num_scale_value_metrics + num_log_metrics + num_uptime_metrics, memfault_metrics_heartbeat_get_num_metrics()); } void teardown() { diff --git a/tests/src/test_memfault_heartbeat_metrics_debug.cpp b/tests/src/test_memfault_heartbeat_metrics_debug.cpp index 35ff8b9a8..9d8234092 100644 --- a/tests/src/test_memfault_heartbeat_metrics_debug.cpp +++ b/tests/src/test_memfault_heartbeat_metrics_debug.cpp @@ -91,6 +91,7 @@ TEST(MemfaultHeartbeatMetricsDebug, Test_DebugPrints) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: null", " test_key_signed: null", " test_key_timer: 0", @@ -115,6 +116,7 @@ TEST(MemfaultHeartbeatMetricsDebug, Test_DebugPrints) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: 1", " MemfaultSDKMetric_log_recorded_lines: 1", + " uptime_s: 5", " test_key_unsigned: 1234", " test_key_signed: -100", " test_key_timer: 5000", @@ -138,6 +140,7 @@ TEST(MemfaultHeartbeatMetricsDebug, Test_DebugPrints) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: null", " test_key_signed: null", " test_key_timer: 0", @@ -159,6 +162,7 @@ TEST(MemfaultHeartbeatMetricsDebug, Test_DebugPrints) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: 123", " test_key_signed: null", " test_key_timer: 0", diff --git a/tests/src/test_memfault_heartbeat_metrics_nocustom.cpp b/tests/src/test_memfault_heartbeat_metrics_nocustom.cpp index 827a38243..6592d874a 100644 --- a/tests/src/test_memfault_heartbeat_metrics_nocustom.cpp +++ b/tests/src/test_memfault_heartbeat_metrics_nocustom.cpp @@ -57,7 +57,7 @@ TEST_GROUP(MemfaultHeartbeatMetricsNoCustom){ //! Confirm compilation and metric count is correct TEST(MemfaultHeartbeatMetricsNoCustom, Test_CompileAndMetricCount) { size_t num_metrics = memfault_metrics_heartbeat_get_num_metrics(); - LONGS_EQUAL(6, num_metrics); + LONGS_EQUAL(7, num_metrics); } //! Confirm we can boot without any issues (eg writing to unpopulated key diff --git a/tests/src/test_memfault_session_metrics_debug.cpp b/tests/src/test_memfault_session_metrics_debug.cpp index e6877c46e..98e94de3e 100644 --- a/tests/src/test_memfault_session_metrics_debug.cpp +++ b/tests/src/test_memfault_session_metrics_debug.cpp @@ -104,6 +104,7 @@ TEST(MemfaultSessionMetricsDebug, Test_HeartbeatResetState) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: null", " test_key_signed: null", " test_key_timer: 0", @@ -135,6 +136,7 @@ TEST(MemfaultSessionMetricsDebug, Test_HeartbeatCollectionUpdateAndReset) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: 1234", " test_key_signed: -100", " test_key_timer: 5000", @@ -164,6 +166,7 @@ TEST(MemfaultSessionMetricsDebug, Test_HeartbeatCollectionUpdateAndReset) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: null", " test_key_signed: null", " test_key_timer: 0", @@ -185,6 +188,7 @@ TEST(MemfaultSessionMetricsDebug, Test_HeartbeatUpdateAdd) { " operational_crashfree_hours: null", " MemfaultSDKMetric_log_dropped_lines: null", " MemfaultSDKMetric_log_recorded_lines: null", + " uptime_s: null", " test_key_unsigned: 123", " test_key_signed: null", " test_key_timer: 0",