runners: nrfjprog: boilerplate and recover rework

Rework the runner to improve various issues.

Every board.cmake file for an nRF SoC target is repeating boilerplate
needed for the nrfjprog runner's --nrf-family argument. The
information we need to decide the --nrf-family is already available in
Kconfig, so just get it from there instead. Keep the --nrf-family
argument around for compatibility, though.

This cuts boilerplate burden for board maintainers.

We also need to revisit how this runner handles recovery to fix it
in nRF53 and keep things consistent everywhere else.

To cleanly handle additional readback protection features in nRF53,
add a --recover option that does an 'nrfjprog --recover' before
flashing. Keep the behavior consistent across SoCs by supporting it on
those too. Because this is expected to be a bit tricky for users to
understand, check if a --recover is needed if the 'nrfjprog --program'
fails because of protection, and tell the user how to fix it.

Finally, instead of performing a separate 'nrfjprog --eraseall', just
give --chiperase to 'nrfjprog --program' process's arguments instead
of --sectorerase. This is cleaner, resulting in fewer subprocesses and
avoiding an extra chip reset.

Having a separate 'west flash --recover' option doubles the number of
test cases if we want to keep exhaustively enumerating them. That
doesn't feel worthwhile, so update the test cases by picking a
representative subset of the possibilities. Each test now has enough
state that it's worth wrapping it up in a named tuple for readability.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-11-23 13:19:23 -08:00 committed by Maureen Helm
parent 065722fef0
commit 6628a16e4d
36 changed files with 396 additions and 260 deletions

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF91")
board_runner_args(jlink "--device=cortex-m33" "--speed=4000") board_runner_args(jlink "--device=cortex-m33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,7 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(pyocd "--target=nrf51") board_runner_args(pyocd "--target=nrf51")
board_runner_args(nrfjprog "--nrf-family=NRF51")
board_runner_args(jlink "--device=nrf51" "--speed=4000") board_runner_args(jlink "--device=nrf51" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF91")
board_runner_args(jlink "--device=cortex-m33" "--speed=4000") board_runner_args(jlink "--device=cortex-m33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,7 +1,6 @@
# Copyright (c) 2019 Atmark Techno, Inc. # Copyright (c) 2019 Atmark Techno, Inc.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,4 +1,4 @@
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF51")
board_runner_args(jlink "--device=nrf51" "--speed=4000") board_runner_args(jlink "--device=nrf51" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF51")
board_runner_args(jlink "--device=nrf51" "--speed=4000") board_runner_args(jlink "--device=nrf51" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF51")
board_runner_args(jlink "--device=nrf51" "--speed=4000") board_runner_args(jlink "--device=nrf51" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52820" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52820" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52833" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -2,7 +2,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -6,12 +6,10 @@ endif()
if((CONFIG_BOARD_NRF5340PDK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340PDK_NRF5340_CPUAPPNS) OR if((CONFIG_BOARD_NRF5340PDK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340PDK_NRF5340_CPUAPPNS) OR
(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPPNS)) (CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPPNS))
board_runner_args(nrfjprog "--nrf-family=NRF53" "--tool-opt=--coprocessor CP_APPLICATION")
board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000")
endif() endif()
if(CONFIG_BOARD_NRF5340PDK_NRF5340_CPUNET OR CONFIG_BOARD_NRF5340DK_NRF5340_CPUNET) if(CONFIG_BOARD_NRF5340PDK_NRF5340_CPUNET OR CONFIG_BOARD_NRF5340DK_NRF5340_CPUNET)
board_runner_args(nrfjprog "--nrf-family=NRF53" "--tool-opt=--coprocessor CP_NETWORK")
board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000")
endif() endif()

View file

@ -1,7 +1,6 @@
# Copyright (c) 2020 InnBlue # Copyright (c) 2020 InnBlue
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF91")
board_runner_args(jlink "--device=cortex-m33" "--speed=4000") board_runner_args(jlink "--device=cortex-m33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,7 +1,6 @@
# Copyright (c) 2020 InnBlue # Copyright (c) 2020 InnBlue
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF91")
board_runner_args(jlink "--device=cortex-m33" "--speed=4000") board_runner_args(jlink "--device=cortex-m33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -4,7 +4,6 @@ if(CONFIG_BOARD_NRF9160DK_NRF9160NS)
set(TFM_PUBLIC_KEY_FORMAT "full") set(TFM_PUBLIC_KEY_FORMAT "full")
endif() endif()
board_runner_args(nrfjprog "--nrf-family=NRF91")
board_runner_args(jlink "--device=cortex-m33" "--speed=4000") board_runner_args(jlink "--device=cortex-m33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -4,7 +4,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -4,7 +4,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -5,7 +5,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,7 +1,6 @@
# Copyright (c) 2020 Ruuvi Innovations Ltd (Oy) # Copyright (c) 2020 Ruuvi Innovations Ltd (Oy)
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") board_runner_args(nrfjprog "--softreset")
board_runner_args(jlink "--device=nrf52" "--speed=4000") board_runner_args(jlink "--device=nrf52" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -7,10 +7,11 @@
import os import os
import shlex import shlex
import subprocess
import sys import sys
from re import fullmatch, escape from re import fullmatch, escape
from runners.core import ZephyrBinaryRunner, RunnerCaps from runners.core import ZephyrBinaryRunner, RunnerCaps, BuildConfiguration
try: try:
from intelhex import IntelHex from intelhex import IntelHex
@ -33,19 +34,22 @@ def has_region(regions, hex_file):
except FileNotFoundError: except FileNotFoundError:
return False return False
# https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf_cltools%2FUG%2Fcltools%2Fnrf_nrfjprogexe_return_codes.html&cp=9_1_3_1
UnavailableOperationBecauseProtectionError = 16
class NrfJprogBinaryRunner(ZephyrBinaryRunner): class NrfJprogBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for nrfjprog.''' '''Runner front-end for nrfjprog.'''
def __init__(self, cfg, family, softreset, snr, erase=False, def __init__(self, cfg, family, softreset, snr, erase=False,
tool_opt=[], force=False): tool_opt=[], force=False, recover=False):
super().__init__(cfg) super().__init__(cfg)
self.hex_ = cfg.hex_file self.hex_ = cfg.hex_file
self.family = family self.family = family
self.softreset = softreset self.softreset = softreset
self.snr = snr self.snr = snr
self.erase = erase self.erase = bool(erase)
self.force = force self.force = force
self.recover = bool(recover)
self.tool_opt = [] self.tool_opt = []
for opts in [shlex.split(opt) for opt in tool_opt]: for opts in [shlex.split(opt) for opt in tool_opt]:
@ -61,9 +65,10 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
@classmethod @classmethod
def do_add_parser(cls, parser): def do_add_parser(cls, parser):
parser.add_argument('--nrf-family', required=True, parser.add_argument('--nrf-family',
choices=['NRF51', 'NRF52', 'NRF53', 'NRF91'], choices=['NRF51', 'NRF52', 'NRF53', 'NRF91'],
help='family of nRF MCU') help='''MCU family; still accepted for
compatibility only''')
parser.add_argument('--softreset', required=False, parser.add_argument('--softreset', required=False,
action='store_true', action='store_true',
help='use reset instead of pinreset') help='use reset instead of pinreset')
@ -76,16 +81,23 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
parser.add_argument('--force', required=False, parser.add_argument('--force', required=False,
action='store_true', action='store_true',
help='Flash even if the result cannot be guaranteed.') help='Flash even if the result cannot be guaranteed.')
parser.add_argument('--recover', required=False,
action='store_true',
help='''erase all user available non-volatile
memory and disable read back protection before
flashing (erases flash for both cores on nRF53)''')
@classmethod @classmethod
def do_create(cls, cfg, args): def do_create(cls, cfg, args):
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset, return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
args.snr, erase=args.erase, args.snr, erase=args.erase,
tool_opt=args.tool_opt, force=args.force) tool_opt=args.tool_opt, force=args.force,
recover=args.recover)
def ensure_snr(self): def ensure_snr(self):
if not self.snr or "*" in self.snr: if not self.snr or "*" in self.snr:
self.snr = self.get_board_snr(self.snr or "*") self.snr = self.get_board_snr(self.snr or "*")
self.snr = self.snr.lstrip("0")
def get_boards(self): def get_boards(self):
snrs = self.check_output(['nrfjprog', '--ids']) snrs = self.check_output(['nrfjprog', '--ids'])
@ -150,42 +162,40 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
return snrs[value - 1] return snrs[value - 1]
def do_run(self, command, **kwargs): def ensure_family(self):
self.require('nrfjprog') # Ensure self.family is set.
self.ensure_snr() if self.family is not None:
return
commands = [] if self.build_conf.get('CONFIG_SOC_SERIES_NRF51X', False):
board_snr = self.snr.lstrip("0") self.family = 'NRF51'
elif self.build_conf.get('CONFIG_SOC_SERIES_NRF52X', False):
if not os.path.isfile(self.hex_): self.family = 'NRF52'
raise ValueError('Cannot flash; hex file ({}) does not exist. '. elif self.build_conf.get('CONFIG_SOC_SERIES_NRF53X', False):
format(self.hex_) + self.family = 'NRF53'
'Try enabling CONFIG_BUILD_OUTPUT_HEX.') elif self.build_conf.get('CONFIG_SOC_SERIES_NRF91X', False):
self.family = 'NRF91'
program_cmd = ['nrfjprog', '--program', self.hex_, '-f', self.family,
'--snr', board_snr] + self.tool_opt
self.logger.info('Flashing file: {}'.format(self.hex_))
if self.erase:
commands.extend([
['nrfjprog',
'--eraseall',
'-f', self.family,
'--snr', board_snr],
program_cmd
])
else: else:
if self.family == 'NRF51': raise RuntimeError(f'unknown nRF; update {__file__}')
commands.append(program_cmd + ['--sectorerase'])
elif self.family == 'NRF52': def check_force_uicr(self):
commands.append(program_cmd + ['--sectoranduicrerase']) # On SoCs without --sectoranduicrerase, we want to fail by
else: # default if the application contains UICR data and we're not sure
uicr = { # that the flash will succeed.
# A map from SoCs which need this check to their UICR address
# ranges. If self.family isn't in here, do nothing.
uicr_ranges = {
'NRF53': ((0x00FF8000, 0x00FF8800), 'NRF53': ((0x00FF8000, 0x00FF8800),
(0x01FF8000, 0x01FF8800)), (0x01FF8000, 0x01FF8800)),
'NRF91': ((0x00FF8000, 0x00FF8800),), 'NRF91': ((0x00FF8000, 0x00FF8800),),
}[self.family] }
if self.family not in uicr_ranges:
return
uicr = uicr_ranges[self.family]
if not self.force and has_region(uicr, self.hex_): if not self.force and has_region(uicr, self.hex_):
# Hex file has UICR contents. # Hex file has UICR contents.
@ -193,25 +203,103 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
'The hex file contains data placed in the UICR, which ' 'The hex file contains data placed in the UICR, which '
'needs a full erase before reprogramming. Run west ' 'needs a full erase before reprogramming. Run west '
'flash again with --force or --erase.') 'flash again with --force or --erase.')
else:
commands.append(program_cmd + ['--sectorerase'])
def recover_target(self):
if self.family == 'NRF53':
self.logger.info(
'Recovering and erasing flash memory for both the network '
'and application cores.')
else:
self.logger.info('Recovering and erasing all flash memory.')
if self.family == 'NRF53':
self.check_call(['nrfjprog', '--recover', '-f', self.family,
'--coprocessor', 'CP_NETWORK',
'--snr', self.snr])
self.check_call(['nrfjprog', '--recover', '-f', self.family,
'--snr', self.snr])
def program_hex(self):
# Get the nrfjprog command use to actually program self.hex_.
self.logger.info('Flashing file: {}'.format(self.hex_))
# What type of erase argument should we pass to nrfjprog?
if self.erase:
erase_arg = '--chiperase'
else:
if self.family == 'NRF52':
erase_arg = '--sectoranduicrerase'
else:
erase_arg = '--sectorerase'
if self.family == 'NRF53':
if self.build_conf.get('CONFIG_SOC_NRF5340_CPUAPP', False):
coprocessor = 'CP_APPLICATION'
elif self.build_conf.get('CONFIG_SOC_NRF5340_CPUNET', False):
coprocessor = 'CP_NETWORK'
else:
# When it's time to update this file, it would probably be best
# to handle this by adding common 'SOC_NRF53X_CPUAPP'
# and 'SOC_NRF53X_CPUNET' options, so we don't have to
# maintain a list of SoCs in this file too.
raise RuntimeError(f'unknown nRF53; update {__file__}')
coprocessor_args = ['--coprocessor', coprocessor]
else:
coprocessor_args = []
# It's important for tool_opt to come last, so it can override
# any options that we set here.
try:
self.check_call(['nrfjprog', '--program', self.hex_, erase_arg,
'-f', self.family, '--snr', self.snr] +
coprocessor_args + self.tool_opt)
except subprocess.CalledProcessError as cpe:
if cpe.returncode == UnavailableOperationBecauseProtectionError:
if self.family == 'NRF53':
family_help = (
' Note: your target is an nRF53; all flash memory '
'for both the network and application cores will be '
'erased prior to reflashing.')
else:
family_help = (
' Note: this will recover and erase all flash memory '
'prior to reflashing.')
self.logger.error(
'Flashing failed because the target '
'must be recovered.\n'
' To fix, run "west flash --recover" instead.\n' +
family_help)
raise
def reset_target(self):
if self.family == 'NRF52' and not self.softreset: if self.family == 'NRF52' and not self.softreset:
commands.extend([ self.check_call(['nrfjprog', '--pinresetenable', '-f', self.family,
# Enable pin reset '--snr', self.snr]) # Enable pin reset
['nrfjprog', '--pinresetenable', '-f', self.family,
'--snr', board_snr],
])
if self.softreset: if self.softreset:
commands.append(['nrfjprog', '--reset', '-f', self.family, self.check_call(['nrfjprog', '--reset', '-f', self.family,
'--snr', board_snr]) '--snr', self.snr])
else: else:
commands.append(['nrfjprog', '--pinreset', '-f', self.family, self.check_call(['nrfjprog', '--pinreset', '-f', self.family,
'--snr', board_snr]) '--snr', self.snr])
for cmd in commands: def do_run(self, command, **kwargs):
self.check_call(cmd) self.require('nrfjprog')
self.build_conf = BuildConfiguration(self.cfg.build_dir)
if not os.path.isfile(self.hex_):
raise RuntimeError(
f'Cannot flash; hex file ({self.hex_}) does not exist. '
'Try enabling CONFIG_BUILD_OUTPUT_HEX.')
self.logger.info('Board with serial number {} flashed successfully.'. self.ensure_snr()
format(board_snr)) self.ensure_family()
self.check_force_uicr()
if self.recover:
self.recover_target()
self.program_hex()
self.reset_target()
self.logger.info(f'Board with serial number {self.snr} '
'flashed successfully.')

View file

@ -1,9 +1,11 @@
# Copyright (c) 2018 Foundries.io # Copyright (c) 2018 Foundries.io
# Copyright (c) 2020 Nordic Semiconductor ASA
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import argparse import argparse
import os import os
import typing
from unittest.mock import patch, call from unittest.mock import patch, call
import pytest import pytest
@ -20,205 +22,237 @@ TEST_DEF_SNR = 'test-default-serial-number' # for mocking user input
TEST_OVR_SNR = 'test-override-serial-number' TEST_OVR_SNR = 'test-override-serial-number'
# #
# Expected results. # A dictionary mapping test cases to expected results.
# #
# This dictionary maps different configurations to the commands we expect to be # The keys are TC objects.
# executed for them. Verification is done by mocking the check_call() method,
# which is used to run the commands.
# #
# The key naming scheme is <F><SR><SN><E>, where: # The values are the nrfjprog commands we expect to be executed for
# # each test case. Verification is done by mocking the check_call()
# - F: family, 1 for 'NRF51' or 2 for 'NRF52' # ZephyrBinaryRunner method which is used to run the commands.
# - SR: soft reset, Y for yes, N for pin reset
# - SNR: serial number override, Y for yes, N for 'use default'
# - E: full chip erase, Y for yes, N for sector / sector and UICR only
# #
EXPECTED_COMMANDS = { class TC(typing.NamedTuple): # 'TestCase'
# NRF51: # NRF51, NRF52, etc.
'1NNN': family: str
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
# 'APP', 'NET', or None.
coprocessor: typing.Optional[str]
# Run 'nrfjprog --recover' first if True
recover: bool
# Use --reset instead of --pinreset if True
softreset: bool
# --snr TEST_OVR_SNR if True, --snr TEST_DEF_SNR if False
snr: bool
# --chiperase if True,
# --sectorerase if False (or --sectoranduicrerase on nRF52)
erase: bool
EXPECTED_RESULTS = {
# -------------------------------------------------------------------------
# NRF51
#
# family CP recov soft snr erase
TC('NRF51', None, False, False, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1NNY': TC('NRF51', None, False, False, False, True):
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF51',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1NYN': TC('NRF51', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1NYY': TC('NRF51', None, False, True, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YNY': TC('NRF51', None, True, False, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR], (['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YYN': TC('NRF51', None, True, True, True, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF51',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1YYY': # -------------------------------------------------------------------------
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR], # NRF52
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501 #
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), # family CP recov soft snr erase
TC('NRF52', None, False, False, False, False):
# NRF52: (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'2NNN': '-f', 'NRF52', '--snr', TEST_DEF_SNR],
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NNY': TC('NRF52', None, False, False, False, True):
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF52',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NYN': TC('NRF52', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501 (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2NYY': TC('NRF52', None, False, True, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501 '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YNY': TC('NRF52', None, True, False, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR], (['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YYN': TC('NRF52', None, True, True, True, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501 (['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF52',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2YYY': # -------------------------------------------------------------------------
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR], # NRF53 APP
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501 #
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), # family CP recov soft snr erase
# NRF53: TC('NRF53', 'APP', False, False, False, False):
'3NNN': (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501 '--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3NNY': TC('NRF53', 'APP', False, False, False, True):
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_DEF_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF53',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR], # noqa: E501 '--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3NYN': TC('NRF53', 'APP', False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_OVR_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
'3NYY': TC('NRF53', 'APP', False, True, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_OVR_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR], # noqa: E501 '--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
TC('NRF53', 'APP', True, False, False, False):
(['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
TC('NRF53', 'APP', True, True, True, True):
(['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF53',
'--snr', TEST_OVR_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
# -------------------------------------------------------------------------
# NRF53 NET
#
# family CP recov soft snr erase
TC('NRF53', 'NET', False, False, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
TC('NRF53', 'NET', False, False, False, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
TC('NRF53', 'NET', False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_OVR_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
'3YNN': TC('NRF53', 'NET', False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3YNY': TC('NRF53', 'NET', True, False, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_DEF_SNR], (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3YYN': TC('NRF53', 'NET', True, True, True, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF53',
'--snr', TEST_OVR_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
'3YYY': # -------------------------------------------------------------------------
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_OVR_SNR], # NRF91
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR], # noqa: E501 #
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), # family CP recov soft snr erase
TC('NRF91', None, False, False, False, False):
# NRF91: (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'9NNN': '--snr', TEST_DEF_SNR],
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NNY': TC('NRF91', None, False, False, False, True):
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF91',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NYN': TC('NRF91', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9NYY': TC('NRF91', None, False, True, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_OVR_SNR], (['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR], # noqa: E501 '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YNY': TC('NRF91', None, True, False, False, False):
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR], (['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YYN': TC('NRF91', None, True, True, True, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501 (['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF91',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
} }
def expected_commands(family, softreset, snr, erase):
'''Expected NrfJprogBinaryRunner results given parameters.
Returns a factory function which expects the following arguments:
- family: string, 'NRF51', 'NRF52' or 'NRF91'
- softreset: boolean, controls whether soft reset is performed
- snr: string serial number of board, or None
- erase: boolean, whether to do a full chip erase or not
'''
expected_key = '{}{}{}{}'.format(
'1' if family == 'NRF51' else '2' if family == 'NRF52' else '3' if family == 'NRF53' else '9', # noqa: E501
'Y' if softreset else 'N',
'Y' if snr else 'N',
'Y' if erase else 'N')
return EXPECTED_COMMANDS[expected_key]
# #
# Test cases # Monkey-patches
# #
TEST_CASES = [(f, sr, snr, e)
for f in ('NRF51', 'NRF52', 'NRF53', 'NRF91')
for sr in (False, True)
for snr in (TEST_OVR_SNR, None)
for e in (False, True)]
def get_board_snr_patch(glob): def get_board_snr_patch(glob):
return TEST_DEF_SNR return TEST_DEF_SNR
@ -230,51 +264,92 @@ def os_path_isfile_patch(filename):
return True return True
return os.path.isfile(filename) return os.path.isfile(filename)
def id_fn(test_case): def build_configuration(test_case):
ret = '' ret = {
for x in test_case: f'CONFIG_SOC_SERIES_{test_case.family}X': 'y',
if x in ('NRF51', 'NRF52', 'NRF53'): }
ret += x[-1:]
# Would need an update if we have more SoCs than nRF5340 supported.
if test_case.family == 'NRF53':
if test_case.coprocessor == 'APP':
ret['CONFIG_SOC_NRF5340_CPUAPP'] = 'y'
elif test_case.coprocessor == 'NET':
ret['CONFIG_SOC_NRF5340_CPUNET'] = 'y'
else: else:
ret += 'Y' if x else 'N' assert False, f'bad nRF53 coprocessor {test_case.coprocessor}'
return ret return ret
@pytest.mark.parametrize('test_case', TEST_CASES, ids=id_fn) #
# Test functions.
#
# These are white box tests that rely on the above monkey-patches.
#
def id_fn(test_case):
if test_case.coprocessor is None:
cp = ''
else:
cp = f', {test_case.coprocessor}'
s = 'soft reset' if test_case.softreset else 'pin reset'
sn = 'default snr' if test_case.snr else 'override snr'
e = 'chip erase' if test_case.erase else 'sector[anduicr] erase'
r = 'recover' if test_case.recover else 'no recover'
return f'{test_case.family}{cp}, {s}, {sn}, {e}, {r}'
@pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn)
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr', @patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr',
side_effect=get_board_snr_patch) side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call') @patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_init(cc, get_snr, req, test_case, runner_config): @patch('runners.nrfjprog.BuildConfiguration')
family, softreset, snr, erase = test_case def test_nrfjprog_init(build_conf, check_call, get_snr, require, test_case,
runner_config):
build_conf.return_value = build_configuration(test_case)
expected = EXPECTED_RESULTS[test_case]
snr = TEST_OVR_SNR if test_case.snr else None
runner = NrfJprogBinaryRunner(runner_config,
test_case.family,
test_case.softreset,
snr,
erase=test_case.erase,
recover=test_case.recover)
runner = NrfJprogBinaryRunner(runner_config, family, softreset, snr,
erase=erase)
with patch('os.path.isfile', side_effect=os_path_isfile_patch): with patch('os.path.isfile', side_effect=os_path_isfile_patch):
runner.run('flash') runner.run('flash')
assert req.called assert require.called
assert cc.call_args_list == [call(x) for x in
expected_commands(*test_case)] if expected is not None:
assert check_call.call_args_list == [call(x) for x in expected]
else:
assert not check_call.called
if snr is None: if snr is None:
get_snr.assert_called_once_with('*') get_snr.assert_called_once_with('*')
else: else:
get_snr.assert_not_called() get_snr.assert_not_called()
@pytest.mark.parametrize('test_case', TEST_CASES, ids=id_fn) @pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn)
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr', @patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr',
side_effect=get_board_snr_patch) side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call') @patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_create(cc, get_snr, req, test_case, runner_config): @patch('runners.nrfjprog.BuildConfiguration')
family, softreset, snr, erase = test_case def test_nrfjprog_create(build_conf, check_call, get_snr, require, test_case,
runner_config):
build_conf.return_value = build_configuration(test_case)
expected = EXPECTED_RESULTS[test_case]
args = ['--nrf-family', family] args = []
if softreset: if test_case.softreset:
args.append('--softreset') args.append('--softreset')
if snr is not None: if test_case.snr:
args.extend(['--snr', snr]) args.extend(['--snr', TEST_OVR_SNR])
if erase: if test_case.erase:
args.append('--erase') args.append('--erase')
if test_case.recover:
args.append('--recover')
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
NrfJprogBinaryRunner.add_parser(parser) NrfJprogBinaryRunner.add_parser(parser)
@ -283,10 +358,10 @@ def test_nrfjprog_create(cc, get_snr, req, test_case, runner_config):
with patch('os.path.isfile', side_effect=os_path_isfile_patch): with patch('os.path.isfile', side_effect=os_path_isfile_patch):
runner.run('flash') runner.run('flash')
assert req.called assert require.called
assert cc.call_args_list == [call(x) for x in assert check_call.call_args_list == [call(x) for x in expected]
expected_commands(*test_case)]
if snr is None: if not test_case.snr:
get_snr.assert_called_once_with('*') get_snr.assert_called_once_with('*')
else: else:
get_snr.assert_not_called() get_snr.assert_not_called()