Skip to content

Commit 732dace

Browse files
simensrostadrlubos
authored andcommitted
modules: memfault-firmware-sdk: Add option to post metrics on boot
Add a Kconfig option to enable posting metrics on boot without waiting for the first upload interval. `CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED` Minor cleanup in memfault_lte_coredump: - Add support for the new Kconfig option. - Make state structure variable non-global as global variables should be avoided where possible. - Remove the word "coredump" from state names as the layer not only handles coredumps. Add documentation for the new option. Signed-off-by: Simen S. Røstad <[email protected]>
1 parent ea6f881 commit 732dace

File tree

4 files changed

+85
-43
lines changed

4 files changed

+85
-43
lines changed

doc/nrf/libraries/debug/memfault_ncs.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ The library has built-in connection awareness and tries to post the coredump to
6868
If unsuccessful within the number of attempts, the library gives up.
6969
If at any point the network is lost during the retry process, the library waits for the device to reconnect before restarting the retry process.
7070

71+
When a coredump is found after boot, the library automatically triggers a heartbeat and sends the heartbeat data along with the coredump to Memfault.
72+
73+
To also send an initial heartbeat when no coredump is available, set the :kconfig:option:`CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED` Kconfig option to ``y``.
74+
This is useful for sending initial metrics to Memfault after boot without having to wait for the first automatic upload set by :kconfig:option:`CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD_INTERVAL_SECS`.
75+
7176
This feature is useful when you want to post the coredump as soon as possible after a crash and it is not desirable to wait for the next periodic upload set by :kconfig:option:`CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD_INTERVAL_SECS`.
7277
Alternatively, you can manually trigger the coredump upload by calling the :c:func:`memfault_zephyr_port_post_data` function.
7378
You can use the :c:func:`memfault_coredump_has_valid_coredump` function to check whether a coredump is available.
@@ -122,6 +127,7 @@ Configuration options in |NCS|
122127
The Kconfig options for Memfault that are defined in |NCS| provide some additional features compared to the options that are already implemented in Memfault SDK:
123128

124129
* :kconfig:option:`CONFIG_MEMFAULT_NCS_POST_COREDUMP_ON_NETWORK_CONNECTED`
130+
* :kconfig:option:`CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED`
125131
* :kconfig:option:`CONFIG_MEMFAULT_NCS_POST_MODEM_TRACE_ON_COREDUMP`
126132
* :kconfig:option:`CONFIG_MEMFAULT_NCS_PROJECT_KEY`
127133
* :kconfig:option:`CONFIG_MEMFAULT_NCS_PROVISION_CERTIFICATES`

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,11 @@ Memfault integration
468468

469469
* Updated the ``CONFIG_MEMFAULT_DEVICE_INFO_BUILTIN`` Kconfig option has been renamed to :kconfig:option:`CONFIG_MEMFAULT_NCS_DEVICE_INFO_BUILTIN`.
470470

471+
* Added:
472+
473+
* The option ``CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED`` to control whether an initial heartbeat is sent when the device connects to a network.
474+
Useful to be able to show device status and initial metrics in the Memfault dashboard as soon as possible after boot.
475+
471476
AVSystem integration
472477
--------------------
473478

modules/memfault-firmware-sdk/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ config MEMFAULT_NCS_POST_COREDUMP_THREAD_STACK_SIZE
242242
int "Post coredump thread size"
243243
default 512
244244

245+
config MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED
246+
bool "Post initial heartbeat on network connected without coredump"
247+
default y
248+
help
249+
When enabled, if no coredump is available on network connection, trigger
250+
an initial heartbeat and post data to Memfault. This is useful for sending
251+
initial metrics to Memfault after boot without having to wait for the first automatic upload
252+
set by CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD_INTERVAL_SECONDS.
253+
Note that when a coredump is found, heartbeat data is always sent along with
254+
the coredump regardless of this setting.
255+
245256
endif # MEMFAULT_NCS_POST_COREDUMP_ON_NETWORK_CONNECTED
246257

247258
config MEMFAULT_NCS_ETB_CAPTURE

modules/memfault-firmware-sdk/memfault_lte_coredump.c

Lines changed: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ enum library_state {
3232
STATE_WAITING_FOR_NRF_MODEM_LIB_INIT,
3333
STATE_WAITING_FOR_NETWORK_CONNECTION,
3434
STATE_NETWORK_CONNECTED,
35-
STATE_COREDUMP_SEND_ATTEMPT,
36-
STATE_COREDUMP_SEND_BACKOFF,
35+
STATE_SEND_ATTEMPT,
36+
STATE_SEND_BACKOFF,
3737
STATE_FINISHED,
3838
STATE_ERROR
3939
};
@@ -46,9 +46,9 @@ enum library_event {
4646
EVENT_PDN_ACTIVATED,
4747
EVENT_PDN_DEACTIVATED,
4848
EVENT_BACKOFF_TIMER_EXPIRED,
49-
EVENT_COREDUMP_SEND_FAIL,
50-
EVENT_COREDUMP_SEND_SUCCESS,
51-
EVENT_COREDUMP_SEND_RETRY_COUNT_EXCEEDED,
49+
EVENT_SEND_FAIL,
50+
EVENT_SEND_SUCCESS,
51+
EVENT_SEND_RETRY_COUNT_EXCEEDED,
5252
EVENT_ERROR
5353
};
5454

@@ -61,16 +61,26 @@ struct fsm_state_object {
6161
/* This must be first */
6262
struct smf_ctx ctx;
6363

64+
/* Current event being processed by the state machine */
6465
enum library_event event;
6566

67+
/* Number of retry attempts for sending data to Memfault */
6668
uint8_t retry_count;
6769

70+
/* Delayed work for retry backoff timing */
6871
struct k_work_delayable backoff_work;
6972

73+
/* Flag that represents if the device is registered to LTE network */
7074
bool lte_registered;
75+
76+
/* Flag that represents if PDN (Packet Data Network) connection is active */
7177
bool pdn_active;
7278

79+
/* Heartbeat has been triggered (ensures single trigger per session) */
7380
bool heartbeat_triggered;
81+
82+
/* Valid coredump is available to send */
83+
bool has_coredump;
7484
};
7585

7686
/* Forward declarations: Local functions */
@@ -89,10 +99,10 @@ static enum smf_state_result state_waiting_for_nrf_modem_lib_init_run(void *o);
8999
static enum smf_state_result state_waiting_for_network_connection_run(void *o);
90100
static void state_network_connected_entry(void *o);
91101
static enum smf_state_result state_network_connected_run(void *o);
92-
static void state_coredump_send_attempt_entry(void *o);
93-
static enum smf_state_result state_coredump_send_attempt_run(void *o);
94-
static void state_coredump_send_backoff_entry(void *o);
95-
static enum smf_state_result state_coredump_send_backoff_run(void *o);
102+
static void state_send_attempt_entry(void *o);
103+
static enum smf_state_result state_send_attempt_run(void *o);
104+
static void state_send_backoff_entry(void *o);
105+
static enum smf_state_result state_send_backoff_run(void *o);
96106
static void state_finished_entry(void *o);
97107
static void state_error_entry(void *o);
98108

@@ -121,19 +131,19 @@ static const struct smf_state states[] = {
121131
NULL,
122132
&states[STATE_RUNNING],
123133
#if defined(CONFIG_MEMFAULT_NCS_POST_COREDUMP_AFTER_INITIAL_DELAY)
124-
&states[STATE_COREDUMP_SEND_BACKOFF]),
134+
&states[STATE_SEND_BACKOFF]),
125135
#else
126-
&states[STATE_COREDUMP_SEND_ATTEMPT]),
136+
&states[STATE_SEND_ATTEMPT]),
127137
#endif /* CONFIG_MEMFAULT_NCS_POST_COREDUMP_AFTER_INITIAL_DELAY */
128-
[STATE_COREDUMP_SEND_ATTEMPT] =
129-
SMF_CREATE_STATE(state_coredump_send_attempt_entry,
130-
state_coredump_send_attempt_run,
138+
[STATE_SEND_ATTEMPT] =
139+
SMF_CREATE_STATE(state_send_attempt_entry,
140+
state_send_attempt_run,
131141
NULL,
132142
&states[STATE_NETWORK_CONNECTED],
133143
NULL),
134-
[STATE_COREDUMP_SEND_BACKOFF] =
135-
SMF_CREATE_STATE(state_coredump_send_backoff_entry,
136-
state_coredump_send_backoff_run,
144+
[STATE_SEND_BACKOFF] =
145+
SMF_CREATE_STATE(state_send_backoff_entry,
146+
state_send_backoff_run,
137147
NULL,
138148
&states[STATE_NETWORK_CONNECTED],
139149
NULL),
@@ -153,11 +163,11 @@ static const struct smf_state states[] = {
153163

154164
static void timer_work_fn(struct k_work *work)
155165
{
166+
ARG_UNUSED(work);
167+
156168
event_send(EVENT_BACKOFF_TIMER_EXPIRED);
157169
}
158170

159-
static struct fsm_state_object state_object = { 0 };
160-
161171
/* nRF Modem Library Handlers */
162172

163173
static void on_modem_lib_init(int ret, void *ctx)
@@ -341,10 +351,10 @@ static enum smf_state_result state_running_run(void *o)
341351

342352
return SMF_EVENT_HANDLED;
343353

344-
case EVENT_COREDUMP_SEND_RETRY_COUNT_EXCEEDED:
354+
case EVENT_SEND_RETRY_COUNT_EXCEEDED:
345355
__fallthrough;
346356

347-
case EVENT_COREDUMP_SEND_SUCCESS:
357+
case EVENT_SEND_SUCCESS:
348358
smf_set_state(SMF_CTX(state_object), &states[STATE_FINISHED]);
349359

350360
return SMF_EVENT_HANDLED;
@@ -413,22 +423,24 @@ static enum smf_state_result state_network_connected_run(void *o)
413423
return SMF_EVENT_PROPAGATE;
414424
}
415425

416-
static void state_coredump_send_attempt_entry(void *o)
426+
static void state_send_attempt_entry(void *o)
417427
{
418428
int err;
419429

420430
struct fsm_state_object *state_object = o;
421431

422-
LOG_DBG("state_coredump_send_attempt_entry");
432+
LOG_DBG("state_send_attempt_entry");
423433

424434
if (!state_object->heartbeat_triggered) {
425-
LOG_DBG("Triggering heartbeat");
435+
LOG_DBG("Triggering Memfault metrics heartbeat");
426436
memfault_metrics_heartbeat_debug_trigger();
427437

428438
state_object->heartbeat_triggered = true;
439+
LOG_DBG("Memfault metrics heartbeat triggered successfully");
429440
}
430441

431-
if (IS_ENABLED(CONFIG_MEMFAULT_NCS_POST_MODEM_TRACE_ON_COREDUMP)) {
442+
if (state_object->has_coredump &&
443+
IS_ENABLED(CONFIG_MEMFAULT_NCS_POST_MODEM_TRACE_ON_COREDUMP)) {
432444
err = memfault_lte_coredump_modem_trace_init();
433445
if (err == -EIO) {
434446
LOG_ERR("memfault_lte_coredump_modem_trace_init, error: %d", err);
@@ -443,50 +455,50 @@ static void state_coredump_send_attempt_entry(void *o)
443455
}
444456
}
445457

446-
LOG_DBG("Attempting to send coredump");
458+
LOG_DBG("Attempting to send Memfault data (coredump and/or heartbeat)");
447459

448460
err = memfault_zephyr_port_post_data();
449461
if (err) {
450-
LOG_DBG("Failed to post data to Memfault");
451-
event_send(EVENT_COREDUMP_SEND_FAIL);
462+
LOG_WRN("Failed to post data to Memfault, error: %d", err);
463+
event_send(EVENT_SEND_FAIL);
452464
} else {
453-
LOG_DBG("Succeeded posting data to Memfault");
454-
event_send(EVENT_COREDUMP_SEND_SUCCESS);
465+
LOG_DBG("Successfully posted data to Memfault");
466+
event_send(EVENT_SEND_SUCCESS);
455467
}
456468
}
457469

458-
static enum smf_state_result state_coredump_send_attempt_run(void *o)
470+
static enum smf_state_result state_send_attempt_run(void *o)
459471
{
460472
struct fsm_state_object *state_object = o;
461473

462-
LOG_DBG("state_coredump_send_attempt_run");
474+
LOG_DBG("state_send_attempt_run");
463475

464-
if (state_object->event == EVENT_COREDUMP_SEND_FAIL) {
465-
smf_set_state(SMF_CTX(state_object), &states[STATE_COREDUMP_SEND_BACKOFF]);
476+
if (state_object->event == EVENT_SEND_FAIL) {
477+
smf_set_state(SMF_CTX(state_object), &states[STATE_SEND_BACKOFF]);
466478

467479
return SMF_EVENT_HANDLED;
468480
}
469481

470482
return SMF_EVENT_PROPAGATE;
471483
}
472484

473-
static void state_coredump_send_backoff_entry(void *o)
485+
static void state_send_backoff_entry(void *o)
474486
{
475487
struct fsm_state_object *state_object = o;
476488

477-
LOG_DBG("state_coredump_send_backoff_entry");
489+
LOG_DBG("state_send_backoff_entry");
478490

479491
schedule_send_backoff(state_object);
480492
}
481493

482-
static enum smf_state_result state_coredump_send_backoff_run(void *o)
494+
static enum smf_state_result state_send_backoff_run(void *o)
483495
{
484496
struct fsm_state_object *state_object = o;
485497

486-
LOG_DBG("state_coredump_send_backoff_run");
498+
LOG_DBG("state_send_backoff_run");
487499

488500
if (state_object->event == EVENT_BACKOFF_TIMER_EXPIRED) {
489-
smf_set_state(SMF_CTX(state_object), &states[STATE_COREDUMP_SEND_ATTEMPT]);
501+
smf_set_state(SMF_CTX(state_object), &states[STATE_SEND_ATTEMPT]);
490502
return SMF_EVENT_HANDLED;
491503
}
492504

@@ -529,7 +541,7 @@ static void schedule_send_backoff(struct fsm_state_object *state_object)
529541
state_object->retry_count++;
530542

531543
if (state_object->retry_count >= CONFIG_MEMFAULT_NCS_POST_COREDUMP_RETRIES_MAX) {
532-
event_send(EVENT_COREDUMP_SEND_RETRY_COUNT_EXCEEDED);
544+
event_send(EVENT_SEND_RETRY_COUNT_EXCEEDED);
533545

534546
LOG_DBG("Retry count exceeded");
535547

@@ -549,21 +561,29 @@ static void schedule_send_backoff(struct fsm_state_object *state_object)
549561
static void mflt_lte_coredump_fn(void)
550562
{
551563
int err;
564+
struct fsm_state_object state_object = { 0 };
552565

553566
k_work_init_delayable(&state_object.backoff_work, timer_work_fn);
554567

555-
bool has_coredump = memfault_coredump_has_valid_coredump(NULL);
568+
state_object.has_coredump = memfault_coredump_has_valid_coredump(NULL);
556569

557-
if (has_coredump) {
558-
LOG_DBG("Coredump found");
570+
if (state_object.has_coredump) {
571+
LOG_DBG("Coredump found, sending coredump with heartbeat data");
559572
smf_set_initial(SMF_CTX(&state_object),
560573
&states[STATE_WAITING_FOR_NRF_MODEM_LIB_INIT]);
561574
} else {
562575
LOG_DBG("No coredump found");
576+
577+
#if defined(CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED)
578+
LOG_DBG("Posting initial heartbeat data to Memfault");
579+
smf_set_initial(SMF_CTX(&state_object),
580+
&states[STATE_WAITING_FOR_NRF_MODEM_LIB_INIT]);
581+
#else
563582
smf_set_initial(SMF_CTX(&state_object),
564583
&states[STATE_FINISHED]);
565584

566585
return;
586+
#endif /* CONFIG_MEMFAULT_NCS_POST_INITIAL_HEARTBEAT_ON_NETWORK_CONNECTED */
567587
}
568588

569589
while (1) {

0 commit comments

Comments
 (0)