From 2d38c095a612e38b209484328f4b7408879d116b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 26 Sep 2023 13:09:06 +0200 Subject: [PATCH] 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 Signed-off-by: Jamie McCrae --- scripts/west_commands/runners/core.py | 19 ++++++++++++++++++- scripts/west_commands/runners/esp32.py | 17 +++++++++++------ scripts/west_commands/runners/ezflashcli.py | 12 ++++++++---- scripts/west_commands/runners/jlink.py | 18 +++++++++--------- scripts/west_commands/runners/nrf_common.py | 10 +++++++--- scripts/west_commands/runners/nrfjprog.py | 1 + scripts/west_commands/runners/nrfutil.py | 5 +++-- scripts/west_commands/runners/stm32flash.py | 7 +++---- 8 files changed, 60 insertions(+), 29 deletions(-) diff --git a/scripts/west_commands/runners/core.py b/scripts/west_commands/runners/core.py index b569625e4e6..68ad0eea024 100644 --- a/scripts/west_commands/runners/core.py +++ b/scripts/west_commands/runners/core.py @@ -229,6 +229,9 @@ class RunnerCaps: 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 @@ class RunnerCaps: 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 @@ class RunnerCaps: 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 @@ class ZephyrBinaryRunner(abc.ABC): 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 @@ class ZephyrBinaryRunner(abc.ABC): _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 @@ class ZephyrBinaryRunner(abc.ABC): 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 d435014fc38..0ccf0c98d1f 100644 --- a/scripts/west_commands/runners/esp32.py +++ b/scripts/west_commands/runners/esp32.py @@ -16,13 +16,15 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): '''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 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): @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 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): 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 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): 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 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): 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 4d9d3d3ae51..a3e1aea3d25 100644 --- a/scripts/west_commands/runners/ezflashcli.py +++ b/scripts/west_commands/runners/ezflashcli.py @@ -10,13 +10,14 @@ DEFAULT_EZFLASHCLI = "ezFlashCLI" 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 @@ class EzFlashCliBinaryRunner(ZephyrBinaryRunner): @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 @@ class EzFlashCliBinaryRunner(ZephyrBinaryRunner): 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 @@ class EzFlashCliBinaryRunner(ZephyrBinaryRunner): 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 @@ class EzFlashCliBinaryRunner(ZephyrBinaryRunner): 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 80b7de2dffb..4fa71720673 100644 --- a/scripts/west_commands/runners/jlink.py +++ b/scripts/west_commands/runners/jlink.py @@ -35,7 +35,7 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): 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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): 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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): @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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): 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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): 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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): 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 @@ class JLinkBinaryRunner(ZephyrBinaryRunner): # 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 1a66ed0bded..68540669868 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -28,7 +28,7 @@ class NrfBinaryRunner(ZephyrBinaryRunner): '''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 @@ class NrfBinaryRunner(ZephyrBinaryRunner): 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 @@ class NrfBinaryRunner(ZephyrBinaryRunner): @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 @@ class NrfBinaryRunner(ZephyrBinaryRunner): 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 @@ class NrfBinaryRunner(ZephyrBinaryRunner): 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 9671def33c1..8762ce0e740 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -30,6 +30,7 @@ class NrfJprogBinaryRunner(NrfBinaryRunner): 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 9c92c07f07d..719e432a23b 100644 --- a/scripts/west_commands/runners/nrfutil.py +++ b/scripts/west_commands/runners/nrfutil.py @@ -16,9 +16,9 @@ class NrfUtilBinaryRunner(NrfBinaryRunner): '''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 @@ class NrfUtilBinaryRunner(NrfBinaryRunner): 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 052c45dbb49..5aa544d4b2a 100644 --- a/scripts/west_commands/runners/stm32flash.py +++ b/scripts/west_commands/runners/stm32flash.py @@ -37,7 +37,7 @@ class Stm32flashBinaryRunner(ZephyrBinaryRunner): @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 @@ class Stm32flashBinaryRunner(ZephyrBinaryRunner): 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,