How to do software update of a Bluetooth Mesh device running Apache Mynewt

As you might know, there is not yet specified way for a software update over the Bluetooth Mesh. This is high demand feature and for sure it will come. However, if this feature is needed just right now and your product uses Apache Mynewt, there is a way to mitigate the issue.

Apache Mynewt supports Bluetooth 5 features and in particular the one called Advertising Extensions. It gives a way to support multi advertising and this gives an idea to have advertising instance dedicated to Mesh operations and in the same time an instance which will allow to connect for the software update purpose.

This tutorial will guide you through configuration and simple update of firmware over BLE on Mynewt of Mesh node supporting Generic On/Off model.

This example scenario use:

  • Device A (nRF52840 DK) with `btshell` app
  • Device B (nRF52840 DK) with `btshell` app
  • PC with Newtmgr

Configuration for targets

Device A system configuration modification:

  • BLE_EXT_ADV: 1
  • BLE_MESH: 1
  • BLE_MESH_SHELL: 1
  • BLE_MESH_CFG_CLI: 1
  • BLE_SM: 1
  • BLE_SM_SC: 1
  • BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0x02, 0x1a, 0xde, 0xc0, 0xde, 0xc0})
  • ​BLE_MESH_SHELL_MODELS: 1

Device B system configuration modification:

  • BLE_EXT_ADV: 1
  • BLE_MULTI_ADV_INSTANCES: 2
  • BLE_MESH: 1
  • BLE_MESH_SHELL: 1
  • BLE_MESH_CFG_CLI: 1
  • BLE_SM: 1
  • BLE_SM_SC: 1
  • BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0x02, 0x1b, 0xde, 0xc0, 0xde, 0xc0})
  • NEWTMGR_BLE_HOST: 1
  • BLE_MESH_SHELL_MODELS: 1

Additional packages requirement by Device B

Since Device B will be updated via BLE it requires some additional packages.

Packages required:

  • boot/split
  • boot/bootutil
  • mgmt/imgmgr
  • mgmt/newtmgr
  • mgmt/newtmgr/transport/ble

Building images

Both devices running Mynewt have to be flashed with bootloader first as presented below.

Example configuration:

$ newt target show nrf52840pdk_boot
targets/nrf52840pdk_boot
    app=@apache-mynewt-core/apps/boot
    bsp=@apache-mynewt-core/hw/bsp/nrf52840pdk
    build_profile=optimized

Then devices have to be flashed with target application.

Example configuration (Dev B):

$ newt target show nrf52840pdk_btshell
targets/nrf52840pdk_btshell
    app=@apache-mynewt-core/apps/btshell
    bsp=@apache-mynewt-core/hw/bsp/nrf52840pdk
    build_profile=debug
    syscfg=BLE_EXT_ADV=1:BLE_MESH=1:BLE_MESH_CFG_CLI=1:BLE_MESH_GATT_PROXY=0:BLE_MESH_SHELL=1:BLE_MESH_SHELL_MODELS=1:BLE_MONITOR_RTT=1:BLE_MONITOR_RTT_BUFFER_SIZE=2048:BLE_MULTI_ADV_INSTANCES=2:BLE_PUBLIC_DEV_ADDR=((uint8_t[6]){0x02, 0x1b, 0xde, 0xc0, 0xde,0xc0}):BLE_SM=1:BLE_SM_SC=1:IMGMGR_COREDUMP=1:NEWTMGR_BLE_HOST=1:BLE_MESH_SHELL_MODELS:1

Build and flash devices example. Start with bootloader:

$ newt clean nrf52840pdk_boot
$ newt build nrf52840pdk_boot
$ newt load nrf52840pdk_boot
$ newt clean nrf52840pdk_btshell

Then application (use 1.0.1 as version for second image of Dev B):

$ newt build nrf52840pdk_btshell
$ newt create-image nrf52840pdk_btshell 1.0.0
$ newt load nrf52840pdk_btshell

Afterwards, devices are ready to interact via shell.

Default serial setup for communication with boards

  • speed = 115200
  • data bits = 8
  • stop bits = 1
  • parity = None
  • flow control = None

Configure simple Mesh network

As soon as devices are set up and terminal is connected, it’s time to configure mesh and make some data traffic.
Mynewt Mesh provides simple configuration client over shell which will be used to configure Generic On/Off client/server in our scenario.

Initialize mesh and application in mesh module

First we need to provision devices. Since Apache Mynewt does not support provisioner yet, let us use hardcored credentials. Run below commands on both devices changing <addr> to 0x0001 on Device A and 0x0002 on Device B.

btshell> select mesh
mesh> init
mesh> provision 0 <addr>

Configure Device A as a Client and Device B as a Server. Configuration will be done from Device A.

mesh> app-key-add 0 0 1
mesh> mod-app-bind 1 0 0x1001

Now we are ready to configure Device B to be a server. For this set destination address of Device B on Device A, then continue configuration on Device A of test applications.

mesh> dst 0x0002
mesh> app-key-add 0 0 1
mesh> mod-app-bind 2 0 0x1000

To verify mesh configuration is successfully, send some generic model operations e.g. set on/off from Device A

mesh> gen-onoff-set 5

If changing of value was successfully you will get indication on Device B.

Light state: onoff=5 lvl=0x0000

Prepare stack for firmware update over air of Device B

To update firmware over air, Device B has to configure advertising instance first. Pay attention on device name, since it is required by Newtmgr to connect.

Example setting:

mesh> select btshell
btshell> advertise-configure connectable=1 scannable=1 legacy=1 own_addr_type=random
btshell> advertise-set-adv-data name=deviceB
btshell> advertise-set-addr addr=ff:de:cb:11:22:33
btshell> security-set-data our_key_dist=7
btshell> security-set-data their_key_dist=7
btshell> advertise-start

PC (Newtmgr)

Configure connection and upload image to slot 2 on device via Bluetooth:
Note: To access Bluetooth controller on host, newtmgr may require to be run as root thus you may need to run all commands via sudo.

$ newtmgr conn add myble type=ble connstring="peer_name=deviceB"
$ newtmgr -c myble image upload deviceB2.img

Upload progress will be indicated with progress bar and current upload data to total data indicator. Successful upload of image will be indicated with “done” information on Newtmgr.

After successful upload a test of image is required. By test it means that image will be swapped to slot 0 after reboot and this image will be run. If something goes wrong with tested image, system will be rebooted automatically (program asserts, corrupted image). The Mynewt has also feature which backs up in case of wrong firmware – not confirmed image will be swapped back to slot 1 and previous image will be run from slot 0 after any system reboot.

Current status of device slots can be checked with command:

$ newtmgr -c myble image list
Images:
 slot=0
    version: 1.0.0
    bootable: true
    flags: active confirmed
    hash: a8e9fbba9c690da87faf714496e55453967fcfe05bb10f9863c983a5b4788cd0
 slot=1
    version: 1.0.1
    bootable: true
    flags:
    hash: 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250

Select image for testing after reboot of system

$ newtmgr -c myble image test 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250

And image will be marked with pending flag

$ newtmgr -c myble image list
Images:
 slot=0
    version: 1.0.0
    bootable: true
    flags: active confirmed
    hash: a8e9fbba9c690da87faf714496e55453967fcfe05bb10f9863c983a5b4788cd0
 slot=1
    version: 1.0.1
    bootable: true
    flags: pending
    hash: 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250

System can be easily rebooted with Newtmgr using reset command

newtmgr -c myble reset

After system reboot a new image should be run from slot 0 with active flag set

$ newtmgr -c myble image list
Images:
 slot=0
    version: 1.0.1
    bootable: true
    flags: active
    hash: 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250
 slot=1
    version: 1.0.0
    bootable: true
    flags: confirmed
    hash: a8e9fbba9c690da87faf714496e55453967fcfe05bb10f9863c983a5b4788cd0

Image can be confirmed to be permanently set as default running image after reboot

$ newtmgr -c myble image confirm 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250
$ newtmgr -c myble image list
Images:
 slot=0
    version: 1.0.1
    bootable: true
    flags: active confirmed
    hash: 31c58b0a207ecf96d62bf6ea8acc9073375d92a8b0cf76fa29cb8f48c29b5250
 slot=1
    version: 1.0.0
    bootable: true
    flags:
    hash: a8e9fbba9c690da87faf714496e55453967fcfe05bb10f9863c983a5b4788cd0

Not confirmed but active image after reboot will be swapped back to slot 1 and confirmed image will be default again.

Swap back to confirmed image prevents system from being deadlocked on bad image.

Uploaded image verification

btshell> select mesh
mesh> init
mesh> provision 0 <addr> (suggested address on A = 0x0001, B = 0x0002)
mesh> dst 0x0002

Final mesh verification

To check if everything goes right it’s recommended to do verification of  some data exchange. Data exchange operation and mesh setup was previously described in “Initialize mesh and application in mesh module” part.