Skip to content

Commit c9151be

Browse files
carlescufiaescolar
authored andcommitted
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>
1 parent 9388349 commit c9151be

File tree

4 files changed

+56
-11
lines changed

4 files changed

+56
-11
lines changed

scripts/west_commands/runners/core.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ class RunnerCaps:
268268
connected to a single computer, in order to select which one will be used
269269
with the command provided.
270270
271+
- mult_dev_ids: whether the runner supports multiple device identifiers
272+
for a single operation, allowing for bulk flashing of devices.
273+
271274
- flash_addr: whether the runner supports flashing to an
272275
arbitrary address. Default is False. If true, the runner
273276
must honor the --dt-flash option.
@@ -305,6 +308,7 @@ class RunnerCaps:
305308

306309
commands: set[str] = field(default_factory=lambda: set(_RUNNERCAPS_COMMANDS))
307310
dev_id: bool = False
311+
mult_dev_ids: bool = False
308312
flash_addr: bool = False
309313
erase: bool = False
310314
reset: bool = False
@@ -316,6 +320,8 @@ class RunnerCaps:
316320
# to allow other commands to use the rtt address
317321

318322
def __post_init__(self):
323+
if self.mult_dev_ids and not self.dev_id:
324+
raise RuntimeError('dev_id must be set along mult_dev_ids')
319325
if not self.commands.issubset(_RUNNERCAPS_COMMANDS):
320326
raise ValueError(f'{self.commands=} contains invalid command')
321327

@@ -543,7 +549,9 @@ def add_parser(cls, parser):
543549
caps = cls.capabilities()
544550

545551
if caps.dev_id:
552+
action = 'append' if caps.mult_dev_ids else 'store'
546553
parser.add_argument('-i', '--dev-id',
554+
action=action,
547555
dest='dev_id',
548556
help=cls.dev_id_help())
549557
else:
@@ -749,10 +757,13 @@ def thread_info_enabled(self) -> bool:
749757
@classmethod
750758
def dev_id_help(cls) -> str:
751759
''' Get the ArgParse help text for the --dev-id option.'''
752-
return '''Device identifier. Use it to select
760+
help = '''Device identifier. Use it to select
753761
which debugger, device, node or instance to
754762
target when multiple ones are available or
755763
connected.'''
764+
addendum = '''\nThis option can be present multiple times.''' if \
765+
cls.capabilities().mult_dev_ids else ''
766+
return help + addendum
756767

757768
@classmethod
758769
def extload_help(cls) -> str:

scripts/west_commands/runners/nrf_common.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,13 @@ def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
101101
self.tool_opt += opts
102102

103103
@classmethod
104-
def capabilities(cls):
105-
return RunnerCaps(commands={'flash'}, dev_id=True, erase=True,
106-
reset=True, tool_opt=True)
104+
def _capabilities(cls, mult_dev_ids=False):
105+
return RunnerCaps(commands={'flash'}, dev_id=True,
106+
mult_dev_ids=mult_dev_ids, erase=True, reset=True,
107+
tool_opt=True)
107108

108109
@classmethod
109-
def dev_id_help(cls) -> str:
110+
def _dev_id_help(cls) -> str:
110111
return '''Device identifier. Use it to select the J-Link Serial Number
111112
of the device connected over USB. '*' matches one or more
112113
characters/digits'''
@@ -146,9 +147,19 @@ def args_from_previous_runner(cls, previous_runner, args):
146147
args.dev_id = previous_runner.dev_id
147148

148149
def ensure_snr(self):
149-
if not self.dev_id or "*" in self.dev_id:
150-
self.dev_id = self.get_board_snr(self.dev_id or "*")
151-
self.dev_id = self.dev_id.lstrip("0")
150+
# dev_id can be None, str or list of str
151+
dev_id = self.dev_id
152+
if isinstance(dev_id, list):
153+
if len(dev_id) == 0:
154+
dev_id = None
155+
elif len(dev_id) == 1:
156+
dev_id = dev_id[0]
157+
else:
158+
self.dev_id = [d.lstrip("0") for d in dev_id]
159+
return
160+
if not dev_id or "*" in dev_id:
161+
dev_id = self.get_board_snr(dev_id or "*")
162+
self.dev_id = dev_id.lstrip("0")
152163

153164
@abc.abstractmethod
154165
def do_get_boards(self):
@@ -528,5 +539,5 @@ def do_run(self, command, **kwargs):
528539
# All done, now flush any outstanding ops
529540
self.flush(force=True)
530541

531-
self.logger.info(f'Board with serial number {self.dev_id} '
532-
'flashed successfully.')
542+
self.logger.info(f'Board(s) with serial number(s) {self.dev_id} '
543+
'flashed successfully.')

scripts/west_commands/runners/nrfjprog.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
3030
def name(cls):
3131
return 'nrfjprog'
3232

33+
@classmethod
34+
def capabilities(cls):
35+
return NrfBinaryRunner._capabilities()
36+
37+
@classmethod
38+
def dev_id_help(cls) -> str:
39+
return NrfBinaryRunner._dev_id_help()
40+
3341
@classmethod
3442
def tool_opt_help(cls) -> str:
3543
return 'Additional options for nrfjprog, e.g. "--clockspeed"'

scripts/west_commands/runners/nrfutil.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ def __init__(self, cfg, family, softreset, pinreset, dev_id, erase=False,
3333
def name(cls):
3434
return 'nrfutil'
3535

36+
@classmethod
37+
def capabilities(cls):
38+
return NrfBinaryRunner._capabilities(mult_dev_ids=True)
39+
40+
@classmethod
41+
def dev_id_help(cls) -> str:
42+
return NrfBinaryRunner._dev_id_help() + \
43+
'''.\n This option can be specified multiple times'''
44+
3645
@classmethod
3746
def tool_opt_help(cls) -> str:
3847
return 'Additional options for nrfutil, e.g. "--log-level"'
@@ -107,6 +116,12 @@ def _insert_op(self, op):
107116
self._op_id += 1
108117
self._ops.append(op)
109118

119+
def _format_dev_ids(self):
120+
if isinstance(self.dev_id, list):
121+
return ','.join(self.dev_id)
122+
else:
123+
return self.dev_id
124+
110125
def _append_batch(self, op, json_file):
111126
_op = op['operation']
112127
op_type = _op['type']
@@ -151,7 +166,7 @@ def _exec_batch(self):
151166
precmd = ['--x-ext-mem-config-file', self.ext_mem_config_file]
152167

153168
self._exec(precmd + ['x-execute-batch', '--batch-path', f'{json_file}',
154-
'--serial-number', f'{self.dev_id}'])
169+
'--serial-number', self._format_dev_ids()])
155170

156171
def do_exec_op(self, op, force=False):
157172
self.logger.debug(f'Executing op: {op}')

0 commit comments

Comments
 (0)