Skip to content

Commit e403b90

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 0.36.0 (Build 838)
1 parent d7ed96d commit e403b90

28 files changed

+1342
-369
lines changed

CHANGES.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
### Changes between Memfault SDK 0.34.2 and SDK 0.35.0 - Dec 6, 2022
2+
3+
#### :chart_with_upwards_trend: Improvements
4+
5+
- ESP-IDF:
6+
7+
- Add support for
8+
[just-released ESP-IDF v5](https://github.com/espressif/esp-idf/releases/tag/v5.0)
9+
🎉!
10+
- Add an auto-OTA (and auto-WiFi-join) feature to the
11+
[ESP32 example app](examples/esp32)- enabled by default but can be disabled
12+
with Kconfig
13+
14+
- The [Heap Stats tracing component](https://mflt.io/mcu-heap-stats) has been
15+
revamped to make more efficient usage of the bookeeping structure. Usage
16+
should be the same as before, but now should provide more data without
17+
significantly expanding the memory utilization.
18+
119
### Changes between Memfault SDK 0.35.0 and SDK 0.34.2 - Nov 22, 2022
220

321
#### :rocket: New Features

VERSION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
BUILD ID: 615
2-
GIT COMMIT: 465ee2834
1+
BUILD ID: 838
2+
GIT COMMIT: 588aa169f

components/core/src/memfault_heap_stats.c

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
//! malloc/free implementation to track last allocations with callsite
88
//! information.
99

10-
#include "memfault/core/heap_stats.h"
11-
#include "memfault/core/heap_stats_impl.h"
12-
1310
#include <stdbool.h>
1411
#include <stddef.h>
1512
#include <stdint.h>
@@ -18,14 +15,20 @@
1815
#include "memfault/config.h"
1916
#include "memfault/core/compiler.h"
2017
#include "memfault/core/debug_log.h"
18+
#include "memfault/core/heap_stats.h"
19+
#include "memfault/core/heap_stats_impl.h"
2120
#include "memfault/core/math.h"
2221
#include "memfault/core/platform/debug_log.h"
2322
#include "memfault/core/platform/overrides.h"
2423

25-
#define MEMFAULT_HEAP_STATS_VERSION 1
24+
#define MEMFAULT_HEAP_STATS_VERSION 2
25+
26+
MEMFAULT_STATIC_ASSERT(MEMFAULT_HEAP_STATS_MAX_COUNT < MEMFAULT_HEAP_STATS_LIST_END,
27+
"Number of entries in heap stats exceeds limits");
2628

2729
sMfltHeapStats g_memfault_heap_stats = {
2830
.version = MEMFAULT_HEAP_STATS_VERSION,
31+
.stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END,
2932
};
3033
sMfltHeapStatEntry g_memfault_heap_stats_pool[MEMFAULT_HEAP_STATS_MAX_COUNT];
3134

@@ -43,7 +46,10 @@ static void prv_heap_stats_unlock(void) {
4346

4447
void memfault_heap_stats_reset(void) {
4548
prv_heap_stats_lock();
46-
g_memfault_heap_stats = (sMfltHeapStats){0};
49+
g_memfault_heap_stats = (sMfltHeapStats){
50+
.version = MEMFAULT_HEAP_STATS_VERSION,
51+
.stats_pool_head = MEMFAULT_HEAP_STATS_LIST_END,
52+
};
4753
memset(g_memfault_heap_stats_pool, 0, sizeof(g_memfault_heap_stats_pool));
4854
prv_heap_stats_unlock();
4955
}
@@ -54,13 +60,43 @@ bool memfault_heap_stats_empty(void) {
5460
return g_memfault_heap_stats_pool[0].info.size == 0;
5561
}
5662

57-
//! Return the next slot to write
58-
static sMfltHeapStatEntry *prv_get_next_entry(void) {
59-
sMfltHeapStatEntry *slot =
60-
&g_memfault_heap_stats_pool[g_memfault_heap_stats.stats_pool_head];
61-
g_memfault_heap_stats.stats_pool_head = (g_memfault_heap_stats.stats_pool_head + 1) %
62-
MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool);
63-
return slot;
63+
//! Get the previous entry index of the entry index to be found
64+
//!
65+
//! Iterates through the entry array checking if entry is in use and if the
66+
//! next entry index matches the search index. If the previous entry cannot be found,
67+
//! MEMFAULT_HEAP_STATS_LIST_END is returned
68+
static uint16_t prv_get_previous_entry(uint16_t search_entry_index) {
69+
uint16_t index = MEMFAULT_HEAP_STATS_LIST_END;
70+
71+
for (uint16_t i = 0; i < MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool); i++) {
72+
sMfltHeapStatEntry *entry = &g_memfault_heap_stats_pool[i];
73+
if (entry->info.in_use && entry->info.next_entry_index == search_entry_index) {
74+
index = i;
75+
break;
76+
}
77+
}
78+
79+
return index;
80+
}
81+
82+
//! Return the next entry index to write new data to
83+
//!
84+
//! First searches for unused entries
85+
//! If none are found then traverses list to oldest (last) entry
86+
static uint16_t prv_get_new_entry_index(void) {
87+
sMfltHeapStatEntry *entry;
88+
89+
for (uint16_t i = 0; i < MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool); i++) {
90+
entry = &g_memfault_heap_stats_pool[i];
91+
92+
if (!entry->info.in_use) {
93+
return i; // favor unused entries
94+
}
95+
}
96+
97+
// No unused entry found, return the oldest (entry with next index of
98+
// MEMFAULT_HEAP_STATS_LIST_END)
99+
return prv_get_previous_entry(MEMFAULT_HEAP_STATS_LIST_END);
64100
}
65101

66102
void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
@@ -71,8 +107,9 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
71107
if (g_memfault_heap_stats.in_use_block_count > g_memfault_heap_stats.max_in_use_block_count) {
72108
g_memfault_heap_stats.max_in_use_block_count = g_memfault_heap_stats.in_use_block_count;
73109
}
74-
sMfltHeapStatEntry *slot = prv_get_next_entry();
75-
*slot = (sMfltHeapStatEntry){
110+
uint16_t new_entry_index = prv_get_new_entry_index();
111+
sMfltHeapStatEntry *new_entry = &g_memfault_heap_stats_pool[new_entry_index];
112+
*new_entry = (sMfltHeapStatEntry){
76113
.lr = lr,
77114
.ptr = ptr,
78115
.info =
@@ -81,6 +118,19 @@ void memfault_heap_stats_malloc(const void *lr, const void *ptr, size_t size) {
81118
.in_use = 1u,
82119
},
83120
};
121+
122+
// Append new entry to head of the list
123+
new_entry->info.next_entry_index = g_memfault_heap_stats.stats_pool_head;
124+
g_memfault_heap_stats.stats_pool_head = new_entry_index;
125+
126+
// Find next oldest entry (points to new entry)
127+
// Update next entry index to MEMFAULT_HEAP_STATS_LIST_END
128+
uint16_t next_oldest_entry_index = prv_get_previous_entry(new_entry_index);
129+
130+
if (next_oldest_entry_index != MEMFAULT_HEAP_STATS_LIST_END) {
131+
g_memfault_heap_stats_pool[next_oldest_entry_index].info.next_entry_index =
132+
MEMFAULT_HEAP_STATS_LIST_END;
133+
}
84134
}
85135

86136
prv_heap_stats_unlock();
@@ -92,9 +142,26 @@ void memfault_heap_stats_free(const void *ptr) {
92142
g_memfault_heap_stats.in_use_block_count--;
93143

94144
// if the pointer exists in the tracked stats, mark it as freed
95-
for (size_t i = 0; i < MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool); i++) {
96-
if ((g_memfault_heap_stats_pool[i].ptr == ptr) && g_memfault_heap_stats_pool[i].info.in_use) {
97-
g_memfault_heap_stats_pool[i].info.in_use = 0;
145+
for (uint16_t i = 0; i < MEMFAULT_ARRAY_SIZE(g_memfault_heap_stats_pool); i++) {
146+
sMfltHeapStatEntry *entry = &g_memfault_heap_stats_pool[i];
147+
if ((entry->ptr == ptr) && entry->info.in_use) {
148+
entry->info.in_use = 0;
149+
150+
// Find the entry previous to the removed entry
151+
uint16_t previous_entry_index = prv_get_previous_entry(i);
152+
153+
// If list head removed, set next entry as new list head
154+
if (g_memfault_heap_stats.stats_pool_head == i) {
155+
g_memfault_heap_stats.stats_pool_head = entry->info.next_entry_index;
156+
}
157+
158+
// If there's a valid previous entry, set it's next index to removed entry's
159+
if (previous_entry_index != MEMFAULT_HEAP_STATS_LIST_END) {
160+
g_memfault_heap_stats_pool[previous_entry_index].info.next_entry_index =
161+
entry->info.next_entry_index;
162+
}
163+
164+
entry->info.next_entry_index = MEMFAULT_HEAP_STATS_LIST_END;
98165
break;
99166
}
100167
}

components/include/memfault/core/heap_stats_impl.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ extern "C" {
2222
//! Number of regions used by heap stats
2323
#define MEMFAULT_HEAP_STATS_NUM_RAM_REGIONS 2
2424

25+
//! Value used to indicate entry is the end of the list
26+
#define MEMFAULT_HEAP_STATS_LIST_END UINT16_MAX
27+
28+
typedef struct MfltHeapStatEntry sMfltHeapStatEntry;
2529

2630
//! The heap stats data structure, which is exported when capturing a core.
2731
typedef struct MfltHeapStatEntry {
@@ -37,10 +41,11 @@ typedef struct MfltHeapStatEntry {
3741
uint32_t size : 31;
3842
// 1 bit indicating whether this entry is still in use or has been freed
3943
uint32_t in_use : 1;
44+
// Index to next oldest entry in heap stats entry array,
45+
uint16_t next_entry_index;
4046
} info;
4147
} sMfltHeapStatEntry;
4248

43-
4449
typedef struct MfltHeapStats {
4550
uint8_t version;
4651

@@ -51,7 +56,7 @@ typedef struct MfltHeapStats {
5156
uint32_t max_in_use_block_count;
5257

5358
// Allocation entry list pointer
54-
size_t stats_pool_head;
59+
uint16_t stats_pool_head;
5560
} sMfltHeapStats;
5661

5762
extern sMfltHeapStats g_memfault_heap_stats;

components/include/memfault/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ typedef struct {
1919
uint8_t patch;
2020
} sMfltSdkVersion;
2121

22-
#define MEMFAULT_SDK_VERSION { .major = 0, .minor = 35, .patch = 0 }
22+
#define MEMFAULT_SDK_VERSION { .major = 0, .minor = 36, .patch = 0 }
2323

2424
#ifdef __cplusplus
2525
}

examples/esp32/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ As a sanity check, let's request the device info from the debug console, enter
160160
esp32> get_device_info
161161
I (55239) mflt: S/N: 30AEA44AFF28
162162
I (55239) mflt: SW type: esp32-main
163-
I (55239) mflt: SW version: 1.0.0
163+
I (55239) mflt: SW version: 1.0.0-dev
164164
I (55239) mflt: HW version: esp32-proto
165165
```
166166

@@ -269,9 +269,9 @@ The following steps can be used to exercise OTA functionality:
269269
I (33288) mflt: Result: 0
270270
```
271271

272-
3. Change the `MEMFAULT_ESP32_MAIN_FIRMWARE_VERSION` to `"1.0.1"` in
273-
[`apps/memfault_demo_app/main/memfault_platform_device_info.c`](apps/memfault_demo_app/main/memfault_platform_device_info.c),
274-
and rebuild (`idf.py build`), but don't load it to the device. We'll use this
272+
3. Use `idf.py menuconfig` to change the value of
273+
`MEMFAULT_ESP32_MAIN_FIRMWARE_VERSION` config variable to `"1.0.1"`, and
274+
rebuild (`idf.py build`), but don't load it to the device. We'll use this
275275
build as our OTA payload!
276276

277277
4. In the Memfault web app, go to "Software->OTA Releases" and create an OTA

examples/esp32/apps/memfault_demo_app/main/CMakeLists.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
set(COMPONENT_SRCS
1+
list(APPEND
2+
COMPONENT_SRCS
23
cmd_app.c
34
cmd_system.c
4-
cmd_wifi.c
55
console_example_main.c
66
memfault_platform_device_info.c
77
)
8+
if("${IDF_VERSION_MAJOR}" VERSION_GREATER_EQUAL 4)
9+
list(APPEND
10+
COMPONENT_SRCS
11+
cmd_wifi.c
12+
)
13+
else()
14+
list(APPEND
15+
COMPONENT_SRCS
16+
cmd_wifi_legacy.c
17+
)
18+
endif()
819

920
set(COMPONENT_ADD_INCLUDEDIRS .)
1021

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
menu "Example Configuration"
1+
menu "Memfault App Configuration"
22

33
config STORE_HISTORY
44
bool "Store command history in flash"
@@ -8,4 +8,24 @@ config STORE_HISTORY
88
command history. If this option is enabled, initalizes a FAT filesystem
99
and uses it to store command history.
1010

11-
endmenu
11+
config MEMFAULT_ESP32_MAIN_FIRMWARE_VERSION
12+
string "Main firmware version"
13+
default "1.0.0-dev"
14+
help
15+
The version of the main firmware. Used when the device reports in as
16+
well as for OTA checks.
17+
18+
config MEMFAULT_APP_OTA
19+
bool "Enable automatic periodic check+update for OTA"
20+
default y
21+
help
22+
Enables the Memfault OTA subsystem. This will periodically check for
23+
updates and apply them if available.
24+
25+
config MEMFAULT_APP_WIFI_AUTOJOIN
26+
bool "Enable automatic WiFi connection"
27+
default y
28+
help
29+
Automatically join if credentials are configured.
30+
31+
endmenu

examples/esp32/apps/memfault_demo_app/main/cmd_app.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
//! Miscellaneous commands specific to this example app
66
//!
77

8+
#include <ctype.h>
89
#include <stdio.h>
910
#include <string.h>
10-
#include <ctype.h>
11-
#include "esp_log.h"
12-
#include "esp_console.h"
11+
1312
#include "cmd_decl.h"
13+
#include "esp_console.h"
14+
#include "esp_log.h"
1415
#include "freertos/FreeRTOS.h"
1516
#include "freertos/semphr.h"
1617
#include "sdkconfig.h"
1718

1819
//! cause the task watchdog to fire by deadlocking the example task
19-
static int test_task_watchdog(int argc, char** argv)
20-
{
20+
static int test_task_watchdog(int argc, char** argv) {
2121
(void)argc, (void)argv;
2222
ESP_LOGI(__func__, "Setting the example_task to stuck, will cause the task watchdog to fire");
2323

@@ -26,18 +26,16 @@ static int test_task_watchdog(int argc, char** argv)
2626
return 0;
2727
}
2828

29-
static void register_test_task_watchdog(void)
30-
{
29+
static void register_test_task_watchdog(void) {
3130
const esp_console_cmd_t cmd = {
32-
.command = "test_task_watchdog",
33-
.help = "Demonstrate the task watchdog tripping on a deadlock",
34-
.hint = NULL,
35-
.func = &test_task_watchdog,
31+
.command = "test_task_watchdog",
32+
.help = "Demonstrate the task watchdog tripping on a deadlock",
33+
.hint = NULL,
34+
.func = &test_task_watchdog,
3635
};
37-
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
36+
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
3837
}
3938

40-
void register_app(void)
41-
{
39+
void register_app(void) {
4240
register_test_task_watchdog();
4341
}

examples/esp32/apps/memfault_demo_app/main/cmd_decl.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@
1111
#include "freertos/FreeRTOS.h"
1212
#include "freertos/semphr.h"
1313

14-
// Register system functions
14+
// Register system console commands
1515
void register_system(void);
1616

17-
// Register WiFi functions
17+
// Register WiFi console commands
1818
void register_wifi(void);
1919

20-
// Register app-specific functions
20+
// Attempt to join a wifi network
21+
bool wifi_join(const char* ssid, const char* pass);
22+
void wifi_load_creds(char** ssid, char** password);
23+
24+
// Register app-specific console commands
25+
void register_app(void);
2126

2227
// This semaphore is used to control the Task Watchdog example task
2328
extern SemaphoreHandle_t g_example_task_lock;
24-
25-
void register_app(void);

0 commit comments

Comments
 (0)