diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4869f634..052c0d7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,6 +2,11 @@ name: Build on: workflow_call: + inputs: + build_bl_update: + type: boolean + required: false + default: false push: branches: - main @@ -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: | diff --git a/.github/workflows/dfu_check.yml b/.github/workflows/dfu_check.yml index a027e5ff..59372c55 100644 --- a/.github/workflows/dfu_check.yml +++ b/.github/workflows/dfu_check.yml @@ -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' diff --git a/.github/workflows/on_target.yml b/.github/workflows/on_target.yml index a4693481..bc8f83f4 100644 --- a/.github/workflows/on_target.yml +++ b/.github/workflows/on_target.yml @@ -10,6 +10,8 @@ jobs: build: uses: ./.github/workflows/build.yml secrets: inherit + with: + build_bl_update: true test: name: Test @@ -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 @@ -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" diff --git a/scripts/connectivity_bridge.patch b/scripts/connectivity_bridge.patch new file mode 100644 index 00000000..a058d95b --- /dev/null +++ b/scripts/connectivity_bridge.patch @@ -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 + #include + #include ++#include ++#include ++#include + + #include + 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 */ diff --git a/scripts/connectivity_bridge_extra_sample.yaml b/scripts/connectivity_bridge_extra_sample.yaml deleted file mode 100644 index 91360de6..00000000 --- a/scripts/connectivity_bridge_extra_sample.yaml +++ /dev/null @@ -1,11 +0,0 @@ - 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/tests/on_target/requirements.txt b/tests/on_target/requirements.txt index d57948bb..cc8ce52d 100644 --- a/tests/on_target/requirements.txt +++ b/tests/on_target/requirements.txt @@ -1,3 +1,5 @@ pytest pyserial termcolor +pyusb +imgtool diff --git a/tests/on_target/tests/pytest.ini b/tests/on_target/tests/pytest.ini new file mode 100644 index 00000000..9a48342b --- /dev/null +++ b/tests/on_target/tests/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + dut1 + dut2 diff --git a/tests/on_target/tests/test_serial_dfu.py b/tests/on_target/tests/test_serial_dfu.py new file mode 100644 index 00000000..bc5b03cc --- /dev/null +++ b/tests/on_target/tests/test_serial_dfu.py @@ -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") diff --git a/tests/on_target/tests/test_uart_output.py b/tests/on_target/tests/test_uart_output.py index 0877c55a..d53509fe 100644 --- a/tests/on_target/tests/test_uart_output.py +++ b/tests/on_target/tests/test_uart_output.py @@ -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))