Standardize to nrfutil error codes instead of nrfjprog ones. This is because nrfutil has a wider range of functionality and will eventually be the default runner for all nRF devices. It is also consistent with the internal operation representation, which is now using the nrfutil format already. Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
# Copyright (c) 2017 Linaro Limited.
|
|
# Copyright (c) 2023 Nordic Semiconductor ASA.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
'''Runner for flashing with nrfjprog.'''
|
|
|
|
import subprocess
|
|
import sys
|
|
|
|
from runners.nrf_common import ErrNotAvailableBecauseProtection, ErrVerify, \
|
|
NrfBinaryRunner
|
|
|
|
# https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf_cltools%2FUG%2Fcltools%2Fnrf_nrfjprogexe_return_codes.html&cp=9_1_3_1
|
|
UnavailableOperationBecauseProtectionError = 16
|
|
VerifyError = 55
|
|
|
|
class NrfJprogBinaryRunner(NrfBinaryRunner):
|
|
'''Runner front-end for nrfjprog.'''
|
|
|
|
@classmethod
|
|
def name(cls):
|
|
return 'nrfjprog'
|
|
|
|
@classmethod
|
|
def tool_opt_help(cls) -> str:
|
|
return 'Additional options for nrfjprog, e.g. "--recover"'
|
|
|
|
@classmethod
|
|
def do_create(cls, cfg, args):
|
|
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
|
|
args.dev_id, erase=args.erase,
|
|
tool_opt=args.tool_opt, force=args.force,
|
|
recover=args.recover)
|
|
|
|
def do_get_boards(self):
|
|
snrs = self.check_output(['nrfjprog', '--ids'])
|
|
return snrs.decode(sys.getdefaultencoding()).strip().splitlines()
|
|
|
|
def do_require(self):
|
|
self.require('nrfjprog')
|
|
|
|
def do_exec_op(self, op, force=False):
|
|
self.logger.debug(f'Executing op: {op}')
|
|
# Translate the op
|
|
|
|
families = {'NRF51_FAMILY': 'NRF51', 'NRF52_FAMILY': 'NRF52',
|
|
'NRF53_FAMILY': 'NRF53', 'NRF91_FAMILY': 'NRF91'}
|
|
cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION',
|
|
'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'}
|
|
|
|
core_opt = ['--coprocessor', cores[op['core']]] \
|
|
if op.get('core') else []
|
|
|
|
cmd = ['nrfjprog']
|
|
_op = op['operation']
|
|
op_type = _op['type']
|
|
# options that are an empty dict must use "in" instead of get()
|
|
if op_type == 'pinreset-enable':
|
|
cmd.append('--pinresetenable')
|
|
elif op_type == 'program':
|
|
cmd.append('--program')
|
|
cmd.append(_op['firmware']['file'])
|
|
erase = _op['chip_erase_mode']
|
|
if erase == 'ERASE_ALL':
|
|
cmd.append('--chiperase')
|
|
elif erase == 'ERASE_PAGES':
|
|
cmd.append('--sectorerase')
|
|
elif erase == 'ERASE_PAGES_INCLUDING_UICR':
|
|
cmd.append('--sectoranduicrerase')
|
|
else:
|
|
raise RuntimeError(f'Invalid erase mode: {erase}')
|
|
|
|
if _op.get('qspi_erase_mode'):
|
|
# In the future there might be multiple QSPI erase modes
|
|
cmd.append('--qspisectorerase')
|
|
if _op.get('verify'):
|
|
# In the future there might be multiple verify modes
|
|
cmd.append('--verify')
|
|
elif op_type == 'recover':
|
|
cmd.append('--recover')
|
|
elif op_type == 'reset':
|
|
if _op['option'] == 'RESET_SYSTEM':
|
|
cmd.append('--reset')
|
|
if _op['option'] == 'RESET_PIN':
|
|
cmd.append('--pinreset')
|
|
else:
|
|
raise RuntimeError(f'Invalid operation: {op_type}')
|
|
|
|
try:
|
|
self.check_call(cmd + ['-f', families[self.family]] + core_opt +
|
|
['--snr', self.dev_id] + self.tool_opt)
|
|
except subprocess.CalledProcessError as cpe:
|
|
# Translate error codes
|
|
if cpe.returncode == UnavailableOperationBecauseProtectionError:
|
|
cpe.returncode = ErrNotAvailableBecauseProtection
|
|
elif cpe.returncode == VerifyError:
|
|
cpe.returncode = ErrVerify
|
|
raise cpe
|
|
return True
|