Skip to main content

Demo CLI for Zephyr RTOS

The demo CLI lets you explore features of the SDK components before integrating the SDK into your product. You might also find it helpful to adapt the CLI to your product and use it to exercise your own Memfault implementation.

This guide explains the commands available in the demo CLI built for Zephyr-based platforms and how to interpret their output.

Enabling the Demo CLI

The demo CLI is enabled automatically through Zephyr's build system, however here are the steps to confirm the demo CLI is part of your build:

  1. Set the required Kconfigs in prj.conf, other conf files, or through default values:

    CONFIG_SHELL=y
    CONFIG_MEMFAULT=y
    CONFIG_MEMFAULT_SHELL=y

    Note that for NCS, there is an additional set of shell commands, which are enabled by default when CONFIG_MEMFAULT_SHELL=y but are explicitly enabled with:

    CONFIG_MEMFAULT_NRF_SHELL=y

Running a Command

The CLI displays a prompt to indicate it is ready to accept a command. To see if the CLI is running, press enter and the prompt should be printed:

uart:~$ mflt

To run a command, type mflt followed by its name and press enter. Try the mflt command to get started.

Command Reference

mflt

The mflt command shows all available commands. Type mflt and press enter:

uart:~$ mflt
mflt - Memfault Test Commands
Subcommands:
clear_core :clear coredump collected
export :dump chunks collected by Memfault SDK using
https://mflt.io/chunk-data-export
get_core :check if coredump is stored and present
get_device_info :display device information
get_latest_release :checks to see if new ota payload is available
coredump_size :print coredump computed size and storage capacity
heartbeat_dump :dump current Memfault metrics heartbeat state
post_chunks :Post Memfault data to cloud
test :commands to verify memfault data collection
(https://mflt.io/mcu-test-commands)
uart:~$

Some reference implementations have more commands than others. For example, some targets have network connectivity and can send data directly to the Memfault cloud via the post_chunks command. Devices without this ability will not have that command.

get_device_info

The get_device_info command shows the information configured in the reference implementation's memfault_platform_get_device_info():

uart:~$ get_device_info
[08:50:44.140,000] <inf> mflt: S/N: DEMOSERIAL
[08:50:44.140,000] <inf> mflt: SW type: zephyr-app
[08:50:44.140,000] <inf> mflt: SW version: 1.0.0+35a4cfddd2
[08:50:44.140,000] <inf> mflt: HW version: qemu_cortex_m3
uart:~$

This information is sent to Memfault with any communications to identify the device and the firmware it is running.

test [sub-command] for crashes

Most test commands exercise Memfault through crashing:

  • test assert - trigger a Memfault assert
  • test busfault - trigger a C assert
  • test hang - trigger a busfault
  • test hardfault - trigger a hardfault
  • test memmanage - trigger a memory management fault
  • test usagefault - trigger a usage fault
  • test zassert - trigger a Zephyr assert
  • test double_free - trigger a double free error
  • test badptr - trigger a fault via a store to a bad address
  • test isr_badptr - trigger a fault via a store to a bad address from an ISR

The crash will be intercepted by the fault handler in the Memfault panics component, a coredump will be generated and stored, and then the device reboots. Typically, build id and device info will be printed on boot, making it easy to tell that we have rebooted. For example:

uart:~$ mflt test assert
[00:00:13.290,000] <err> os: ***** USAGE FAULT *****
[00:00:13.290,000] <err> os: Attempt to execute undefined instruction
[00:00:13.290,000] <err> os: r0/a1: 0x00008001 r1/a2: 0x20001fd0 r2/a3: 0x20007148
[00:00:13.290,000] <err> os: r3/a4: 0x0000e1e9 r12/ip: 0x000125b6 r14/lr: 0x000074a5
[00:00:13.290,000] <err> os: xpsr: 0x21000000
[00:00:13.290,000] <err> os: r4/v1: 0x00000000 r5/v2: 0x00000001 r6/v3: 0x000125b6
[00:00:13.290,000] <err> os: r7/v4: 0x20001fe0 r8/v5: 0x20002060 r9/v6: 0x0000f600
[00:00:13.290,000] <err> os: r10/v7: 0x00000002 r11/v8: 0x00000000 psp: 0x20001fb0
[00:00:13.290,000] <err> os: EXC_RETURN: 0xfffffffd
[00:00:13.290,000] <err> os: Faulting instruction address (r15/pc): 0x000074a4
*** Booting Zephyr OS build zephyr-v3.5.0 ***
[00:00:00.000,000] <inf> mflt: GNU Build ID: f7477dc0a82cb2275bb2f3578d9192e426ca09ab
[00:00:00.000,000] <inf> main: 👋 Memfault Demo App! Board qemu_cortex_m3

[00:00:00.000,000] <inf> mflt: S/N: DEMOSERIAL
[00:00:00.000,000] <inf> mflt: SW type: zephyr-app
[00:00:00.000,000] <inf> mflt: SW version: 1.0.0+35a4cfddd2
[00:00:00.000,000] <inf> mflt: HW version: qemu_cortex_m3
uart:~$

If you do not see these messages and the prompt return, nor any other indications that the system reset, then something may have gone wrong in the fault handler. Another possibility is that a debugger is attached and it is sitting on a breakpoint. The fault handler in most reference implementations will break into the debugger if one is attached. In GDB, you should be able to use stepi to resume, but see the README for the specific reference implementation you are using in case it has other instructions.

Once the prompt has returned, the storage can be checked with the get_core command. It can then be cleared with clear_core or read out of the coredump storage with export.

note

Once a coredump has been stored in the coredump storage, it will remain there until either storage is cleared (clear_core command) or read out (export command). If you crash again without doing one of these, saving the coredump will fail silently. The device will still crash and reset but the existing coredump will be overwritten.

get_core

The get_core command displays the state of the coredump storage.

If a coredump is present in the coredump storage:

uart:~$ mflt get_core
[00:00:57.670,000] <inf> mflt: Has coredump with size: 3572
uart:~$

If a coredump is not present:

uart:~$ mflt get_core
[00:01:33.540,000] <inf> mflt: No coredump present!
uart:~$

Running get_core only displays information. It does not affect the state of the coredump storage.

clear_core

The clear_core command unconditionally invalidates the coredump storage so that a new coredump can be stored:

uart:~$ mflt clear_core
[00:01:54.730,000] <inf> mflt: Invalidating coredump
uart:~$

The clear_core command will show the same output regardless of whether a coredump was present in the coredump storage or not.

heartbeat_dump

The heartbeat_dump command will print out the current values of the heartbeat metrics. If a value has not been written to a metric in the current heartbeat window, it's value will be shown as null.

uart:~$ mflt heartbeat_dump
[00:02:19.140,000] <inf> mflt: Heartbeat keys/values:
[00:02:19.140,000] <inf> mflt: MemfaultSdkMetric_IntervalMs: 139140
[00:02:19.140,000] <inf> mflt: MemfaultSdkMetric_UnexpectedRebootCount: null
[00:02:19.140,000] <inf> mflt: operational_hours: null
[00:02:19.140,000] <inf> mflt: operational_crashfree_hours: null
[00:02:19.140,000] <inf> mflt: TimerTaskFreeStack: null
[00:02:19.140,000] <inf> mflt: Heap_BytesFree: null
[00:02:19.140,000] <inf> mflt: MainStack_MinBytesFree: null
uart:~$

The heartbeat metrics will only reset after a heartbeat interval has expired or by running the heartbeat command.

test heartbeat

The test heartbeat command captures the current heartbeat, writes it to event storage, and resets the running heartbeat metrics.

uart:~$ mflt test heartbeat
Triggering Heartbeat
[00:02:46.150,000] <inf> mflt: Heartbeat keys/values:
[00:02:46.150,000] <inf> mflt: MemfaultSdkMetric_IntervalMs: 166150
[00:02:46.150,000] <inf> mflt: MemfaultSdkMetric_UnexpectedRebootCount: null
[00:02:46.150,000] <inf> mflt: operational_hours: null
[00:02:46.150,000] <inf> mflt: operational_crashfree_hours: null
[00:02:46.150,000] <inf> mflt: TimerTaskFreeStack: 744
[00:02:46.160,000] <inf> mflt: Heap_BytesFree: 4020
[00:02:46.160,000] <inf> mflt: MainStack_MinBytesFree: 3224
uart:~$

The current values of the heartbeat metrics may or may not get printed like above depending on if memfault_metrics_heartbeat_debug_print() is being called in memfault_metrics_heartbeat_collect_data(). memfault_metrics_heartbeat_collect_data() is a function that can be overridden with a user definition if they want to set certain metric values at the end of a heartbeat right before collection.

test reboot

The test reboot command records a reboot reason, the current PC and LR, and then forces a system reboot. This command does not cause a coredump capture since the reboot recorded is considered an expected reboot. Unexpected reboot reboots can also be recorded, and are typically paired with a coredump to aid with debugging.

test logs

The test logs command writes test logs to Memfault's logging buffer.

uart:~$ mflt test logs
Raw log!
[00:03:34.480,000] <inf> mflt: Info log!
[00:03:34.480,000] <wrn> mflt: Warning log!
[00:03:34.480,000] <err> mflt: Error log!
uart:~$

test log_capture

The test_log_capture command captures the current log buffer contents, so they will be ready once data is exported.

test trace

The test trace command captures a trace event and writes it to the event storage.

uart:~$ mflt test trace
uart:~$

Once a trace has been captured, it can be read out of the event storage with the export command.

note

The event storage is completely separate from the coredump storage. The commands get_core and clear_core work only on the coredump storage. There are no equivalents for the event storage.

export

The export command reads out all data from both the coredump storage and the event storage. It then formats this data into a base64-encoded chunk that can be sent to the Memfault cloud using one of the strategies described here.

# example export command output
uart:~$ mflt export
MC:CAKnAgIDAQpqemVwaHlyLWFwcAlwMS4wLjArMzVhNGNmZGRkMgZucWVtdV9jb3J0ZXhfbTMLRvdHfcCoLASkARmAAQIZ0WADGeHpBQD3qQ==:
MC:SE8CpwIBAwEKanplcGh5ci1hcHAJcDEuMC4wKzM1YTRjZmRkZDIGbnFlbXVfY29ydGV4X20zC0b3R33AqCwEogIAAYcAA/b2GQyYGQ+0GQw=:
...
uart:~$
note

The export command has the side effect of clearing the data. After the packetizer consumes the coredump storage and the event storage, they will both be cleared and ready for new data.

If the upload succeeds but you don't see the data processed on Memfault, go to the Processing Log under the “Integration Hub” sub-menu. The Processing Log contains details on what data has been received and processed by Memfault, as well as any error that may have occurred. Note that you need to upload the symbols to get a complete analysis of uploaded coredumps.

post_chunks

The post_chunks command is available on targets with direct network connectivity:

uart:~$ mflt post_chunks
Posting Memfault Data
uart:~$

It will read out all data from both the coredump storage and event storage and then send the data directly to the Memfault cloud. The target must already be configured on a network and be able to make an HTTPS connection to the Memfault cloud servers. A valid Memfault project key must also be configured. See the instructions in the reference implementation for how to do this.

note

The post_chunks command has the side effect of clearing the data. After the packetizer consumes the coredump storage and the event storage, they will both be cleared and ready for new data.

If the upload succeeds but you don't see the data processed on Memfault, you probably need to upload the symbols.

test self

The test self command runs tests on the most important subsystems of Memfault to validate proper integration of the SDK.

get_latest_release

The get_latest_release command queries Memfault for a OTA update payload. If there is one available for this device, then the system will proceed to pull the payload. Once the payload is downloaded completely, the system will reboot with the new image.

uart:~$ mflt get_latest_release
<inf> Checking for OTA update
<inf> mflt: FOTA Update Available. Starting Download!
<inf> download_client: Downloading: <download url>
<inf> mflt: FOTA In Progress
[00:00:22.308,074] <inf> download_client: Setting up TLS credentials, sec tag count 1
[00:00:22.308,197] <inf> download_client: Connecting to <download url>
[00:00:24.139,343] <inf> download_client: Downloaded 1024/428252 bytes (0%)
[00:00:24.718,231] <inf> download_client: Downloaded 2048/428252 bytes (0%)
...
[00:02:45.686,706] <inf> download_client: Downloaded 427008/428252 bytes (99%)
uart:~$ *** Booting nRF Connect SDK v2.5.99-dev1-461-gacec825d9b5c ***

If there is no OTA payload, the command with return immediately:

uart:~$ mflt get_latest_release
Checking for OTA update
Up to date!

For further information on performing OTA updates, see the OTA integration guide.

nRF Connect SDK (NCS) Commands

If you are using the nRF Connect SDK, go instead through the mflt_nrf command menu for OTA testing.

uart:~$ mflt_nrf
mflt_nrf - Memfault nRF Connect SDK Test Commands
Subcommands:
fota :Perform a FOTA using Memfault client
get_latest_url :Get the latest URL for the latest FOTA
uart:~$

get_latest_url

The mflt_nrf get_latest_url command queries Memfault for a OTA update payload. If one is available, the download URL will be printed.

mflt_nrf fota

Similar to the mflt get_latest_release command, the mflt_nrf fota command queries Memfault for a OTA update payload. If there is one available for this device, then the system will proceed to pull the payload. Once the payload is downloaded completely, the system will reboot with the new image.

SDK Components

This list summarizes which demo CLI commands are used to test each SDK component:

Data can be exported and cleared with: