Over-The-Air Device Firmware Upgrade#

To upgrade an application on a device, you need to:

  • Once only (on the Border Router platform):

    • Install libcoap2 & libcoap2-bin

    • Install a TFTP server

    • Start a CoAP notification server (optional, used to monitor the upgrade process)

    • Start a Linux Border Router

      • Add known IPv6 addresses to the Border Router tun0 interface

  • Once per device hardware:

    • Create an OTA-capable bootloader, with the compression algorithm(s) of your choice

  • Once per project:

    • Add the OTA DFU component

      • This will add the CoAP and TFTP components

    • Set the Wi-SUN network to auto-connect to the Border Router (Optional. If not, you will need to trigger connection on the device)

  • Once per device:

    • Flash the OTA-capable bootloader to the device, with the compression algorithm(s) of your choice

    • Flash an initial OTA-capable application to the device

    • Have the device connect to the Wi-SUN network

  • For every upgrade:

    • Build the project

    • Create a .gbl file from the .s37 file (optionally using compression)

    • Copy the .gbl to the expected name in the TFTP server folder

    • Trigger the OTA upgrade using a coap-client 'post' method

    • Check file download results

    • Trigger the reboot on the new firmware (the initial version of the OTA DFU component uses auto-reboot)

The following explains how to perform these steps based on the 'Wi-SUN SoC Empty' example application. OTA DFU can be applied using the same steps to all Wi-SUN example projects.

It is recommended to set an initial startup message in the application to show that the upgrade worked.

Prerequisites#

libcoap2 Installation#

libcoap2 is used for:

  • The (optional) CoAP notification server

  • The CoAP client used to trigger and monitor the firmware update

Both can be installed on separate machines, as long as they can be reached using IPv6. For the sake of simplicity, use the Linux platform supporting wsbrd for both functions. You will add a separate IPv6 address to the Border Router Wi-SUN interface to demonstrate this capability.

sudo apt-get install libcoap2
sudo apt-get install libcoap2-bin

TFTP Server Installation on the Linux Border Router#

On the selected file server, install a TFTP server through the following steps. Here also you use the Linux platform used as the Border Router for this purpose, with a separate IPv6 address.

TFTP Daemon Installation#

sudo apt-get install tftpd-hpa tftp-hpa

TFTP Service Configuration#

sudo nano /etc/default/tftpd-hpa

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure"

(optional) Set the TFTP_USERNAME and TFTP_DIRECTORY to match you setup, if it differs from the defaults.

Restart the TFTPD Service#

/etc/init.d/tftpd-hpa restart

From this point, files stored under the TFTP_DIRECTORY are accessible using TFTP.

Start a Linux Border Router#

Start a Border Router set to allows connecting your devices. The devices should connect before adding OTA DFU to their application.

Add known IPv6 addresses to the Border Router (acting as CoAP server and Notification Server)#

What you need here is:

  • A TFTP server, such that your devices can send TFTP requests for the .gbl files.

  • A (optional, highly recommended) CoAP Notification Server such that your devices can send progress notifications during OTA DFU download.

The TFTP and CoAP servers may not be on the Border Router platform, as long as they can be reached by your Wi-SUN devices via the Border Router. For the sake of simplicity in this first setup, use the same Linux platform as for wsbrd (i.e, your Wi-SUN Border Router) for both uses.

Using separate IPv6 addresses makes it clear that the three entities (Border Router, TFTP server, CoAP Notification Server) can be on different platforms. Since the Border Router application is 'wsbrd', you have control over the IPv6 prefix used by your Wi-SUN network (set in your wsbrd.conf file).

ipv6_prefix = fd00:6172:6d00::/64

You can then add a first IPv6 address to the tun0 interface using this IPv6 prefix for the 'OTA DFU HOST' role:

sudo ip -6 address add fd00:6172:6d00::1/64 dev tun0

Add a second IPv6 address to the tun0 interface 'OTA DFU NOTIFY HOST' role:

sudo ip -6 address add fd00:6172:6d00::2/64 dev tun0

Then check that you now have two IPv6 addresses for the 'tun0' interface:

ip address show tun0 | grep global'
    inet6 fd00:6172:6d00::1/64 scope global
    inet6 fd00:6172:6d00::2/64 scope global
    inet6 fd00:6172:6d00:0:92fd:9fff:fe00:333a/64 scope global

You will later set the IPv6 OTA_DFU_HOST and OTA_DFU_NOTIFY_HOST addresses in the OTA component code to match these fixed (fd00:6172:6d00::1 and fd00:6172:6d00::2, respectively) addresses.

Start the CoAP Notification Server#

The CoAP Notification server is optional, but it's useful to follow the upgrade process. Silicon Labs highly recommends using it.

Checking coap-server Options#

Use coap-server --help to get the help. Below is an abstract with the version info and options used.

coap-server: invalid option -- '-'
coap-server v4.2.1 -- a small CoAP implementation
(c) 2010,2011,2015-2018 Olaf Bergmann <bergmann@tzi.org> and others

TLS Library: None

Usage: coap-server [-d max] [-g group] [-l loss] [-p port] [-v num]
                [-A address] [-N]
                [[-k key] [-h hint]]
                [[-c certfile][-C cafile] [-n] [-R root_cafile]]
General Options
        -d max          Allow dynamic creation of up to a total of max
                        resources. If max is reached, a 4.06 code is returned
                        until one of the dynamic resources has been deleted
        -g group        Join the given multicast group
        -p port         Listen on specified port
        -v num          Verbosity level (default 3, maximum is 9). Above 7,
                        there is increased verbosity in GnuTLS logging
        -A address      Interface address to bind to
        -N              Make "observe" responses NON-confirmable. Even if set
                        every fifth response will still be sent as a confirmable
                        response (RFC 7641 requirement)

Starting the COAP Notification Server#

Start the CoAP notification server with -d 10 to allow dynamic resource creation:

coap-server -A fd00:6172:6d00::2 -p 5685 -d 10

Bootloader Application#

You need a Bootloader Application using SPI Flash for a single image of max 1024k bytes. This is to be manually flashed once to the part to allow OTA.

TIP:If you use the Erase option before Program when flashing the Wi-SUN application, you will need to re-flash the bootloader.

In Simplicity Studio:

  1. Select the board you want to flash the bootloader to in the Debug Adapter window.

  2. Open the Launcher perspective.

  3. Select the EXAMPLE PROJECTS & DEMOS tab.

  4. On the projects filtering section, under MCU, check Bootloader to reduce the list of available projects.

  5. Further reduce by filtering on SPI, single and 1024. Enter these strings in the Filter on keywords box, pressing Enter after each string.

  6. 'Create' a Bootloader - SoC SPI Flash Storage (single image with slot size of 1024k) project.

    creation

Bootloader Configuration#

The Bootloader settings are defined in config/btl_storage_cfg.h. No need to change anything here, the default values are fine.

  • The Base Address is defined as BTL_STORAGE_BASE_ADDRESS.

  • The memory slots to store the images are defined as well.

  • Only SLOT0 is enabled, with a SLOT0_SIZE of 1048576 = 1024 * 1024 = 1024 kBytes, starting at SLOT0_START 0.

Add LZ4 Compression to Bootloader#

By default, the bootloader projects don't include the LZ4 compression algorithm, so install it if you want to use it.

TIP: Use lzma instead of lz4, lzma has better compression performance.

add lz4

Add LZMA Compression to Bootloader#

By default, the bootloader projects don't include the most efficient LZMA compression algorithm, so install it if you want to use it.

TIP: Using lzma to compress .gbl files to save transmission time and therefore power when transmitting data.

add lzma

Build the Bootloader Project#

build

or

build

See Simplicity Studio 5 Users Guide for details.

Flash the Bootloader Binary to the Debug Adapter#

A new Binaries folder appeared in the project. This corresponds to the binaries present under GNU ARM v10.3.1 - Default.

If you have several devices in your Debug Adapters window, you will be asked to select the device.

select device

TIP: It's always better to erase the part before flashing a bootloader. As opposed to this, do not erase before flashing the Wi-SUN application; otherwise, you will need to re-flash the bootloader.

erase

Finally, click the Program button.

flash

Application Project Creation (if not already existing)#

If you have no previous application to flash to the device for testing, you can create a new 'Wi-SUN SoC Empty' project as described in Building and Connecting to a Wi-SUN Network. Otherwise, use your working Wi-SUN project.

Adding the 'Wi-SUN Over-The-Air Device Firmware Upgrade (OTA DFU)' Component#

To perform OTA upgrades:

  • The bootloader on your device must support OTA DFU.

  • The application running on your device must support OTA DFU.

In the Simplicity IDE perspective, open wisun_soc_empty.slcp select the SOFTWARE COMPONENTS tab, filter on 'DFU', and look for the Wi-SUN Over-The-Air Device Firmware Upgrade (OTA DFU) Component.

Install the OTA DFU Component#

install_ota_dfu

Check the OTA DFU Settings#

NOTE: It will take ~30 seconds for the Configure button to be active after installing the OTA DFU component.

There are two ways to change the OTA DFU component settings. The first way is through the SOFTWARE COMPONENTS view.

  1. In the SOFTWARE COMPONENTS view, click Configure to access the corresponding GUI. Changes you make here will be reflected in config/sl_wisun_ota_dfu_config.h.

    • Verbose mode is enabled by default to follow the upgrade process in the device's console.

    • Host notifications are enabled by default to follow the upgrade process from the Border Router.

    • The OTA DFU service stack size in CPU word is set to 360 words (1440 bytes) to avoid stack overflow.

  2. Set the TFTP service listening address to match the TFTP server IPv6.

  3. Set the OTA DFU notification server address to match the notification server IPv6.

Optionally, you can change the Firmware image (gbl) file name on TFTP server to match your hardware. This can make it easier to manage various devices in the future. For the time being, keep using wisun_firmware.gbl.

OTA DFU GUI

  • The OTA DFU GUI reflects in config/sl_wisun_ota_dfu_config.h. You can open it from the GUI, using the View Source button.

OTA DFU config

The settings must match between:

  • The TFTP server IPv6 (fd00:6172:6d00::1)

  • The .gbl file name

  • The CoAP Notification server IPv6 (fd00:6172:6d00::2)

  • The OTA DFU component

  • The coap-server command

  • The coap-client commands

TIP: Use the OTA DFU cheat sheet to check your settings.

Enable OTA DFU Verbose Mode#

  • In config/sl_wisun_ota_dfu_config.h, SL_WISUN_OTA_DFU_VERBOSE_MODE_ENABLED is set to 1U to get messages traced in the device's console during download. Once you get familiar with OTA DFU, you can disable verbose mode.

[wisun-btl] (0) Storage info: version: 196608, capabilities: 0, storageType: 0, numStorageSlots: 1
[wisun-btl] (7) Firmware upgrade started
[wisun-btl] (17) TFTP init done
[wisun-btl] (27) TFTP download started: tftp://[fd00:6172:6d00::1]:69/wisun_firmware.gbl
[wisun-btl] (429) download: received chunk 1, offset: 0x00000000
[wisun-btl] (853) download: received chunk 2, offset: 0x00000200
[wisun-btl] (1077) download: received chunk 3, offset: 0x00000400
[wisun-btl] (1302) download: received chunk 4, offset: 0x00000600
[wisun-btl] (1526) download: received chunk 5, offset: 0x00000800
[wisun-btl] (1949) download: received chunk 6, offset: 0x00000a00
[wisun-btl] (2174) download: received chunk 7, offset: 0x00000c00

Enable OTA DFU Notifications#

  • In config/sl_wisun_ota_dfu_config.h, SL_WISUN_OTA_DFU_HOST_NOTIFY_ENABLED is set to 1U to get notification CoAP messages sent by the device to the notification server during download, every SL_WISUN_OTA_DFU_NOTIFY_DOWNLOAD_CHUNK_CNT chunks (default 10U). This can be changed later on to a larger value to reduce the amount of notification messages. Setting it to a very large number will avoid all intermediate notifications while still keeping the final notification message, which is important to indicate file download completion and the validity of the new firmware.

    • The notification server doesn't need to be the Border Router. It can be any other machine. Use a dedicated IPv6 address to make this clear.

Version 1 Application with OTA DFU Support#

Now that you have OTA DFU configured, you can set your Wi-SUN network to match your Border Router. Do this with the Wi-SUN Configurator.

Set the Wi-SUN Configuration#

Set the Wi-SUN Configuration to match the Border Router setup.

Add a Startup Text Indicating the Version of the Application#

Here, add the following to app.c/app_task() to get minimal information on your application and make sure you can tell which version is running through the startup messages that you'll get in the Serial 1 console when you reset the device.

  printf("Version 1. Compiled on %s at %s\n", __DATE__, __TIME__);

version info 1

(Optional) Add a Startup Text Indicating OTA DFU Support#

Since it's interesting to know if OTA DFU is supported, add a second message if OTA DFU is supported.

To locate where active components are declared, select in app.c/app_task() the SL_CATALOG_WISUN_APP_CORE_PRESENT text on line 83, right-click, and select Open Declaration.

open declaration

You end up in autogen/sl_component_catalog.h, where SL_CATALOG_WISUN_OTA_DFU_PRESENT is declared on line 33.

component catalog

TIP: You also see that SL_CATALOG_WISUN_COAP_PRESENT is declared on line 27, indicating that the CoAP component is also present. CoAP is a dependency for the OTA DFU component, so it has been installed automatically when you added OTA DFU (if not previously installed).

Back to app.c/app_task(), add the following code below your previous message:

#ifdef SL_CATALOG_WISUN_OTA_DFU_PRESENT
  printf("OTA DFU is supported\n");
#endif

OTA check

(Optional) Add More Information on OTA DFU Once Connected#

Once the device is connected to the Wi-SUN network the application can retrieve it's IPv6 global address and display information on how OTA DFU can be used.

This is interesting to add for the first OTA DFU tests, to get you familiar with the commands and the parameters.

In app.c, add the following code in the #include area:

#include "sl_wisun_ota_dfu_config.h"

and the following code before the while (1) loop in app_task()

#ifdef SL_CATALOG_WISUN_OTA_DFU_PRESENT
  sl_wisun_ip_address_t global_ipv6;

  printf("OTA DFU will download chunks of '<TFTP_DIRECTORY>/%s' from %s/%d\n",
         SL_WISUN_OTA_DFU_GBL_FILE,
         SL_WISUN_OTA_DFU_HOST_ADDR,
         SL_WISUN_OTA_DFU_TFTP_PORT
       );

  sl_wisun_get_ip_address(SL_WISUN_IP_ADDRESS_TYPE_LINK_LOCAL, &global_ipv6);
  printf("OTA DFU 'start' command:\n");
  printf(" coap-client -m post -N -B 10 -t text coap://[%s]:%d%s -e \"start\"\n",
         app_wisun_trace_util_get_ip_str(&global_ipv6),
         5683,
         SL_WISUN_OTA_DFU_URI_PATH
       );
  printf("Follow OTA DFU progress (from node, intrusive) using:\n");
  printf(" coap-client -m get -N -B 10 -t text coap://[%s]:%d%s\n",
       app_wisun_trace_util_get_ip_str(&global_ipv6),
       SL_WISUN_COAP_RESOURCE_HND_SERVICE_PORT,
       SL_WISUN_OTA_DFU_URI_PATH
  );

  if (SL_WISUN_OTA_DFU_HOST_NOTIFY_ENABLED) {
      printf("OTA DFU notifications enabled (every %d chunks)\n",
        SL_WISUN_OTA_DFU_NOTIFY_DOWNLOAD_CHUNK_CNT
      );
      printf("OTA DFU notifications will be POSTed to notification server coap://[%s]:%d%s\n",
         SL_WISUN_OTA_DFU_NOTIFY_HOST_ADDR,
         SL_WISUN_OTA_DFU_NOTIFY_PORT,
         SL_WISUN_OTA_DFU_NOTIFY_URI_PATH
      );
    printf("Follow OTA DFU progress (from notification server) using:\n");
    printf(" coap-client -m get -N -B 1 -t text coap://[%s]:%d%s\n",
       SL_WISUN_OTA_DFU_NOTIFY_HOST_ADDR,
       SL_WISUN_OTA_DFU_NOTIFY_PORT,
       SL_WISUN_OTA_DFU_NOTIFY_URI_PATH
    );
  }
#endif

OTA DFU Info

Rebuild the 'Version 1' Application#

build soc empty

Unfortunately, with GSDK 4.3.0, this will fail because of an assert from <gecko_sdk>/app/wisun/component/ftp_posix_port/sl_wisun_ftp_posix_port.c line 160. The root cause is not the assert. The assert is here to stop you at this point such that you correct the underlying code and safely compile with no runtime issue to expect. If you don't solve the assert, you may get issues when running your code.

The point is that the TFTP code is using a data block size of 512 bytes by default, while the socket buffer is using 128 bytes per default. As a consequence, the TFTP packets won't fit in the socket buffer, so the socket buffer needs to be bigger.

With GSDK 4.3.0, setting this was not done automatically in the generation flow when adding TFTP and the OTA DFU component, so this change needs to be done manually. This is improved in later GSDK versions using the following condition in the .slcp file:

socket buffer size ota dfu

With GSDK 4.3.0, you will experience this error:

build soc empty failing

As the error message indicates, the solution consists of increasing SL_SOCKET_BUFFER_SIZE to be higher than SL_TFTP_DATA_BLOCK_SIZE + 4.

  • You find the value of SL_TFTP_DATA_BLOCK_SIZE using Open Declaration (F3).

#define SL_TFTP_DATA_BLOCK_SIZE 512UL

  • Go to the SL_SOCKET_BUFFER_SIZE declaration and set it to 512 + 4 = 516.

#define SL_SOCKET_BUFFER_SIZE 516U

Now you can compile without errors.

build soc empty

build soc empty compiled

Manually Install the 'Version 1' Application#

  1. Flash it manually (if it's the first OTA-capable application you flash, it needs to be flashed manually, since resources to flash it using OTA DFU are not present yet).

    NOTE: If you use the Erase Feature, you will need to re-flash the bootloader then flash the application.

    version 1 flash

  2. Open a console on the device.

  3. Select Serial 1 and press Enter to connect.

  4. Reset the device (using the RESET button on the WSTK/WPK).

    • The startup message indicates that:

      • You're running 'Version 1'

      • OTA DFU is supported

The 'Wi-SUN SoC Empty' example application is set for auto-connection to the Wi-SUN Network, so you see it starting to connect.

version info 1 serial1

Rename the 'Version 1'Binary to Keep It#

Add _version_1 to the file name to clearly identify it.

rename version_1

renaming version_1

renamed version_1

Version 2 Application with OTA DFU Support#

Change the Startup Text for 'Version 2'#

  printf("Version 2. Compiled on %s at %s\n", __DATE__, __TIME__);

version 2

Rebuild the 'Version 2' Application#

build soc empty

The wisun_soc_empty.s37 file is back in the Binaries folder. It now corresponds to your 'Version 2' application.

Rename the 'Version 2' Binary to Keep It#

Add _version_2 to the file name to clearly identify it.

rename version_2

Convert the 'Version 2' Binary to GBL Format#

The 'Version 2' binary needs to be converted to the GBL (Gecko BootLoader) format using Simplicity Commander. It will have a .gbl extension after conversion.

On Windows platforms, Simplicity Commander is by default installed under C:\SiliconLabs\SimplicityStudio\v5\developer\adapter_packs\commander.

TIP: To access Simplicity Commander easily, it's a good option to add the path to the commander.exe in your environment variables. Remember that command line windows only check environment variables upon starting, so you need to re-open them to benefit from the change.

  • Open a command window in the C:\Users\username\SimplicityStudio\v5_workspace\wisun_soc_empty\GNU ARM v10.3.1 - Default folder where binaries are stored.

  • Check that the .s37 files are present:

C:\Users\username\SimplicityStudio\v5_workspace\wisun_soc_empty\GNU ARM v10.3.1 - Default>dir *.s37

29/06/2023  15:00         1 888 290 wisun_soc_empty_version_1.s37
29/06/2023  15:12         1 888 290 wisun_soc_empty_version_2.s37
  • Create the GBL file for the application to transfer over OTA DFU

    • commander gbl create --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2.gbl

    • To reduce the size of the file to be transferred, you can compress the resulting file with either --compress lz4 or --compress lzma

      • commander gbl create --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2_lz4.gbl --compress lz4

      • commander gbl create --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2_lzma.gbl --compress lzma

CAUTION: Only compress with the algorithms supported by your bootloader, otherwise the verification step will fail once downloaded.

C:\Users\username\SimplicityStudio\OTA\wisun_soc_empty\GNU ARM v10.3.1 - Default>commander gbl create  --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2.gbl
Parsing file wisun_soc_empty_version_2.s37...
Initializing GBL file...
Adding application to GBL...
Writing GBL file wisun_soc_empty_version_2.gbl...
DONE

C:\Users\username\SimplicityStudio\OTA\wisun_soc_empty\GNU ARM v10.3.1 - Default>commander gbl create  --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2_lz4.gbl --compress lz4
Parsing file wisun_soc_empty_version_2.s37...
Initializing GBL file...
Adding application to GBL...
Compressing using lz4...
Writing GBL file wisun_soc_empty_version_2_lz4.gbl...
DONE

C:\Users\username\SimplicityStudio\OTA\wisun_soc_empty\GNU ARM v10.3.1 - Default>commander gbl create  --app wisun_soc_empty_version_2.s37 wisun_soc_empty_version_2_lzma.gbl --compress lzma
Parsing file wisun_soc_empty_version_2.s37...
Initializing GBL file...
Adding application to GBL...
Compressing using lzma...
Writing GBL file wisun_soc_empty_version_2_lzma.gbl...
DONE

As you can see, the best compression method is lzma:

Compression

Size (bytes)

None/Compressed ratio

None

629476

100 %

lz4

544424

86 %

lzma

385996

61 %

C:\Users\username\SimplicityStudio\v5_workspace\wisun_soc_empty\GNU ARM v10.3.1 - Default>dir *version_2*.gbl

29/06/2023  15:17           629 476 wisun_soc_empty_version_2.gbl
29/06/2023  15:18           544 424 wisun_soc_empty_version_2_lz4.gbl
29/06/2023  15:18           385 996 wisun_soc_empty_version_2_lzma.gbl

At this point, you have all the resources you need to start using OTA DFU to upgrade from 'Version 1' (manually flashed) to 'Version 2' (using OTA DFU).

  • A running TFTP server on the Linux Border Router.

  • A bootloader with OTA DFU support, flashed to your device.

  • A 'Version 1' application with OTA DFU support, flashed to your device.

  • A 'Version 2' file in GBL format (you'll use the lzma-compressed file).

    • The 'Version 2' binary also has OTA DFU support, to get ready to accept future upgrades to a 'Version 3' application.

And you can follow the process using the notifications, which will be sent to the notification server by the device.

both versions

Transfer the 'Version 2' .gbl Files to the Linux Border Router#

From the machine where the .gbl files were created, use scp to copy the files to the Linux Border Router host. You can use your preferred file copy method.

scp wisun_soc_empty_*.gbl <linux_user>@<linux_hostname>:/tmp/

NOTE: The rest of the operations will occur on the Linux Border Router.

Check 'Version 1' Connection to the Border Router#

On the Border Router#

In wsbrd_cli status, the MAC address of the device should be visible:

network_name: Linux_BZ_3_8
fan_version: FAN 1.1
domain: BZ
phy_mode_id: 8
chan_plan_id: 3
panid: 0xd4ec
size: CERT
GAK[0]: 36:b6:1e:81:fa:c4:88:b4:03:f7:b4:9b:38:b3:41:47
GAK[1]: 79:8b:b2:98:7f:ef:d3:55:4a:b8:cf:23:d4:a2:8f:5b
GAK[2]: 79:8b:b2:98:7f:ef:d3:55:4a:b8:cf:23:d4:a2:8f:5b
GAK[3]: 79:8b:b2:98:7f:ef:d3:55:4a:b8:cf:23:d4:a2:8f:5b
GTK[0]: 00:10:20:30:40:50:60:70:80:90:a0:b0:c0:d0:e0:f0
GTK[1]: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
GTK[2]: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
GTK[3]: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
LGAK[0]: 62:80:53:11:03:45:b6:f5:16:67:e6:14:65:21:e4:99
LGAK[1]: 79:8b:b2:98:7f:ef:d3:55:4a:b8:cf:23:d4:a2:8f:5b
LGAK[2]: 79:8b:b2:98:7f:ef:d3:55:4a:b8:cf:23:d4:a2:8f:5b
LGTK[0]: 66:70:4e:08:8c:ce:82:c9:d2:aa:c7:62:83:18:97:b9
LGTK[1]: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
LGTK[2]: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
90:fd:9f:ff:fe:00:33:3a
  `- 60:a4:23:ff:fe:37:a5:1d

On the Device#

  • Check the content of 'Serial 1'. By now, it should be connected if the Border Router and the device settings match and both are working as expected.

    version 1 connected

  • Since it's now connected, the information strings you prepared are now visible, providing hints to the user.

    • Information on TFTP settings

      • OTA DFU will download chunks of '<TFTP_DIRECTORY>/wisun_firmware.gbl' from fd00:6172:6d00::1/69

    • Information on the OTA start command (to be executed on the Border Router)

      • coap-client -m post -N -B 10 -t text coap://[fe80::62a4:23ff:fe37:a51d]:5683/ota/dfu -e "start"

    • Information on the notification settings

      • OTA DFU notifications enabled (every 10 chunks)

      • OTA DFU notifications will be POSTed to notification server coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify

    • Information on how to follow the OTA progress

      • Follow OTA DFU progress (from notification server) using:

      • coap-client -m get -N -B 1 -t text coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify

Store the Device's IPv6 GLOBAL Address#

Copy the GLOBAL IPv6 address either from the Addresses [GLOBAL : <IPv6>] section, or from the above info on the "start" command. This is the device's IPv6 address you will need to use for OTA DFU as the WISUN_NODE_IPV6_ADDR value.

On the Border Router, set a command line variable to make it easier to repeat the OTA process for other devices:

WISUN_NODE_IPV6_ADDR=fd00:6172:6d00:0:62a4:23ff:fe37:a51d (in the example)

TIP: You need to do this for each bash window you open.

Store the Border Router's IPv6 Address#

Copy the BORDER_ROUTER IPv6 address from the Addresses [BORDER_ROUTER : <IPv6>] section.

On the Border Router, set a command line variable to make it easier to repeat the OTA process for other devices:

WISUN_BR_IPV6_ADDR=fd00:6172:6d00:0:92fd:9fff:fe00:333a (in the example)

TIP: You need to do this for each bash window you open.

OTA DFU on the Linux Border Router#

Copy the .gbl file to the TFTP Server Directory#

  • Check the TFTP server directory from its config file:

sudo cat /etc/default/tftpd-hpa
# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure"
  • Copy the .gbl files in the TFTP_DIRECTORY folder:

sudo cp /tmp/*.gbl /srv/tftp/.
ls -l /srv/tftp/*.gbl
-rw-r--r-- 1 root root 629476 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2.gbl
-rw-r--r-- 1 root root 544424 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2_lz4.gbl
-rw-r--r-- 1 root root 385996 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2_lzma.gbl
  • Copy the .gbl file of your choice to the name set as SL_WISUN_OTA_DFU_GBL_FILE in config/sl_wisun_ota_dfu_config.h.

  • First, start testing with the un-compressed file.

sudo cp /srv/tftp/wisun_soc_empty_version_2.gbl /srv/tftp/wisun_firmware.gbl
  • Check the presence of the .gbl file:

ls -al /srv/tftp/*.gbl
-rw-r--r-- 1 root root 629476 Jun 29 15:41 /srv/tftp/wisun_firmware.gbl
-rw-r--r-- 1 root root 629476 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2.gbl
-rw-r--r-- 1 root root 544424 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2_lz4.gbl
-rw-r--r-- 1 root root 385996 Jun 29 15:38 /srv/tftp/wisun_soc_empty_version_2_lzma.gbl

See that the file sizes for wisun_firmware.gbl and wisun_soc_empty_version_2.gbl match, indicating that you're using the uncompressed file for the time being.

Check that you can Ping the Border Router#

ping $WISUN_BR_IPV6_ADDR -c 1
PING fd00:6172:6d00:0:92fd:9fff:fe00:333a(fd00:6172:6d00:0:92fd:9fff:fe00:333a) 56 data bytes
64 bytes from fd00:6172:6d00:0:92fd:9fff:fe00:333a: icmp_seq=1 ttl=64 time=0.214 ms

--- fd00:6172:6d00:0:92fd:9fff:fe00:333a ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.214/0.214/0.214/0.000 ms

Successfully pinging the Border Router means that it's started and the IPv6 address that you retrieved from the device is correct.

Check that you can Ping the TFTP Server#

ping fd00:6172:6d00::1

Successfully pinging the TFTP server means that it's IPv6 has been added to tun0and it is accessible from your devices.

Check that you can Ping the Notification Server#

ping fd00:6172:6d00::2

Successfully pinging the notification server means that it's IPv6 has been added to tun0and it is accessible from your devices and from the Border Router.

  • Your devices will use coap 'POST' messages to store their OTA status.

  • You'll use coap 'GET' messages to check the devices status.

  • Note that:

    • You're not directly asking the devices for status, because:

      • Doing so, you reduce the traffic on your Wi-SUN network.

      • If a device reboots after the upgrade, it will not be able to respond anymore to CoAP requests, while the notification server will be able to tell if OTA was successful, since the last notification message will show the last notification received from the device.

Check that you can Ping the Node#

ping $WISUN_NODE_IPV6_ADDR -c 1
PING fd00:6172:6d00:0:62a4:23ff:fe37:a51d(fd00:6172:6d00:0:62a4:23ff:fe37:a51d) 56 data bytes
64 bytes from fd00:6172:6d00:0:62a4:23ff:fe37:a51d: icmp_seq=1 ttl=63 time=74.9 ms

--- fd00:6172:6d00:0:62a4:23ff:fe37:a51d ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 74.892/74.892/74.892/0.000 ms

Successfully pinging the device means that it's connected to the Wi-SUN network and is working as expected. You can now test OTA DFU.

Check that CoAP is Running on the Node#

Send your coap-client GET method with -v 6 to get some level of debug information.

coap-client -m get coap://[$WISUN_NODE_IPV6_ADDR]:5683/ota/dfu -v 6

TIP: Here add -v 6 to add verbosity and get more details on the CoAP command. Once you get used to the procedure, you may not want to keep using this method.

v:1 t:CON c:GET i:ded0 {} [ Uri-Path:ota, Uri-Path:dfu ]
v:1 t:ACK c:2.01 i:ded0 {} [ Content-Format:application/json ] :: '{\x0A"elapsed_t":"00:23:44",\x0A"downl_bytes":0,\x0A"flags": "0x00000000",\x0A"fw_update_started": 0,\x0A"fw_downloaded": 0,\x0A"fw_verified": 0,\x0A"fw_set": 0,\x0A"fw_stopped": 0,\x0A"fw_download_error": 0,\x0A"fw_verify_error": 0,\x0A"fw_set_error": 0\x0A}\x0A'
{
"elapsed_t":"00:23:44",
"downl_bytes":0,
"flags": "0x00000000",
"fw_update_started": 0,
"fw_downloaded": 0,
"fw_verified": 0,
"fw_set": 0,
"fw_stopped": 0,
"fw_download_error": 0,
"fw_verify_error": 0,
"fw_set_error": 0
}

TIP: The "elapsed_t" value is the time since connection to the Wi-SUN network, as long as OTA DFU hasn't been started.

On the device console, you see the CoAP 'Received packet' and 'Response packet'.

[CoAP-RHND-Service: Received packet]
{
  "token_len": 0,
  "coap_status": 0,
  "msg_code": 1,
  "msg_type": 0,
  "content_format": 4294967295,
  "msg_id": 57040,
  "payload_len": 0,
  "uri_path_len": 7,
  "token": "n/a",
  "uri_path": "ota/dfu",
  "payload": "n/a",
}
[CoAP-RHND-Service: Response packet]
{
  "token_len": 0,
  "coap_status": 0,
  "msg_code": 65,
  "msg_type": 32,
  "content_format": 50,
  "msg_id": 57040,
  "payload_len": 224,
  "uri_path_len": 0,
  "token": "n/a",
  "uri_path": "n/a",
  "payload": 
{
"elapsed_t":"00:23:44",
"downl_bytes":0,
"flags": "0x00000000",
"fw_update_started": 0,
"fw_downloaded": 0,
"fw_verified": 0,
"fw_set": 0,
"fw_stopped": 0,
"fw_download_error": 0,
"fw_verify_error": 0,
"fw_set_error": 0
}

}

TIP: You can check that the message index i:ded0 in v:1 t:CON c:GET i:ded0 matches the "msg_id": 57040 in the Device's console (57040 = 0xded0).

Start OTA DFU for the Wi-SUN Device#

At this point, you can trigger an OTA DFU for the device.

Checking coap-client Options#

Use coap-client --help to get the help. Below is an abstract with the version info and options used.

coap-client --help
coap-client v4.1.2 -- a small CoAP implementation
(c) 2010-2015 Olaf Bergmann <bergmann@tzi.org>

usage: coap-client [-A type...] [-t type] [-b [num,]size] [-B seconds] [-e text]
                [-m method] [-N] [-o file] [-P addr[:port]] [-p port]
                [-s duration] [-O num,text] [-T string] [-v num] [-a addr] [-U] URI

        URI can be an absolute or relative coap URI,
        -B seconds      break operation after waiting given seconds
                        (default is 90)
        -e text         include text as payload (use percent-encoding for
                        non-ASCII characters)
        -m method       request method (get|put|post|delete), default is 'get'
        -N              send NON-confirmable message
        -v num          verbosity level (default: 3)

Starting Firmware Download using coap-client#

coap-client -m post -N -B 3 -t text coap://[$WISUN_NODE_IPV6_ADDR]:5683/ota/dfu -e "start" -v 6
OTA DFU Starting on the Border Router#
v:1 t:NON c:POST i:4186 {} [ Uri-Path:ota, Uri-Path:dfu, Content-Format:text/plain ] :: 'start'
v:1 t:NON c:2.01 i:0000 {} [ Content-Format:application/json ] :: '{\x0A"elapsed_t":"00:00:00",\x0A"downl_bytes":0,\x0A"flags": "0x00000001",\x0A"fw_update_started": 1,\x0A"fw_downloaded": 0,\x0A"fw_verified": 0,\x0A"fw_set": 0,\x0A"fw_stopped": 0,\x0A"fw_download_error": 0,\x0A"fw_verify_error": 0,\x0A"fw_set_error": 0\x0A}\x0A'
{
"elapsed_t":"00:00:00",
"downl_bytes":0,
"flags": "0x00000001",
"fw_update_started": 1,
"fw_downloaded": 0,
"fw_verified": 0,
"fw_set": 0,
"fw_stopped": 0,
"fw_download_error": 0,
"fw_verify_error": 0,
"fw_set_error": 0
}

The "fw_update_started": 1 flag is set!

OTA DFU Starting on the Device#
[CoAP-RHND-Service: Received packet]
{
  "token_len": 0,
  "coap_status": 0,
  "msg_code": 2,
  "msg_type": 16,
  "content_format": 0,
  "msg_id": 16774,
  "payload_len": 5,
  "uri_path_len": 7,
  "token": "n/a",
  "uri_path": "ota/dfu",
  "payload": "start"}
[CoAP-RHND-Service: Response packet]
{
  "token_len": 0,
  "coap_status": 0,
  "msg_code": 65,
  "msg_type": 16,
  "content_format": 50,
  "msg_id": 0,
  "payload_len": 224,
  "uri_path_len": 0,
  "token": "n/a",
  "uri_path": "n/a",
  "payload": 
{
"elapsed_t":"00:00:00",
"downl_bytes":0,
"flags": "0x00000001",
"fw_update_started": 1,
"fw_downloaded": 0,
"fw_verified": 0,
"fw_set": 0,
"fw_stopped": 0,
"fw_download_error": 0,
"fw_verify_error": 0,
"fw_set_error": 0
}

}
[wisun-btl] (0) Storage info: version: 196608, capabilities: 0, storageType: 0, numStorageSlots: 1
[wisun-btl] (7) Firmware upgrade started
[wisun-btl] (11) notify: coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify
[wisun-btl] (18) TFTP init done
[wisun-btl] (21) notify: coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify
[wisun-btl] (27) TFTP download started: tftp://[fd00:6172:6d00::1]:69/wisun_firmware.gbl
[wisun-btl] (442) download: received chunk 1, offset: 0x00000000
[wisun-btl] (866) download: received chunk 2, offset: 0x00000200
[wisun-btl] (1090) download: received chunk 3, offset: 0x00000400
[wisun-btl] (1315) download: received chunk 4, offset: 0x00000600
[wisun-btl] (1739) download: received chunk 5, offset: 0x00000800
[wisun-btl] (1964) download: received chunk 6, offset: 0x00000a00
[wisun-btl] (2189) download: received chunk 7, offset: 0x00000c00
[wisun-btl] (2414) download: received chunk 8, offset: 0x00000e00
[wisun-btl] (2920) download: received chunk 9, offset: 0x00001000
[wisun-btl] (3128) notify: coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify
[wisun-btl] (3153) download: received chunk 10, offset: 0x00001200
[wisun-btl] (3377) download: received chunk 11, offset: 0x00001400
[wisun-btl] (3802) download: received chunk 12, offset: 0x00001600
  • The "ota/dfu" "start" command has been received

  • The OTA DFU process started

  • The first chunks of wisun_firmware.gbl have been received

  • The first two notifications have been sent to the notification server's IPV6

Monitoring OTA DFU Progress on Notification Server#

coap-client -m get -N -B 1 -t text coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify

TIP: A more convenient way to follow the process is to use watch as follows:

watch --interval 2 coap-client -m get -N -B 1 -t text coap://[fd00:6172:6d00::2]:5685/ota/dfu_notify

ota dfu watch

  • The "elapsed_t" and "downl_bytes" will increase during image download

  • The "fw_update_started" flag is 1 from the start

  • The "fw_downloaded" flag will be 1 when download is complete (several minutes at 50 kbps/1 Hop)

  • The "fw_verified" flag will be 1 when verification is complete (this can take an additional ~20 sec)

  • The "fw_set" flag will be 1 when reboot is about to be triggered (using the NVIC_SystemReset() low-level function)

    • Note that the device will send its last notification with "fw_set" then reboot, so whatever you retrieve from the notification server is this message until you start a new upgrade.

Monitoring OTA DFU Progress on Device (intrusive!)#

You can also check the progress using a CoAP GET method on the device, but because this is using the Wi-SUN network, it has an impact on the OTA DFU duration if used frequently. The device will also stop responding for a while while rebooting and reconnecting, then respond with "fw_update_started": 0 once reconnected.

coap-client -m get coap://[$WISUN_NODE_IPV6_ADDR]:5683/ota/dfu
{
"elapsed_t":"00:01:59",
"downl_bytes":204800,
"flags": "0x00000001",
"fw_update_started": 1,
"fw_downloaded": 0,
"fw_verified": 0,
"fw_set": 0,
"fw_stopped": 0,
"fw_download_error": 0,
"fw_verify_error": 0,
"fw_set_error": 0
}

TIP: Using watch --interval 10 coap-client -m get coap://[$WISUN_NODE_IPV6_ADDR]:5683/ota/dfu, you can get the request sent to the device every 10 seconds. This is a convenient way to follow the upgrade process, but it's even more intrusive than not using watch.

Checking OTA DFU Success on the Device#

In the device console, check the startup message, looking for 'Version 2'.

Wi-SUN Empty application
Version 2. Compiled on Jul  6 2023 at 13:27:37
OTA DFU is supported
[Join state: Acquire PAN Config (3)]

[Connecting to "Linux_BZ_3_8"]

[Join state: Configure Routing (4)]
[Join state: Operational (5)]

Addresses:
[GLOBAL        : fd00:6172:6d00:0:b635:22ff:fe98:2527]
[LINK_LOCAL    : fe80::b635:22ff:fe98:2527]
[BORDER_ROUTER : fd00:6172:6d00:0:92fd:9fff:fe00:333a]
[25 s]

OTA DFU Cheat Sheet#

Below are all items used for OTA DFU that need to match between various parts of the setup. Check these in case of issues.

  • The TFTP server

  • The .gbl file

  • The CoAP Notification server

  • The OTA DFU component

  • The coap-server command

  • The coap-client commands

  • The bootloader

Below are the relationships between the settings:

Configuration

Setting on Linux Host

Setting on Node project

TFTP Server IPv6 address

Command line: sudo ip address add fd00:6172:6d00::2/64 dev tun0

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_NOTIFY_HOST_ADDR "fd00:6172:6d00::2"

TFTP Server Port

TFTP Server configuration file: /etc/default/tftpd-hpa TFTP_ADDRESS=":69"

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_TFTP_PORT "69U"

TFTP Directory

TFTP Server configuration file: /etc/default/tftpd-hpa TFTP_DIRECTORY="/srv/tftp"

Location of .gbl files: /srv/tftp/

.gbl file name

Command line: ls -l /srv/tftp/*.gbl

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_GBL_FILE "wisun_firmware.gbl"

OTA DFU Notifications

Command line: coap-server... started

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_HOST_NOTIFY_ENABLED 1U

Notification server IPv6 address

Command line: sudo ip -6 address add fd00:6172:6d00::2/64 dev tun0

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_NOTIFY_HOST_ADDR "fd00:6172:6d00::2"

OTA DFU notify URI path

Command line: coap-client -m get ... coap://[<node_ipv6>]:<port>/ota/dfu_notify

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_NOTIFY_URI_PATH "/ota/dfu_notify"

CoAP Notification server IPv6

Command line: coap-server -A fd00:6172:6d00::2 ...

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_NOTIFY_HOST_ADDR "fd00:6172:6d00::2"

CoAP Notification server UDP port

Command line: coap-server ... -p 5685 ...

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_NOTIFY_PORT 5685U

CoAP Notification server dynamic resources count

Command line: coap-server ... -d 10 (dynamic resources)

Number of devices concurrently performing OTA DFU

OTA DFU control port

Command line: coap-client -m post ... coap://[<node_ipv6>]:5683...

CoAP Configuration file: config/sl_wisun_coap_config.h SL_WISUN_COAP_RESOURCE_HND_SERVICE_PORT 5683U

OTA DFU control URI path

Command line: coap-client -m post ... coap://[<node_ipv6>]:<port>/ota/dfu ...

OTA DFU Configuration file: config/sl_wisun_ota_dfu_config.h SL_WISUN_OTA_DFU_URI_PATH "/ota/dfu"

OTA DFU start command

Command line: coap-client -m post ... -e "start"

OTA DFU Source file: <GSDK>\app\wisun\component\ota_dfu\sl_wisun_ota_dfu.c SL_WISUN_OTA_DFU_START_PAYLOAD_STR "start"

OTA DFU stop command

Command line: coap-client -m post ... -e "stop"

OTA DFU Source file: <GSDK>\app\wisun\component\ota_dfu\sl_wisun_ota_dfu.c SL_WISUN_OTA_DFU_STOP_PAYLOAD_STR "stop"

OTA DFU boot command

Command line: coap-client -m post ... -e "boot"

OTA DFU Source file: <GSDK>\app\wisun\component\ota_dfu\sl_wisun_ota_dfu.c (not implemented in GSDK 4.3.0, uses 'auto-reboot')

Below are other items that need to be selected correctly:

Configuration

Compression component

project .gbl file creation

no compression

Bootloader Compression: none

commander gbl create --app <projectname>.s37 <projectname>.gbl

lz4 compression

Bootloader Component: GBL Compression (LZ4)

commander gbl create --app <projectname>.s37 <projectname>.gbl --compress lz4

lzma compression

Bootloader Component: GBL Compression (LZMA)

commander gbl create --app <projectname>.s37 <projectname>.gbl --compress lzma

Configuration

Part

Bootloader Binary

Bootloader binary for Series 1

xG12

<projectname>-combined.s37

Bootloader binary for Series 2

xG25 or xG28

<projectname>.s37

NOTE: An application with OTA DFU support will crash during OTA if no OTA-capable bootloader is flashed to the device, because the application expects certain low-level functions to be available in the bootloader. This is a common pitfall when customers experiment with OTA DFU and start flashing their OTA DFU application to multiple devices: if they forget to also flash an OTA-capable bootloader they end up having unexpected crashes while their first test device works fine.

Application configuration

Bootloader configuration

Expected behavior

Application with OTA DFU

Bootloader without OTA DFU

Crashes

Application with OTA DFU

Bootloader with OTA DFU

Okay

Application without OTA DFU

Bootloader without OTA DFU

Okay

Application without OTA DFU

Bootloader with OTA DFU

Okay