Skip to main content

Using the Demo CLI

Most reference implementations of the Memfault embedded SDK include a Command Line Interface (CLI) demo app. 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 and how to interpret their output.

Enabling the Demo CLI

note

On some platforms with integrated Memfault support (Zephyr or ESP-IDF), the demo component is enabled automatically, but will have no effect on the target if the system shell is not enabled. On unhosted platforms, see the instructions below for enabling the Demo CLI.

To include the Demo component in your project, the demo sources will need to be added. Select the tab below that applies to your project.

Include the demo component in the MEMFAULT_COMPONENTS list:

MEMFAULT_COMPONENTS := core util panics metrics demo

The Demo component has an additional dependency that must be implemented: memfault_platform_log_raw(). An example implementation can be found below, which uses printf as the output backend.

#include <stdarg.h>
#include <stdio.h>

void memfault_platform_log_raw(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
printf("\n");
va_end(args);
}

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:

mflt>

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

Command Reference

help

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

mflt> help
get_device_info: Get device info
crash: Trigger a crash
get_core: Get coredump info
clear_core: Clear an existing coredump
trace: Capture trace event
export: Get next Memfault data chunk to send and print as a curl command
help: Lists all commands
mflt>

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_chunk 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():

mflt> get_device_info
MFLT: [INFO] S/N: 123456789012345678901234
MFLT: [INFO] SW type: NAME-main
MFLT: [INFO] SW version: 1.0.0
MFLT: [INFO] HW version: NAME-proto
mflt>

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

ℹ️ Remember to increment the software version (SW version: above) each time you create a new build. Memfault uses the software version to associate a coredump with its symbols. If you upload a coredump from a new build of the firmware without updating the software version, the old symbols may be used and the analysis on Memfault may not make sense.

crash

The crash command causes the target the crash in various ways:

  • crash 0 or just crash causes a crash by MEMFAULT_ASSERT(0)
  • crash 1 causes a crash by jumping to a non-executable address (0xbadcafe)
  • crash 2 causes a crash by performing an unaligned memory store

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 rebooted:

mflt> crash
MFLT: [INFO] Memfault demo app started...
mflt>

The demo CLI prints Memfault demo app started... whenever the device reboots. If you do not see this message and the prompt return, 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.

⚠️ 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 not be overwritten.

get_core

The get_core command displays the state of the coredump storage.

If a coredump is present in the coredump storage:

mflt> get_core
MFLT: [INFO] Has coredump with size: 20224
mflt>

If a coredump is not present:

mflt> get_core
MFLT: [INFO] No coredump present!
mflt>

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:

mflt> clear_core
MFLT: [INFO] Invalidating coredump
mflt>

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

trace

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

mflt> trace
mflt>

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

⚠️ 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
mflt> export
MC:CAKnAgIDAQpqemVwaHlyLWFwcAltMS4wLjArZGJkZWI0OAZucWVtdV9jb3J0ZXhfbTMLRvknGqz1fwSiAQAFAMQ5:
MC:SE8CpwIBAwEKanplcGh5ci1hcHAJbTEuMC4wK2RiZGViNDgGbnFlbXVfY29ydGV4X20zC0b5Jxqs9X8EoQGIAAEBGQyIGefcGfWnGQ+0GQw=:

⚠️ 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 Issues page and click on "Queue Status" to see the status of recent uploads. You probably need to upload the symbols.

post_chunk

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

mflt> post_chunk
Posting data to the Memfault cloud...
All data has been posted!
mflt>

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.

⚠️ The post_chunk 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.

SDK Components

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

Implementation Notes

The demo CLI itself is implemented as two components:

  • demo/memfault_demo_shell implements the console. It handles character input and output, displaying the prompt, and dispatching the command to a C function in memfault_demo_cli that performs it. The demo shell is not used on all reference implementations. Some target platforms have a similar shell toolkit built-in. For those platforms, the built-in shell maybe used to call memfault_demo_cli functions directly.

  • demo/memfault_demo_cli implements the actual demo. It has one function for each command on the CLI. Each function typically calls one function in the SDK, checks the result, and formats the output.

Using Invoke Commands in the SDK

The CLI runs on the embedded device itself and communicates with a host computer over a communications interface. The interface varies depending on what is available on the target but it will commonly be serial (UART), Segger RTT, or semihosting. The README file for the example implementations explains the interface and any steps needed to wire it up. The console works the same regardless of the interface used.

The CLI is started with an Invoke command similar to this:

$ invoke NAME.console

Replace NAME with the name of the reference implementation (eg mbed). The README file for the implementation will give the exact command. If the invoke command does not halt with an error message, the console is active and can accept commands.

ℹ️ The invoke command does more than just pass through characters as a terminal would. It actively listens to the connection and provides a special feature used with the export command.

If you are running the demo CLI via the Invoke wrapper,you should see this prompt:

Invoke CLI wrapper detected 'export' call
Would you like to run the command displayed above? [y/n]

The above prompt comes from your computer, not from the demo CLI running on the target. The Invoke wrapper monitors all output from the demo CLI and when it detects the output from the export command, it interrupts the session and offers to run the curl command automatically.

After you accept (or decline) to run the curl command, the Invoke wrapper will return you to your session with the demo CLI. If you don't see the mflt> prompt, press enter and it should appear:

mflt>