Skip to content

Commit

Permalink
workflows: Add serial_dfu test
Browse files Browse the repository at this point in the history
This patch adds a test for the serial DFU features of the thingy91x.
Both application and bootloader updates are tested on both the
nrf91 and nrf53. The build workflow is extended to provide the necessary
artifacts for the test.

Signed-off-by: Maximilian Deubel <[email protected]>
  • Loading branch information
maxd-nordic committed Jun 25, 2024
1 parent 4b82432 commit 34b1c01
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 15 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ name: Build

on:
workflow_call:
inputs:
build_bl_update:
type: boolean
required: false
default: false
push:
branches:
- main
Expand Down Expand Up @@ -76,6 +81,20 @@ jobs:
run: |
cp $(pwd)/nrf/applications/connectivity_bridge/build/dfu_application.zip $(pwd)/thingy91x-oob/app/build/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-dfu.zip
- name: Apply Connectivity Bridge Patch
run: git apply thingy91x-oob/scripts/connectivity_bridge.patch --directory=nrf

- name: Build BL Update
if: ${{ inputs.build_bl_update }}
working-directory: thingy91x-oob
run: |
west twister -T . --test app/app.build.bootloader_update -v -p thingy91x/nrf9151/ns --inline-logs
cp twister-out/thingy91x_nrf9151_ns/app/app.build.bootloader_update/dfu_mcuboot.zip app/build/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf91-bootloader.zip
rm -rf twister-out
west twister -T ../nrf/applications/connectivity_bridge --test applications.connectivity_bridge.bootloader_update -v -p thingy91x/nrf5340/cpuapp --inline-logs
cp twister-out/thingy91x_nrf5340_cpuapp/applications.connectivity_bridge.bootloader_update/dfu_mcuboot.zip app/build/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-bootloader.zip
cp twister-out/thingy91x_nrf5340_cpuapp/applications.connectivity_bridge.bootloader_update/dfu_application.zip app/build/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-connectivity-bridge-verbose.zip
- name: Rename artifacts
working-directory: thingy91x-oob/app/build
run: |
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/dfu_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ jobs:
python3 scripts/nsib_signature_check.py -i twister-out/thingy91x_nrf9151_ns/app/app.build.bootloader_update/signed_by_mcuboot_and_b0_mcuboot.hex -p verifying_key_nrf91.pem -a 0x00008200 -v 2
python3 scripts/nsib_signature_check.py -i twister-out/thingy91x_nrf9151_ns/app/app.build.bootloader_update/signed_by_mcuboot_and_b0_s1_image.hex -p verifying_key_nrf91.pem -a 0x0001c200 -v 2
- name: Apply Connectivity Bridge Patch
run: git apply thingy91x-oob/scripts/connectivity_bridge.patch --directory=nrf

- name: Build Connectivity Bridge
working-directory: thingy91x-oob
run: |
cat scripts/connectivity_bridge_extra_sample.yaml >> ${CI_NRF_DIR}/applications/connectivity_bridge/sample.yaml
west twister -T ${CI_NRF_DIR}/applications/connectivity_bridge -v -p thingy91x/nrf5340/cpuapp --inline-logs
- name: 'nrf53: check partition layout'
Expand Down
27 changes: 25 additions & 2 deletions .github/workflows/on_target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ jobs:
build:
uses: ./.github/workflows/build.yml
secrets: inherit
with:
build_bl_update: true

test:
name: Test
Expand All @@ -22,6 +24,7 @@ jobs:
volumes:
- /dev:/dev:rw
- /run/udev:/run/udev
- /opt/setup-jlink:/opt/setup-jlink
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -53,9 +56,29 @@ jobs:
run: |
pip install -r requirements.txt --break-system-packages
- name: Run tests
- name: Run UART output tests
working-directory: thingy91x-oob/tests/on_target
run: |
pytest -s -v tests --firmware-hex artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-debug-app.hex
pytest -s -v -m dut1 tests --firmware-hex artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-debug-app.hex
env:
SEGGER: ${{ secrets.SEGGER_DUT_1 }}

- name: Run DFU tests
working-directory: thingy91x-oob/tests/on_target
run: |
pytest -s -v -m dut2 tests
env:
SEGGER_NRF53: ${{ secrets.SEGGER_DUT_2_EXT_DBG }}
SEGGER_NRF91: ${{ secrets.SEGGER_DUT_2_NRF91 }}
UART_ID: ${{ secrets.UART_DUT_2 }}
NRF53_HEX_FILE: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-connectivity-bridge.hex
NRF53_APP_UPDATE_ZIP: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-connectivity-bridge-verbose.zip
NRF53_BL_UPDATE_ZIP: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf53-bootloader.zip
NRF91_HEX_FILE: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-bootloader.hex
NRF91_APP_UPDATE_ZIP: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf91-dfu.zip
NRF91_BL_UPDATE_ZIP: artifacts/hello.nrfcloud.com-${{ env.VERSION }}-thingy91x-nrf91-bootloader.zip

- name: Check nRF53 connectivity bridge version
working-directory: thingy91x-oob
run: |
python3 ./tests/on_target/utils/thingy91x_dfu.py --check-nrf53-version --serial THINGY91X_${{ secrets.UART_DUT_2 }} 2>&1 >/dev/null | grep "S1: 1"
81 changes: 81 additions & 0 deletions scripts/connectivity_bridge.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
diff --git a/applications/connectivity_bridge/boards/thingy91x_nrf5340_cpuapp.conf b/applications/connectivity_bridge/boards/thingy91x_nrf5340_cpuapp.conf
index c59f3dc494..da01110297 100644
--- a/applications/connectivity_bridge/boards/thingy91x_nrf5340_cpuapp.conf
+++ b/applications/connectivity_bridge/boards/thingy91x_nrf5340_cpuapp.conf
@@ -34,3 +34,7 @@ CONFIG_REBOOT=y
CONFIG_GPIO=y

CONFIG_DK_LIBRARY=y
+
+# Bootloader firmware information
+CONFIG_FW_INFO=y
+CONFIG_SECURE_BOOT_STORAGE=y
diff --git a/applications/connectivity_bridge/sample.yaml b/applications/connectivity_bridge/sample.yaml
index 3074559e7f..06d3a19a72 100644
--- a/applications/connectivity_bridge/sample.yaml
+++ b/applications/connectivity_bridge/sample.yaml
@@ -12,3 +12,14 @@ tests:
- thingy91/nrf52840
- thingy91x/nrf5340/cpuapp
tags: ci_build sysbuild
+ applications.connectivity_bridge.bootloader_update:
+ build_only: true
+ sysbuild: true
+ integration_platforms:
+ - thingy91x/nrf5340/cpuapp
+ platform_allow:
+ - thingy91x/nrf5340/cpuapp
+ tags: ci_build sysbuild
+ extra_args:
+ - mcuboot_CONFIG_FW_INFO_FIRMWARE_VERSION=2
+ - CONFIG_BUILD_S1_VARIANT=y
diff --git a/applications/connectivity_bridge/src/modules/usb_bulk_commands.c b/applications/connectivity_bridge/src/modules/usb_bulk_commands.c
index 55367dc403..97653fbc26 100644
--- a/applications/connectivity_bridge/src/modules/usb_bulk_commands.c
+++ b/applications/connectivity_bridge/src/modules/usb_bulk_commands.c
@@ -8,6 +8,9 @@
#include <zephyr/sys/reboot.h>
#include <zephyr/drivers/gpio.h>
#include <dk_buttons_and_leds.h>
+#include <fw_info.h>
+#include <bl_storage.h>
+#include <ncs_commit.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bulk_commands, CONFIG_BRIDGE_BULK_LOG_LEVEL);
@@ -16,10 +19,12 @@ LOG_MODULE_REGISTER(bulk_commands, CONFIG_BRIDGE_BULK_LOG_LEVEL);
#define ID_DAP_VENDOR15 (0x80 + 15)
#define ID_DAP_VENDOR16 (0x80 + 16)
#define ID_DAP_VENDOR17 (0x80 + 17)
+#define ID_DAP_VENDOR18 (0x80 + 18)
#define ID_DAP_VENDOR_NRF53_BOOTLOADER ID_DAP_VENDOR14
#define ID_DAP_VENDOR_NRF91_BOOTLOADER ID_DAP_VENDOR15
#define ID_DAP_VENDOR_NRF53_RESET ID_DAP_VENDOR16
#define ID_DAP_VENDOR_NRF91_RESET ID_DAP_VENDOR17
+#define ID_DAP_VENDOR_NRF53_VERSION ID_DAP_VENDOR18

#define DAP_COMMAND_SUCCESS 0x00
#define DAP_COMMAND_FAILED 0xFF
@@ -125,6 +130,22 @@ size_t dap_execute_cmd(uint8_t *in, uint8_t *out)
}
goto success;
}
+ if (in[0] == ID_DAP_VENDOR_NRF53_VERSION) {
+ const struct fw_info *s0_info = fw_info_find(s0_address_read());
+ const struct fw_info *s1_info = fw_info_find(s1_address_read());
+ __ASSERT_NO_MSG(s0_info != NULL);
+ __ASSERT_NO_MSG(s1_info != NULL);
+ int len = snprintf(out + 2, 64 - 2,
+ "S0: %u, S1: %u, app: " NCS_COMMIT_STRING,
+ s0_info->version, s1_info->version);
+ if (len < 0) {
+ LOG_ERR("Failed to format version string");
+ goto error;
+ }
+ out[0] = in[0];
+ out[1] = len;
+ return len + 2;
+ }

error:
/* default reply: command failed */
11 changes: 0 additions & 11 deletions scripts/connectivity_bridge_extra_sample.yaml

This file was deleted.

2 changes: 2 additions & 0 deletions tests/on_target/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pytest
pyserial
termcolor
pyusb
imgtool
4 changes: 4 additions & 0 deletions tests/on_target/tests/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
markers =
dut1
dut2
95 changes: 95 additions & 0 deletions tests/on_target/tests/test_serial_dfu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
##########################################################################################
# Copyright (c) 2024 Nordic Semiconductor
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
##########################################################################################

import pytest
import time
import os
import types
from utils.flash_tools import flash_device, reset_device, recover_device, setup_jlink, dfu_device
from utils.uart import Uart
from tests.conftest import get_uarts
import sys
sys.path.append(os.getcwd())
from utils.logger import get_logger

logger = get_logger()

def wait_until_uart_available(name, timeout_seconds=60):
base_path = "/dev/serial/by-id"
while timeout_seconds > 0:
try:
serial_paths = [os.path.join(base_path, entry) for entry in os.listdir(base_path)]
for path in sorted(serial_paths):
if name in path:
break
except (FileNotFoundError, PermissionError) as e:
logger.error(e)
time.sleep(1)
timeout_seconds -= 1

@pytest.fixture(scope="function")
def t91x_dfu():
SEGGER_NRF53 = os.getenv('SEGGER_NRF53')
SEGGER_NRF91 = os.getenv('SEGGER_NRF91')
CONNECTIVITY_BRIDGE_UART = os.getenv('UART_ID')
NRF53_HEX_FILE = os.getenv('NRF53_HEX_FILE')
NRF91_HEX_FILE = os.getenv('NRF91_HEX_FILE')

setup_jlink(SEGGER_NRF53)
wait_until_uart_available(SEGGER_NRF91)
flash_device(hexfile=NRF91_HEX_FILE, serial=SEGGER_NRF91)
logger.info("nRF91 initialized successfully")
recover_device(serial=SEGGER_NRF53, core='Network')
recover_device(serial=SEGGER_NRF53, core='Application')
flash_device(hexfile=NRF53_HEX_FILE, serial=SEGGER_NRF53, extra_args=['--core', 'Network', '--options', 'reset=RESET_NONE,chip_erase_mode=ERASE_ALL,verify=VERIFY_NONE'])
flash_device(hexfile=NRF53_HEX_FILE, serial=SEGGER_NRF53, extra_args=['--options', 'reset=RESET_SYSTEM,chip_erase_mode=ERASE_ALL,verify=VERIFY_NONE'])
wait_until_uart_available(CONNECTIVITY_BRIDGE_UART)

logger.info("nRF53 initialized successfully")

all_uarts = get_uarts()
logger.info(f"All uarts discovered: {all_uarts}")
if not all_uarts:
pytest.fail("No UARTs found")
log_uart_string = all_uarts[0]
logger.info(f"Log UART: {log_uart_string}")

uart = Uart(log_uart_string, timeout=60)

yield types.SimpleNamespace(uart=uart)

uart.stop()


@pytest.mark.dut2
def test_dfu(t91x_dfu):
CONNECTIVITY_BRIDGE_UART = "THINGY91X_" + os.getenv('UART_ID')

NRF91_APP_UPDATE_ZIP = os.getenv('NRF91_APP_UPDATE_ZIP')
NRF91_BL_UPDATE_ZIP = os.getenv('NRF91_BL_UPDATE_ZIP')

NRF53_APP_UPDATE_ZIP = os.getenv('NRF53_APP_UPDATE_ZIP')
NRF53_BL_UPDATE_ZIP = os.getenv('NRF53_BL_UPDATE_ZIP')

t91x_dfu.uart.stop()

dfu_device(NRF91_APP_UPDATE_ZIP, serial=CONNECTIVITY_BRIDGE_UART)
dfu_device(NRF91_BL_UPDATE_ZIP, serial=CONNECTIVITY_BRIDGE_UART)

t91x_dfu.uart.start()

expected_lines = ["Firmware version 2", "Zephyr OS"]
t91x_dfu.uart.wait_for_str(expected_lines, timeout=60)
logger.info("nRF91 DFU test passed successfully")

t91x_dfu.uart.stop()

dfu_device(NRF53_APP_UPDATE_ZIP, serial=CONNECTIVITY_BRIDGE_UART)
wait_until_uart_available(CONNECTIVITY_BRIDGE_UART)
# TODO: Fix the CI issue with nRF53 BL DFU
# dfu_device(NRF53_BL_UPDATE_ZIP, serial=CONNECTIVITY_BRIDGE_UART)
# wait_until_uart_available(CONNECTIVITY_BRIDGE_UART)

logger.info("nRF53 DFU successful, checking version")
2 changes: 1 addition & 1 deletion tests/on_target/tests/test_uart_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

TEST_TIMEOUT = 1 * 60


@pytest.mark.dut1
def test_program_board_and_check_uart(t91x_board, hex_file):
flash_device(os.path.abspath(hex_file))

Expand Down

0 comments on commit 34b1c01

Please sign in to comment.