This DFU application demonstrates how to connect with Golioth and use Device Firmware Upgrade (DFU) procedure.
The app is first built and flashed to the device which will then listen to Golioth Cloud for a new firmware binary to become available. A second binary is built with a new version number, registered as an artifact, and deployed as a release. The device will detect this change and automatically download and install.
- Golioth credentials
- Network connectivity
Golioth offers two authentication methods: Pre-Shared Keys (PSK) or Public Key Cryptography using Certificates (certs). Normally, it is the responsibility of the Golioth SDK user to load these credentials at runtime. For simplicity, we provide facilities to hardcode these credentials or set them at runtime for our samples.
Configure the following Kconfig options based on your Golioth credentials:
GOLIOTH_SAMPLE_HARDCODED_PSK_ID
- PSK ID of registered deviceGOLIOTH_SAMPLE_HARDCODED_PSK
- PSK of registered device
by adding these lines to configuration file (e.g. prj.conf
):
CONFIG_GOLIOTH_SAMPLE_HARDCODED_PSK_ID="my-psk-id"
CONFIG_GOLIOTH_SAMPLE_HARDCODED_PSK="my-psk"
We provide an option for setting Golioth credentials through the Zephyr shell. This is based on the Zephyr Settings subsystem.
Enable the settings shell by including the following configuration overlay file:
$ west build -- -DEXTRA_CONF_FILE=${ZEPHYR_GOLIOTH_MODULE_DIR}/samples/common/runtime_settings.conf
Alternatively, you can add the following options to prj.conf
:
CONFIG_GOLIOTH_SAMPLE_HARDCODED_CREDENTIALS=n
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_GOLIOTH_SAMPLE_PSK_SETTINGS=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_AUTOLOAD=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_SHELL=y
At runtime, configure PSK-ID and PSK using the device shell based on your Golioth credentials:
uart:~$ settings set golioth/psk-id <my-psk-id@my-project>
uart:~$ settings set golioth/psk <my-psk>
uart:-$ kernel reboot cold
Configure the following Kconfig options based on your Golioth credentials:
CONFIG_GOLIOTH_AUTH_METHOD_CERT
- use certificate-based authenticationCONFIG_GOLIOTH_SAMPLE_HARDCODED_CRT_PATH
- device certificateCONFIG_GOLIOTH_SAMPLE_HARDCODED_KEY_PATH
- device private key
by adding these lines to configuration file (e.g. prj.conf
):
CONFIG_GOLIOTH_AUTH_METHOD_CERT=y
CONFIG_GOLIOTH_SAMPLE_HARDCODED_CRT_PATH="keys/device.crt.der"
CONFIG_GOLIOTH_SAMPLE_HARDCODED_KEY_PATH="keys/device.key.der"
Build Zephyr sample application for nRF9160 DK:
$ west build -b nrf9160dk_nrf9160_ns samples/dfu
$ west flash
Now rebuild the application with the new version number 1.2.3 to distinguish it from the old firmware:
$ west build -b nrf9160dk_nrf9160_ns samples/dfu -- -DCONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION=\"1.2.3\"
Run following command on host PC to upload new firmware as artifact to Golioth:
$ goliothctl dfu artifact create build/zephyr/app_update.bin --version 1.2.3
Then create new release consisting of this single firmware and roll it out to all devices in a project:
$ goliothctl dfu release create --release-tags 1.2.3 --components [email protected] --rollout true
Jump down to the Observe DFU process in target console output section lower on this page to see the expected behavior of the target device during DFU.
This subsection documents using nRF52840 DK running Zephyr with offloaded ESP-AT WiFi driver and ESP32-WROOM-32 module based board (such as ESP32 DevkitC rev. 4) running WiFi stack. See AT Binary Lists for links to ESP-AT binaries and details on how to flash ESP-AT image on ESP chip. Flash ESP chip with following command:
esptool.py write_flash --verify 0x0 PATH_TO_ESP_AT/factory/factory_WROOM-32.bin
Connect nRF52840 DK and ESP32-DevKitC V4 (or other ESP32-WROOM-32 based board) using wires:
nRF52840 DK | ESP32-WROOM-32 | ESP32-WROVER-32 |
---|---|---|
P1.01 (RX) | IO17 (TX) | IO22 (TX) |
P1.02 (TX) | IO16 (RX) | IO19 (RX) |
P1.03 (CTS) | IO14 (RTS) | IO14 (RTS) |
P1.04 (RTS) | IO15 (CTS) | IO15 (CTS) |
P1.05 | EN | EN |
GND | GND | GND |
On your host computer open a terminal window, locate the source code of this
sample application (i.e., samples/dfu
) and type:
$ west build -b <board> --sysbuild samples/dfu
$ west flash
Substitute <board> for one of the boards supported by the sample.
Run following command in Zephyr shell to confirm content of first application slot (primary area):
uart:~$ mcuboot
swap type: none
confirmed: 1
primary area (1):
version: 0.0.0+0
image size: 221104
image hash: f48973eed40a9d30795df7121183e7a828e9b89aa5ee84f2db1318f7cf51be0b
magic: good
swap type: test
copy done: set
image ok: set
failed to read secondary area (2) header: -5
(nRF52840 DK + ESP32-WROOM-32
and ESP32
only) Configure WiFi SSID and PSK using the device
shell:
uart:~$ settings set wifi/ssid <my-ssid>
uart:~$ settings set wifi/psk <my-psk>
For testing purposes of DFU mechanism the same firmware will be used. To distinguish between old firmware and new firmware, a firmware version will be assigned during image signing process. Execute following command to generate new signed application image:
$ west build -b <board> --sysbuild samples/dfu -- -DCONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS='"--version 1.2.3"'
Please note that --version 1.2.3
was specified to distinguish between old
firmware (default version is 0.0.0
if not explicitly specified) and new
firmware.
Run following command on host PC to upload new firmware as artifact to Golioth:
$ goliothctl dfu artifact create build/zephyr/zephyr.signed.bin --version 1.2.3
Then create new release consisting of this single firmware and roll it out to all devices in a project:
$ goliothctl dfu release create --release-tags 1.2.3 --components [email protected] --rollout true
DFU process should be started in Zephyr and this is what should be visible on serial console:
[00:00:06.483,764] <dbg> golioth_dfu: Desired
a3 01 1a 61 7a be 80 02 78 40 61 66 62 66 38 34 |...az... x@afbf84
33 31 33 61 36 66 65 30 66 37 63 30 35 35 39 37 |313a6fe0 f7c05597
62 36 31 37 32 38 32 30 64 31 37 65 30 64 30 39 |b6172820 d17e0d09
37 63 31 32 34 35 36 31 64 34 30 34 65 38 32 34 |7c124561 d404e824
37 39 32 30 64 38 66 30 39 33 03 81 a6 01 64 6d |7920d8f0 93....dm
61 69 6e 02 65 31 2e 32 2e 33 03 78 40 35 30 34 |ain.e1.2 .3.x@504
39 36 32 37 30 38 31 39 33 32 39 37 66 36 38 66 |96270819 3297f68f
62 61 34 61 33 31 39 64 65 65 66 61 34 39 61 37 |ba4a319d eefa49a7
35 31 33 32 39 30 31 31 35 36 63 32 37 31 63 62 |51329011 56c271cb
31 34 65 37 39 66 63 61 38 30 33 64 66 04 1a 00 |14e79fca 803df...
09 b0 a0 05 70 2f 2e 75 2f 63 2f 6d 61 69 6e 40 |....p/.u /c/main@
31 2e 32 2e 33 06 67 6d 63 75 62 6f 6f 74 |1.2.3.gm cuboot
[00:00:06.484,130] <inf> golioth: Manifest sequence-number: 1635434112
[00:00:06.637,725] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 0
[00:00:06.637,847] <inf> mcuboot_util: Swap type: none
[00:00:06.637,847] <inf> golioth_dfu: swap type: none
[00:00:06.863,555] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 1024
[00:00:07.000,457] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 2048
[00:00:07.137,786] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 3072
...
[00:03:44.913,208] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 218112
[00:03:44.956,146] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 219136
[00:03:44.995,086] <dbg> golioth_dfu.data_received: Received 1024 bytes at offset 220160
[00:03:45.030,334] <dbg> golioth_dfu.data_received: Received 768 bytes at offset 221184 (last)
[00:03:45.210,205] <inf> golioth_dfu: Requesting upgrade
[00:03:45.210,540] <inf> golioth_dfu: Rebooting in 1 second(s)
At this point mcuboot swaps first application slot (containing old firmware) with second application slot (containing new firmware). After few seconds (or a minute depending on firmware size) new firmware will be booted from first application slot and following messages should appear on serial console:
*** Booting Zephyr OS build zephyr-v2.5.0-2205-g3276779c5a88 ***
[00:00:00.008,850] <dbg> golioth_dfu.main: Start DFU sample
[00:00:00.009,155] <inf> golioth_dfu: Initializing golioth client
[00:00:00.009,246] <inf> golioth_dfu: Golioth client initialized
[00:00:00.009,307] <inf> golioth_dfu: Starting connect
Execute mcuboot
shell command in Zephyr to confirm that new firmware is
running from primary area (first application slot):
uart:~$ mcuboot
swap type: none
confirmed: 1
primary area (1):
version: 1.2.3+0
image size: 221104
image hash: 40710f0bd8171d7614b13da4821da57066f4431e4f3ebb473de9e95f6467ae65
magic: good
swap type: test
copy done: set
image ok: set
secondary area (2):
version: 0.0.0+0
image size: 221104
image hash: f48973eed40a9d30795df7121183e7a828e9b89aa5ee84f2db1318f7cf51be0b
magic: unset
swap type: none
copy done: unset
image ok: unset