SMP Server Sample

Overview

This sample application implements a Simple Management Protocol (SMP) server. SMP is a basic transfer encoding for use with the MCUmgr management protocol. For more information about MCUmgr and SMP, please see Device Management.

This sample application supports the following mcumgr transports by default:

  • Shell
  • Bluetooth

smp_svr enables support for the following command groups:

  • fs_mgmt
  • img_mgmt
  • os_mgmt
  • stat_mgmt

Caveats

  • The Zephyr port of smp_svr is configured to run on a Nordic nRF52x MCU. The application should build and run for other platforms without modification, but the file system management commands will not work. To enable file system management for a different platform, adjust the CONFIG_FS_NFFS_FLASH_DEV_NAME setting in prj.conf accordingly.
  • The MCUboot bootloader is required for img_mgmt to function properly. More information about the Device Firmware Upgrade subsystem and MCUboot can be found in MCUboot.
  • The mcumgr command-line tool only works with Bluetooth Low Energy (BLE) on Linux and macOS. On Windows there is no support for Device Firmware Upgrade over BLE yet.

Building a BLE Controller (optional)

Note

This section is only relevant for Linux users

If you want to try out Device Firmware Upgrade (DFU) over the air using Bluetooth Low Energy (BLE) and do not have a built-in or pluggable BLE radio, you can build one and use it following the instructions in Using the controller with BlueZ.

Building and Running

The below steps describe how to build and run the smp_svr sample in Zephyr. Where examples are given, they assume the sample is being built for the Nordic nRF52 Development Kit (BOARD=nrf52_pca10040).

If you would like to use a more constrained platform, such as the nRF51 DK, you should use the prj_tiny.conf configuration file rather than the default prj.conf.

Step 1: Build MCUboot

Build MCUboot by following the instructions in the MCUboot documentation page.

Step 2: Flash MCUboot

Flash the resulting image file to address 0x0 of flash memory. This can be done in multiple ways.

Using make or ninja:

make flash
# or
ninja flash

Using GDB:

restore <path-to-mcuboot-zephyr.bin> binary 0

Step 3: Build smp_svr

smp_svr can be built for the nRF52 as follows:

# On Linux/macOS
cd $ZEPHYR_BASE/samples/subsys/mgmt/mcumgr/smp_svr
mkdir -p build/nrf52_pca10040 && cd build/nrf52_pca10040

# On Windows
cd %ZEPHYR_BASE%\samples\subsys\mgmt\mcumgr\smp_svr
mkdir build\nrf52_pca10040 & cd build\nrf52_pca10040

# Use cmake to configure a Ninja-based build system:
cmake -GNinja -DBOARD=nrf52_pca10040 ../..

# Now run ninja on the generated build system:
ninja

Step 4: Sign the image

Note

From this section onwards you can use either a binary (.bin) or an Intel Hex (.hex) image format. This is written as (bin|hex) in this document.

Using MCUboot’s imgtool.py script, sign the zephyr.(bin|hex) file you built in Step 3. In the below example, the MCUboot repo is located at ~/src/mcuboot.

~/src/mcuboot/scripts/imgtool.py sign \
     --key ~/src/mcuboot/root-rsa-2048.pem \
     --header-size 0x200 \
     --align 8 \
     --version 1.0 \
     --slot-size <image-slot-size> \
     <path-to-zephyr.(bin|hex)> signed.(bin|hex)

The above command creates an image file called signed.(bin|hex) in the current directory.

Step 5: Flash the smp_svr image

Upload the signed.(bin|hex) file from Step 4 to image slot-0 of your board. The location of image slot-0 varies by board, as described in MCUboot Partitions. For the nRF52 DK, slot-0 is located at address 0xc000.

Using nrfjprog you don’t need to specify the slot-0 starting address, since .hex files already contain that information:

nrfjprog --program <path-to-signed.hex>

Using GDB:

restore <path-to-signed.bin> binary 0xc000

Step 6: Run it!

Note

If you haven’t installed mcumgr yet, then do so by following the instructions in the Command-line Tool section of the Management subsystem documentation.

Note

The mcumgr command-line tool requires a connection string in order to identify the remote target device. In this sample we use a BLE-based connection string, and you might need to modify it depending on the BLE controller you are using.

The smp_svr app is ready to run. Just reset your board and test the app with the mcumgr command-line tool’s echo functionality, which will send a string to the remote target device and have it echo it back:

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' echo hello
hello

Step 7: Device Firmware Upgrade

Now that the SMP server is running on your board and you are able to communicate with it using mcumgr, you might want to test what is commonly called “OTA DFU”, or Over-The-Air Device Firmware Upgrade.

To do this, build a second sample (following the steps below) to verify it is sent over the air and properly flashed into slot-1, and then swapped into slot-0 by MCUboot.

Build a second sample

Perhaps the easiest sample to test with is the samples/hello_world sample provided by Zephyr, documented in the Hello World section.

Edit samples/hello_world/prj.conf and enable the required MCUboot Kconfig option as described in MCUboot by adding the following line to it:

CONFIG_BOOTLOADER_MCUBOOT=y

Then build the sample as usual (see Hello World).

Sign the second sample

Next you will need to sign the sample just like you did for smp_svr, since it needs to be loaded by MCUboot. Follow the same instructions described in Step 4: Sign the image, but this time you must use a .bin image, since mcumgr does not yet support .hex files.

Upload the image over BLE

Now we are ready to send or upload the image over BLE to the target remote device.

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' image upload signed.bin

If all goes well the image will now be stored in slot-1, ready to be swapped into slot-0 and executed.

Note

At the beginning of the upload process, the target might start erasing the image slot, taking several dozen seconds for some targets. This might cause an NMP timeout in the management protocol tool. Use the -t <timeout-in-seconds option to increase the response timeout for the mcumgr command line tool if this occurs.

List the images

We can now obtain a list of images (slot-0 and slot-1) present in the remote target device by issuing the following command:

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' image list

This should print the status and hash values of each of the images present.

Test the image

In order to instruct MCUboot to swap the images we need to test the image first, making sure it boots:

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' image test <hash of slot-1 image>

Now MCUBoot will swap the image on the next reset.

Reset remotely

We can reset the device remotely to observe (use the console output) how MCUboot swaps the images:

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' reset

Upon reset MCUboot will swap slot-0 and slot-1.

The new image is the basic hello_world sample that does not contain SMP or BLE functionality, so we cannot communicate with it using mcumgr. Instead simply reset the board manually to force MCUboot to revert (i.e. swap back the images) due to the fact that the new image has not been confirmed.

If you had instead built and uploaded a new image based on smp_svr (or another BLE and SMP enabled sample), you could confirm the new image and make the swap permanent by using this command:

sudo mcumgr --conntype ble --connstring ctlr_name=hci0,peer_name='Zephyr' image confirm

Note that if you try to send the very same image that is already flashed in slot-0 then the procedure will not complete successfully since the hash values for both slots will be identical.