west: runners: Add support for a common --reset argument
Some of the runners in the tree have been adding their own,
class-specific versions of a switch to instruct the runner to reset or
not the device after flashing.
In order to better support multi-image builds that require more than one
flash operation, introduce a new --reset,--no-reset command-line
parameter that is part of the RunnerCaps so taht this functionality can
be accessed in a standardized manner.
Implementations for the new parameter are provided for the runner
classes that were already configurable in this regard.
Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
diff --git a/scripts/west_commands/runners/core.py b/scripts/west_commands/runners/core.py
index b569625..68ad0ee 100644
--- a/scripts/west_commands/runners/core.py
+++ b/scripts/west_commands/runners/core.py
@@ -229,6 +229,9 @@
erased by the underlying tool before flashing; UICR on nRF SoCs
is one example.)
+ - reset: whether the runner supports a --reset option, which
+ resets the device after a flash operation is complete.
+
- tool_opt: whether the runner supports a --tool-opt (-O) option, which
can be given multiple times and is passed on to the underlying tool
that the runner wraps.
@@ -240,12 +243,14 @@
dev_id: bool = False,
flash_addr: bool = False,
erase: bool = False,
+ reset: bool = False,
tool_opt: bool = False,
file: bool = False):
self.commands = commands
self.dev_id = dev_id
self.flash_addr = bool(flash_addr)
self.erase = bool(erase)
+ self.reset = bool(reset)
self.tool_opt = bool(tool_opt)
self.file = bool(file)
@@ -254,6 +259,7 @@
f'dev_id={self.dev_id}, '
f'flash_addr={self.flash_addr}, '
f'erase={self.erase}, '
+ f'reset={self.reset}, '
f'tool_opt={self.tool_opt}, '
f'file={self.file}'
')')
@@ -521,9 +527,16 @@
parser.add_argument('--erase', '--no-erase', nargs=0,
action=_ToggleAction,
- help=("mass erase flash before loading, or don't"
+ help=("mass erase flash before loading, or don't. "
+ "Default action depends on each specific runner."
if caps.erase else argparse.SUPPRESS))
+ parser.add_argument('--reset', '--no-reset', nargs=0,
+ action=_ToggleAction,
+ help=("reset device after flashing, or don't. "
+ "Default action depends on each specific runner."
+ if caps.reset else argparse.SUPPRESS))
+
parser.add_argument('-O', '--tool-opt', dest='tool_opt',
default=[], action='append',
help=(cls.tool_opt_help() if caps.tool_opt
@@ -552,6 +565,8 @@
_missing_cap(cls, '--dt-flash')
if args.erase and not caps.erase:
_missing_cap(cls, '--erase')
+ if args.reset and not caps.reset:
+ _missing_cap(cls, '--reset')
if args.tool_opt and not caps.tool_opt:
_missing_cap(cls, '--tool-opt')
if args.file and not caps.file:
@@ -564,6 +579,8 @@
ret = cls.do_create(cfg, args)
if args.erase:
ret.logger.info('mass erase requested')
+ if args.reset:
+ ret.logger.info('reset after flashing requested')
return ret
@classmethod
diff --git a/scripts/west_commands/runners/esp32.py b/scripts/west_commands/runners/esp32.py
index d435014..0ccf0c9 100644
--- a/scripts/west_commands/runners/esp32.py
+++ b/scripts/west_commands/runners/esp32.py
@@ -16,13 +16,15 @@
'''Runner front-end for espidf.'''
def __init__(self, cfg, device, boot_address, part_table_address,
- app_address, erase=False, baud=921600, flash_size='detect',
- flash_freq='40m', flash_mode='dio', espidf='espidf',
- bootloader_bin=None, partition_table_bin=None, no_stub=False):
+ app_address, erase=False, reset=False, baud=921600,
+ flash_size='detect', flash_freq='40m', flash_mode='dio',
+ espidf='espidf', bootloader_bin=None, partition_table_bin=None,
+ no_stub=False):
super().__init__(cfg)
self.elf = cfg.elf_file
self.app_bin = cfg.bin_file
self.erase = bool(erase)
+ self.reset = bool(reset)
self.device = device
self.boot_address = boot_address
self.part_table_address = part_table_address
@@ -42,7 +44,7 @@
@classmethod
def capabilities(cls):
- return RunnerCaps(commands={'flash'}, erase=True)
+ return RunnerCaps(commands={'flash'}, erase=True, reset=True)
@classmethod
def do_add_parser(cls, parser):
@@ -77,6 +79,8 @@
parser.add_argument('--esp-no-stub', default=False, action='store_true',
help='Disable launching the flasher stub, only talk to ROM bootloader')
+ parser.set_defaults(reset=True)
+
@classmethod
def do_create(cls, cfg, args):
if args.esp_tool:
@@ -88,7 +92,7 @@
return Esp32BinaryRunner(
cfg, args.esp_device, boot_address=args.esp_boot_address,
part_table_address=args.esp_partition_table_address,
- app_address=args.esp_app_address, erase=args.erase,
+ app_address=args.esp_app_address, erase=args.erase, reset=args.reset,
baud=args.esp_baud_rate, flash_size=args.esp_flash_size,
flash_freq=args.esp_flash_freq, flash_mode=args.esp_flash_mode,
espidf=espidf, bootloader_bin=args.esp_flash_bootloader,
@@ -111,7 +115,8 @@
cmd_flash.extend(['--port', self.device])
cmd_flash.extend(['--baud', self.baud])
cmd_flash.extend(['--before', 'default_reset'])
- cmd_flash.extend(['--after', 'hard_reset', 'write_flash', '-u'])
+ if self.reset:
+ cmd_flash.extend(['--after', 'hard_reset', 'write_flash', '-u'])
cmd_flash.extend(['--flash_mode', self.flash_mode])
cmd_flash.extend(['--flash_freq', self.flash_freq])
cmd_flash.extend(['--flash_size', self.flash_size])
diff --git a/scripts/west_commands/runners/ezflashcli.py b/scripts/west_commands/runners/ezflashcli.py
index 4d9d3d3..a3e1aea 100644
--- a/scripts/west_commands/runners/ezflashcli.py
+++ b/scripts/west_commands/runners/ezflashcli.py
@@ -10,13 +10,14 @@
class EzFlashCliBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for ezFlashCLI'''
- def __init__(self, cfg, tool, sn, erase=False):
+ def __init__(self, cfg, tool, sn, erase=False, reset=True):
super().__init__(cfg)
self.bin_ = cfg.bin_file
self.tool = tool
self.sn_arg = ['-j', f'{sn}'] if sn is not None else []
self.erase = bool(erase)
+ self.reset = bool(reset)
@classmethod
def name(cls):
@@ -24,7 +25,7 @@
@classmethod
def capabilities(cls):
- return RunnerCaps(commands={'flash'}, erase=True)
+ return RunnerCaps(commands={'flash'}, erase=True, reset=True)
@classmethod
def do_add_parser(cls, parser):
@@ -34,6 +35,8 @@
parser.add_argument('--sn', default=None, required=False,
help='J-Link probe serial number')
+ parser.set_defaults(reset=True)
+
@classmethod
def do_create(cls, cfg, args):
return EzFlashCliBinaryRunner(cfg, tool=args.tool, sn=args.sn,
@@ -64,7 +67,7 @@
load_offset = self.build_conf['CONFIG_FLASH_LOAD_OFFSET']
self.check_call([self.tool] + self.sn_arg + ["write_flash", f'0x{load_offset:x}', self.bin_])
- def reset(self):
+ def reset_device(self):
self.logger.info("Resetting...")
self.check_call([self.tool] + self.sn_arg + ["go"])
@@ -72,4 +75,5 @@
self.require(self.tool)
self.ensure_output('bin')
self.program_bin()
- self.reset()
+ if self.reset:
+ self.reset_device()
diff --git a/scripts/west_commands/runners/jlink.py b/scripts/west_commands/runners/jlink.py
index 80b7de2..4fa71720 100644
--- a/scripts/west_commands/runners/jlink.py
+++ b/scripts/west_commands/runners/jlink.py
@@ -35,7 +35,7 @@
def __init__(self, cfg, device, dev_id=None,
commander=DEFAULT_JLINK_EXE,
- dt_flash=True, erase=True, reset_after_load=False,
+ dt_flash=True, erase=True, reset=False,
iface='swd', speed='auto',
loader=None,
gdbserver='JLinkGDBServer',
@@ -54,7 +54,7 @@
self.commander = commander
self.dt_flash = dt_flash
self.erase = erase
- self.reset_after_load = reset_after_load
+ self.reset = reset
self.gdbserver = gdbserver
self.iface = iface
self.speed = speed
@@ -74,7 +74,7 @@
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug', 'debugserver', 'attach'},
- dev_id=True, flash_addr=True, erase=True,
+ dev_id=True, flash_addr=True, erase=True, reset=True,
tool_opt=True, file=True)
@classmethod
@@ -114,11 +114,11 @@
help=f'''J-Link Commander, default is
{DEFAULT_JLINK_EXE}''')
parser.add_argument('--reset-after-load', '--no-reset-after-load',
- dest='reset_after_load', nargs=0,
+ dest='reset', nargs=0,
action=ToggleAction,
- help='reset after loading? (default: no)')
+ help='obsolete synonym for --reset/--no-reset')
- parser.set_defaults(reset_after_load=False)
+ parser.set_defaults(reset=False)
@classmethod
def do_create(cls, cfg, args):
@@ -127,7 +127,7 @@
commander=args.commander,
dt_flash=args.dt_flash,
erase=args.erase,
- reset_after_load=args.reset_after_load,
+ reset=args.reset,
iface=args.iface, speed=args.speed,
gdbserver=args.gdbserver,
loader=args.loader,
@@ -266,7 +266,7 @@
client_cmd += ['-ex', 'monitor halt',
'-ex', 'monitor reset',
'-ex', 'load']
- if self.reset_after_load:
+ if self.reset:
client_cmd += ['-ex', 'monitor reset']
if not self.gdb_host:
self.require(self.gdbserver)
@@ -326,7 +326,7 @@
# Flash the selected build artifact
lines.append(flash_cmd)
- if self.reset_after_load:
+ if self.reset:
lines.append('r') # Reset and halt the target
lines.append('g') # Start the CPU
diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py
index 1a66ed0..6854066 100644
--- a/scripts/west_commands/runners/nrf_common.py
+++ b/scripts/west_commands/runners/nrf_common.py
@@ -28,7 +28,7 @@
'''Runner front-end base class for nrf tools.'''
def __init__(self, cfg, family, softreset, dev_id, erase=False,
- tool_opt=[], force=False, recover=False):
+ reset=True, tool_opt=[], force=False, recover=False):
super().__init__(cfg)
self.hex_ = cfg.hex_file
if family and not family.endswith('_FAMILY'):
@@ -37,6 +37,7 @@
self.softreset = softreset
self.dev_id = dev_id
self.erase = bool(erase)
+ self.reset = bool(reset)
self.force = force
self.recover = bool(recover)
@@ -47,7 +48,7 @@
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash'}, dev_id=True, erase=True,
- tool_opt=True)
+ reset=True, tool_opt=True)
@classmethod
def dev_id_help(cls) -> str:
@@ -75,6 +76,8 @@
memory and disable read back protection before
flashing (erases flash for both cores on nRF53)''')
+ parser.set_defaults(reset=True)
+
def ensure_snr(self):
if not self.dev_id or "*" in self.dev_id:
self.dev_id = self.get_board_snr(self.dev_id or "*")
@@ -398,7 +401,8 @@
if self.recover:
self.recover_target()
self.program_hex()
- self.reset_target()
+ if self.reset:
+ self.reset_target()
# All done, now flush any outstanding ops
self.flush(force=True)
diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py
index 9671def..8762ce0 100644
--- a/scripts/west_commands/runners/nrfjprog.py
+++ b/scripts/west_commands/runners/nrfjprog.py
@@ -30,6 +30,7 @@
def do_create(cls, cfg, args):
return NrfJprogBinaryRunner(cfg, args.nrf_family, args.softreset,
args.dev_id, erase=args.erase,
+ reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
recover=args.recover)
diff --git a/scripts/west_commands/runners/nrfutil.py b/scripts/west_commands/runners/nrfutil.py
index 9c92c07..719e432 100644
--- a/scripts/west_commands/runners/nrfutil.py
+++ b/scripts/west_commands/runners/nrfutil.py
@@ -16,9 +16,9 @@
'''Runner front-end for nrfutil.'''
def __init__(self, cfg, family, softreset, dev_id, erase=False,
- tool_opt=[], force=False, recover=False):
+ reset=True, tool_opt=[], force=False, recover=False):
- super().__init__(cfg, family, softreset, dev_id, erase,
+ super().__init__(cfg, family, softreset, dev_id, erase, reset,
tool_opt, force, recover)
self._ops = []
self._op_id = 1
@@ -35,6 +35,7 @@
def do_create(cls, cfg, args):
return NrfUtilBinaryRunner(cfg, args.nrf_family, args.softreset,
args.dev_id, erase=args.erase,
+ reset=args.reset,
tool_opt=args.tool_opt, force=args.force,
recover=args.recover)
diff --git a/scripts/west_commands/runners/stm32flash.py b/scripts/west_commands/runners/stm32flash.py
index 052c45d..5aa544d 100644
--- a/scripts/west_commands/runners/stm32flash.py
+++ b/scripts/west_commands/runners/stm32flash.py
@@ -37,7 +37,7 @@
@classmethod
def capabilities(cls):
- return RunnerCaps(commands={'flash'})
+ return RunnerCaps(commands={'flash'}, reset=True)
@classmethod
def do_add_parser(cls, parser):
@@ -72,12 +72,11 @@
parser.add_argument('--serial-mode', default='8e1', required=False,
help='serial port mode, default \'8e1\'')
- parser.add_argument('--reset', default=False, required=False, action='store_true',
- help='reset device at exit, default False')
-
parser.add_argument('--verify', default=False, required=False, action='store_true',
help='verify writes, default False')
+ parser.set_defaults(reset=False)
+
@classmethod
def do_create(cls, cfg, args):
return Stm32flashBinaryRunner(cfg, device=args.device, action=args.action,