Skip to content

Commit 5a16c1d

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.7.0 (Build 6257)
1 parent 0ca1a2a commit 5a16c1d

File tree

71 files changed

+1396
-159
lines changed

Some content is hidden

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

71 files changed

+1396
-159
lines changed

.codecov.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ coverage:
22
precision: 2
33
round: down
44
range: "70...100"
5+
status:
6+
project:
7+
default:
8+
target: 70%
59

610
ignore:
711
- "tests" # Don't include the tests themselves in the code coverage report

.git-blame-ignore-revs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view
2+
#
3+
# This file contains a list of commits that are not likely what you
4+
# are looking for in a blame, such as mass reformatting or renaming.
5+
# You can set this file as a default ignore file for blame by running
6+
# the following command.
7+
#
8+
# git config blame.ignoreRevsFile .git-blame-ignore-revs
9+
10+
0ca1a2a16f7cbf0420d795ca3a4f508fe09f95bd # SDK v1.6.2 clang-format run

CHANGELOG.md

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

3+
## [1.7.0] - 2024-01-29
4+
5+
### :rocket: New Features
6+
7+
- General:
8+
9+
- :tada:Custom Reboot Reasons!:tada: The SDK now allows creating custom reboot
10+
reasons in addition to those defined in
11+
[`components/include/memfault/core/reboot_reason_types.h`](components/include/memfault/core/reboot_reason_types.h).
12+
Users can create custom reboot reasons for both expected and unexpected
13+
reboots. For more information see
14+
[`components/include/memfault/core/reboot_tracking.h`](components/include/memfault/core/reboot_tracking.h).
15+
Enable this feature with Kconfigs in Zephyr and ESP-IDF
16+
(`CONFIG_MEMFAULT_REBOOT_REASON_CUSTOM_ENABLE=y`) or by adding
17+
`#define MEMFAULT_REBOOT_REASON_CUSTOM_ENABLE 1` to your
18+
`memfault_platform_config.h`.
19+
- Added an option to include a Project Key in a chunk message header. This
20+
allows a chunk to specify which project the included data should be sent to.
21+
The default behavior is to use the project specified by the Project Key
22+
header in the POST upload. To enable, add
23+
`#define MEMFAULT_MESSAGE_HEADER_CONTAINS_PROJECT_KEY 1` and
24+
`#define MEMFAULT_PROJECT_KEY "<project key string>"` to your
25+
`memfault_platform_config.h`. Any chunks sent using this configuration will
26+
be sent to the project routed with `MEMFAULT_PROJECT_KEY` rather than the
27+
project routed with the POST header's Project Key.
28+
29+
### :chart_with_upwards_trend: Improvements
30+
31+
- General:
32+
33+
- Improved suggested linker snippets defining coredump memory regions
34+
- Added a self test to validate platform time functions,
35+
`memfault_platform_get_time_since_boot_ms()` and
36+
`memfault_platform_time_get_current()`. This test will catch errors like
37+
non-monotonically increasing counters and current time reported as near
38+
epoch time
39+
- Fixed backspace handling in the FreeRTOS QEMU example console
40+
- Added `-fsanitize=leak` to the SDK unit tests (Linux only)
41+
- Fixed a missing `strnlen()` definition when enabling the self test with some
42+
libc implementations. This function is part of a POSIX standard that might
43+
be missing from some libc implementations
44+
- Added the previous release commit for 1.6.2 to `.git-blame-ignore-revs` to
45+
allow for better `git blame` output since this commit contains _only_
46+
formatting changes.
47+
48+
- Zephyr:
49+
50+
- Added an example CDR implementation to the example QEMU app
51+
- Added a Kconfig, (`CONFIG_MEMFAULT_RECORD_REBOOT_ON_SYSTEM_INIT`) to allow
52+
deferring reboot reason collection to a later point in time. Setting this
53+
option to `n` is intended to help when device info is only available after
54+
boot completes.
55+
- Added built-in metrics for Zephyr's IP subsystem,
56+
(`CONFIG_MEMFAULT_METRICS_TCP_IP`)
57+
- Added Kconfig to select either PEM or DER formats for TLS certificates,
58+
(`CONFIG_MEMFAULT_TLS_CERTS_USE_DER`)
59+
60+
- ESP-IDF:
61+
- Added a Kconfig to enable/disable compact logging
62+
(`CONFIG_MEMFAULT_COMPACT_LOG_ENABLE`)
63+
- Improved build compatibility when building with PlatformIO
64+
- Added support for networking over Ethernet interfaces
65+
- Added a built-in `connectivity_connected_time` core metric for WiFi devices,
66+
(`CONFIG_MEMFAULT_ESP_WIFI_CONNECTIVITY_TIME_METRICS`)
67+
368
## [1.6.2] - 2024-01-29
469

570
### :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: 5836
2-
GIT COMMIT: ed83a4f3c
3-
VERSION: 1.6.2
1+
BUILD ID: 6257
2+
GIT COMMIT: 8cd2342158
3+
VERSION: 1.7.0

components/core/src/memfault_data_packetizer.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,36 @@ typedef struct {
133133
sMfltChunkTransportCtx curr_msg_ctx;
134134
} sMfltTransportState;
135135

136+
#if MEMFAULT_MESSAGE_HEADER_CONTAINS_PROJECT_KEY
137+
MEMFAULT_STATIC_ASSERT(
138+
sizeof(MEMFAULT_PROJECT_KEY) > 1,
139+
"MEMFAULT_PROJECT_KEY must be a string literal of at least 1 character + null terminator");
140+
#endif
141+
136142
typedef MEMFAULT_PACKED_STRUCT {
137-
uint8_t mflt_msg_type; // eMfltMessageType
143+
// The first byte of the header is the message type. Bit layout:
144+
// ┌───────────┬─┬─┐
145+
// │0|1|2|3|4|5│6│7│
146+
// └─────┬─────┴┬┴┬┘
147+
// │ │ │
148+
// │ │ └►RLE in use:
149+
// │ │ 0b0=no RLE
150+
// │ │ 0b1=RLE
151+
// │ │
152+
// │ └──►Project Key follows:
153+
// │ 0b0=no Project Key
154+
// │ 0b1=32 byte Project Key follows header byte
155+
// │
156+
// └─────────►eMfltMessageType
157+
// 6 bits (63 values)
158+
#define MEMFAULT_MESSAGE_HEADER_RLE_ENABLE_MASK (1u << 7)
159+
#if MEMFAULT_MESSAGE_HEADER_CONTAINS_PROJECT_KEY
160+
#define MEMFAULT_MESSAGE_HEADER_PROJECT_KEY_ENABLE_MASK (1u << 6)
161+
#endif
162+
uint8_t mflt_msg_type;
163+
#if MEMFAULT_MESSAGE_HEADER_CONTAINS_PROJECT_KEY
164+
uint8_t project_key[sizeof(MEMFAULT_PROJECT_KEY)]; // including null term
165+
#endif
138166
}
139167
sMfltPacketizerHdr;
140168

@@ -162,12 +190,20 @@ static void prv_data_source_chunk_transport_msg_reader(uint32_t offset, void *bu
162190

163191
const sMessageMetadata *msg_metadata = &s_mflt_packetizer_state.msg_metadata;
164192
if (offset < hdr_size) {
165-
const uint8_t rle_enable_mask = 0x80;
166193
const uint8_t msg_type = (uint8_t)msg_metadata->source.type;
167194

168195
sMfltPacketizerHdr hdr = {
169-
.mflt_msg_type = msg_metadata->source.use_rle ? msg_type | rle_enable_mask : msg_type,
196+
.mflt_msg_type = msg_type,
170197
};
198+
if (msg_metadata->source.use_rle) {
199+
const uint8_t rle_enable_mask = MEMFAULT_MESSAGE_HEADER_RLE_ENABLE_MASK;
200+
hdr.mflt_msg_type |= rle_enable_mask;
201+
}
202+
#if MEMFAULT_MESSAGE_HEADER_CONTAINS_PROJECT_KEY
203+
const uint8_t prj_key_enable_mask = MEMFAULT_MESSAGE_HEADER_PROJECT_KEY_ENABLE_MASK;
204+
hdr.mflt_msg_type |= prj_key_enable_mask;
205+
memcpy(hdr.project_key, MEMFAULT_PROJECT_KEY, sizeof(hdr.project_key));
206+
#endif
171207
uint8_t *hdr_bytes = (uint8_t *)&hdr;
172208

173209
const size_t bytes_to_copy = MEMFAULT_MIN(hdr_size - offset, buf_len);
@@ -245,12 +281,14 @@ static bool prv_load_next_message_to_send(bool enable_multi_packet_chunks,
245281
return false;
246282
}
247283

284+
const size_t hdr_size = sizeof(sMfltPacketizerHdr);
285+
248286
*state = (sMfltTransportState){
249287
.active_message = true,
250288
.msg_metadata = msg_metadata,
251289
.curr_msg_ctx =
252290
(sMfltChunkTransportCtx){
253-
.total_size = msg_metadata.total_size + sizeof(sMfltPacketizerHdr),
291+
.total_size = msg_metadata.total_size + hdr_size,
254292
.read_msg = prv_data_source_chunk_transport_msg_reader,
255293
.enable_multi_call_chunk = enable_multi_packet_chunks,
256294
},

components/core/src/memfault_self_test.c

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "memfault/core/math.h"
1919
#include "memfault/core/platform/core.h"
2020
#include "memfault/core/platform/device_info.h"
21+
#include "memfault/core/platform/system_time.h"
2122
#include "memfault/core/reboot_tracking.h"
2223
#include "memfault/core/self_test.h"
2324
#include "memfault/core/trace_event.h"
@@ -76,7 +77,7 @@ static bool is_field_valid(const char *str, eDeviceInfoField field) {
7677
}
7778
// First validate min and max length
7879
// Max + 1 needed determine if we exceeded bounds before NULL found
79-
size_t len = strnlen(str, MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE + 1);
80+
size_t len = memfault_strnlen(str, MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE + 1);
8081
if ((len < 1) || (len > MEMFAULT_DEVICE_INFO_MAX_STRING_SIZE)) {
8182
MEMFAULT_LOG_ERROR("Invalid length %zu for %s", len, s_device_info_field_names[field]);
8283
return false;
@@ -311,6 +312,72 @@ uint32_t memfault_self_test_reboot_reason_test_verify(void) {
311312
return success ? 0 : 1;
312313
}
313314

315+
// Use MEMFAULT_NO_OPT to prevent busy loop from being removed
316+
MEMFAULT_NO_OPT static uint32_t prv_get_time_since_boot_test(void) {
317+
uint64_t start_time_ms = memfault_platform_get_time_since_boot_ms();
318+
319+
if (start_time_ms == 0) {
320+
MEMFAULT_LOG_ERROR("Time since boot reported as 0");
321+
return (1 << 0);
322+
}
323+
324+
// Force a 100ms delay to ensure enough time has passed to yield a different timestamp
325+
memfault_self_test_platform_delay(100);
326+
327+
uint64_t end_time_ms = memfault_platform_get_time_since_boot_ms();
328+
if ((end_time_ms <= start_time_ms)) {
329+
MEMFAULT_LOG_ERROR("Time since boot not monotonically increasing: start[%" PRIu64
330+
"] vs end[%" PRIu64 "]",
331+
start_time_ms, end_time_ms);
332+
return (1 << 1);
333+
}
334+
335+
MEMFAULT_LOG_INFO("Time since boot test succeeded");
336+
return 0;
337+
}
338+
339+
// Arbitrary point in recent history
340+
// The time test did not exist before 2024/01/29 UTC
341+
#define MEMFAULT_SELF_TEST_TIMESTAMP_ANCHOR (1706486400)
342+
343+
static uint32_t prv_platform_time_get_current_test(void) {
344+
sMemfaultCurrentTime time = {
345+
.type = kMemfaultCurrentTimeType_Unknown,
346+
.info = {
347+
.unix_timestamp_secs = 0,
348+
},
349+
};
350+
bool result = memfault_platform_time_get_current(&time);
351+
if (!result) {
352+
MEMFAULT_LOG_ERROR("Current timestamp could not be recovered");
353+
return (1 << 2);
354+
}
355+
356+
if (time.type != kMemfaultCurrentTimeType_UnixEpochTimeSec) {
357+
MEMFAULT_LOG_ERROR("Invalid time type returned: %u", time.type);
358+
return (1 << 3);
359+
}
360+
361+
if (time.info.unix_timestamp_secs < MEMFAULT_SELF_TEST_TIMESTAMP_ANCHOR) {
362+
MEMFAULT_LOG_ERROR("Timestamp too far in the past: %" PRIu64, time.info.unix_timestamp_secs);
363+
return (1 << 4);
364+
}
365+
366+
MEMFAULT_LOG_INFO("Verify received timestamp for accuracy. Timestamp received %" PRIu64,
367+
time.info.unix_timestamp_secs);
368+
return 0;
369+
}
370+
371+
uint32_t memfault_self_test_time_test(void) {
372+
MEMFAULT_SELF_TEST_PRINT_HEADER("Time Test");
373+
374+
uint32_t result = prv_get_time_since_boot_test();
375+
result |= prv_platform_time_get_current_test();
376+
377+
MEMFAULT_LOG_INFO(MEMFAULT_SELF_TEST_END_OUTPUT);
378+
return result;
379+
}
380+
314381
#endif // defined(MEMFAULT_UNITTEST_SELF_TEST)
315382

316383
int memfault_self_test_run(uint32_t run_flags) {
@@ -333,5 +400,8 @@ int memfault_self_test_run(uint32_t run_flags) {
333400
if (run_flags & kMemfaultSelfTestFlag_RebootReasonVerify) {
334401
result = memfault_self_test_reboot_reason_test_verify();
335402
}
403+
if (run_flags & kMemfaultSelfTestFlag_PlatformTime) {
404+
result |= memfault_self_test_time_test();
405+
}
336406
return (result == 0) ? 0 : 1;
337407
}

components/core/src/memfault_self_test_private.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include <stdbool.h>
8+
#include <stddef.h>
89
#include <stdint.h>
910

1011
#include "memfault/core/compiler.h"
@@ -56,6 +57,21 @@ MEMFAULT_NORETURN void memfault_self_test_reboot_reason_test(void);
5657
//! Verifies reboot reason test results
5758
uint32_t memfault_self_test_reboot_reason_test_verify(void);
5859

60+
//! Runs tests against platform time functions
61+
uint32_t memfault_self_test_time_test(void);
62+
63+
//! Internal implementation of strnlen
64+
//!
65+
//! Support for strnlen is inconsistent across a lot of libc implementations so we implement this
66+
//! here for compatibility reasons. See
67+
//! https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html
68+
//! @param str Pointer to a C string. Pointer must not be NULL
69+
//! @param n Maximum number of characters to examine when determining the length of the string
70+
//! @returns The strnlen() function shall return the number of bytes preceding the first null byte
71+
//! in the array to which s points, if s contains a null byte within the first maxlen bytes;
72+
//! otherwise, it shall return maxlen
73+
size_t memfault_strnlen(const char *str, size_t n);
74+
5975
#ifdef __cplusplus
6076
}
6177
#endif

components/core/src/memfault_self_test_utils.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,21 @@ uint32_t memfault_self_test_arg_to_flag(const char *arg) {
5252
MEMFAULT_LOG_WARN("No test type found for arg: %s. Default tests selected", arg);
5353
return kMemfaultSelfTestFlag_Default;
5454
}
55+
56+
// Include an implementation of strnlen, based on picolibc/newlib
57+
// For reference: https://github.com/picolibc/picolibc/blob/main/newlib/libc/string/strnlen.c
58+
size_t memfault_strnlen(const char *str, size_t n) {
59+
size_t count = 0;
60+
61+
// Must check n first to prevent out of bounds access
62+
while (n-- && *str) {
63+
count++;
64+
str++;
65+
}
66+
67+
return count;
68+
}
69+
70+
MEMFAULT_WEAK void memfault_self_test_platform_delay(MEMFAULT_UNUSED uint32_t delay_ms) {
71+
MEMFAULT_LOG_ERROR("%s not implemented for this platform", __func__);
72+
}

0 commit comments

Comments
 (0)