Skip to content

Commit fa74810

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.5.2 (Build 5100)
1 parent ae77446 commit fa74810

33 files changed

+683
-47
lines changed

CHANGELOG.md

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

3+
## [1.5.2] - 2023-12-12
4+
5+
### :chart_with_upwards_trend: Improvements
6+
7+
- General:
8+
9+
- Add a self-test component which checks the device's integration state. This
10+
self test is available via the demo cli command `self_test`, or can be
11+
called directly via `memfault_self_test_run()` (see
12+
[`self_test.h`](components/include/memfault/core/self_test.h) for details).
13+
Currently, it validates device info and the build ID.
14+
15+
- Add a helper macro called `MEMFAULT_REBOOT_MARK_RESET_IMMINENT` in order to
16+
make marking an imminent reboot easier. It takes the reboot reason as an
17+
argument.
18+
19+
- ESP-IDF:
20+
21+
- Add an opt-in assert on malloc failure, controlled with
22+
`CONFIG_MEMFAULT_ASSERT_ON_ALLOC_FAILURE`. This is useful for tracking heap
23+
memory issues. Depending on the design, a system may in general not have any
24+
expected malloc failures, and may not be set up to handle them. This feature
25+
will generate issues tagged as `Out Of Memory` in the Memfault platform.
26+
27+
- Zephyr:
28+
29+
- Adjust the implementation of `memfault_zephyr_port_http_upload_sdk_data()`
30+
to check the socket before each incremental call to the `send()` socket
31+
operation and wait for the socket to become available. If the socket takes
32+
too long (a healthy 5 second timeout is given), the function will return
33+
with an error. Note this function was previously blocking, but may now abort
34+
mid-transfer. This check was primarily added to prevent a busy loop that
35+
hogs the CPU, preventing lower priority threads from running. This situation
36+
could occur with larger HTTP transfers during which the socket may be busy
37+
processing tx data when another send request occurs.
38+
39+
- Fix a build error in the Zephyr RTC port.
40+
341
## [1.5.1] - 2023-12-07
442

543
### :chart_with_upwards_trend: Improvements

VERSION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
BUILD ID: 4929
2-
GIT COMMIT: 138e44883
3-
VERSION: 1.5.1
1+
BUILD ID: 5100
2+
GIT COMMIT: 6c3661b0e
3+
VERSION: 1.5.2
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
//!
6+
//! @brief
7+
//! Memfault SDK self test functions to verify SDK integration
8+
#include <ctype.h>
9+
#include <stdbool.h>
10+
#include <string.h>
11+
12+
#include "memfault/core/build_info.h"
13+
#include "memfault/core/debug_log.h"
14+
#include "memfault/core/math.h"
15+
#include "memfault/core/platform/device_info.h"
16+
#include "memfault/core/self_test.h"
17+
#include "memfault_reboot_tracking_private.h"
18+
#include "memfault_self_test_private.h"
19+
20+
typedef enum {
21+
kDeviceInfoField_DeviceSerial = 0,
22+
kDeviceInfoField_SoftwareType,
23+
kDeviceInfoField_SoftwareVersion,
24+
kDeviceInfoField_HardwareVersion,
25+
kDeviceInfoField_BuildId,
26+
kDeviceInfoField_Max,
27+
} eDeviceInfoField;
28+
29+
static const char *s_device_info_field_names[] = {
30+
[kDeviceInfoField_DeviceSerial] = "Device Serial",
31+
[kDeviceInfoField_SoftwareType] = "Software Type",
32+
[kDeviceInfoField_SoftwareVersion] = "Software Version",
33+
[kDeviceInfoField_HardwareVersion] = "Hardware Version",
34+
[kDeviceInfoField_BuildId] = "Build ID",
35+
};
36+
37+
typedef bool (*FieldCharValidator)(unsigned char c);
38+
39+
static const FieldCharValidator s_device_info_str_validators[] = {
40+
[kDeviceInfoField_DeviceSerial] = memfault_self_test_valid_device_serial,
41+
[kDeviceInfoField_SoftwareType] = memfault_self_test_valid_hw_version_sw_type,
42+
[kDeviceInfoField_SoftwareVersion] = memfault_self_test_valid_sw_version,
43+
[kDeviceInfoField_HardwareVersion] = memfault_self_test_valid_hw_version_sw_type,
44+
NULL,
45+
};
46+
47+
MEMFAULT_STATIC_ASSERT(MEMFAULT_ARRAY_SIZE(s_device_info_field_names) == kDeviceInfoField_Max,
48+
"Mismatch in field name table, must be equal");
49+
MEMFAULT_STATIC_ASSERT(MEMFAULT_ARRAY_SIZE(s_device_info_str_validators) == kDeviceInfoField_Max,
50+
"Mismatch in string validator table, must be equal");
51+
52+
static bool prv_validate_string(const char *str, size_t len, FieldCharValidator is_valid) {
53+
for (size_t idx = 0; idx < len; ++idx) {
54+
unsigned char c = (unsigned char)str[idx];
55+
if (!is_valid(c)) {
56+
MEMFAULT_LOG_ERROR("Invalid char %c, found in %s", c, str);
57+
return false;
58+
}
59+
}
60+
return true;
61+
}
62+
63+
static bool is_field_valid(const char *str, eDeviceInfoField field) {
64+
if (str == NULL) {
65+
return false;
66+
}
67+
// First validate min and max length
68+
// Max + 1 needed determine if we exceeded bounds before NULL found
69+
size_t len = strnlen(str, MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE + 1);
70+
if ((len < 1) || (len > MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE)) {
71+
MEMFAULT_LOG_ERROR("Invalid length %zu for %s", len, s_device_info_field_names[field]);
72+
return false;
73+
}
74+
75+
if (field < kDeviceInfoField_Max) {
76+
FieldCharValidator validator = s_device_info_str_validators[field];
77+
return (validator != NULL) ? prv_validate_string(str, len, validator) : false;
78+
} else {
79+
MEMFAULT_LOG_ERROR("Invalid device info string type %u for %s", field, str);
80+
return false;
81+
}
82+
}
83+
84+
static uint32_t prv_validate_device_info_field(const char *str, eDeviceInfoField field) {
85+
uint32_t result = 0;
86+
if (!is_field_valid(str, field)) {
87+
result = (uint32_t)(1 << field);
88+
}
89+
90+
return result;
91+
}
92+
93+
static uint32_t prv_validate_device_info(void) {
94+
sMemfaultDeviceInfo device_info = { 0 };
95+
memfault_platform_get_device_info(&device_info);
96+
uint32_t results = 0;
97+
98+
// Validate each field in device_info
99+
results |=
100+
prv_validate_device_info_field(device_info.device_serial, kDeviceInfoField_DeviceSerial);
101+
102+
results |=
103+
prv_validate_device_info_field(device_info.hardware_version, kDeviceInfoField_HardwareVersion);
104+
105+
results |=
106+
prv_validate_device_info_field(device_info.software_version, kDeviceInfoField_SoftwareVersion);
107+
108+
results |=
109+
prv_validate_device_info_field(device_info.software_type, kDeviceInfoField_SoftwareType);
110+
111+
return results;
112+
}
113+
114+
static uint32_t prv_validate_build_id(void) {
115+
char build_id_str[(MEMFAULT_BUILD_ID_LEN * 2) + 1] = {0};
116+
uint32_t result = 0;
117+
118+
if (!memfault_build_id_get_string(build_id_str, MEMFAULT_ARRAY_SIZE(build_id_str))) {
119+
result = (uint32_t)(1 << kDeviceInfoField_BuildId);
120+
}
121+
122+
return result;
123+
}
124+
125+
static void prv_device_info_test_describe(uint32_t results) {
126+
MEMFAULT_LOG_INFO("Device Info Test Results");
127+
MEMFAULT_LOG_INFO("------------------------");
128+
129+
if (results == 0) {
130+
MEMFAULT_LOG_INFO("All fields valid");
131+
return;
132+
}
133+
134+
MEMFAULT_LOG_ERROR("One or more fields is invalid. Check for correct length and contents");
135+
for (uint8_t i = 0; i < kDeviceInfoField_Max; i++) {
136+
// Check if bit cleared, cleared bits indicate an invalid field
137+
if ((results & (1 << i))) {
138+
MEMFAULT_LOG_ERROR("%s invalid", s_device_info_field_names[i]);
139+
}
140+
}
141+
}
142+
143+
uint32_t memfault_self_test_device_info_test(void) {
144+
uint32_t results = 0;
145+
// Validate the build ID
146+
results |= prv_validate_build_id();
147+
// Valid device info fields
148+
results |= prv_validate_device_info();
149+
150+
prv_device_info_test_describe(results);
151+
return results;
152+
}
153+
154+
int memfault_self_test_run(void) {
155+
// Run each test one at a time and return result of all runs OR'd together
156+
return (memfault_self_test_device_info_test() != 0);
157+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
#pragma once
6+
7+
#include <stdbool.h>
8+
#include <stdint.h>
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
// Checks if char fits regex: [-a-zA-z0-0_]
15+
bool memfault_self_test_valid_device_serial(unsigned char c);
16+
17+
//! Checks if char fits regex: [-a-zA-Z0-9_\.\+:]
18+
bool memfault_self_test_valid_hw_version_sw_type(unsigned char c);
19+
20+
//! Simple wrapper for isprint, software version does not have any regex to match
21+
bool memfault_self_test_valid_sw_version(unsigned char c);
22+
23+
//! Runs device info and build ID test
24+
uint32_t memfault_self_test_device_info_test(void);
25+
26+
#ifdef __cplusplus
27+
}
28+
#endif
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
#include <ctype.h>
6+
#include <stdbool.h>
7+
8+
#include "memfault_self_test_private.h"
9+
10+
bool memfault_self_test_valid_device_serial(unsigned char c) {
11+
return (isalnum(c) > 0) || (c == '_') || (c == '-');
12+
}
13+
14+
bool memfault_self_test_valid_hw_version_sw_type(unsigned char c) {
15+
return (memfault_self_test_valid_device_serial(c)) || (c == '.') || (c == '+') || (c == ':');
16+
}
17+
18+
bool memfault_self_test_valid_sw_version(unsigned char c) {
19+
return (isprint(c) > 0);
20+
}

components/demo/src/memfault_demo_shell_commands.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "memfault/core/data_export.h"
1313
#include "memfault/core/debug_log.h"
1414
#include "memfault/core/math.h"
15+
#include "memfault/core/self_test.h"
1516
#include "memfault/demo/cli.h"
1617
#include "memfault/demo/shell_commands.h"
1718
#include "memfault/metrics/metrics.h"
@@ -63,6 +64,10 @@ int memfault_demo_cli_cmd_heartbeat(MEMFAULT_UNUSED int argc, MEMFAULT_UNUSED ch
6364
return 0;
6465
}
6566

67+
int memfault_demo_cli_cmd_self_test(MEMFAULT_UNUSED int argc, MEMFAULT_UNUSED char *argv[]) {
68+
return memfault_self_test_run();
69+
}
70+
6671
static const sMemfaultShellCommand s_memfault_shell_commands[] = {
6772
{"clear_core", memfault_demo_cli_cmd_clear_core, "Clear an existing coredump"},
6873
{"drain_chunks", memfault_demo_drain_chunk_data,
@@ -100,6 +105,8 @@ static const sMemfaultShellCommand s_memfault_shell_commands[] = {
100105
{"test_reboot", memfault_demo_cli_cmd_system_reboot,
101106
"Force system reset and track it with a trace event"},
102107
{"test_trace", memfault_demo_cli_cmd_trace_event_capture, "Capture an example trace event"},
108+
{ "self_test", memfault_demo_cli_cmd_self_test,
109+
"Run a self test to check integration with the SDK" },
103110

104111
{"help", memfault_shell_help_handler, "Lists all commands"},
105112
};

components/include/memfault/components.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "memfault/core/reboot_reason_types.h"
4141
#include "memfault/core/reboot_tracking.h"
4242
#include "memfault/core/sdk_assert.h"
43+
#include "memfault/core/self_test.h"
4344
#include "memfault/core/task_watchdog.h"
4445
#include "memfault/core/trace_event.h"
4546
#include "memfault/demo/cli.h"

components/include/memfault/core/platform/device_info.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
extern "C" {
1717
#endif
1818

19+
//! Maximum string size of a field in MemfaultDeviceInfo. Does not include NULL terminator
20+
#if !defined(MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE)
21+
#define MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE 128
22+
#endif // !defined(MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE)
23+
1924
typedef struct MemfaultDeviceInfo {
2025
//! The device's serial number or unique identifier.
2126
//! Regular expression defining valid device serials: ^[-a-zA-Z0-9_]+$

components/include/memfault/core/reboot_tracking.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <inttypes.h>
2424
#include <stddef.h>
2525

26+
#include "memfault/core/compiler.h"
2627
#include "memfault/core/event_storage.h"
2728
#include "memfault/core/reboot_reason_types.h"
2829

@@ -109,6 +110,21 @@ typedef struct MfltRebootTrackingRegInfo {
109110
void memfault_reboot_tracking_mark_reset_imminent(eMemfaultRebootReason reboot_reason,
110111
const sMfltRebootTrackingRegInfo *reg);
111112

113+
//! Helper macro to capture the current pc & lr and call
114+
//! memfault_reboot_tracking_mark_reset_imminent
115+
#define MEMFAULT_REBOOT_MARK_RESET_IMMINENT(reason_) \
116+
do { \
117+
void *mflt_pc; \
118+
MEMFAULT_GET_PC(mflt_pc); \
119+
void *mflt_lr; \
120+
MEMFAULT_GET_LR(mflt_lr); \
121+
sMfltRebootTrackingRegInfo mflt_reg_info = { \
122+
.pc = (uint32_t)mflt_pc, \
123+
.lr = (uint32_t)mflt_lr, \
124+
}; \
125+
memfault_reboot_tracking_mark_reset_imminent(reason_, &mflt_reg_info); \
126+
} while (0)
127+
112128
//! Collects recent reset info and pushes it to memfault_event_storage so that the data can
113129
//! can be sent out using the Memfault data packetizer
114130
//!
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
//!
6+
//! @brief
7+
//! Public interface for self_test component
8+
#pragma once
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
//! Main entry point to performing a self test
15+
//!
16+
//! This function will carry out all component tests and return after completing all tests
17+
//! See output for test results and feedback on any errors detected
18+
//!
19+
//! @returns 0 on success or 1 if a subtest failed
20+
int memfault_self_test_run(void);
21+
22+
#ifdef __cplusplus
23+
}
24+
#endif

0 commit comments

Comments
 (0)