This is a Rust program to run mcumgr commands, used for example for Zephyr, for uploading firmware updates from a PC to an embedded device. It is a faster alternative to the mcumgr Go program.
Released builds for Windows (x86-64), Linux (x86-64 and aarch64), and macOS (universal binary for Intel and Apple Silicon) are here.
Example download:
wget https://github.com/vouch-opensource/mcumgr-client/releases/latest/download/mcumgr-client-linux-x86.zip
wget -O - https://github.com/vouch-opensource/mcumgr-client/releases/latest/download/mcumgr-client-linux-x86.zip.sha256sum | sha256sum --check
unzip mcumgr-client-linux-x86.zip
The Linux builds need libdbus-1 for BLE support, which is installed by default on most distributions.
Install Rust:
Recommended is with rustup, because then it is easy to keep it up to date.
On Linux, BLE support needs the D-Bus development files:
sudo apt-get install libdbus-1-dev pkg-configChange to this directory and build it:
cargo build --release
Without --release, it builds in debug mode.
mcumgr-client supports three transport methods:
Use -d or --device to specify a serial port:
mcumgr-client -d /dev/ttyACM0 <command>If not specified and only one serial device exists, it will be used automatically.
For testing without hardware, -d test uses a simulated device which supports the image management commands (list, upload, test, erase).
Use --host to connect over UDP (SMP over UDP):
mcumgr-client --host 192.0.2.1 <command>The default UDP port is 1337. Use --port to specify a different port:
mcumgr-client --host 192.0.2.1 --port 1338 <command>IPv6 addresses are supported as well:
mcumgr-client --host 2001:db8::1 <command>Use --ble-address or --ble-name to connect over Bluetooth Low Energy (SMP over BLE):
mcumgr-client --ble-address AA:BB:CC:DD:EE:FF <command>
mcumgr-client --ble-name Zephyr <command>--ble-name connects to the first device whose advertised name contains the given text. On macOS, device addresses are not available, so use --ble-name there. If a BLE option is given, BLE is used even if --host or -d are specified too.
Use --ble-timeout to change the scan/connect timeout (default 10 seconds). The default --ble-mtu of 244 bytes requires an ATT MTU of 247. If the device supports only a smaller MTU, reduce it accordingly, for example --ble-mtu 20 for the BLE default ATT MTU of 23.
BLE is tested on Linux with BlueZ. Windows and macOS are supported by the underlying btleplug library, but not tested yet.
List images:
mcumgr-client -d /dev/ttyACM0 list
mcumgr-client --host 192.0.2.1 listUpload firmware:
mcumgr-client -d /dev/ttyACM0 upload firmware-image.bin
mcumgr-client --host 192.0.2.1 upload firmware-image.bin
# Upload to a specific slot
mcumgr-client -d /dev/ttyACM0 upload firmware-image.bin --slot 1Test/confirm an image:
# Mark image for test boot
mcumgr-client -d /dev/ttyACM0 test <image-hash>
# Confirm the current image
mcumgr-client -d /dev/ttyACM0 test <image-hash> --confirm trueErase an image slot:
mcumgr-client -d /dev/ttyACM0 erase
mcumgr-client -d /dev/ttyACM0 erase --slot 1Reset the device:
mcumgr-client -d /dev/ttyACM0 reset
mcumgr-client --host 192.0.2.1 resetEcho test:
mcumgr-client --host 192.0.2.1 echo "hello world"Get task/thread statistics:
mcumgr-client --host 192.0.2.1 taskstatGet MCUmgr parameters:
mcumgr-client --host 192.0.2.1 mcumgr-paramsGet OS/application information:
mcumgr-client --host 192.0.2.1 os-info
mcumgr-client --host 192.0.2.1 os-info --format a # all info
mcumgr-client --host 192.0.2.1 os-info --format s # kernel name
mcumgr-client --host 192.0.2.1 os-info --format v # kernel versionFormat specifiers: s=kernel name, n=node name, r=release, v=version, b=build date, m=machine, p=processor, i=platform, o=OS, a=all
Get bootloader information:
mcumgr-client --host 192.0.2.1 bootloader-info
mcumgr-client --host 192.0.2.1 bootloader-info --query modeGet hardware ID:
mcumgr-client --host 192.0.2.1 hwidNote: Requires a custom os-info hook on the device supporting format h (CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y and CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=y).
Execute shell commands on the device (requires CONFIG_MCUMGR_GRP_SHELL=y):
mcumgr-client --host 192.0.2.1 shell "kernel uptime"
mcumgr-client --host 192.0.2.1 shell "kernel version"
mcumgr-client --host 192.0.2.1 shell "device list"
mcumgr-client --host 192.0.2.1 shell "sensor get bmi088@0"Requires CONFIG_MCUMGR_GRP_FS=y on the device.
Download a file from the device:
mcumgr-client --host 192.0.2.1 fs-download /lfs/config.txt ./config.txtUpload a file to the device:
mcumgr-client --host 192.0.2.1 fs-upload ./config.txt /lfs/config.txtGet file size:
mcumgr-client --host 192.0.2.1 fs-stat /lfs/config.txtCalculate file hash:
mcumgr-client --host 192.0.2.1 fs-hash /lfs/config.txt
mcumgr-client --host 192.0.2.1 fs-hash /lfs/config.txt --hash-type crc32Requires CONFIG_MCUMGR_GRP_STAT=y on the device.
List available statistics groups:
mcumgr-client --host 192.0.2.1 stat-listRead statistics from a group:
mcumgr-client --host 192.0.2.1 stat-read mygroupRequires CONFIG_MCUMGR_GRP_SETTINGS=y on the device.
Read a setting:
mcumgr-client --host 192.0.2.1 settings-read my/setting/key
mcumgr-client --host 192.0.2.1 settings-read my/setting/key --max-size 256Write a setting (hex value):
mcumgr-client --host 192.0.2.1 settings-write my/setting/key 48656c6c6fDelete a setting:
mcumgr-client --host 192.0.2.1 settings-delete my/setting/keyCommit/load/save settings:
mcumgr-client --host 192.0.2.1 settings-commit
mcumgr-client --host 192.0.2.1 settings-load
mcumgr-client --host 192.0.2.1 settings-saveSend a raw request to an application-defined MCUmgr group (group IDs 64 and up are reserved for user groups):
mcumgr-client --host 192.0.2.1 custom --group 64 --id 0 --op read --body a1636b657907| Option | Description | Default |
|---|---|---|
-g, --group |
MCUmgr group ID | - |
-i, --id |
Command ID within the group | 0 |
-o, --op |
Operation: read or write |
read |
--body |
CBOR request body as hex string | empty map |
The body above is the CBOR encoding of {"key": 7}. It can be generated with e.g. pip install cbor2 and python3 -c 'import cbor2; print(cbor2.dumps({"key": 7}).hex())'. The response is printed as JSON, including any error code returned by the device.
Query HCDF fragment info from a CogniPilot device (custom group 100):
mcumgr-client --host 192.0.2.1 hcdf-info| Option | Description | Default |
|---|---|---|
-d, --device |
Serial port device | Auto-detect |
--host |
UDP host (use instead of serial) | - |
--port |
UDP port | 1337 |
--ble-address |
BLE device address (use instead of serial) | - |
--ble-name |
BLE device name to scan for (use instead of serial) | - |
--ble-timeout |
BLE scan/connect timeout in seconds | 10 |
--ble-mtu |
BLE ATT MTU payload size in bytes | 244 |
-v, --verbose |
Enable debug logging | false |
-s, --silent |
Only print command results, no banner or log messages | false |
-t, --initial_timeout |
Initial timeout in seconds | 60 |
-u, --subsequent_timeout |
Subsequent timeout in ms | 200 |
--nb-retry |
Number of retries per packet | 4 |
-l, --linelength |
Maximum line length (serial) | 128 |
-m, --mtu |
Maximum request size | 512 |
-b, --baudrate |
Serial baud rate | 115200 |
-V, --version |
Print version | - |
To enable MCUmgr features on your Zephyr device, add the relevant Kconfig options:
CONFIG_NET_BUF=y
CONFIG_ZCBOR=y
CONFIG_MCUMGR=y
Plus at least one transport:
CONFIG_BASE64=y
CONFIG_CRC=y
CONFIG_CONSOLE=y
CONFIG_UART_MCUMGR=y
CONFIG_MCUMGR_TRANSPORT_UART=y
The UART is selected with zephyr,uart-mcumgr in the devicetree chosen node, which many boards already define.
CONFIG_NETWORKING=y
CONFIG_NET_UDP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_IPV4=y
CONFIG_MCUMGR_TRANSPORT_UDP=y
CONFIG_MCUMGR_TRANSPORT_UDP_IPV4=y # CONFIG_NET_IPV6 and CONFIG_MCUMGR_TRANSPORT_UDP_IPV6 for IPv6
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_MCUMGR_TRANSPORT_BT=y
CONFIG_MCUMGR_GRP_OS=y
CONFIG_MCUMGR_GRP_OS_INFO=y
CONFIG_THREAD_MONITOR=y
CONFIG_MCUMGR_GRP_OS_TASKSTAT=y
CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS=y
CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO=y
For the stack columns of taskstat, add:
CONFIG_THREAD_STACK_INFO=y
CONFIG_INIT_STACKS=y
CONFIG_MCUMGR_GRP_OS_TASKSTAT_STACK_INFO=y
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_STREAM_FLASH=y
CONFIG_IMG_MANAGER=y
CONFIG_MCUMGR_GRP_IMG=y
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_DUMMY=y
CONFIG_BASE64=y
CONFIG_MCUMGR_GRP_SHELL=y
CONFIG_STATS=y
CONFIG_STATS_NAMES=y
CONFIG_MCUMGR_GRP_STAT=y
CONFIG_FILE_SYSTEM=y
CONFIG_MCUMGR_GRP_FS=y
CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH=y # for fs-hash
The application needs to mount a file system, e.g. LittleFS with CONFIG_FILE_SYSTEM_LITTLEFS=y.
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_MCUMGR_GRP_SETTINGS=y
A custom group is registered in the application with mgmt_register_group() and MCUMGR_HANDLER_DEFINE(). See the MCUmgr handlers documentation and the example in Zephyr's tests/subsys/mgmt/mcumgr/handler_demo. For simple commands, a regular shell command executed with shell is often easier.
Flash firmware over serial with optimized settings:
mcumgr-client -m 4096 -l 8192 -d /dev/ttyACM0 upload firmware-image.binMonitor device over UDP:
mcumgr-client --host 192.0.2.1 os-info
mcumgr-client --host 192.0.2.1 taskstat
mcumgr-client --host 192.0.2.1 shell "kernel uptime"Flash firmware over BLE:
mcumgr-client --ble-name Zephyr upload firmware-image.binUse from scripts:
With -s, only the command result is printed, without the version banner and log messages. Error messages are suppressed as well, so check the exit code, which is 1 on failure:
mcumgr-client -s --host 192.0.2.1 list || echo "failed"Auto-detect serial device:
You can omit the -d parameter. If only one device exists, it will be used automatically. If the filename contains slot1 or slot3, it flashes to that slot:
mcumgr-client upload firmware-slot1.bin
mcumgr-client upload ext-flash-slot3.binThere is a bug in the Zephyr CDC ACM driver. When building mcuboot for it, it needs this patch:
--- a/subsys/usb/device/class/cdc_acm.c
+++ b/subsys/usb/device/class/cdc_acm.c
@@ -70,7 +70,7 @@ LOG_MODULE_REGISTER(usb_cdc_acm, CONFIG_USB_CDC_ACM_LOG_LEVEL);
#define CDC_ACM_DEFAULT_BAUDRATE {sys_cpu_to_le32(115200), 0, 0, 8}
/* Size of the internal buffer used for storing received data */
-#define CDC_ACM_BUFFER_SIZE (CONFIG_CDC_ACM_BULK_EP_MPS)
+#define CDC_ACM_BUFFER_SIZE 512
/* Serial state notification timeout */
#define CDC_CONTROL_SERIAL_STATE_TIMEOUT_US 100000
With the default settings for the line length and MTU, it needs about 1:48 minutes to flash 917,504 bytes (5 times faster than the original mcumgr program). With these settings for mcuboot:
CONFIG_BOOT_MAX_LINE_INPUT_LEN=8192
CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE=4096
The line length and MTU size can be increased, like this for the example:
./target/release/mcumgr-client -m 4096 -l 8192 -d /dev/ttyACM0 upload firmware-image.bin
This needs 17 seconds for the same file (instead of 1:48 minutes with the default buffer sizes), which is more than 10 times faster than the original mcumgr Go program.
To make it easier to use the program from Python, there is a wrapper for it here.