Skip to content

Commit 3d51c80

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.6.0 (Build 5464)
1 parent fa74810 commit 3d51c80

File tree

70 files changed

+1363
-238
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1363
-238
lines changed

CHANGELOG.md

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

3+
## [1.6.0] - 2024-01-09
4+
5+
### :chart_with_upwards_trend: Improvements
6+
7+
- ESP-IDF:
8+
9+
- In the [ESP32 example app](examples/esp32), disable the shell history cache
10+
for the FatFS shell command handler, which saves some ~20kB of heap memory.
11+
12+
- Also in the [ESP32 example app](examples/esp32), add a new built-in metric
13+
`sync_successful` which is set to `1` when a successful Memfault OTA
14+
check-in is performed. Primarily added for demonstration purposes for the
15+
metric. See more information about Memfault Core Metrics
16+
[here](https://docs.memfault.com/docs/platform/memfault-core-metrics).
17+
18+
- General:
19+
20+
- Enhanced the Self-Test component with the following new features:
21+
22+
- Check that other components are initialized correctly (boot test)
23+
- Check that exporting data over the console is supported (primiarly
24+
checking that the output buffer is large enough)
25+
- Print information about the coredump regions that would be collected
26+
during a crash, for diagnostic purposes
27+
28+
- nRF-Connect SDK:
29+
30+
- Fix a use-after-free problem in the Memfault FOTA helper code
31+
([`ports/zephyr/ncs/src/memfault_fota.c`](ports/zephyr/ncs/src/memfault_fota.c)),
32+
where the allocated Memfault OTA download URL was freed too early. This
33+
issue was introduced in Memfault SDK v1.5.0, where support for FOTA on
34+
nRF-Connect SDK v2.4+ was improved.
35+
36+
- Zephyr:
37+
38+
- Fix a concurrent access bug in the Memfault Zephyr Logging Backend. Only
39+
affected configurations with `CONFIG_LOG_MODE_IMMEDIATE=y`. In certain cases
40+
the logging `ctx` could be corrupted, causing unpredictable behavior.
41+
Replace the synchronization approach with an atomic primitive and correct a
42+
potential concurrency issue in the log panic handler.
43+
44+
- Fix a build warning for certain Zephyr configurations (when using
45+
`CONFIG_NEWLIB_LIBC=y`) due to a missing declaration for `strnlen`. This
46+
warning was introduced with the Memfault Self-Test additions in Memfault SDK
47+
v1.5.2.
48+
49+
### :boom: Breaking Changes
50+
51+
- General:
52+
53+
- The Battery Metrics platform API has been consolidated into a single
54+
function,
55+
`int memfault_platform_get_stateofcharge(sMfltPlatformBatterySoc *soc)`,
56+
where the platform data is loaded into the `soc` struct. This should
57+
simplify the platform implementation, and enables platforms to return a
58+
non-zero value to indicate state-of-charge is unknown. See the new API in
59+
the header file
60+
[`memfault/metrics/platform/battery.h`](components/include/memfault/metrics/platform/battery.h)
61+
362
## [1.5.2] - 2023-12-12
463

564
### :chart_with_upwards_trend: Improvements

Dockerfile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
FROM ubuntu:22.04
2+
3+
4+
# Install dependencies like wget
5+
RUN apt-get update && apt-get install -y --no-install-recommends \
6+
ca-certificates \
7+
gnupg \
8+
wget \
9+
&& rm -rf /var/lib/apt/lists/*
10+
11+
# # Add llvm apt src
12+
# RUN cat > /etc/apt/sources.list.d/llvm.sources <<EOF
13+
# Types: deb
14+
# URIs: https://example.com/apt
15+
# Suites: stable
16+
# Components: main
17+
# Signed-By:
18+
# $(wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key | sed -e 's/^$/./' -e 's/^/ /')
19+
# EOF
20+
21+
# RUN chmod 644 /etc/apt/sources.list.d/llvm.sources
22+
23+
# RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \
24+
# && echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main" >> /etc/apt/sources.list.d/llvm.list \
25+
# echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main\
26+
# >> /etc/apt/sources.list.d/llvm.list
27+
# echo deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy main\
28+
# >> /etc/apt/sources.list.d/llvm.list
29+
# && apt-get update
30+
31+
# RUN apt-get update && apt-get install -y --no-install-recommends \
32+
# clang-17 \
33+
# llvm-17 \
34+
# && rm -rf /var/lib/apt/lists/*
35+
36+
37+
RUN \
38+
echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main >> /etc/apt/sources.list.d/llvm.list && \
39+
echo deb-src http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main >> /etc/apt/sources.list.d/llvm.list && \
40+
wget -q -O - http://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add - && \
41+
apt-get update && apt-get install -y clang-17 llvm-17

VERSION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
BUILD ID: 5100
2-
GIT COMMIT: 6c3661b0e
3-
VERSION: 1.5.2
1+
BUILD ID: 5464
2+
GIT COMMIT: 96c12257a
3+
VERSION: 1.6.0

components/core/src/memfault_event_storage.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,23 @@ size_t memfault_event_storage_bytes_free(void) {
467467

468468
return bytes_free;
469469
}
470+
471+
bool memfault_event_storage_booted(void) {
472+
// The event storage component does not have any internal state we can check to see if
473+
// memfault_events_storage_boot was called. As an indirect method, we can check the value of the
474+
// circular buffer used internally. If the buffer structure has been initialized (storage pointer
475+
// is not null), then we can assume that memfault_events_storage_boot was called.
476+
// This check breaks the circular buffer API contract but is intentional for simplicity/efficiency
477+
return (s_event_storage.storage != NULL);
478+
}
479+
480+
// Resets the internal structures of the event storage component. This function is to only be used
481+
// in event storage unit tests. Declaration here to silence -Wmissing-prototypes
482+
void memfault_event_storage_reset(void);
483+
void memfault_event_storage_reset(void) {
484+
// Delete the circular buffer and read/write state
485+
// NB: storage implementation is const so cannot be reset
486+
memset(&s_event_storage, 0, sizeof(s_event_storage));
487+
s_event_storage_write_state = (sMemfaultEventStorageWriteState){ 0 };
488+
s_event_storage_read_state = (sMemfaultEventStorageReadState){ 0 };
489+
}

components/core/src/memfault_log.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,7 @@ void memfault_log_reset(void) {
483483
.enabled = false,
484484
};
485485
}
486+
487+
bool memfault_log_booted(void) {
488+
return s_memfault_ram_logger.enabled;
489+
}

components/core/src/memfault_ram_reboot_info_tracking.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,8 @@ void memfault_reboot_tracking_clear_reboot_reason(void) {
274274
.is_valid = false,
275275
};
276276
}
277+
278+
bool memfault_reboot_tracking_booted(void) {
279+
return ((s_mflt_reboot_info != NULL) &&
280+
(s_mflt_reboot_info->magic == MEMFAULT_REBOOT_INFO_MAGIC));
281+
}

components/core/src/memfault_self_test.c

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,23 @@
55
//!
66
//! @brief
77
//! Memfault SDK self test functions to verify SDK integration
8+
89
#include <ctype.h>
10+
#include <inttypes.h>
911
#include <stdbool.h>
1012
#include <string.h>
1113

1214
#include "memfault/core/build_info.h"
15+
#include "memfault/core/data_export.h"
1316
#include "memfault/core/debug_log.h"
17+
#include "memfault/core/event_storage.h"
1418
#include "memfault/core/math.h"
1519
#include "memfault/core/platform/device_info.h"
20+
#include "memfault/core/reboot_tracking.h"
1621
#include "memfault/core/self_test.h"
17-
#include "memfault_reboot_tracking_private.h"
22+
#include "memfault/core/trace_event.h"
23+
#include "memfault/panics/coredump.h"
24+
#include "memfault/panics/coredump_impl.h"
1825
#include "memfault_self_test_private.h"
1926

2027
typedef enum {
@@ -112,7 +119,7 @@ static uint32_t prv_validate_device_info(void) {
112119
}
113120

114121
static uint32_t prv_validate_build_id(void) {
115-
char build_id_str[(MEMFAULT_BUILD_ID_LEN * 2) + 1] = {0};
122+
char build_id_str[(MEMFAULT_BUILD_ID_LEN * 2) + 1] = { 0 };
116123
uint32_t result = 0;
117124

118125
if (!memfault_build_id_get_string(build_id_str, MEMFAULT_ARRAY_SIZE(build_id_str))) {
@@ -123,8 +130,7 @@ static uint32_t prv_validate_build_id(void) {
123130
}
124131

125132
static void prv_device_info_test_describe(uint32_t results) {
126-
MEMFAULT_LOG_INFO("Device Info Test Results");
127-
MEMFAULT_LOG_INFO("------------------------");
133+
MEMFAULT_SELF_TEST_PRINT_HEADER("Device Info Test");
128134

129135
if (results == 0) {
130136
MEMFAULT_LOG_INFO("All fields valid");
@@ -138,6 +144,7 @@ static void prv_device_info_test_describe(uint32_t results) {
138144
MEMFAULT_LOG_ERROR("%s invalid", s_device_info_field_names[i]);
139145
}
140146
}
147+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_END_OUTPUT);
141148
}
142149

143150
uint32_t memfault_self_test_device_info_test(void) {
@@ -151,7 +158,123 @@ uint32_t memfault_self_test_device_info_test(void) {
151158
return results;
152159
}
153160

161+
typedef enum MfltBootComponent {
162+
kMfltBootComponent_EventStorage = 0,
163+
kMfltBootComponent_Logging,
164+
kMfltBootComponent_RebootTracking,
165+
kMfltBootComponent_TraceEvent,
166+
kMfltBootComponent_NumTypes,
167+
} eMfltBootComponent;
168+
169+
static const struct {
170+
char *component_name;
171+
bool (*booted)(void);
172+
} s_boot_components[kMfltBootComponent_NumTypes] = {
173+
[kMfltBootComponent_EventStorage] =
174+
{
175+
.component_name = "Event Storage",
176+
memfault_event_storage_booted,
177+
},
178+
[kMfltBootComponent_Logging] =
179+
{
180+
.component_name = "Logging",
181+
memfault_log_booted,
182+
},
183+
[kMfltBootComponent_RebootTracking] =
184+
{
185+
.component_name = "Reboot Tracking",
186+
memfault_reboot_tracking_booted,
187+
},
188+
[kMfltBootComponent_TraceEvent] =
189+
{
190+
.component_name = "Trace Event",
191+
memfault_trace_event_booted,
192+
},
193+
};
194+
195+
void memfault_self_test_component_boot_test(void) {
196+
MEMFAULT_SELF_TEST_PRINT_HEADER("Component Boot Test");
197+
MEMFAULT_LOG_INFO("%-16s|%8s|", "Component", "Booted?");
198+
MEMFAULT_LOG_INFO("-----------------------------");
199+
for (size_t i = 0; i < MEMFAULT_ARRAY_SIZE(s_boot_components); i++) {
200+
bool booted = s_boot_components[i].booted();
201+
MEMFAULT_LOG_INFO("%-16s|%8s|", s_boot_components[i].component_name, booted ? "yes" : "no");
202+
}
203+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_END_OUTPUT);
204+
}
205+
206+
void memfault_self_test_data_export_test(void) {
207+
char test_line[MEMFAULT_DATA_EXPORT_BASE64_CHUNK_MAX_LEN] = { 0 };
208+
// Set every char to '+' except for the last char before null terminator
209+
memset(test_line, '+', MEMFAULT_ARRAY_SIZE(test_line) - 2);
210+
// Last character before null should be '1'
211+
test_line[MEMFAULT_DATA_EXPORT_BASE64_CHUNK_MAX_LEN - 2] = '1';
212+
213+
MEMFAULT_SELF_TEST_PRINT_HEADER("Data Export Line Test");
214+
MEMFAULT_LOG_INFO("Printing %u characters, confirm line ends with '1' and is not split",
215+
(unsigned)(MEMFAULT_DATA_EXPORT_BASE64_CHUNK_MAX_LEN - 1));
216+
MEMFAULT_LOG_INFO("%s", test_line);
217+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_END_OUTPUT);
218+
}
219+
220+
static void prv_print_region_group_info(const char *group_name, const sMfltCoredumpRegion *regions,
221+
const size_t num_regions) {
222+
MEMFAULT_LOG_INFO("Coredump group: %s", group_name);
223+
MEMFAULT_LOG_INFO("-----------------------------");
224+
MEMFAULT_LOG_INFO("%10s|%10s|%6s|", "Address", "Length", "Type");
225+
MEMFAULT_LOG_INFO("-----------------------------");
226+
for (size_t i = 0; i < num_regions; i++) {
227+
sMfltCoredumpRegion region = regions[i];
228+
MEMFAULT_LOG_INFO("0x%08" PRIxPTR "|%10" PRIu32 "|%6u|", (uintptr_t)region.region_start,
229+
region.region_size, region.type);
230+
}
231+
MEMFAULT_LOG_INFO("-----------------------------");
232+
}
233+
234+
uint32_t memfault_self_test_coredump_regions_test(void) {
235+
uint32_t result = 0;
236+
const sMfltCoredumpRegion *platform_regions = NULL;
237+
size_t num_platform_regions = 0;
238+
239+
// Set stack address to current sp and unknown reboot reason
240+
// These are dummy values so we can get as close as possible to the regions
241+
// that memfault_platform_coredump_get_regions will return
242+
sCoredumpCrashInfo info = {
243+
.stack_address = &num_platform_regions,
244+
.trace_reason = kMfltRebootReason_Unknown,
245+
};
246+
247+
// Call memfault_platform_coredump_get_regions
248+
platform_regions = memfault_platform_coredump_get_regions(&info, &num_platform_regions);
249+
250+
// Get arch and SDK regions
251+
size_t num_arch_regions = 0;
252+
const sMfltCoredumpRegion *arch_regions = memfault_coredump_get_arch_regions(&num_arch_regions);
253+
size_t num_sdk_regions = 0;
254+
const sMfltCoredumpRegion *sdk_regions = memfault_coredump_get_sdk_regions(&num_sdk_regions);
255+
256+
MEMFAULT_SELF_TEST_PRINT_HEADER("Coredump Regions Test");
257+
if (num_platform_regions == 0) {
258+
MEMFAULT_LOG_ERROR("Number of platform regions = 0");
259+
result = 1;
260+
}
261+
262+
if (platform_regions == NULL) {
263+
MEMFAULT_LOG_ERROR("Platform regions was NULL");
264+
result = 1;
265+
}
266+
267+
prv_print_region_group_info("Platform Regions", platform_regions, num_platform_regions);
268+
prv_print_region_group_info("Arch Regions", arch_regions, num_arch_regions);
269+
prv_print_region_group_info("SDK Regions", sdk_regions, num_sdk_regions);
270+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_END_OUTPUT);
271+
return result;
272+
}
273+
154274
int memfault_self_test_run(void) {
155275
// Run each test one at a time and return result of all runs OR'd together
276+
memfault_self_test_component_boot_test();
277+
memfault_self_test_data_export_test();
278+
memfault_self_test_coredump_regions_test();
156279
return (memfault_self_test_device_info_test() != 0);
157280
}

components/core/src/memfault_self_test_private.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
extern "C" {
1212
#endif
1313

14+
//! Macro for beginning of test string
15+
#define MEMFAULT_SELF_TEST_END_OUTPUT "=============================\n"
16+
//! Macro for end of test string
17+
#define MEMFAULT_SELF_TEST_BEGIN_OUTPUT "============================="
18+
19+
#define MEMFAULT_SELF_TEST_PRINT_HEADER(test_name) \
20+
do { \
21+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_BEGIN_OUTPUT); \
22+
MEMFAULT_LOG_INFO(test_name); \
23+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_BEGIN_OUTPUT); \
24+
} while (0)
25+
1426
// Checks if char fits regex: [-a-zA-z0-0_]
1527
bool memfault_self_test_valid_device_serial(unsigned char c);
1628

@@ -23,6 +35,15 @@ bool memfault_self_test_valid_sw_version(unsigned char c);
2335
//! Runs device info and build ID test
2436
uint32_t memfault_self_test_device_info_test(void);
2537

38+
//! Runs component boot test
39+
void memfault_self_test_component_boot_test(void);
40+
41+
//! Data export test
42+
void memfault_self_test_data_export_test(void);
43+
44+
//! Runs coredump regions test
45+
uint32_t memfault_self_test_coredump_regions_test(void);
46+
2647
#ifdef __cplusplus
2748
}
2849
#endif

0 commit comments

Comments
 (0)