MCUmgr
Overview
The management subsystem allows remote management of Zephyr-enabled devices. The following management operations are available:
Image management
File System management
OS management
Settings (config) management
Shell management
Statistic management
Zephyr management
over the following transports:
BLE (Bluetooth Low Energy)
Serial (UART)
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 server that provides management functionality over BLE and serial.
Tools/libraries
There are various tools and libraries available which enable usage of MCUmgr functionality on a device which are listed below. Note that these tools are not part of or related to the Zephyr project.
Name |
OS support |
Transports |
Groups |
Type |
Language |
License |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Windows |
Linux |
mac |
Mobile |
Embedded |
Serial |
Bluetooth |
UDP |
OS |
IMG |
Stat |
Settings |
FS |
Shell |
Zephyr |
||||
✓ |
✓ |
✓ |
✕ |
✕ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
Application |
C++ (Qt) |
GPLv3 |
|
✓ |
✓ |
✓ |
✕ |
✕ |
✓ |
✕ |
✕ |
✕ |
✓ |
✕ |
✕ |
✕ |
✕ |
✕ |
Application |
Rust |
BSD |
|
✓ |
✓ |
✓ |
✕ |
✕ |
✕ |
✓ |
✕ |
✕ |
✓ |
✕ |
✕ |
✕ |
✕ |
✕ |
Web page (chrome only) |
Javascript |
MIT |
|
✕ |
✕ |
✕ |
✓ |
✕ |
✕ |
✓ |
✕ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
Library and application |
Java, Kotlin, Swift |
Apache |
|
Zephyr MCUmgr client (in-tree) |
✕ |
✓ |
✕ |
✕ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✕ |
✕ |
✕ |
✕ |
✕ |
Library |
C |
Apache |
Note that a tick for a particular group indicates basic support for that group in the code, it is possible that not all commands/features of a group are supported by the implementation.
Command-line Tool
MCUmgr provides a command-line tool, mcumgr
, for managing remote devices.
The tool is written in the Go programming language.
Note
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. It is recommended that usage of tools listed above in the Tools/libraries section are used instead of the go client.
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:
--conntype
is used to choose the transport used, and--connstring
is used to pass a comma separated list of options in thekey=value
format, where each validkey
depends on the particularconntype
.
Valid transports for --conntype
are serial
, ble
and udp
. Each
transport expects a different set of key/value options:
--connstring
accepts the following key
values:
|
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 key
values:
|
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. |
--connstring
takes the form [addr]:port
where:
|
can be a DNS name (if it can be resolved to the device IP), IPv4 addr (app must be
built with |
|
any valid UDP port. |
Saving the connection config
The transport configuration can be managed with the conn
sub-command and
later used with --conn
(or -c
) parameter to skip typing both --conntype
and --connstring
. For example a new config for a serial device that would
require typing 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
General options
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:
Tip
Running mcumgr
with no parameters, or -h
will display the list
of commands.
Command |
Description |
---|---|
|
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 |
|
Execute a command in the remote shell. This option is disabled by default
and can be enabled with |
|
Read statistics from a device. More info in Statistics Management. |
|
Read task statistics from a device. This command is part of the |
Tip
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 CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE
option.
Warning
To display the correct stack size in the taskstat
command, the
CONFIG_THREAD_STACK_INFO
option must be set.
To display the correct stack usage in the taskstat
command, both
CONFIG_THREAD_STACK_INFO
and CONFIG_INIT_STACKS
options
must be set.
J-Link Virtual MSD Interaction Note
On boards where a J-Link OB is present which has both CDC and MSC (virtual Mass Storage Device, also known as drag-and-drop) support, the MSD functionality can prevent MCUmgr commands over the CDC UART port from working due to how USB endpoints are configured in the J-Link firmware (for example on the Nordic nrf52840dk/nrf52840 board) because of limiting the maximum packet size (most likely to occur when using image management commands for updating firmware). This issue can be resolved by disabling MSD functionality on the J-Link device, follow the instructions on Disabling the Mass Storage Device functionality to disable MSD support.
Image Management
The image management provided by mcumgr
is based on the image format defined
by MCUboot. For more details on the internals see MCUboot design and Signing Binaries.
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)
Where 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 1
for
secondary. This image being active
and 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
partition.
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.
Tip
The -e
option should always be passed in because the upload
command
already checks if an erase is required, respecting the
CONFIG_IMG_ERASE_PROGRESSIVELY
setting.
Tip
If the upload
command times out while waiting for a response from the
device, -t
might be used to increase the wait time to something larger
than the default of 10s. See general_options.
Warning
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.Tip
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
like this:
$ 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 revert
back to the image that was previously running on the device on the subsequent reset.
When a 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)
Tip
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>
,
where -k <your-signature-key
can be skipped if no signature validation
was enabled.
The 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.
The confirm
command used to confirm that an image is OK and no revert
should happen (empty hash
required) is:
mcumgr <connection-options> image confirm ""
The confirm
command can also be run passing in a hash
so that instead of
doing a test
/revert
procedure, the image in the secondary partition is
directly upgraded to, eg:
mcumgr <connection-options> image confirm <hash>
Tip
The whole test
/revert
cycle does not need to be done using only the
mcumgr
command-line tool. A better alternative is to perform a test
and allow the new running image to self-confirm after any checks by calling
boot_write_img_confirmed()
.
Tip
Building with CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR
enables better error
messages when failures happen (but increases the application size).
Statistics Management
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
available under 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 my_stats
:
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
STATS_SECT_ENTRY32
), STATS_SECT_ENTRY16
or
STATS_SECT_ENTRY64
.
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
of the CONFIG_STATS_NAMES
option. Using names requires an extra
declaration step:
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);
Tip
Disabling 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.
Tip
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
STATS_CLEAR
.
Let’s suppose we want to increment those counters by 1
, 2
and 3
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 my_stats
:
$ 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
When 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
Filesystem Management
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>
Using the 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 (fs_mount()
).
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
Where 25
is the size of the file.
For downloading a file, let’s first use the fs
command
(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
Where 0
is the return code, and 9
is the size of the file.
Warning
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.
Tip
CONFIG_MCUMGR_GRP_FS_PATH_LEN
sets the maximum PATH accepted for a file
name. It might require tweaking for longer file names.
Note
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.
Bootloader Integration
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 channel
Developers welcome!
Discord mcumgr channel: https://discord.com/invite/Ck7jw53nU2