west: runners: Add support for multiple device IDs
In order to enable the use case where the underlying flash tool supports bulk-flashing using multiple device IDs, augment the core runner class with this new runner capability and implement it in the nrfutil runner, since the nrfutil tool supports it natively. Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
9388349957
commit
c9151be798
4 changed files with 56 additions and 11 deletions
|
@ -268,6 +268,9 @@ class RunnerCaps:
|
||||||
connected to a single computer, in order to select which one will be used
|
connected to a single computer, in order to select which one will be used
|
||||||
with the command provided.
|
with the command provided.
|
||||||
|
|
||||||
|
- mult_dev_ids: whether the runner supports multiple device identifiers
|
||||||
|
for a single operation, allowing for bulk flashing of devices.
|
||||||
|
|
||||||
- flash_addr: whether the runner supports flashing to an
|
- flash_addr: whether the runner supports flashing to an
|
||||||
arbitrary address. Default is False. If true, the runner
|
arbitrary address. Default is False. If true, the runner
|
||||||
must honor the --dt-flash option.
|
must honor the --dt-flash option.
|
||||||
|
@ -305,6 +308,7 @@ class RunnerCaps:
|
||||||
|
|
||||||
commands: set[str] = field(default_factory=lambda: set(_RUNNERCAPS_COMMANDS))
|
commands: set[str] = field(default_factory=lambda: set(_RUNNERCAPS_COMMANDS))
|
||||||
dev_id: bool = False
|
dev_id: bool = False
|
||||||
|
mult_dev_ids: bool = False
|
||||||
flash_addr: bool = False
|
flash_addr: bool = False
|
||||||
erase: bool = False
|
erase: bool = False
|
||||||
reset: bool = False
|
reset: bool = False
|
||||||
|
@ -316,6 +320,8 @@ class RunnerCaps:
|
||||||
# to allow other commands to use the rtt address
|
# to allow other commands to use the rtt address
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
|
if self.mult_dev_ids and not self.dev_id:
|
||||||
|
raise RuntimeError('dev_id must be set along mult_dev_ids')
|
||||||
if not self.commands.issubset(_RUNNERCAPS_COMMANDS):
|
if not self.commands.issubset(_RUNNERCAPS_COMMANDS):
|
||||||
raise ValueError(f'{self.commands=} contains invalid command')
|
raise ValueError(f'{self.commands=} contains invalid command')
|
||||||
|
|
||||||
|
@ -543,7 +549,9 @@ class ZephyrBinaryRunner(abc.ABC):
|
||||||
caps = cls.capabilities()
|
caps = cls.capabilities()
|
||||||
|
|
||||||
if caps.dev_id:
|
if caps.dev_id:
|
||||||
|
action = 'append' if caps.mult_dev_ids else 'store'
|
||||||
parser.add_argument('-i', '--dev-id',
|
parser.add_argument('-i', '--dev-id',
|
||||||
|
action=action,
|
||||||
dest='dev_id',
|
dest='dev_id',
|
||||||
help=cls.dev_id_help())
|
help=cls.dev_id_help())
|
||||||
else:
|
else:
|
||||||
|
@ -749,10 +757,13 @@ class ZephyrBinaryRunner(abc.ABC):
|
||||||
@classmethod
|
@classmethod
|
||||||
def dev_id_help(cls) -> str:
|
def dev_id_help(cls) -> str:
|
||||||
''' Get the ArgParse help text for the --dev-id option.'''
|
''' Get the ArgParse help text for the --dev-id option.'''
|
||||||
return '''Device identifier. Use it to select
|
help = '''Device identifier. Use it to select
|
||||||
which debugger, device, node or instance to
|
which debugger, device, node or instance to
|
||||||
target when multiple ones are available or
|
target when multiple ones are available or
|
||||||
connected.'''
|
connected.'''
|
||||||
|
addendum = '''\nThis option can be present multiple times.''' if \
|
||||||
|
cls.capabilities().mult_dev_ids else ''
|
||||||
|
return help + addendum
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extload_help(cls) -> str:
|
def extload_help(cls) -> str:
|
||||||
|
|
|
@ -101,12 +101,13 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
|
||||||
self.tool_opt += opts
|
self.tool_opt += opts
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def capabilities(cls):
|
def _capabilities(cls, mult_dev_ids=False):
|
||||||
return RunnerCaps(commands={'flash'}, dev_id=True, erase=True,
|
return RunnerCaps(commands={'flash'}, dev_id=True,
|
||||||
reset=True, tool_opt=True)
|
mult_dev_ids=mult_dev_ids, erase=True, reset=True,
|
||||||
|
tool_opt=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dev_id_help(cls) -> str:
|
def _dev_id_help(cls) -> str:
|
||||||
return '''Device identifier. Use it to select the J-Link Serial Number
|
return '''Device identifier. Use it to select the J-Link Serial Number
|
||||||
of the device connected over USB. '*' matches one or more
|
of the device connected over USB. '*' matches one or more
|
||||||
characters/digits'''
|
characters/digits'''
|
||||||
|
@ -146,9 +147,19 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
|
||||||
args.dev_id = previous_runner.dev_id
|
args.dev_id = previous_runner.dev_id
|
||||||
|
|
||||||
def ensure_snr(self):
|
def ensure_snr(self):
|
||||||
if not self.dev_id or "*" in self.dev_id:
|
# dev_id can be None, str or list of str
|
||||||
self.dev_id = self.get_board_snr(self.dev_id or "*")
|
dev_id = self.dev_id
|
||||||
self.dev_id = self.dev_id.lstrip("0")
|
if isinstance(dev_id, list):
|
||||||
|
if len(dev_id) == 0:
|
||||||
|
dev_id = None
|
||||||
|
elif len(dev_id) == 1:
|
||||||
|
dev_id = dev_id[0]
|
||||||
|
else:
|
||||||
|
self.dev_id = [d.lstrip("0") for d in dev_id]
|
||||||
|
return
|
||||||
|
if not dev_id or "*" in dev_id:
|
||||||
|
dev_id = self.get_board_snr(dev_id or "*")
|
||||||
|
self.dev_id = dev_id.lstrip("0")
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def do_get_boards(self):
|
def do_get_boards(self):
|
||||||
|
@ -528,5 +539,5 @@ class NrfBinaryRunner(ZephyrBinaryRunner):
|
||||||
# All done, now flush any outstanding ops
|
# All done, now flush any outstanding ops
|
||||||
self.flush(force=True)
|
self.flush(force=True)
|
||||||
|
|
||||||
self.logger.info(f'Board with serial number {self.dev_id} '
|
self.logger.info(f'Board(s) with serial number(s) {self.dev_id} '
|
||||||
'flashed successfully.')
|
'flashed successfully.')
|
||||||
|
|
|
@ -30,6 +30,14 @@ class NrfJprogBinaryRunner(NrfBinaryRunner):
|
||||||
def name(cls):
|
def name(cls):
|
||||||
return 'nrfjprog'
|
return 'nrfjprog'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def capabilities(cls):
|
||||||
|
return NrfBinaryRunner._capabilities()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def dev_id_help(cls) -> str:
|
||||||
|
return NrfBinaryRunner._dev_id_help()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tool_opt_help(cls) -> str:
|
def tool_opt_help(cls) -> str:
|
||||||
return 'Additional options for nrfjprog, e.g. "--clockspeed"'
|
return 'Additional options for nrfjprog, e.g. "--clockspeed"'
|
||||||
|
|
|
@ -33,6 +33,15 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
|
||||||
def name(cls):
|
def name(cls):
|
||||||
return 'nrfutil'
|
return 'nrfutil'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def capabilities(cls):
|
||||||
|
return NrfBinaryRunner._capabilities(mult_dev_ids=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def dev_id_help(cls) -> str:
|
||||||
|
return NrfBinaryRunner._dev_id_help() + \
|
||||||
|
'''.\n This option can be specified multiple times'''
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tool_opt_help(cls) -> str:
|
def tool_opt_help(cls) -> str:
|
||||||
return 'Additional options for nrfutil, e.g. "--log-level"'
|
return 'Additional options for nrfutil, e.g. "--log-level"'
|
||||||
|
@ -107,6 +116,12 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
|
||||||
self._op_id += 1
|
self._op_id += 1
|
||||||
self._ops.append(op)
|
self._ops.append(op)
|
||||||
|
|
||||||
|
def _format_dev_ids(self):
|
||||||
|
if isinstance(self.dev_id, list):
|
||||||
|
return ','.join(self.dev_id)
|
||||||
|
else:
|
||||||
|
return self.dev_id
|
||||||
|
|
||||||
def _append_batch(self, op, json_file):
|
def _append_batch(self, op, json_file):
|
||||||
_op = op['operation']
|
_op = op['operation']
|
||||||
op_type = _op['type']
|
op_type = _op['type']
|
||||||
|
@ -151,7 +166,7 @@ class NrfUtilBinaryRunner(NrfBinaryRunner):
|
||||||
precmd = ['--x-ext-mem-config-file', self.ext_mem_config_file]
|
precmd = ['--x-ext-mem-config-file', self.ext_mem_config_file]
|
||||||
|
|
||||||
self._exec(precmd + ['x-execute-batch', '--batch-path', f'{json_file}',
|
self._exec(precmd + ['x-execute-batch', '--batch-path', f'{json_file}',
|
||||||
'--serial-number', f'{self.dev_id}'])
|
'--serial-number', self._format_dev_ids()])
|
||||||
|
|
||||||
def do_exec_op(self, op, force=False):
|
def do_exec_op(self, op, force=False):
|
||||||
self.logger.debug(f'Executing op: {op}')
|
self.logger.debug(f'Executing op: {op}')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue