diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 904999f9f66..9e148c3f390 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -734,6 +734,11 @@ config BUILD_OUTPUT_UF2 Build a UF2 binary zephyr/zephyr.uf2 in the build directory. The name of this file can be customized with CONFIG_KERNEL_BIN_NAME. +config BUILD_OUTPUT_ZIP + bool "Build a DFU update file" + help + Build a DFU update file zephyr/dfu_application.zip in the build directory. + if BUILD_OUTPUT_UF2 config BUILD_OUTPUT_UF2_FAMILY_ID diff --git a/boards/common/nrfutil_dfu.board.cmake b/boards/common/nrfutil_dfu.board.cmake new file mode 100644 index 00000000000..7fe3a21e442 --- /dev/null +++ b/boards/common/nrfutil_dfu.board.cmake @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(nrfutil_dfu) +board_finalize_runner_args(nrfutil_dfu) # No default arguments to provide. diff --git a/cmake/flash/CMakeLists.txt b/cmake/flash/CMakeLists.txt index 392274891f1..5ccb9aee9d4 100644 --- a/cmake/flash/CMakeLists.txt +++ b/cmake/flash/CMakeLists.txt @@ -56,6 +56,10 @@ function(runners_yaml_append_config) get_runners_prop(bin_file bin "${KERNEL_BIN_NAME}") runners_yaml_append(" bin_file: ${bin}") endif() + if(CONFIG_BUILD_OUTPUT_ZIP) + get_runners_prop(zip_file zip "${KERNEL_ZIP_NAME}") + runners_yaml_append(" zip_file: ${zip}") + endif() if(CONFIG_BUILD_OUTPUT_UF2) get_runners_prop(uf2_file uf2 "${KERNEL_UF2_NAME}") runners_yaml_append(" uf2_file: ${uf2}") diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index 3e0160382b4..24b16194226 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -157,6 +157,7 @@ set(KERNEL_NAME ${CONFIG_KERNEL_BIN_NAME}) set(KERNEL_ELF_NAME ${KERNEL_NAME}.elf) set(KERNEL_BIN_NAME ${KERNEL_NAME}.bin) +set(KERNEL_ZIP_NAME ${KERNEL_NAME}.zip) set(KERNEL_HEX_NAME ${KERNEL_NAME}.hex) set(KERNEL_UF2_NAME ${KERNEL_NAME}.uf2) set(KERNEL_MAP_NAME ${KERNEL_NAME}.map) diff --git a/scripts/west_commands/run_common.py b/scripts/west_commands/run_common.py index c0796c5335f..4c1d4250b1e 100644 --- a/scripts/west_commands/run_common.py +++ b/scripts/west_commands/run_common.py @@ -648,6 +648,7 @@ def filetype(attr): output_file('exe'), output_file('hex'), output_file('bin'), + output_file('zip'), output_file('uf2'), config('file'), filetype('file_type'), diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index aa5686f73b0..ded1be0ae9f 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -44,6 +44,7 @@ def _import_runner_module(runner_name): 'nios2', 'nrfjprog', 'nrfutil', + 'nrfutil_dfu', 'nsim', 'nxp_s32dbg', 'openocd', diff --git a/scripts/west_commands/runners/core.py b/scripts/west_commands/runners/core.py index b1b53fe20b1..37b625937c7 100644 --- a/scripts/west_commands/runners/core.py +++ b/scripts/west_commands/runners/core.py @@ -305,6 +305,7 @@ class RunnerConfig(NamedTuple): exe_file: Optional[str] # zephyr.exe path, or None hex_file: Optional[str] # zephyr.hex path, or None bin_file: Optional[str] # zephyr.bin path, or None + zip_file: Optional[str] # zephyr.zip path, or None uf2_file: Optional[str] # zephyr.uf2 path, or None file: Optional[str] # binary file path (provided by the user), or None file_type: Optional[FileType] = FileType.OTHER # binary file type @@ -813,7 +814,7 @@ def ensure_output(self, output_type: str) -> None: else: return - if output_type in ('elf', 'hex', 'bin', 'uf2'): + if output_type in ('elf', 'hex', 'bin', 'uf2', 'zip'): err += f' Try enabling CONFIG_BUILD_OUTPUT_{output_type.upper()}.' # RuntimeError avoids a stack trace saved in run_common. diff --git a/scripts/west_commands/runners/nrfutil_dfu.py b/scripts/west_commands/runners/nrfutil_dfu.py new file mode 100644 index 00000000000..698c0a09987 --- /dev/null +++ b/scripts/west_commands/runners/nrfutil_dfu.py @@ -0,0 +1,76 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +from runners.core import ZephyrBinaryRunner, RunnerCaps +import subprocess + +class NrfutilDfuRunner(ZephyrBinaryRunner): + """Runner for dfu-programming devices with nrfutil.""" + + def __init__(self, cfg, dev_id): + super(NrfutilDfuRunner, self).__init__(cfg) + self.cfg = cfg + self.family = None + self.dev_id = dev_id + + @classmethod + def do_create(cls, cfg, args): + return NrfutilDfuRunner(cfg, args.dev_id) + + @classmethod + def name(cls): + return 'nrfutil_dfu' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash'}, dev_id=True) + + @classmethod + def do_add_parser(cls, parser): + pass + + def ensure_family(self): + # Ensure self.family is set. + + if self.family is not None: + return + + if self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF51X'): + self.family = 'nrf51' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF52X'): + self.family = 'nrf52' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF53X'): + self.family = 'nrf53' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54LX'): + self.family = 'nrf54l' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54HX'): + self.family = 'nrf54h' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF91X'): + self.family = 'nrf91' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF92X'): + self.family = 'nrf92' + else: + raise RuntimeError(f'unknown nRF; update {__file__}') + + def do_run(self, command, **kwargs): + self.require('nrfutil') + + self.ensure_output('zip') + + self.ensure_family() + + if self.build_conf.getboolean('CONFIG_SOC_NRF5340_CPUNET'): + self.logger.info('skipping DFU for network core, ' + \ + 'this is done as part of the application core DFU') + return + + cmd = ['nrfutil', 'device', 'program', + '--x-family', self.family, + '--firmware', self.cfg.zip_file] + if self.dev_id: + cmd += ['--serial-number', self.dev_id] + + subprocess.Popen(cmd).wait() + + diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index b101ab42fe6..c1c55be6901 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -35,6 +35,7 @@ def test_runner_imports(): 'nios2', 'nrfjprog', 'nrfutil', + 'nrfutil_dfu', 'nxp_s32dbg', 'openocd', 'pyocd',