The management subsystem allows remote management of Zephyr-enabled devices. The following management operations are available:
File System management
over the following transports:
BLE (Bluetooth Low Energy)
UDP over IP
The management subsystem is based on the Simple Management Protocol (SMP) provided by MCUmgr, an open source project that provides a management subsystem that is portable across multiple real-time operating systems.
The management subsystem is located in subsys/mgmt/ inside of the Zephyr tree.
Additionally, there is a sample that provides management functionality over BLE and serial.
MCUmgr provides a command-line tool,
mcumgr, for managing remote devices.
The tool is written in the Go programming language.
This tool is provided for evaluation use only and is not recommended for use in a production environment. It has known issues and will not respect the MCUmgr protocol properly e.g. when an error is received, instead of aborting will, in some circumstances, sit in an endless loop of sending the same command over and over again. A universal replacement for this tool is currently in development and once released, support for the go tool will be dropped entirely.
To install the tool:
go get github.com/apache/mynewt-mcumgr-cli/mcumgr
go install github.com/apache/mynewt-mcumgr-cli/mcumgr@latest
Configuring the transport
There are two command-line options that are responsible for setting and configuring the transport layer to use when communicating with managed device:
--conntypeis used to choose the transport used, and
--connstringis used to pass a comma separated list of options in the
key=valueformat, where each valid
keydepends on the particular
Valid transports for
transport expects a different set of key/value options:
--connstring accepts the following
the device name for the OS
the communication speed; must match the baudrate of the server.
aka Maximum Transmission Unit, the maximum protocol packet size.
--connstring accepts the following
an OS specific string for the controller name.
can be one of
the name the peer BLE device advertises, this should match the configuration specified with
the peer BLE device address or UUID. Only required when
a float number representing the connection timeout in seconds.
Saving the connection config
The transport configuration can be managed with the
conn sub-command and
later used with
-c) parameter to skip typing both
--connstring. For example a new config for a serial device that would
mcumgr --conntype serial --connstring dev=/dev/ttyACM0,baud=115200,mtu=512
can be saved with:
mcumgr conn add acm0 type="serial" connstring="dev=/dev/ttyACM0,baud=115200,mtu=512"
Accessing this port can now be done with:
mcumgr -c acm0
Some options work for every
mcumgr command and might be helpful to debug and fix
issues with the communication, among them the following deserve special mention:
Configures the log level, which can be one of
Changes the timeout waiting for a response from the default of 10s to a given value. Some commands might take a long time of processing, eg, the erase before an image upload, and might need incrementing the timeout to a larger value.
Changes the number of retries on timeout from the default of 1 to a given value.
List of Commands
Not all commands defined by
mcumgr (and SMP protocol) are currently supported
on Zephyr. The ones that are supported are described in the following table:
mcumgr with no parameters, or
-h will display the list
Send data to a device and display the echoed back data. This command is
part of the
Access files on a device. More info in Filesystem Management.
Manage images on a device. More info in Image Management.
Perform a soft reset of a device. This command is part of the
Read statistics from a device. More info in Statistics Management.
Read task statistics from a device. This command is part of the
taskstat has a few options that might require tweaking. The
CONFIG_THREAD_NAME must be set to display the task names, otherwise
the priority is displayed. Since the
taskstat packets are large, they
might need increasing the
To list available images in a device:
mcumgr <connection-options> image list
This should result in an output similar to this:
$ mcumgr -c acm0 image list Images: image=0 slot=0 version: 1.0.0 bootable: true flags: active confirmed hash: 86dca73a3439112b310b5e033d811ec2df728d2264265f2046fced5a9ed00cc7 Split status: N/A (0)
image is the number of the image pair in a multi-image system, and slot
is the number of the slot where the image is stored,
0 for primary and
secondary. This image being
confirmed means it will run again on
next reset. Also relevant is the
hash, which is used by other commands to
refer to this specific image when performing operations.
An image can be manually erased using:
mcumgr <connection-options> image erase
The behavior of
erase is defined by the server (
MCUmgr in the device).
The current implementation is limited to erasing the image in the secondary
To upload a new image:
mcumgr <connection-options> image upload [-n] [-e] [-u] [-w] <signed-bin>
-n: This option allows uploading a new image to a specific set of images in a multi-image system, and is currently only supported by MCUboot when the CONFIG_MCUBOOT_SERIAL option is enabled.
-e: This option avoids performing a full erase of the partition before starting a new upload.
-e option should always be passed in because the
already checks if an erase is required, respecting the
upload command times out while waiting for a response from the
-t might be used to increase the wait time to something larger
than the default of 10s. See general_options.
mcumgr does not understand .hex files, when uploading a new image always
use the .bin file.
-u: This option allows upgrading only to newer image version.
-w: This option allows setting the maximum size for the window of outstanding chunks in transit. It is set to 5 by default.
If the option is set to a value lower than the default one, for example
-w 1, less chunks are transmitted on the window, resulting in lower risk of errors. Conversely, setting a value higher than 5 increases risk of errors and may impact performance.
After an image upload is finished, a new
image list would now have an output
$ mcumgr -c acm0 image upload -e build/zephyr/zephyr.signed.bin 35.69 KiB / 92.92 KiB [==========>---------------] 38.41% 2.97 KiB/s 00m19
Now listing the images again:
$ mcumgr -c acm0 image list Images: image=0 slot=0 version: 1.0.0 bootable: true flags: active confirmed hash: 86dca73a3439112b310b5e033d811ec2df728d2264265f2046fced5a9ed00cc7 image=0 slot=1 version: 1.1.0 bootable: true flags: hash: e8cf0dcef3ec8addee07e8c4d5dc89e64ba3fae46a2c5267fc4efbea4ca0e9f4 Split status: N/A (0)
To test a new upgrade image the
test command is used:
mcumgr <connection-options> image test <hash>
This command should mark a
test upgrade, which means that after the next
reboot the bootloader will execute the upgrade and jump into the new image. If no
other image operations are executed on the newly running image, it will
back to the image that was previously running on the device on the subsequent reset.
test is requested,
flags will be updated with
pending to inform
that a new image will be run after a reset:
$ mcumgr -c acm0 image test e8cf0dcef3ec8addee07e8c4d5dc89e64ba3fae46a2c5267fc4efbea4ca0e9f4 Images: image=0 slot=0 version: 1.0.0 bootable: true flags: active confirmed hash: 86dca73a3439112b310b5e033d811ec2df728d2264265f2046fced5a9ed00cc7 image=0 slot=1 version: 1.1.0 bootable: true flags: pending hash: e8cf0dcef3ec8addee07e8c4d5dc89e64ba3fae46a2c5267fc4efbea4ca0e9f4 Split status: N/A (0)
After a reset the output with change to:
$ mcumgr -c acm0 image list Images: image=0 slot=0 version: 1.1.0 bootable: true flags: active hash: e8cf0dcef3ec8addee07e8c4d5dc89e64ba3fae46a2c5267fc4efbea4ca0e9f4 image=0 slot=1 version: 1.0.0 bootable: true flags: confirmed hash: 86dca73a3439112b310b5e033d811ec2df728d2264265f2046fced5a9ed00cc7 Split status: N/A (0)
It’s important to mention that an upgrade only ever happens if the image is
valid. The first thing MCUboot does when an upgrade is requested is to
validate the image, using the SHA-256 and/or the signature (depending on
the configuration). So before uploading an image, one way to be sure it is
valid is to run
imgtool verify -k <your-signature-key> <your-image>,
-k <your-signature-key can be skipped if no signature validation
confirmed flag in the secondary slot tells that after the next reset a
revert upgrade will be performed to switch back to the original layout.
confirm command used to confirm that an image is OK and no revert
should happen (empty
hash required) is:
mcumgr <connection-options> image confirm ""
confirm command can also be run passing in a
hash so that instead of
revert procedure, the image in the secondary partition is
directly upgraded to, eg:
mcumgr <connection-options> image confirm <hash>
revert cycle does not need to be done using only the
mcumgr command-line tool. A better alternative is to perform a
and allow the new running image to self-confirm after any checks by calling
CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR enables better error
messages when failures happen (but increases the application size).
Statistics are used for troubleshooting, maintenance, and usage monitoring; it
consists basically of user-defined counters which are tightly connected to
mcumgr and can be used to track any information for easy retrieval. The
available sub-commands are:
mcumgr <connection-options> stat list mcumgr <connection-options> stat <section-name>
Statistics are organized in sections (also called groups), and each section can
be individually queried. Defining new statistics sections is done by using macros
zephyr/stats/stats.h. Each section consists of multiple
variables (or counters), all with the same size (16, 32 or 64 bits).
To create a new section
STATS_SECT_START(my_stats) STATS_SECT_ENTRY(my_stat_counter1) STATS_SECT_ENTRY(my_stat_counter2) STATS_SECT_ENTRY(my_stat_counter3) STATS_SECT_END; STATS_SECT_DECL(my_stats) my_stats;
Each entry can be declared with
STATS_SECT_ENTRY (or the equivalent
All statistics in a section must be declared with the same size.
The statistics counters can either have names or not, depending on the setting
CONFIG_STATS_NAMES option. Using names requires an extra
STATS_NAME_START(my_stats) STATS_NAME(my_stats, my_stat_counter1) STATS_NAME(my_stats, my_stat_counter2) STATS_NAME(my_stats, my_stat_counter3) STATS_NAME_END(my_stats);
CONFIG_STATS_NAMES will free resources. When this option
is disabled the
STATS_NAME* macros output nothing, so adding them in the
code does not increase the binary size.
CONFIG_MCUMGR_GRP_STAT_MAX_NAME_LEN sets the maximum length of a section
name that can can be accepted as parameter for showing the section data, and
might require tweaking for long section names.
The final steps to use a statistics section is to initialize and register it:
rc = STATS_INIT_AND_REG(my_stats, STATS_SIZE_32, "my_stats"); assert (rc == 0);
In the running code a statistics counter can be incremented by 1 using
STATS_INC, by N using
STATS_INCN or reset with
Let’s suppose we want to increment those counters by
every second. To get a list of stats:
$ mcumgr --conn acm0 stat list stat groups: my_stats
To get the current value of the counters in
$ mcumgr --conn acm0 stat my_stats stat group: my_stats 13 my_stat_counter1 26 my_stat_counter2 39 my_stat_counter3 $ mcumgr --conn acm0 stat my_stats stat group: my_stats 16 my_stat_counter1 32 my_stat_counter2 48 my_stat_counter3
CONFIG_STATS_NAMES is disabled the output will look like this:
$ mcumgr --conn acm0 stat my_stats stat group: my_stats 8 s0 16 s1 24 s2
The filesystem module is disabled by default due to security concerns:
because of a lack of access control by default, every file in the FS will be
accessible, including secrets, etc. To enable it
CONFIG_MCUMGR_GRP_FS must be set (
y). Once enabled the
following sub-commands can be used:
mcumgr <connection-options> fs download <remote-file> <local-file> mcumgr <connection-options> fs upload <local-file> <remote-file>
fs command, requires
CONFIG_FILE_SYSTEM to be enabled,
and that some particular filesystem is enabled and properly mounted by the running
application, eg for littlefs this would mean enabling
CONFIG_FILE_SYSTEM_LITTLEFS, defining a storage partition Flash map
and mounting the filesystem in the startup (
Uploading a new file to a littlefs storage, mounted under
/lfs, can be done with:
$ mcumgr -c acm0 fs upload foo.txt /lfs/foo.txt 25 Done
25 is the size of the file.
For downloading a file, let’s first use the
CONFIG_FILE_SYSTEM_SHELL must be enabled) in a remote shell to create
a new file:
uart:~$ fs write /lfs/bar.txt 41 42 43 44 31 32 33 34 0a uart:~$ fs read /lfs/bar.txt File size: 9 00000000 41 42 43 44 31 32 33 34 0A ABCD1234.
Now it can be downloaded using:
$ mcumgr -c acm0 fs download /lfs/bar.txt bar.txt 0 9 Done $ cat bar.txt ABCD1234
0 is the return code, and
9 is the size of the file.
The commands might exhaust the system workqueue, if its size is not large
enough, so increasing
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE might be
required for correct behavior.
The size of the stack allocated buffer used to store the blocks, while transferring
a file can be adjusted with
CONFIG_MCUMGR_GRP_FS_DL_CHUNK_SIZE; this allows
saving RAM resources.
CONFIG_MCUMGR_GRP_FS_PATH_LEN sets the maximum PATH accepted for a file
name. It might require tweaking for longer file names.
To add security to the filesystem management group, callbacks for MCUmgr hooks can be registered by a user application when the upload/download functions are ran which allows the application to control if access to a file is allowed or denied. See the MCUmgr Callbacks section for details.
The Device Firmware Upgrade subsystem integrates the management subsystem with the bootloader, providing the ability to send and upgrade a Zephyr image to a device.
Currently only the MCUboot bootloader is supported. See MCUboot for more information.
Discord mcumgr channel: https://discord.com/invite/Ck7jw53nU2
- group mcumgr_mgmt_api
MCUmgr mgmt API.
Used at end of MCUmgr handlers to return an error if the message size limit was reached, or OK if it was not.
typedef void *(*mgmt_alloc_rsp_fn)(const void *src_buf, void *arg)
Allocates a buffer suitable for holding a response.
If a source buf is provided, its user data is copied into the new buffer.
- Param src_buf:
An optional source buffer to copy user data from.
- Param arg:
Optional streamer argument.
Newly-allocated buffer on success NULL on failure.
typedef void (*mgmt_reset_buf_fn)(void *buf, void *arg)
Resets a buffer to a length of 0.
The buffer’s user data remains, but its payload is cleared.
- Param buf:
The buffer to reset.
- Param arg:
Optional streamer argument.
Opcodes; encoded in first byte of header.
enumerator MGMT_OP_READ = 0
Read response op-code.
Write response op-code.
- enumerator MGMT_OP_READ = 0
The first 64 groups are reserved for system level mcumgr commands. Per-user commands are then defined after group 64.
enumerator MGMT_GROUP_ID_OS = 0
OS (operating system) group.
Image management group, used for uploading firmware images.
Statistic management group, used for retieving statistics.
Settings management (config) group, used for reading/writing settings.
Log management group (unused)
Crash group (unused)
Split image management group (unused)
Run group (unused)
FS (file system) group, used for performing file IO operations.
Shell management group, used for executing shell commands.
enumerator MGMT_GROUP_ID_PERUSER = 64
User groups defined from 64 onwards.
- enumerator MGMT_GROUP_ID_OS = 0
MCUmgr error codes.
enumerator MGMT_ERR_EOK = 0
No error (success).
Insufficient memory (likely not enough space for CBOR object).
Error in input value.
Operation timed out.
No such file/entry.
Current state disallows command.
Response too large.
Command not supported.
Command blocked by processing of other command.
Access to specific function, command or resource denied.
Requested SMP MCUmgr protocol version is not supported (too old)
Requested SMP MCUmgr protocol version is not supported (too new)
enumerator MGMT_ERR_EPERUSER = 256
User errors defined from 256 onwards.
- enumerator MGMT_ERR_EOK = 0
void mgmt_register_group(struct mgmt_group *group)
Registers a full command group.
group – The group to register.
void mgmt_unregister_group(struct mgmt_group *group)
Unregisters a full command group.
group – The group to register.
- #include <mgmt.h>
Read handler and write handler for a single command ID.
- #include <mgmt.h>
A collection of handlers for an entire command group.
- MGMT_CTXT_SET_RC_RSN(mc, rsn)