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
commit 6628a16e4d
36 changed files with 396 additions and 260 deletions

View file

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

View file

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

View file

@ -1,6 +1,6 @@
# 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")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,6 @@
# 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(pyocd "--target=nrf52833" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

@ -1,6 +1,6 @@
# 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")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -1,6 +1,6 @@
# 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")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
# 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/nrfjprog.board.cmake)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
board_runner_args(nrfjprog "--nrf-family=NRF52")
board_runner_args(jlink "--device=nrf52" "--speed=4000")
board_runner_args(pyocd "--target=nrf52" "--frequency=4000000")
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
(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")
endif()
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")
endif()

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
# 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(pyocd "--target=nrf52840" "--frequency=4000000")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)

View file

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

View file

@ -1,6 +1,6 @@
# 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")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

View file

@ -7,10 +7,11 @@
import os
import shlex
import subprocess
import sys
from re import fullmatch, escape
from runners.core import ZephyrBinaryRunner, RunnerCaps
from runners.core import ZephyrBinaryRunner, RunnerCaps, BuildConfiguration
try:
from intelhex import IntelHex
@ -33,19 +34,22 @@ def has_region(regions, hex_file):
except FileNotFoundError:
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):
'''Runner front-end for nrfjprog.'''
def __init__(self, cfg, family, softreset, snr, erase=False,
tool_opt=[], force=False):
tool_opt=[], force=False, recover=False):
super().__init__(cfg)
self.hex_ = cfg.hex_file
self.family = family
self.softreset = softreset
self.snr = snr
self.erase = erase
self.erase = bool(erase)
self.force = force
self.recover = bool(recover)
self.tool_opt = []
for opts in [shlex.split(opt) for opt in tool_opt]:
@ -61,9 +65,10 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
@classmethod
def do_add_parser(cls, parser):
parser.add_argument('--nrf-family', required=True,
parser.add_argument('--nrf-family',
choices=['NRF51', 'NRF52', 'NRF53', 'NRF91'],
help='family of nRF MCU')
help='''MCU family; still accepted for
compatibility only''')
parser.add_argument('--softreset', required=False,
action='store_true',
help='use reset instead of pinreset')
@ -76,16 +81,23 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
parser.add_argument('--force', required=False,
action='store_true',
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
def do_create(cls, cfg, args):
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
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):
if not self.snr or "*" in self.snr:
self.snr = self.get_board_snr(self.snr or "*")
self.snr = self.snr.lstrip("0")
def get_boards(self):
snrs = self.check_output(['nrfjprog', '--ids'])
@ -150,68 +162,144 @@ class NrfJprogBinaryRunner(ZephyrBinaryRunner):
return snrs[value - 1]
def do_run(self, command, **kwargs):
self.require('nrfjprog')
def ensure_family(self):
# Ensure self.family is set.
self.ensure_snr()
if self.family is not None:
return
commands = []
board_snr = self.snr.lstrip("0")
if not os.path.isfile(self.hex_):
raise ValueError('Cannot flash; hex file ({}) does not exist. '.
format(self.hex_) +
'Try enabling CONFIG_BUILD_OUTPUT_HEX.')
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
])
if self.build_conf.get('CONFIG_SOC_SERIES_NRF51X', False):
self.family = 'NRF51'
elif self.build_conf.get('CONFIG_SOC_SERIES_NRF52X', False):
self.family = 'NRF52'
elif self.build_conf.get('CONFIG_SOC_SERIES_NRF53X', False):
self.family = 'NRF53'
elif self.build_conf.get('CONFIG_SOC_SERIES_NRF91X', False):
self.family = 'NRF91'
else:
if self.family == 'NRF51':
commands.append(program_cmd + ['--sectorerase'])
elif self.family == 'NRF52':
commands.append(program_cmd + ['--sectoranduicrerase'])
raise RuntimeError(f'unknown nRF; update {__file__}')
def check_force_uicr(self):
# On SoCs without --sectoranduicrerase, we want to fail by
# default if the application contains UICR data and we're not sure
# 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),
(0x01FF8000, 0x01FF8800)),
'NRF91': ((0x00FF8000, 0x00FF8800),),
}
if self.family not in uicr_ranges:
return
uicr = uicr_ranges[self.family]
if not self.force and has_region(uicr, self.hex_):
# Hex file has UICR contents.
raise RuntimeError(
'The hex file contains data placed in the UICR, which '
'needs a full erase before reprogramming. Run west '
'flash again with --force or --erase.')
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:
uicr = {
'NRF53': ((0x00FF8000, 0x00FF8800),
(0x01FF8000, 0x01FF8800)),
'NRF91': ((0x00FF8000, 0x00FF8800),),
}[self.family]
erase_arg = '--sectorerase'
if not self.force and has_region(uicr, self.hex_):
# Hex file has UICR contents.
raise RuntimeError(
'The hex file contains data placed in the UICR, which '
'needs a full erase before reprogramming. Run west '
'flash again with --force or --erase.')
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:
commands.append(program_cmd + ['--sectorerase'])
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:
commands.extend([
# Enable pin reset
['nrfjprog', '--pinresetenable', '-f', self.family,
'--snr', board_snr],
])
self.check_call(['nrfjprog', '--pinresetenable', '-f', self.family,
'--snr', self.snr]) # Enable pin reset
if self.softreset:
commands.append(['nrfjprog', '--reset', '-f', self.family,
'--snr', board_snr])
self.check_call(['nrfjprog', '--reset', '-f', self.family,
'--snr', self.snr])
else:
commands.append(['nrfjprog', '--pinreset', '-f', self.family,
'--snr', board_snr])
self.check_call(['nrfjprog', '--pinreset', '-f', self.family,
'--snr', self.snr])
for cmd in commands:
self.check_call(cmd)
def do_run(self, command, **kwargs):
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.'.
format(board_snr))
self.ensure_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) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
import argparse
import os
import typing
from unittest.mock import patch, call
import pytest
@ -20,205 +22,237 @@ TEST_DEF_SNR = 'test-default-serial-number' # for mocking user input
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
# executed for them. Verification is done by mocking the check_call() method,
# which is used to run the commands.
# The keys are TC objects.
#
# The key naming scheme is <F><SR><SN><E>, where:
#
# - F: family, 1 for 'NRF51' or 2 for 'NRF52'
# - 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
# The values are the nrfjprog commands we expect to be executed for
# each test case. Verification is done by mocking the check_call()
# ZephyrBinaryRunner method which is used to run the commands.
#
EXPECTED_COMMANDS = {
# NRF51:
'1NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
class TC(typing.NamedTuple): # 'TestCase'
# NRF51, NRF52, etc.
family: str
# '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]),
'1NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501
TC('NRF51', None, False, False, False, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF51',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF51', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
TC('NRF51', None, False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
TC('NRF51', None, True, False, False, False):
(['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF51',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF51', None, True, True, True, True):
(['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]),
'1YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
# NRF52:
'2NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR, '--sectoranduicrerase'], # noqa: E501
# -------------------------------------------------------------------------
# NRF52
#
# family CP recov soft snr erase
TC('NRF52', None, False, False, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501
TC('NRF52', None, False, False, False, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF52',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501
TC('NRF52', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501
['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
TC('NRF52', None, False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
TC('NRF52', None, True, False, False, False):
(['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase',
'-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501
TC('NRF52', None, True, True, True, True):
(['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]),
'2YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
# -------------------------------------------------------------------------
# NRF53 APP
#
# family CP recov soft snr erase
# NRF53:
'3NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
TC('NRF53', 'APP', False, False, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR], # noqa: E501
TC('NRF53', 'APP', False, False, False, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF53', 'APP', False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_OVR_SNR, '--coprocessor', 'CP_APPLICATION'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
'3NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR], # noqa: E501
TC('NRF53', 'APP', False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--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]),
'3YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
TC('NRF53', 'NET', False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF53',
'--snr', TEST_DEF_SNR, '--coprocessor', 'CP_NETWORK'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
TC('NRF53', 'NET', 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_NETWORK'],
['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]),
'3YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF53', 'NET', 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_NETWORK'],
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
'3YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF53', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF53', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]),
# NRF91:
'9NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
# -------------------------------------------------------------------------
# NRF91
#
# family CP recov soft snr erase
TC('NRF91', None, False, False, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501
TC('NRF91', None, False, False, False, True):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '-f', 'NRF91',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF91', None, False, False, True, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
TC('NRF91', None, False, True, False, False):
(['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
TC('NRF91', None, True, False, False, False):
(['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '-f', 'NRF91',
'--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
TC('NRF91', None, True, True, True, True):
(['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]),
'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):
return TEST_DEF_SNR
@ -230,51 +264,92 @@ def os_path_isfile_patch(filename):
return True
return os.path.isfile(filename)
def id_fn(test_case):
ret = ''
for x in test_case:
if x in ('NRF51', 'NRF52', 'NRF53'):
ret += x[-1:]
def build_configuration(test_case):
ret = {
f'CONFIG_SOC_SERIES_{test_case.family}X': 'y',
}
# 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:
ret += 'Y' if x else 'N'
assert False, f'bad nRF53 coprocessor {test_case.coprocessor}'
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.nrfjprog.NrfJprogBinaryRunner.get_board_snr',
side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_init(cc, get_snr, req, test_case, runner_config):
family, softreset, snr, erase = test_case
@patch('runners.nrfjprog.BuildConfiguration')
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):
runner.run('flash')
assert req.called
assert cc.call_args_list == [call(x) for x in
expected_commands(*test_case)]
assert require.called
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:
get_snr.assert_called_once_with('*')
else:
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.nrfjprog.NrfJprogBinaryRunner.get_board_snr',
side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_create(cc, get_snr, req, test_case, runner_config):
family, softreset, snr, erase = test_case
@patch('runners.nrfjprog.BuildConfiguration')
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]
if softreset:
args = []
if test_case.softreset:
args.append('--softreset')
if snr is not None:
args.extend(['--snr', snr])
if erase:
if test_case.snr:
args.extend(['--snr', TEST_OVR_SNR])
if test_case.erase:
args.append('--erase')
if test_case.recover:
args.append('--recover')
parser = argparse.ArgumentParser()
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):
runner.run('flash')
assert req.called
assert cc.call_args_list == [call(x) for x in
expected_commands(*test_case)]
if snr is None:
assert require.called
assert check_call.call_args_list == [call(x) for x in expected]
if not test_case.snr:
get_snr.assert_called_once_with('*')
else:
get_snr.assert_not_called()