Skip to content

Commit d455688

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.21.0 (Build 12963)
1 parent f1a88a8 commit d455688

21 files changed

+446
-47
lines changed

CHANGELOG.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,60 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to
77
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [1.21.0] - 2025-03-06
10+
11+
### 📈 Added
12+
13+
- General:
14+
15+
- Logs captured by Memfault now include a timestamp by default, when the
16+
platform implements `memfault_platform_time_get_current()`. This feature can
17+
be disabled by setting `#define MEMFAULT_LOG_TIMESTAMPS_ENABLE 0` in
18+
`memfault_platform_config.h`.
19+
20+
- ESP-IDF:
21+
22+
- Add new built-in Wi-Fi metrics:
23+
24+
- `wifi_primary_channel` - the primary channel ID of the associated Wi-Fi
25+
access point
26+
- `wifi_auth_mode` - the authentication mode of the associated Wi-Fi access
27+
point, for example `WPA2_PSK`
28+
- `wifi_standard_version` - the Wi-Fi version of the associated Wi-Fi access
29+
point, for example `802.11n`
30+
31+
These metrics are enabled by default and can be disabled (along with other
32+
built-in Wi-Fi metrics) with the Kconfig option
33+
`CONFIG_MEMFAULT_ESP_WIFI_METRICS`
34+
35+
### 🛠️ Changed
36+
37+
- ESP-IDF:
38+
39+
- Support cases where the `IDF_VER` build variable is set to
40+
`"HEAD-HASH-NOTFOUND"` (i.e. using an ESP-IDF SDK that is not a git repo),
41+
when setting the built-in metric `MemfaultSdkMetric_os_version`. In this
42+
case, the value is taken from the `ESP_IDF_VERSION_x` macros, which are less
43+
precise.
44+
45+
- Use more specific Memfault reset reason codes for these watchdog reset
46+
types, previously all categorized as `HardwareWatchdog`
47+
48+
- `ESP_RST_INT_WDT` -> `SoftwareWatchdog`
49+
- `ESP_RST_TASK_WDT` -> `TaskWatchdog`
50+
- `ESP_RST_WDT` (RTC watchdog, the real hardware watchdog), stays as
51+
`HardwareWatchdog`
52+
53+
### 🐛 Fixed
54+
55+
- ESP-IDF:
56+
57+
- Correctly set the Memfault Firmware SDK version inside the
58+
[espressif component](https://components.espressif.com/components/memfault/memfault-firmware-sdk)
59+
version of the SDK. Prior to this fix, the SDK version reports as
60+
`"MemfaultSdkMetric_sdk_version": "0.0.0"`. No change to the SDK, only a
61+
tooling/release change.
62+
963
## [1.20.0] - 2025-02-06
1064

1165
### 📈 Added
@@ -142,6 +196,19 @@ and this project adheres to
142196
Thanks to [@JordanYates](https://github.com/JordanYates) for reporting this
143197
issue in [#81](https://github.com/memfault/memfault-firmware-sdk/issues/85)!
144198

199+
- Fix a configuration issue when building for any of the following parts, but
200+
NOT using nRF-Connect SDK (i.e. using Zephyr instead):
201+
202+
- SOC_SERIES_NRF52X
203+
- SOC_SERIES_NRF53X
204+
- SOC_SERIES_NRF54LX
205+
- SOC_SERIES_NRF91X
206+
207+
The Memfault SDK now correctly enables nRF-Connect-SDK-specific
208+
functionality ONLY when that SDK is included as a Zephyr module. Thanks to
209+
[@JordanYates](https://github.com/JordanYates) for reporting this issue in
210+
[#81](https://github.com/memfault/memfault-firmware-sdk/issues/89)!
211+
145212
- nRF Connect SDK:
146213

147214
- Remove use of child and parent image functionality in the nRF9160 sample

VERSION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
BUILD ID: 12555
2-
GIT COMMIT: 7fcaa50c87
3-
VERSION: 1.20.0
1+
BUILD ID: 12963
2+
GIT COMMIT: 3dabeb442c
3+
VERSION: 1.21.0

components/core/src/memfault_build_id.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,28 @@
3030
#include <version.h>
3131
#define MEMFAULT_OS_VERSION_NAME "zephyr"
3232
#define MEMFAULT_OS_VERSION_STRING KERNEL_VERSION_STRING
33-
#endif /* __has_include("ncs_version.h") */
33+
#endif // __has_include("ncs_version.h")
3434

3535
#elif defined(ESP_PLATFORM)
36-
// ESP-IDF, use the command-line defined IDF_VER string
36+
// ESP-IDF, prefer the command-line provided IDF_VER if set. In rare cases,
37+
// IDF_VER will be set to "HEAD-HASH-NOTFOUND", in which case we fall back
38+
// to the version provided by esp_idf_version.h.
3739
#define MEMFAULT_OS_VERSION_NAME "esp-idf"
38-
#define MEMFAULT_OS_VERSION_STRING IDF_VER
40+
#define STRINGIFY(x) #x
41+
#define XSTRINGIFY(s) STRINGIFY(s)
42+
#include "esp_idf_version.h"
43+
#define MEMFAULT_OS_VERSION_STRING \
44+
((__builtin_strcmp(IDF_VER, "HEAD-HASH-NOTFOUND") != 0) ? \
45+
(IDF_VER) : \
46+
("" XSTRINGIFY(ESP_IDF_VERSION_MAJOR) "." XSTRINGIFY( \
47+
ESP_IDF_VERSION_MINOR) "." XSTRINGIFY(ESP_IDF_VERSION_PATCH) ""))
48+
3949
#else
4050
// No OS version information available
4151
#define MEMFAULT_OS_VERSION_NAME ""
4252
#define MEMFAULT_OS_VERSION_STRING ""
43-
#endif /* defined(__ZEPHYR__) */
44-
#endif /* defined(MEMFAULT_OS_VERSION_NAME) ^ defined(MEMFAULT_OS_VERSION_STRING) \
45-
*/
53+
#endif // defined(__ZEPHYR__)
54+
#endif // defined(MEMFAULT_OS_VERSION_NAME) ^ defined(MEMFAULT_OS_VERSION_STRING)
4655

4756
#if MEMFAULT_USE_GNU_BUILD_ID
4857

components/core/src/memfault_log.c

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "memfault/core/math.h"
2222
#include "memfault/core/platform/debug_log.h"
2323
#include "memfault/core/platform/overrides.h"
24+
#include "memfault/core/platform/system_time.h"
2425
#include "memfault/core/sdk_assert.h"
2526
#include "memfault/util/base64.h"
2627
#include "memfault/util/circular_buffer.h"
@@ -97,15 +98,17 @@ bool memfault_log_get_regions(sMemfaultLogRegions *regions) {
9798
return true;
9899
}
99100

100-
static uint8_t prv_build_header(eMemfaultPlatformLogLevel level, eMemfaultLogRecordType type) {
101+
static uint8_t prv_build_header(eMemfaultPlatformLogLevel level, eMemfaultLogRecordType type,
102+
bool timestamped) {
101103
MEMFAULT_STATIC_ASSERT(kMemfaultPlatformLogLevel_NumLevels <= 8,
102104
"Number of log levels exceed max number that log module can track");
103105
MEMFAULT_STATIC_ASSERT(kMemfaultLogRecordType_NumTypes <= 2,
104106
"Number of log types exceed max number that log module can track");
105107

106108
const uint8_t level_field = (level << MEMFAULT_LOG_HDR_LEVEL_POS) & MEMFAULT_LOG_HDR_LEVEL_MASK;
107109
const uint8_t type_field = (type << MEMFAULT_LOG_HDR_TYPE_POS) & MEMFAULT_LOG_HDR_TYPE_MASK;
108-
return level_field | type_field;
110+
const uint8_t timestamped_field = timestamped ? MEMFAULT_LOG_HDR_TIMESTAMPED_MASK : 0;
111+
return level_field | type_field | timestamped_field;
109112
}
110113

111114
void memfault_log_set_min_save_level(eMemfaultPlatformLogLevel min_log_level) {
@@ -225,10 +228,21 @@ static bool prv_read_log_iter_callback(sMfltLogIterator *iter) {
225228
return false;
226229
}
227230

228-
ctx->log->msg[iter->entry.len] = '\0';
229231
ctx->log->level = memfault_log_get_level_from_hdr(iter->entry.hdr);
230232
ctx->log->type = memfault_log_get_type_from_hdr(iter->entry.hdr);
231233
ctx->log->msg_len = iter->entry.len;
234+
#if MEMFAULT_LOG_TIMESTAMPS_ENABLE
235+
const size_t timestamp_len = sizeof(ctx->log->timestamp);
236+
if (memfault_log_hdr_is_timestamped(iter->entry.hdr) && (iter->entry.len >= timestamp_len)) {
237+
memcpy(&ctx->log->timestamp, ctx->log->msg, timestamp_len);
238+
// shift the message over to remove the timestamp
239+
memmove(ctx->log->msg, &ctx->log->msg[timestamp_len], ctx->log->msg_len - timestamp_len);
240+
ctx->log->msg_len -= timestamp_len;
241+
} else {
242+
ctx->log->timestamp = 0;
243+
}
244+
#endif
245+
ctx->log->msg[ctx->log->msg_len] = '\0';
232246
ctx->has_log = true;
233247
return false;
234248
}
@@ -402,8 +416,25 @@ static void prv_log_save(eMemfaultPlatformLogLevel level, const void *log, size_
402416
}
403417

404418
bool log_written = false;
405-
const size_t truncated_log_len = MEMFAULT_MIN(log_len, MEMFAULT_LOG_MAX_LINE_SAVE_LEN);
406-
const size_t bytes_needed = sizeof(sMfltRamLogEntry) + truncated_log_len;
419+
#if MEMFAULT_LOG_TIMESTAMPS_ENABLE
420+
sMemfaultCurrentTime timestamp;
421+
const bool timestamped = memfault_platform_time_get_current(&timestamp);
422+
uint32_t timestamp_val; // forward declaration for sizeof()
423+
const size_t timestamped_len = timestamped ? sizeof(timestamp_val) : 0;
424+
#else
425+
const bool timestamped = false;
426+
const size_t timestamped_len = 0;
427+
#endif
428+
429+
// maximum msg length is truncated by timestamp, when enabled and valid.
430+
const size_t max_log_msg_len = MEMFAULT_LOG_MAX_LINE_SAVE_LEN - timestamped_len;
431+
432+
const size_t truncated_log_len = MEMFAULT_MIN(log_len, max_log_msg_len);
433+
// total log length for the log entry .len field includes the timestamp.
434+
const uint8_t total_log_len = (uint8_t)(truncated_log_len + timestamped_len);
435+
// circular buffer space needed includes the metadata (hdr + len) and msg
436+
const size_t bytes_needed = sizeof(sMfltRamLogEntry) + total_log_len;
437+
407438
if (should_lock) {
408439
memfault_lock();
409440
}
@@ -413,10 +444,16 @@ static void prv_log_save(eMemfaultPlatformLogLevel level, const void *log, size_
413444
if (space_free) {
414445
s_memfault_ram_logger.recorded_msg_count++;
415446
sMfltRamLogEntry entry = {
416-
.len = (uint8_t)truncated_log_len,
417-
.hdr = prv_build_header(level, log_type),
447+
.hdr = prv_build_header(level, log_type, timestamped),
448+
.len = total_log_len,
418449
};
419450
memfault_circular_buffer_write(circ_bufp, &entry, sizeof(entry));
451+
#if MEMFAULT_LOG_TIMESTAMPS_ENABLE
452+
if (timestamped) {
453+
timestamp_val = timestamp.info.unix_timestamp_secs;
454+
memfault_circular_buffer_write(circ_bufp, &timestamp_val, sizeof(timestamp_val));
455+
}
456+
#endif
420457
memfault_circular_buffer_write(circ_bufp, log, truncated_log_len);
421458
log_written = true;
422459
} else {

components/core/src/memfault_log_data_source.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static bool prv_encode(sMemfaultCborEncoder *encoder, void *iter) {
155155
}
156156
// To save space, all logs are encoded into a single array (as opposed to using a map or
157157
// array per log):
158-
const size_t elements_per_log = 2; // level, msg
158+
const size_t elements_per_log = 2; // hdr, msg
159159
if (!memfault_cbor_encode_array_begin(encoder, elements_per_log * ctx->num_logs)) {
160160
return false;
161161
}

components/core/src/memfault_log_private.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ extern "C" {
2727
// standard.
2828
//
2929
// Header Layout:
30-
// 0brsxx.tlll
30+
// 0brsxT.tlll
3131
// where
3232
// r = read (1 if the message has been read, 0 otherwise)
3333
// s = sent (1 if the message has been sent, 0 otherwise)
34-
// x = rsvd
34+
// x = reserved
35+
// T = timestamped (1 if the first 4 bytes of the message is a timestamp, 0 otherwise)
3536
// t = type (0 = formatted log, 1 = compact log)
3637
// l = log level (eMemfaultPlatformLogLevel)
3738

@@ -41,6 +42,7 @@ extern "C" {
4142
#define MEMFAULT_LOG_HDR_TYPE_MASK 0x08u
4243
#define MEMFAULT_LOG_HDR_READ_MASK 0x80u // Log has been read through memfault_log_read()
4344
#define MEMFAULT_LOG_HDR_SENT_MASK 0x40u // Log has been sent through g_memfault_log_data_source
45+
#define MEMFAULT_LOG_HDR_TIMESTAMPED_MASK 0x10u // Log payload includes a leading 4-byte timestamp
4446

4547
static inline eMemfaultPlatformLogLevel memfault_log_get_level_from_hdr(uint8_t hdr) {
4648
return (eMemfaultPlatformLogLevel)((hdr & MEMFAULT_LOG_HDR_LEVEL_MASK) >>
@@ -51,16 +53,37 @@ static inline eMemfaultLogRecordType memfault_log_get_type_from_hdr(uint8_t hdr)
5153
return (eMemfaultLogRecordType)((hdr & MEMFAULT_LOG_HDR_TYPE_MASK) >> MEMFAULT_LOG_HDR_TYPE_POS);
5254
}
5355

56+
static inline bool memfault_log_hdr_is_timestamped(uint8_t hdr) {
57+
return (hdr & MEMFAULT_LOG_HDR_TIMESTAMPED_MASK) != 0;
58+
}
59+
60+
// A log entry has the following layout:
61+
//
62+
// [ 1 byte ][ 1 byte ][ len bytes ]
63+
// [ hdr ][ len ][ msg ]
64+
//
65+
// If the timestamped bit is set in the header, the first 4 bytes of the message
66+
// will be a little-endian UNIX timestamp:
67+
//
68+
// [ 1 byte ][ 1 byte ][ 4 bytes ][ len - 4 bytes]
69+
// [ hdr ][ len ][ timestamp ][ msg ]
70+
5471
typedef MEMFAULT_PACKED_STRUCT {
5572
// data about the message stored (details below)
5673
uint8_t hdr;
5774
// the length of the msg
5875
uint8_t len;
59-
// underlying message
76+
// underlying message. note that if the timestamped bit is set, the first 4
77+
// bytes of the message will be the little-endian UNIX timestamp.
6078
uint8_t msg[];
6179
}
6280
sMfltRamLogEntry;
6381

82+
// In the current version of the log entry structure, the maximum length of a
83+
// log message is 255 bytes due to the width of the 'len' field.
84+
MEMFAULT_STATIC_ASSERT(MEMFAULT_LOG_MAX_LINE_SAVE_LEN <= 255,
85+
"MEMFAULT_LOG_MAX_LINE_SAVE_LEN must be <= 255");
86+
6487
typedef struct {
6588
uint32_t read_offset;
6689
void *user_ctx;

components/include/memfault/core/log.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ typedef struct {
144144
eMemfaultLogRecordType type;
145145
// the length of the msg (not including NUL character)
146146
uint32_t msg_len;
147+
#if MEMFAULT_LOG_TIMESTAMPS_ENABLE
148+
// if non-zero, the timestamp of the log
149+
uint32_t timestamp;
150+
#endif
147151
// the message to print which will always be NUL terminated when a preformatted log is returned
148152
// (so it is always safe to call printf without copying the log into another buffer yourself)
149153
char msg[MEMFAULT_LOG_MAX_LINE_SAVE_LEN + 1 /* '\0' */];

components/include/memfault/default_config.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ extern "C" {
165165
#define MEMFAULT_COMPACT_LOG_ENABLE 0
166166
#endif
167167

168+
//! Enable log line timestamps, when memfault_platform_time_get_current() is
169+
//! available.
170+
#ifndef MEMFAULT_LOG_TIMESTAMPS_ENABLE
171+
#define MEMFAULT_LOG_TIMESTAMPS_ENABLE 1
172+
#endif
173+
168174
//! Controls whether or not multiple events will be batched into a single
169175
//! message when reading information via the event storage data source.
170176
//!

components/include/memfault/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ typedef struct {
2020
} sMfltSdkVersion;
2121

2222
#define MEMFAULT_SDK_VERSION \
23-
{ .major = 1, .minor = 20, .patch = 0 }
24-
#define MEMFAULT_SDK_VERSION_STR "1.20.0"
23+
{ .major = 1, .minor = 21, .patch = 0 }
24+
#define MEMFAULT_SDK_VERSION_STR "1.21.0"
2525

2626
#ifdef __cplusplus
2727
}

examples/freertos/src/console.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,20 @@ static int prv_leak_memory(int argc, char *argv[]) {
154154
return 0;
155155
}
156156

157+
static int prv_assert_with_reason(int argc, char *argv[]) {
158+
eMemfaultRebootReason reason = kMfltRebootReason_Assert;
159+
if (argc >= 2) {
160+
// integer argument that should be used for trace reason
161+
reason = (eMemfaultRebootReason)strtoul(argv[1], NULL, 0);
162+
}
163+
164+
MEMFAULT_LOG_ERROR("Triggering assert with reason code %d", reason);
165+
166+
MEMFAULT_ASSERT_WITH_REASON(0, reason);
167+
168+
return 0;
169+
}
170+
157171
static const sMemfaultShellCommand s_freertos_example_shell_extension_list[] = {
158172
{
159173
.command = "freertos_vassert",
@@ -189,6 +203,11 @@ static const sMemfaultShellCommand s_freertos_example_shell_extension_list[] = {
189203
.command = "leak",
190204
.handler = prv_leak_memory,
191205
.help = "Allocate memory and leak it. Usage: leak <num_bytes>",
206+
},
207+
{
208+
.command = "assert_with_reason",
209+
.handler = prv_assert_with_reason,
210+
.help = "Execute an assert with a custom reason code",
192211
}
193212
};
194213
#endif

ports/esp_idf/memfault/common/memfault_platform_core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ static void prv_record_reboot_reason(void) {
103103
reboot_reason = kMfltRebootReason_SoftwareReset;
104104
break;
105105
case ESP_RST_INT_WDT:
106+
reboot_reason = kMfltRebootReason_SoftwareWatchdog;
107+
break;
106108
case ESP_RST_TASK_WDT:
109+
reboot_reason = kMfltRebootReason_TaskWatchdog;
110+
break;
107111
case ESP_RST_WDT:
108112
reboot_reason = kMfltRebootReason_HardwareWatchdog;
109113
break;

0 commit comments

Comments
 (0)