scripts: zephyr_flash_debug: refactor into new "runner" package Factor the classes which do the work into a new "runner" package. This package has a core module where ZephyrBinaryRunner and common helpers will live, and one file per subclass / runner front-end. The top-level script, zephyr_flash_debug.py, still exists, but just delegates its work to the core. Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
diff --git a/scripts/support/runner/__init__.py b/scripts/support/runner/__init__.py new file mode 100644 index 0000000..d14f6a4 --- /dev/null +++ b/scripts/support/runner/__init__.py
@@ -0,0 +1,22 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +from .core import ZephyrBinaryRunner + +# We import these here to ensure the ZephyrBinaryRunner subclasses are +# defined; otherwise, ZephyrBinaryRunner.create_for_shell_script() +# won't work. + +# Explicitly silence the unused import warning. +# flake8: noqa: F401 +from . import arc +from . import bossac +from . import dfu +from . import esp32 +from . import nios2 +from . import nrfjprog +from . import openocd +from . import pyocd + +__all__ = ['ZephyrBinaryRunner']
diff --git a/scripts/support/runner/arc.py b/scripts/support/runner/arc.py new file mode 100644 index 0000000..670f534 --- /dev/null +++ b/scripts/support/runner/arc.py
@@ -0,0 +1,155 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''ARC architecture-specific runner.''' + +from os import path +import os +import shlex + +from .core import ZephyrBinaryRunner, get_env_or_bail + +DEFAULT_ARC_TCL_PORT = 6333 +DEFAULT_ARC_TELNET_PORT = 4444 +DEFAULT_ARC_GDB_PORT = 3333 + + +class ArcBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for the ARC architecture, using openocd.''' + + # This unusual 'flash' implementation matches the original shell script. + # + # It works by starting a GDB server in a separate session, connecting a + # client to it to load the program, and running 'continue' within the + # client to execute the application. + # + # TODO: exit immediately when flashing is done, leaving Zephyr running. + + def __init__(self, elf, zephyr_base, arch, board_name, python, + gdb, openocd='openocd', extra_init=None, default_path=None, + tui=None, tcl_port=DEFAULT_ARC_TCL_PORT, + telnet_port=DEFAULT_ARC_TELNET_PORT, + gdb_port=DEFAULT_ARC_GDB_PORT, debug=False): + super(ArcBinaryRunner, self).__init__(debug=debug) + self.elf = elf + self.zephyr_base = zephyr_base + self.arch = arch + self.board_name = board_name + self.python = python + self.gdb = gdb + search_args = [] + if default_path is not None: + search_args = ['-s', default_path] + self.openocd_cmd = [openocd] + search_args + self.extra_init = extra_init if extra_init is not None else [] + self.tui = tui + self.tcl_port = tcl_port + self.telnet_port = telnet_port + self.gdb_port = gdb_port + + def replaces_shell_script(shell_script, command): + return (command in {'flash', 'debug', 'debugserver'} and + shell_script == 'arc_debugger.sh') + + def create_from_env(command, debug): + '''Create runner from environment. + + Required: + + - O: build output directory + - KERNEL_ELF_NAME: zephyr kernel binary in ELF format + - ZEPHYR_BASE: zephyr Git repository base directory + - ARCH: board architecture + - BOARD_NAME: zephyr name of board + - PYTHON: python executable + - GDB: gdb executable + + Optional: + + - OPENOCD: path to openocd, defaults to openocd + - OPENOCD_EXTRA_INIT: initialization command for GDB server + - OPENOCD_DEFAULT_PATH: openocd search path to use + - TUI: if present, passed to gdb server used to flash + - TCL_PORT: openocd TCL port, defaults to 6333 + - TELNET_PORT: openocd telnet port, defaults to 4444 + - GDB_PORT: openocd gdb port, defaults to 3333 + ''' + elf = path.join(get_env_or_bail('O'), + get_env_or_bail('KERNEL_ELF_NAME')) + zephyr_base = get_env_or_bail('ZEPHYR_BASE') + arch = get_env_or_bail('ARCH') + board_name = get_env_or_bail('BOARD_NAME') + python = get_env_or_bail('PYTHON') + gdb = get_env_or_bail('GDB') + + openocd = os.environ.get('OPENOCD', 'openocd') + extra_init = os.environ.get('OPENOCD_EXTRA_INIT', None) + if extra_init is not None: + extra_init = shlex.split(extra_init) + default_path = os.environ.get('OPENOCD_DEFAULT_PATH', None) + tui = os.environ.get('TUI', None) + tcl_port = int(os.environ.get('TCL_PORT', + str(DEFAULT_ARC_TCL_PORT))) + telnet_port = int(os.environ.get('TELNET_PORT', + str(DEFAULT_ARC_TELNET_PORT))) + gdb_port = int(os.environ.get('GDB_PORT', + str(DEFAULT_ARC_GDB_PORT))) + + return ArcBinaryRunner(elf, zephyr_base, arch, board_name, python, + gdb, openocd=openocd, extra_init=extra_init, + default_path=default_path, tui=tui, + tcl_port=tcl_port, telnet_port=telnet_port, + gdb_port=gdb_port, debug=debug) + + def run(self, command, **kwargs): + if command not in {'flash', 'debug', 'debugserver'}: + raise ValueError('{} is not supported'.format(command)) + + kwargs['openocd-cfg'] = path.join(self.zephyr_base, 'boards', + self.arch, self.board_name, + 'support', 'openocd.cfg') + + if command in {'flash', 'debug'}: + self.flash_debug(command, **kwargs) + else: + self.debugserver(**kwargs) + + def flash_debug(self, command, **kwargs): + config = kwargs['openocd-cfg'] + + server_cmd = (self.openocd_cmd + + ['-f', config] + + self.extra_init + + ['-c', 'tcl_port {}'.format(self.tcl_port), + '-c', 'telnet_port {}'.format(self.telnet_port), + '-c', 'gdb_port {}'.format(self.gdb_port), + '-c', 'init', + '-c', 'targets', + '-c', 'halt']) + + tui_arg = [] + if self.tui is not None: + tui_arg = [self.tui] + + continue_arg = [] + if command == 'flash': + continue_arg = ['-ex', 'c'] + + gdb_cmd = ([self.gdb] + + tui_arg + + ['-ex', 'target remote :{}'.format(self.gdb_port), + '-ex', 'load'] + + continue_arg + + [self.elf]) + + self.run_server_and_client(server_cmd, gdb_cmd) + + def debugserver(self, **kwargs): + config = kwargs['openocd-cfg'] + cmd = (self.openocd_cmd + + ['-f', config, + '-c', 'init', + '-c', 'targets', + '-c', 'reset halt']) + self.check_call(cmd)
diff --git a/scripts/support/runner/bossac.py b/scripts/support/runner/bossac.py new file mode 100644 index 0000000..394a9c38 --- /dev/null +++ b/scripts/support/runner/bossac.py
@@ -0,0 +1,64 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''bossac-specific runner (flash only) for Atmel SAM microcontrollers.''' + +from os import path +import os +import platform + +from .core import ZephyrBinaryRunner, get_env_or_bail + +DEFAULT_BOSSAC_PORT = '/dev/ttyACM0' + + +class BossacBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for bossac.''' + + def __init__(self, bin_name, bossac='bossac', + port=DEFAULT_BOSSAC_PORT, debug=False): + super(BossacBinaryRunner, self).__init__(debug=debug) + self.bin_name = bin_name + self.bossac = bossac + self.port = port + + def replaces_shell_script(shell_script, command): + return command == 'flash' and shell_script == 'bossa-flash.sh' + + def create_from_env(command, debug): + '''Create flasher from environment. + + Required: + + - O: build output directory + - KERNEL_BIN_NAME: name of kernel binary + + Optional: + + - BOSSAC: path to bossac, default is bossac + - BOSSAC_PORT: serial port to use, default is /dev/ttyACM0 + ''' + bin_name = path.join(get_env_or_bail('O'), + get_env_or_bail('KERNEL_BIN_NAME')) + bossac = os.environ.get('BOSSAC', 'bossac') + port = os.environ.get('BOSSAC_PORT', DEFAULT_BOSSAC_PORT) + return BossacBinaryRunner(bin_name, bossac=bossac, port=port, + debug=debug) + + def run(self, command, **kwargs): + if command != 'flash': + raise ValueError('only flash is supported') + + if platform.system() != 'Linux': + msg = 'CAUTION: No flash tool for your host system found!' + raise NotImplementedError(msg) + + cmd_stty = ['stty', '-F', self.port, 'raw', 'ispeed', '1200', + 'ospeed', '1200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', + 'eof', '255'] + cmd_flash = [self.bossac, '-p', self.port, '-R', '-e', '-w', '-v', + '-b', self.bin_name] + + self.check_call(cmd_stty) + self.check_call(cmd_flash)
diff --git a/scripts/support/runner/core.py b/scripts/support/runner/core.py new file mode 100644 index 0000000..e451d76 --- /dev/null +++ b/scripts/support/runner/core.py
@@ -0,0 +1,219 @@ +#! /usr/bin/env python3 + +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Zephyr binary runner core interfaces + +This provides the core ZephyrBinaryRunner class meant for public use, +as well as some other helpers for concrete runner classes. +""" + +import abc +import os +import platform +import pprint +import shlex +import signal +import subprocess +import sys + + +def get_env_or_bail(env_var): + '''Get an environment variable, or raise an error. + + In case of KeyError, an error message is printed, along with the + environment, and the exception is re-raised. + ''' + try: + return os.environ[env_var] + except KeyError: + print('Variable {} not in environment:'.format( + env_var), file=sys.stderr) + pprint.pprint(dict(os.environ), stream=sys.stderr) + raise + + +def get_env_bool_or(env_var, default_value): + '''Get an environment variable as a boolean, or return a default value. + + Get an environment variable, interpret it as a base ten + integer, and convert that to a boolean. + + In case the environment variable is not defined, return default_value. + ''' + try: + return bool(int(os.environ[env_var])) + except KeyError: + return default_value + + +def get_env_strip_or(env_var, to_strip, default_value): + '''Get and clean up an environment variable, or return a default value. + + Get the value of env_var from the environment. If it is + defined, return that value with to_strip stripped off. If it + is undefined, return default_value (without any stripping). + ''' + value = os.environ.get(env_var, None) + if value is not None: + return value.strip(to_strip) + else: + return default_value + + +def quote_sh_list(cmd): + '''Transform a command from list into shell string form.''' + fmt = ' '.join('{}' for _ in cmd) + args = [shlex.quote(s) for s in cmd] + return fmt.format(*args) + + +class ZephyrBinaryRunner(abc.ABC): + '''Abstract superclass for binary runners (flashers, debuggers). + + With some exceptions, boards supported by Zephyr must provide + generic means to be flashed (have a Zephyr firmware binary + permanently installed on the device for running) and debugged + (have a breakpoint debugger and program loader on a host + workstation attached to a running target). This is supported by + three top-level commands managed by the Zephyr build system: + + - 'flash': flash a previously configured binary to the board, + start execution on the target, then return. + + - 'debug': connect to the board via a debugging protocol, then + drop the user into a debugger interface with symbol tables + loaded from the current binary, and block until it exits. + + - 'debugserver': connect via a board-specific debugging protocol, + then reset and halt the target. Ensure the user is now able to + connect to a debug server with symbol tables loaded from the + binary. + + Runner functionality relies on a variety of target-specific tools + and configuration values, the user interface to which is + abstracted by this class. Each runner subclass should take any + values it needs to execute one of these commands in its + constructor. The actual command execution is handled in the run() + method. + + This functionality is also replacing the legacy Zephyr runners, + which are shell scripts. + + At present, the Zephyr build system uses a variety of + tool-specific environment variables to control runner behavior. + To support a transition to ZephyrBinaryRunner and subclasses, this + class provides a create_for_shell_script() static factory method. + This method iterates over ZephyrBinaryRUnner subclasses, + determines which (if any) can provide equivalent functionality to + the shell-based runner, and returns a subclass instance with its + configuration determined from the environment. + + To support this, subclasess currently must provide a pair of + static methods, replaces_shell_script() and create_from_env(). The + first allows the runner subclass to declare which commands and + scripts it can replace. The second is called by + create_for_shell_script() to create a concrete runner instance. + + The environment-based factories are for legacy use *only*; the + user must be able to construct and use a runner using only the + constructor and run() method.''' + + def __init__(self, debug=False): + self.debug = debug + + @staticmethod + def create_for_shell_script(shell_script, command, debug): + '''Factory for using as a drop-in replacement to a shell script. + + Command is one of 'flash', 'debug', 'debugserver'. + + Get runner instance to use in place of shell_script, deriving + configuration from the environment.''' + for sub_cls in ZephyrBinaryRunner.__subclasses__(): + if sub_cls.replaces_shell_script(shell_script, command): + return sub_cls.create_from_env(command, debug) + raise ValueError('cannot implement script {} command {}'.format( + shell_script, command)) + + @staticmethod + @abc.abstractmethod + def replaces_shell_script(shell_script, command): + '''Check if this class replaces shell_script for the given command.''' + + @staticmethod + @abc.abstractmethod + def create_from_env(command, debug): + '''Create new flasher instance from environment variables. + + This class must be able to replace the current shell script + (FLASH_SCRIPT or DEBUG_SCRIPT, depending on command). The + environment variables expected by that script are used to build + the flasher in a backwards-compatible manner.''' + + @abc.abstractmethod + def run(self, command, **kwargs): + '''Run a command ('flash', 'debug', 'debugserver'). + + In case of an unsupported command, raise a ValueError.''' + + def run_server_and_client(self, server, client): + '''Run a server that ignores SIGINT, and a client that handles it. + + This routine portably: + + - creates a Popen object for the `server' command which ignores SIGINT + - runs `client' in a subprocess while temporarily ignoring SIGINT + - cleans up the server after the client exits. + + It's useful to e.g. open a GDB server and client.''' + server_proc = self.popen_ignore_int(server) + previous = signal.signal(signal.SIGINT, signal.SIG_IGN) + try: + self.check_call(client) + finally: + signal.signal(signal.SIGINT, previous) + server_proc.terminate() + server_proc.wait() + + def check_call(self, cmd): + '''Subclass subprocess.check_call() wrapper. + + Subclasses should use this command to run command in a + subprocess and check that it executed correctly, rather than + using subprocess directly, to keep accurate debug logs. + ''' + if self.debug: + print(quote_sh_list(cmd)) + subprocess.check_call(cmd) + + def check_output(self, cmd): + '''Subclass subprocess.check_output() wrapper. + + Subclasses should use this command to run command in a + subprocess and check that it executed correctly, rather than + using subprocess directly, to keep accurate debug logs. + ''' + if self.debug: + print(quote_sh_list(cmd)) + return subprocess.check_output(cmd) + + def popen_ignore_int(self, cmd): + '''Spawn a child command, ensuring it ignores SIGINT. + + The returned subprocess.Popen object must be manually terminated.''' + cflags = 0 + preexec = None + system = platform.system() + + if system == 'Windows': + cflags |= subprocess.CREATE_NEW_PROCESS_GROUP + elif system in {'Linux', 'Darwin'}: + preexec = os.setsid + + if self.debug: + print(quote_sh_list(cmd)) + + return subprocess.Popen(cmd, creationflags=cflags, preexec_fn=preexec)
diff --git a/scripts/support/runner/dfu.py b/scripts/support/runner/dfu.py new file mode 100644 index 0000000..5dda9d8 --- /dev/null +++ b/scripts/support/runner/dfu.py
@@ -0,0 +1,78 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for flashing with dfu-util.''' + +import os +import sys +import time + +from .core import ZephyrBinaryRunner, get_env_or_bail + + +class DfuUtilBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for dfu-util.''' + + def __init__(self, pid, alt, img, dfuse=None, exe='dfu-util', debug=False): + super(DfuUtilBinaryRunner, self).__init__(debug=debug) + self.alt = alt + self.img = img + self.dfuse = dfuse + self.cmd = [exe, '-d,{}'.format(pid)] + try: + self.list_pattern = ', alt={},'.format(int(self.alt)) + except ValueError: + self.list_pattern = ', name="{}",'.format(self.alt) + + def replaces_shell_script(shell_script, command): + return command == 'flash' and shell_script == 'dfuutil.sh' + + def create_from_env(command, debug): + '''Create flasher from environment. + + Required: + + - DFUUTIL_PID: USB VID:PID of the board + - DFUUTIL_ALT: interface alternate setting number or name + - DFUUTIL_IMG: binary to flash + + Optional: + + - DFUUTIL_DFUSE_ADDR: target address if the board is a + DfuSe device. Ignored if not present. + - DFUUTIL: dfu-util executable, defaults to dfu-util. + ''' + pid = get_env_or_bail('DFUUTIL_PID') + alt = get_env_or_bail('DFUUTIL_ALT') + img = get_env_or_bail('DFUUTIL_IMG') + dfuse = os.environ.get('DFUUTIL_DFUSE_ADDR', None) + exe = os.environ.get('DFUUTIL', 'dfu-util') + + return DfuUtilBinaryRunner(pid, alt, img, dfuse=dfuse, exe=exe, + debug=debug) + + def find_device(self): + cmd = list(self.cmd) + ['-l'] + output = self.check_output(cmd) + output = output.decode(sys.getdefaultencoding()) + return self.list_pattern in output + + def run(self, command, **kwargs): + if command != 'flash': + raise ValueError('only flash is supported') + + reset = 0 + if not self.find_device(): + reset = 1 + print('Please reset your board to switch to DFU mode...') + while not self.find_device(): + time.sleep(0.1) + + cmd = list(self.cmd) + if self.dfuse is not None: + cmd.extend(['-s', '{}:leave'.format(self.dfuse)]) + cmd.extend(['-a', self.alt, '-D', self.img]) + self.check_call(cmd) + if reset: + print('Now reset your board again to switch back to runtime mode.')
diff --git a/scripts/support/runner/esp32.py b/scripts/support/runner/esp32.py new file mode 100644 index 0000000..0dcacae --- /dev/null +++ b/scripts/support/runner/esp32.py
@@ -0,0 +1,88 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for flashing ESP32 devices with esptool/espidf.''' + +from os import path +import os + +from .core import ZephyrBinaryRunner, get_env_or_bail + + +class Esp32BinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for espidf.''' + + def __init__(self, elf, device, baud=921600, flash_size='detect', + flash_freq='40m', flash_mode='dio', espidf='espidf', + debug=False): + super(Esp32BinaryRunner, self).__init__(debug=debug) + self.elf = elf + self.device = device + self.baud = baud + self.flash_size = flash_size + self.flash_freq = flash_freq + self.flash_mode = flash_mode + self.espidf = espidf + + def replaces_shell_script(shell_script, command): + return command == 'flash' and shell_script == 'esp32.sh' + + def create_from_env(command, debug): + '''Create flasher from environment. + + Required: + + - O: build output directory + - KERNEL_ELF_NAME: name of kernel binary in ELF format + + Optional: + + - ESP_DEVICE: serial port to flash, default /dev/ttyUSB0 + - ESP_BAUD_RATE: serial baud rate, default 921600 + - ESP_FLASH_SIZE: flash size, default 'detect' + - ESP_FLASH_FREQ: flash frequency, default '40m' + - ESP_FLASH_MODE: flash mode, default 'dio' + - ESP_TOOL: complete path to espidf, or set to 'espidf' to look for it + in $ESP_IDF_PATH/components/esptool_py/esptool/esptool.py + ''' + elf = path.join(get_env_or_bail('O'), + get_env_or_bail('KERNEL_ELF_NAME')) + + # TODO add sane device defaults on other platforms than Linux. + device = os.environ.get('ESP_DEVICE', '/dev/ttyUSB0') + baud = os.environ.get('ESP_BAUD_RATE', '921600') + flash_size = os.environ.get('ESP_FLASH_SIZE', 'detect') + flash_freq = os.environ.get('ESP_FLASH_FREQ', '40m') + flash_mode = os.environ.get('ESP_FLASH_MODE', 'dio') + espidf = os.environ.get('ESP_TOOL', 'espidf') + + if espidf == 'espidf': + idf_path = get_env_or_bail('ESP_IDF_PATH') + espidf = path.join(idf_path, 'components', 'esptool_py', 'esptool', + 'esptool.py') + + return Esp32BinaryRunner(elf, device, baud=baud, + flash_size=flash_size, flash_freq=flash_freq, + flash_mode=flash_mode, espidf=espidf, + debug=debug) + + def run(self, command, **kwargs): + if command != 'flash': + raise ValueError('only flash is supported') + + bin_name = path.splitext(self.elf)[0] + path.extsep + 'bin' + cmd_convert = [self.espidf, '--chip', 'esp32', 'elf2image', self.elf] + cmd_flash = [self.espidf, '--chip', 'esp32', '--port', self.device, + '--baud', self.baud, '--before', 'default_reset', + '--after', 'hard_reset', 'write_flash', '-u', + '--flash_mode', self.flash_mode, + '--flash_freq', self.flash_freq, + '--flash_size', self.flash_size, + '0x1000', bin_name] + + print("Converting ELF to BIN") + self.check_call(cmd_convert) + + print("Flashing ESP32 on {} ({}bps)".format(self.device, self.baud)) + self.check_call(cmd_flash)
diff --git a/scripts/support/runner/nios2.py b/scripts/support/runner/nios2.py new file mode 100644 index 0000000..b18145a --- /dev/null +++ b/scripts/support/runner/nios2.py
@@ -0,0 +1,65 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for NIOS II.''' + +from os import path + +from .core import ZephyrBinaryRunner, get_env_or_bail + + +class Nios2BinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for NIOS II.''' + + # From the original shell script: + # + # "XXX [flash] only support[s] cases where the .elf is sent + # over the JTAG and the CPU directly boots from __start. CONFIG_XIP + # and CONFIG_INCLUDE_RESET_VECTOR must be disabled." + + def __init__(self, hex_, cpu_sof, zephyr_base, debug=False): + super(Nios2BinaryRunner, self).__init__(debug=debug) + self.hex_ = hex_ + self.cpu_sof = cpu_sof + self.zephyr_base = zephyr_base + + def replaces_shell_script(shell_script, command): + return command == 'flash' and shell_script == 'nios2.sh' + + def create_from_env(command, debug): + '''Create runner from environment. + + Required: + + - O: build output directory + - KERNEL_HEX_NAME: name of kernel binary in HEX format + - NIOS2_CPU_SOF: location of the CPU .sof data + - ZEPHYR_BASE: zephyr Git repository base directory + ''' + hex_ = path.join(get_env_or_bail('O'), + get_env_or_bail('KERNEL_HEX_NAME')) + cpu_sof = get_env_or_bail('NIOS2_CPU_SOF') + zephyr_base = get_env_or_bail('ZEPHYR_BASE') + + return Nios2BinaryRunner(hex_, cpu_sof, zephyr_base, debug=debug) + + def run(self, command, **kwargs): + if command not in {'flash', 'debug', 'debugserver'}: + raise ValueError('{} is not supported'.format(command)) + + if command == 'flash': + self.flash(**kwargs) + else: + self.debug_debugserver(command, **kwargs) + + def flash(self, **kwargs): + cmd = [path.join(self.zephyr_base, 'scripts', 'support', + 'quartus-flash.py'), + '--sof', self.cpu_sof, + '--kernel', self.hex_] + + self.check_call(cmd) + + def debug_debugserver(command, **kwargs): + raise NotImplementedError()
diff --git a/scripts/support/runner/nrfjprog.py b/scripts/support/runner/nrfjprog.py new file mode 100644 index 0000000..d326a73 --- /dev/null +++ b/scripts/support/runner/nrfjprog.py
@@ -0,0 +1,96 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for flashing with nrfjprog.''' + +from os import path +import sys + +from .core import ZephyrBinaryRunner, get_env_or_bail + + +class NrfJprogBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for nrfjprog.''' + + def __init__(self, hex_, family, board, debug=False): + super(NrfJprogBinaryRunner, self).__init__(debug=debug) + self.hex_ = hex_ + self.family = family + self.board = board + + def replaces_shell_script(shell_script, command): + return command == 'flash' and shell_script == 'nrf_flash.sh' + + def create_from_env(command, debug): + '''Create flasher from environment. + + Required: + + - O: build output directory + - KERNEL_HEX_NAME: name of kernel binary in ELF format + - NRF_FAMILY: e.g. NRF51 or NRF52 + - BOARD: Zephyr board name + ''' + hex_ = path.join(get_env_or_bail('O'), + get_env_or_bail('KERNEL_HEX_NAME')) + family = get_env_or_bail('NRF_FAMILY') + board = get_env_or_bail('BOARD') + + return NrfJprogBinaryRunner(hex_, family, board, debug=debug) + + def get_board_snr_from_user(self): + snrs = self.check_output(['nrfjprog', '--ids']) + snrs = snrs.decode(sys.getdefaultencoding()).strip().splitlines() + + if len(snrs) == 1: + return snrs[0] + + print('There are multiple boards connected.') + for i, snr in enumerate(snrs, 1): + print('{}. {}'.format(i, snr)) + + p = 'Please select one with desired serial number (1-{}): '.format( + len(snrs)) + while True: + value = input(p) + try: + value = int(value) + except ValueError: + continue + if 1 <= value <= len(snrs): + break + + return snrs[value - 1] + + def run(self, command, **kwargs): + if command != 'flash': + raise ValueError('only flash is supported') + + board_snr = self.get_board_snr_from_user() + + print('Flashing file: {}'.format(self.hex_)) + commands = [ + ['nrfjprog', '--eraseall', '-f', self.family, '--snr', board_snr], + ['nrfjprog', '--program', self.hex_, '-f', self.family, '--snr', + board_snr], + ] + if self.family == 'NRF52': + commands.extend([ + # Set reset pin + ['nrfjprog', '--memwr', '0x10001200', '--val', '0x00000015', + '-f', self.family, '--snr', board_snr], + ['nrfjprog', '--memwr', '0x10001204', '--val', '0x00000015', + '-f', self.family, '--snr', board_snr], + ['nrfjprog', '--reset', '-f', self.family, '--snr', board_snr], + ]) + commands.append(['nrfjprog', + '--pinreset', + '-f', self.family, + '--snr', board_snr]) + + for cmd in commands: + self.check_call(cmd) + + print('{} Serial Number {} flashed with success.'.format( + self.board, board_snr))
diff --git a/scripts/support/runner/openocd.py b/scripts/support/runner/openocd.py new file mode 100644 index 0000000..d657a78 --- /dev/null +++ b/scripts/support/runner/openocd.py
@@ -0,0 +1,209 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for openocd.''' + +from os import path +import os +import shlex + +from .core import ZephyrBinaryRunner, get_env_or_bail, get_env_strip_or + +DEFAULT_OPENOCD_TCL_PORT = 6333 +DEFAULT_OPENOCD_TELNET_PORT = 4444 +DEFAULT_OPENOCD_GDB_PORT = 3333 + + +class OpenOcdBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for openocd.''' + + def __init__(self, openocd_config, + openocd='openocd', default_path=None, + bin_name=None, elf_name=None, + load_cmd=None, verify_cmd=None, pre_cmd=None, post_cmd=None, + extra_init=None, + tcl_port=DEFAULT_OPENOCD_TCL_PORT, + telnet_port=DEFAULT_OPENOCD_TELNET_PORT, + gdb_port=DEFAULT_OPENOCD_GDB_PORT, + gdb=None, tui=None, debug=False): + super(OpenOcdBinaryRunner, self).__init__(debug=debug) + self.openocd_config = openocd_config + + search_args = [] + if default_path is not None: + search_args = ['-s', default_path] + self.openocd_cmd = [openocd] + search_args + self.bin_name = bin_name + self.elf_name = elf_name + self.load_cmd = load_cmd + self.verify_cmd = verify_cmd + self.pre_cmd = pre_cmd + self.post_cmd = post_cmd + self.extra_init = extra_init if extra_init is not None else [] + self.tcl_port = tcl_port + self.telnet_port = telnet_port + self.gdb_port = gdb_port + self.gdb_cmd = [gdb] if gdb is not None else None + self.tui_arg = [tui] if tui is not None else [] + + def replaces_shell_script(shell_script, command): + return (command in {'flash', 'debug', 'debugserver'} and + shell_script == 'openocd.sh') + + def create_from_env(command, debug): + '''Create runner from environment. + + Required: + + - ZEPHYR_BASE: zephyr Git repository base directory + - ARCH: board architecture + - BOARD_NAME: zephyr name of board + + Optional: + + - OPENOCD: path to openocd, defaults to openocd + - OPENOCD_DEFAULT_PATH: openocd search path to use + + Required for 'flash': + + - O: build output directory + - KERNEL_BIN_NAME: zephyr kernel binary + - OPENOCD_LOAD_CMD: command to load binary into flash + - OPENOCD_VERIFY_CMD: command to verify flash executed correctly + + Optional for 'flash': + + - OPENOCD_PRE_CMD: command to run before any others + - OPENOCD_POST_CMD: command to run after verifying flash write + + Required for 'debug': + + - GDB: GDB executable + - O: build output directory + - KERNEL_ELF_NAME: zephyr kernel binary, ELF format + + Optional for 'debug': + + - TUI: one additional argument to GDB (e.g. -tui) + - OPENOCD_EXTRA_INIT: additional arguments to pass to openocd + - TCL_PORT: openocd TCL port, defaults to 6333 + - TELNET_PORT: openocd telnet port, defaults to 4444 + - GDB_PORT: openocd gdb port, defaults to 3333 + ''' + zephyr_base = get_env_or_bail('ZEPHYR_BASE') + arch = get_env_or_bail('ARCH') + board_name = get_env_or_bail('BOARD_NAME') + openocd_config = path.join(zephyr_base, 'boards', arch, + board_name, 'support', 'openocd.cfg') + + openocd = os.environ.get('OPENOCD', 'openocd') + default_path = os.environ.get('OPENOCD_DEFAULT_PATH', None) + + o = os.environ.get('O', None) + bin_ = os.environ.get('KERNEL_BIN_NAME', None) + elf = os.environ.get('KERNEL_ELF_NAME', None) + bin_name = None + elf_name = None + if o is not None: + if bin_ is not None: + bin_name = path.join(o, bin_) + if elf is not None: + elf_name = path.join(o, elf) + + load_cmd = get_env_strip_or('OPENOCD_LOAD_CMD', '"', None) + verify_cmd = get_env_strip_or('OPENOCD_VERIFY_CMD', '"', None) + pre_cmd = get_env_strip_or('OPENOCD_PRE_CMD', '"', None) + post_cmd = get_env_strip_or('OPENOCD_POST_CMD', '"', None) + + gdb = os.environ.get('GDB', None) + tui = os.environ.get('TUI', None) + extra_init = os.environ.get('OPENOCD_EXTRA_INIT', None) + if extra_init is not None: + extra_init = shlex.split(extra_init) + tcl_port = int(os.environ.get('TCL_PORT', + str(DEFAULT_OPENOCD_TCL_PORT))) + telnet_port = int(os.environ.get('TELNET_PORT', + str(DEFAULT_OPENOCD_TELNET_PORT))) + gdb_port = int(os.environ.get('GDB_PORT', + str(DEFAULT_OPENOCD_GDB_PORT))) + + return OpenOcdBinaryRunner(openocd_config, + openocd=openocd, default_path=default_path, + bin_name=bin_name, elf_name=elf_name, + load_cmd=load_cmd, verify_cmd=verify_cmd, + pre_cmd=pre_cmd, post_cmd=post_cmd, + extra_init=extra_init, tcl_port=tcl_port, + telnet_port=telnet_port, gdb_port=gdb_port, + gdb=gdb, tui=tui, debug=debug) + + def run(self, command, **kwargs): + if command not in {'flash', 'debug', 'debugserver'}: + raise ValueError('{} is not supported'.format(command)) + + if command == 'flash': + self.do_flash(**kwargs) + elif command == 'debug': + self.do_debug(**kwargs) + else: + self.do_debugserver(**kwargs) + + def do_flash(self, **kwargs): + if self.bin_name is None: + raise ValueError('Cannot flash; binary name is missing') + if self.load_cmd is None: + raise ValueError('Cannot flash; load command is missing') + if self.verify_cmd is None: + raise ValueError('Cannot flash; verify command is missing') + + pre_cmd = [] + if self.pre_cmd is not None: + pre_cmd = ['-c', self.pre_cmd] + + post_cmd = [] + if self.post_cmd is not None: + post_cmd = ['-c', self.post_cmd] + + cmd = (self.openocd_cmd + + ['-f', self.openocd_config, + '-c', 'init', + '-c', 'targets'] + + pre_cmd + + ['-c', 'reset halt', + '-c', self.load_cmd, + '-c', 'reset halt', + '-c', self.verify_cmd] + + post_cmd + + ['-c', 'reset run', + '-c', 'shutdown']) + self.check_call(cmd) + + def do_debug(self, **kwargs): + if self.gdb_cmd is None: + raise ValueError('Cannot debug; no gdb specified') + if self.elf_name is None: + raise ValueError('Cannot debug; no .elf specified') + + server_cmd = (self.openocd_cmd + + ['-f', self.openocd_config] + + self.extra_init + + ['-c', 'tcl_port {}'.format(self.tcl_port), + '-c', 'telnet_port {}'.format(self.telnet_port), + '-c', 'gdb_port {}'.format(self.gdb_port), + '-c', 'init', + '-c', 'targets', + '-c', 'halt']) + + gdb_cmd = (self.gdb_cmd + self.tui_arg + + ['-ex', 'target remote :{}'.format(self.gdb_port), + self.elf_name]) + + self.run_server_and_client(server_cmd, gdb_cmd) + + def do_debugserver(self, **kwargs): + cmd = (self.openocd_cmd + + ['-f', self.openocd_config, + '-c', 'init', + '-c', 'targets', + '-c', 'reset halt']) + self.check_call(cmd)
diff --git a/scripts/support/runner/pyocd.py b/scripts/support/runner/pyocd.py new file mode 100644 index 0000000..d98579e --- /dev/null +++ b/scripts/support/runner/pyocd.py
@@ -0,0 +1,157 @@ +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for pyOCD .''' + +from os import path +import os + +from .core import ZephyrBinaryRunner, get_env_or_bail + +DEFAULT_PYOCD_GDB_PORT = 3333 + + +class PyOcdBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for pyocd-flashtool.''' + + def __init__(self, target, flashtool='pyocd-flashtool', + gdb=None, gdbserver='pyocd-gdbserver', + gdb_port=DEFAULT_PYOCD_GDB_PORT, tui=None, + bin_name=None, elf_name=None, + board_id=None, daparg=None, debug=False): + super(PyOcdBinaryRunner, self).__init__(debug=debug) + + self.target_args = ['-t', target] + self.flashtool = flashtool + self.gdb_cmd = [gdb] if gdb is not None else None + self.gdbserver = gdbserver + self.gdb_port = gdb_port + self.tui_args = [tui] if tui is not None else [] + self.bin_name = bin_name + self.elf_name = elf_name + + board_args = [] + if board_id is not None: + board_args = ['-b', board_id] + self.board_args = board_args + + daparg_args = [] + if daparg is not None: + daparg_args = ['-da', daparg] + self.daparg_args = daparg_args + + def replaces_shell_script(shell_script, command): + return (command in {'flash', 'debug', 'debugserver'} and + shell_script == 'pyocd.sh') + + def port_args(self): + return ['-p', str(self.gdb_port)] + + def create_from_env(command, debug): + '''Create runner from environment. + + Required: + + - PYOCD_TARGET: target override + + Optional: + + - PYOCD_DAPARG: arguments to pass to pyocd tool, default is none + - PYOCD_BOARD_ID: ID of board to flash, default is to prompt + + Required for 'flash': + + - O: build output directory + - KERNEL_BIN_NAME: name of kernel binary + + Optional for 'flash': + + - PYOCD_FLASHTOOL: flash tool path, defaults to pyocd-flashtool + + Required for 'debug': + + - O: build output directory + - KERNEL_ELF_NAME + - GDB: gdb executable + + Optional for 'debug', 'debugserver': + + - TUI: one additional argument to GDB (e.g. -tui) + - GDB_PORT: pyocd gdb port, defaults to 3333 + - PYOCD_GDBSERVER: gdb server executable, defaults to pyocd-gdbserver + ''' + target = get_env_or_bail('PYOCD_TARGET') + + o = os.environ.get('O', None) + bin_ = os.environ.get('KERNEL_BIN_NAME', None) + elf = os.environ.get('KERNEL_ELF_NAME', None) + bin_name = None + elf_name = None + if o is not None: + if bin_ is not None: + bin_name = path.join(o, bin_) + if elf is not None: + elf_name = path.join(o, elf) + + flashtool = os.environ.get('PYOCD_FLASHTOOL', 'pyocd-flashtool') + board_id = os.environ.get('PYOCD_BOARD_ID', None) + daparg = os.environ.get('PYOCD_DAPARG', None) + gdb = os.environ.get('GDB', None) + gdbserver = os.environ.get('PYOCD_GDBSERVER', 'pyocd-gdbserver') + gdb_port = os.environ.get('GDB_PORT', DEFAULT_PYOCD_GDB_PORT) + tui = os.environ.get('TUI', None) + + return PyOcdBinaryRunner(target, flashtool=flashtool, gdb=gdb, + gdbserver=gdbserver, gdb_port=gdb_port, + tui=tui, bin_name=bin_name, elf_name=elf_name, + board_id=board_id, daparg=daparg, debug=debug) + + def run(self, command, **kwargs): + if command not in {'flash', 'debug', 'debugserver'}: + raise ValueError('{} is not supported'.format(command)) + + if command == 'flash': + self.flash(**kwargs) + else: + self.debug_debugserver(command, **kwargs) + + def flash(self, **kwargs): + if self.bin_name is None: + raise ValueError('Cannot flash; bin_name is missing') + + cmd = ([self.flashtool] + + self.daparg_args + + self.target_args + + self.board_args + + [self.bin_name]) + + print('Flashing Target Device') + self.check_call(cmd) + + def print_gdbserver_message(self): + print('pyOCD GDB server running on port {}'.format(self.gdb_port)) + + def debug_debugserver(self, command, **kwargs): + server_cmd = ([self.gdbserver] + + self.daparg_args + + self.port_args() + + self.target_args + + self.board_args) + + if command == 'debugserver': + self.print_gdbserver_message() + self.check_call(server_cmd) + else: + if self.gdb_cmd is None: + raise ValueError('Cannot debug; gdb is missing') + if self.elf_name is None: + raise ValueError('Cannot debug; elf is missing') + client_cmd = (self.gdb_cmd + + self.tui_args + + [self.elf_name] + + ['-ex', 'target remote :{}'.format(self.gdb_port), + '-ex', 'load', + '-ex', 'monitor reset halt']) + self.print_gdbserver_message() + self.run_server_and_client(server_cmd, client_cmd)
diff --git a/scripts/support/zephyr_flash_debug.py b/scripts/support/zephyr_flash_debug.py index 69b1b72..ee8bf3f 100755 --- a/scripts/support/zephyr_flash_debug.py +++ b/scripts/support/zephyr_flash_debug.py
@@ -11,1021 +11,11 @@ emulated hardware. If it can invoke the relevant tools natively, it will do so; otherwise, it delegates to the shell script.""" -import abc from os import path -import os -import pprint -import platform -import shlex -import signal -import sys import subprocess -import time +import sys - -def get_env_or_bail(env_var): - try: - return os.environ[env_var] - except KeyError: - print('Variable {} not in environment:'.format( - env_var), file=sys.stderr) - pprint.pprint(dict(os.environ), stream=sys.stderr) - raise - - -def get_env_bool_or(env_var, default_value): - try: - return bool(int(os.environ[env_var])) - except KeyError: - return default_value - - -def get_env_strip_or(env_var, to_strip, default_value): - value = os.environ.get(env_var, None) - if value is not None: - return value.strip(to_strip) - else: - return default_value - - -def quote_sh_list(cmd): - '''Transform a command from list into shell string form.''' - fmt = ' '.join('{}' for _ in cmd) - args = [shlex.quote(s) for s in cmd] - return fmt.format(*args) - - -def check_call(cmd, debug): - if debug: - print(quote_sh_list(cmd)) - subprocess.check_call(cmd) - - -def check_output(cmd, debug): - if debug: - print(quote_sh_list(cmd)) - return subprocess.check_output(cmd) - - -def popen_ignore_int(cmd, debug): - '''Spawn a child command, ensuring it ignores SIGINT. - - The returned subprocess.Popen object must be manually terminated.''' - cflags = 0 - preexec = None - system = platform.system() - - if system == 'Windows': - cflags |= subprocess.CREATE_NEW_PROCESS_GROUP - elif system in {'Linux', 'Darwin'}: - preexec = os.setsid - - if debug: - print(quote_sh_list(cmd)) - - return subprocess.Popen(cmd, creationflags=cflags, preexec_fn=preexec) - - -class ZephyrBinaryRunner(abc.ABC): - '''Abstract superclass for binary runners (flashers, debuggers). - - With some exceptions, boards supported by Zephyr must provide - generic means to be flashed (have a Zephyr firmware binary - permanently installed on the device for running) and debugged - (have a breakpoint debugger and program loader on a host - workstation attached to a running target). This is supported by - three top-level commands managed by the Zephyr build system: - - - 'flash': flash a previously configured binary to the board, - start execution on the target, then return. - - - 'debug': connect to the board via a debugging protocol, then - drop the user into a debugger interface with symbol tables - loaded from the current binary, and block until it exits. - - - 'debugserver': connect via a board-specific debugging protocol, - then reset and halt the target. Ensure the user is now able to - connect to a debug server with symbol tables loaded from the - binary. - - Runner functionality relies on a variety of target-specific tools - and configuration values, the user interface to which is - abstracted by this class. Each runner subclass should take any - values it needs to execute one of these commands in its - constructor. The actual command execution is handled in the run() - method. - - This functionality is also replacing the legacy Zephyr runners, - which are shell scripts. - - At present, the Zephyr build system uses a variety of - tool-specific environment variables to control runner behavior. - To support a transition to ZephyrBinaryRunner and subclasses, this - class provides a create_for_shell_script() static factory method. - This method iterates over ZephyrBinaryRUnner subclasses, - determines which (if any) can provide equivalent functionality to - the shell-based runner, and returns a subclass instance with its - configuration determined from the environment. - - To support this, subclasess currently must provide a pair of - static methods, replaces_shell_script() and create_from_env(). The - first allows the runner subclass to declare which commands and - scripts it can replace. The second is called by - create_for_shell_script() to create a concrete runner instance. - - The environment-based factories are for legacy use *only*; the - user must be able to construct and use a runner using only the - constructor and run() method.''' - - def __init__(self, debug=False): - self.debug = debug - - @staticmethod - def create_for_shell_script(shell_script, command, debug): - '''Factory for using as a drop-in replacement to a shell script. - - Command is one of 'flash', 'debug', 'debugserver'. - - Get runner instance to use in place of shell_script, deriving - configuration from the environment.''' - for sub_cls in ZephyrBinaryRunner.__subclasses__(): - if sub_cls.replaces_shell_script(shell_script, command): - return sub_cls.create_from_env(command, debug) - raise ValueError('cannot implement script {} command {}'.format( - shell_script, command)) - - @staticmethod - @abc.abstractmethod - def replaces_shell_script(shell_script, command): - '''Check if this class replaces shell_script for the given command.''' - - @staticmethod - @abc.abstractmethod - def create_from_env(command, debug): - '''Create new flasher instance from environment variables. - - This class must be able to replace the current shell script - (FLASH_SCRIPT or DEBUG_SCRIPT, depending on command). The - environment variables expected by that script are used to build - the flasher in a backwards-compatible manner.''' - - @abc.abstractmethod - def run(self, command, **kwargs): - '''Run a command ('flash', 'debug', 'debugserver'). - - In case of an unsupported command, raise a ValueError.''' - - def run_server_and_client(self, server, client): - '''Run a server that ignores SIGINT, and a client that handles it. - - This routine portably: - - - creates a Popen object for the `server' command which ignores SIGINT - - runs `client' in a subprocess while temporarily ignoring SIGINT - - cleans up the server after the client exits. - - It's useful to e.g. open a GDB server and client.''' - server_proc = popen_ignore_int(server, self.debug) - previous = signal.signal(signal.SIGINT, signal.SIG_IGN) - try: - check_call(client, self.debug) - finally: - signal.signal(signal.SIGINT, previous) - server_proc.terminate() - server_proc.wait() - - -DEFAULT_ARC_TCL_PORT = 6333 -DEFAULT_ARC_TELNET_PORT = 4444 -DEFAULT_ARC_GDB_PORT = 3333 - - -class ArcBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for the ARC architecture, using openocd.''' - - # This unusual 'flash' implementation matches the original shell script. - # - # It works by starting a GDB server in a separate session, connecting a - # client to it to load the program, and running 'continue' within the - # client to execute the application. - # - # TODO: exit immediately when flashing is done, leaving Zephyr running. - - def __init__(self, elf, zephyr_base, arch, board_name, python, - gdb, openocd='openocd', extra_init=None, default_path=None, - tui=None, tcl_port=DEFAULT_ARC_TCL_PORT, - telnet_port=DEFAULT_ARC_TELNET_PORT, - gdb_port=DEFAULT_ARC_GDB_PORT, debug=False): - super(ArcBinaryRunner, self).__init__(debug=debug) - self.elf = elf - self.zephyr_base = zephyr_base - self.arch = arch - self.board_name = board_name - self.python = python - self.gdb = gdb - search_args = [] - if default_path is not None: - search_args = ['-s', default_path] - self.openocd_cmd = [openocd] + search_args - self.extra_init = extra_init if extra_init is not None else [] - self.tui = tui - self.tcl_port = tcl_port - self.telnet_port = telnet_port - self.gdb_port = gdb_port - - def replaces_shell_script(shell_script, command): - return (command in {'flash', 'debug', 'debugserver'} and - shell_script == 'arc_debugger.sh') - - def create_from_env(command, debug): - '''Create runner from environment. - - Required: - - - O: build output directory - - KERNEL_ELF_NAME: zephyr kernel binary in ELF format - - ZEPHYR_BASE: zephyr Git repository base directory - - ARCH: board architecture - - BOARD_NAME: zephyr name of board - - PYTHON: python executable - - GDB: gdb executable - - Optional: - - - OPENOCD: path to openocd, defaults to openocd - - OPENOCD_EXTRA_INIT: initialization command for GDB server - - OPENOCD_DEFAULT_PATH: openocd search path to use - - TUI: if present, passed to gdb server used to flash - - TCL_PORT: openocd TCL port, defaults to 6333 - - TELNET_PORT: openocd telnet port, defaults to 4444 - - GDB_PORT: openocd gdb port, defaults to 3333 - ''' - elf = path.join(get_env_or_bail('O'), - get_env_or_bail('KERNEL_ELF_NAME')) - zephyr_base = get_env_or_bail('ZEPHYR_BASE') - arch = get_env_or_bail('ARCH') - board_name = get_env_or_bail('BOARD_NAME') - python = get_env_or_bail('PYTHON') - gdb = get_env_or_bail('GDB') - - openocd = os.environ.get('OPENOCD', 'openocd') - extra_init = os.environ.get('OPENOCD_EXTRA_INIT', None) - if extra_init is not None: - extra_init = shlex.split(extra_init) - default_path = os.environ.get('OPENOCD_DEFAULT_PATH', None) - tui = os.environ.get('TUI', None) - tcl_port = int(os.environ.get('TCL_PORT', - str(DEFAULT_ARC_TCL_PORT))) - telnet_port = int(os.environ.get('TELNET_PORT', - str(DEFAULT_ARC_TELNET_PORT))) - gdb_port = int(os.environ.get('GDB_PORT', - str(DEFAULT_ARC_GDB_PORT))) - - return ArcBinaryRunner(elf, zephyr_base, arch, board_name, python, - gdb, openocd=openocd, extra_init=extra_init, - default_path=default_path, tui=tui, - tcl_port=tcl_port, telnet_port=telnet_port, - gdb_port=gdb_port, debug=debug) - - def run(self, command, **kwargs): - if command not in {'flash', 'debug', 'debugserver'}: - raise ValueError('{} is not supported'.format(command)) - - kwargs['openocd-cfg'] = path.join(self.zephyr_base, 'boards', - self.arch, self.board_name, - 'support', 'openocd.cfg') - - if command in {'flash', 'debug'}: - self.flash_debug(command, **kwargs) - else: - self.debugserver(**kwargs) - - def flash_debug(self, command, **kwargs): - config = kwargs['openocd-cfg'] - - server_cmd = (self.openocd_cmd + - ['-f', config] + - self.extra_init + - ['-c', 'tcl_port {}'.format(self.tcl_port), - '-c', 'telnet_port {}'.format(self.telnet_port), - '-c', 'gdb_port {}'.format(self.gdb_port), - '-c', 'init', - '-c', 'targets', - '-c', 'halt']) - - tui_arg = [] - if self.tui is not None: - tui_arg = [self.tui] - - continue_arg = [] - if command == 'flash': - continue_arg = ['-ex', 'c'] - - gdb_cmd = ([self.gdb] + - tui_arg + - ['-ex', 'target remote :{}'.format(self.gdb_port), - '-ex', 'load'] + - continue_arg + - [self.elf]) - - self.run_server_and_client(server_cmd, gdb_cmd) - - def debugserver(self, **kwargs): - config = kwargs['openocd-cfg'] - cmd = (self.openocd_cmd + - ['-f', config, - '-c', 'init', - '-c', 'targets', - '-c', 'reset halt']) - check_call(cmd, self.debug) - - -DEFAULT_BOSSAC_PORT = '/dev/ttyACM0' - - -class BossacBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for bossac.''' - - def __init__(self, bin_name, bossac='bossac', - port=DEFAULT_BOSSAC_PORT, debug=False): - super(BossacBinaryRunner, self).__init__(debug=debug) - self.bin_name = bin_name - self.bossac = bossac - self.port = port - - def replaces_shell_script(shell_script, command): - return command == 'flash' and shell_script == 'bossa-flash.sh' - - def create_from_env(command, debug): - '''Create flasher from environment. - - Required: - - - O: build output directory - - KERNEL_BIN_NAME: name of kernel binary - - Optional: - - - BOSSAC: path to bossac, default is bossac - - BOSSAC_PORT: serial port to use, default is /dev/ttyACM0 - ''' - bin_name = path.join(get_env_or_bail('O'), - get_env_or_bail('KERNEL_BIN_NAME')) - bossac = os.environ.get('BOSSAC', 'bossac') - port = os.environ.get('BOSSAC_PORT', DEFAULT_BOSSAC_PORT) - return BossacBinaryRunner(bin_name, bossac=bossac, port=port, - debug=debug) - - def run(self, command, **kwargs): - if command != 'flash': - raise ValueError('only flash is supported') - - if platform.system() != 'Linux': - msg = 'CAUTION: No flash tool for your host system found!' - raise NotImplementedError(msg) - - cmd_stty = ['stty', '-F', self.port, 'raw', 'ispeed', '1200', - 'ospeed', '1200', 'cs8', '-cstopb', 'ignpar', 'eol', '255', - 'eof', '255'] - cmd_flash = [self.bossac, '-p', self.port, '-R', '-e', '-w', '-v', - '-b', self.bin_name] - - check_call(cmd_stty, self.debug) - check_call(cmd_flash, self.debug) - - -class DfuUtilBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for dfu-util.''' - - def __init__(self, pid, alt, img, dfuse=None, exe='dfu-util', debug=False): - super(DfuUtilBinaryRunner, self).__init__(debug=debug) - self.alt = alt - self.img = img - self.dfuse = dfuse - self.cmd = [exe, '-d,{}'.format(pid)] - try: - self.list_pattern = ', alt={},'.format(int(self.alt)) - except ValueError: - self.list_pattern = ', name="{}",'.format(self.alt) - - def replaces_shell_script(shell_script, command): - return command == 'flash' and shell_script == 'dfuutil.sh' - - def create_from_env(command, debug): - '''Create flasher from environment. - - Required: - - - DFUUTIL_PID: USB VID:PID of the board - - DFUUTIL_ALT: interface alternate setting number or name - - DFUUTIL_IMG: binary to flash - - Optional: - - - DFUUTIL_DFUSE_ADDR: target address if the board is a - DfuSe device. Ignored if not present. - - DFUUTIL: dfu-util executable, defaults to dfu-util. - ''' - pid = get_env_or_bail('DFUUTIL_PID') - alt = get_env_or_bail('DFUUTIL_ALT') - img = get_env_or_bail('DFUUTIL_IMG') - dfuse = os.environ.get('DFUUTIL_DFUSE_ADDR', None) - exe = os.environ.get('DFUUTIL', 'dfu-util') - - return DfuUtilBinaryRunner(pid, alt, img, dfuse=dfuse, exe=exe, - debug=debug) - - def find_device(self): - cmd = list(self.cmd) + ['-l'] - output = check_output(cmd, self.debug) - output = output.decode(sys.getdefaultencoding()) - return self.list_pattern in output - - def run(self, command, **kwargs): - if command != 'flash': - raise ValueError('only flash is supported') - - reset = 0 - if not self.find_device(): - reset = 1 - print('Please reset your board to switch to DFU mode...') - while not self.find_device(): - time.sleep(0.1) - - cmd = list(self.cmd) - if self.dfuse is not None: - cmd.extend(['-s', '{}:leave'.format(self.dfuse)]) - cmd.extend(['-a', self.alt, '-D', self.img]) - check_call(cmd, self.debug) - if reset: - print('Now reset your board again to switch back to runtime mode.') - - -class Esp32BinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for espidf.''' - - def __init__(self, elf, device, baud=921600, flash_size='detect', - flash_freq='40m', flash_mode='dio', espidf='espidf', - debug=False): - super(Esp32BinaryRunner, self).__init__(debug=debug) - self.elf = elf - self.device = device - self.baud = baud - self.flash_size = flash_size - self.flash_freq = flash_freq - self.flash_mode = flash_mode - self.espidf = espidf - - def replaces_shell_script(shell_script, command): - return command == 'flash' and shell_script == 'esp32.sh' - - def create_from_env(command, debug): - '''Create flasher from environment. - - Required: - - - O: build output directory - - KERNEL_ELF_NAME: name of kernel binary in ELF format - - Optional: - - - ESP_DEVICE: serial port to flash, default /dev/ttyUSB0 - - ESP_BAUD_RATE: serial baud rate, default 921600 - - ESP_FLASH_SIZE: flash size, default 'detect' - - ESP_FLASH_FREQ: flash frequency, default '40m' - - ESP_FLASH_MODE: flash mode, default 'dio' - - ESP_TOOL: complete path to espidf, or set to 'espidf' to look for it - in $ESP_IDF_PATH/components/esptool_py/esptool/esptool.py - ''' - elf = path.join(get_env_or_bail('O'), - get_env_or_bail('KERNEL_ELF_NAME')) - - # TODO add sane device defaults on other platforms than Linux. - device = os.environ.get('ESP_DEVICE', '/dev/ttyUSB0') - baud = os.environ.get('ESP_BAUD_RATE', '921600') - flash_size = os.environ.get('ESP_FLASH_SIZE', 'detect') - flash_freq = os.environ.get('ESP_FLASH_FREQ', '40m') - flash_mode = os.environ.get('ESP_FLASH_MODE', 'dio') - espidf = os.environ.get('ESP_TOOL', 'espidf') - - if espidf == 'espidf': - idf_path = get_env_or_bail('ESP_IDF_PATH') - espidf = path.join(idf_path, 'components', 'esptool_py', 'esptool', - 'esptool.py') - - return Esp32BinaryRunner(elf, device, baud=baud, - flash_size=flash_size, flash_freq=flash_freq, - flash_mode=flash_mode, espidf=espidf, - debug=debug) - - def run(self, command, **kwargs): - if command != 'flash': - raise ValueError('only flash is supported') - - bin_name = path.splitext(self.elf)[0] + path.extsep + 'bin' - cmd_convert = [self.espidf, '--chip', 'esp32', 'elf2image', self.elf] - cmd_flash = [self.espidf, '--chip', 'esp32', '--port', self.device, - '--baud', self.baud, '--before', 'default_reset', - '--after', 'hard_reset', 'write_flash', '-u', - '--flash_mode', self.flash_mode, - '--flash_freq', self.flash_freq, - '--flash_size', self.flash_size, - '0x1000', bin_name] - - print("Converting ELF to BIN") - check_call(cmd_convert, self.debug) - - print("Flashing ESP32 on {} ({}bps)".format(self.device, self.baud)) - check_call(cmd_flash, self.debug) - - -class Nios2BinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for NIOS II.''' - - # From the original shell script: - # - # "XXX [flash] only support[s] cases where the .elf is sent - # over the JTAG and the CPU directly boots from __start. CONFIG_XIP - # and CONFIG_INCLUDE_RESET_VECTOR must be disabled." - - def __init__(self, hex_, cpu_sof, zephyr_base, debug=False): - super(Nios2BinaryRunner, self).__init__(debug=debug) - self.hex_ = hex_ - self.cpu_sof = cpu_sof - self.zephyr_base = zephyr_base - - def replaces_shell_script(shell_script, command): - return command == 'flash' and shell_script == 'nios2.sh' - - def create_from_env(command, debug): - '''Create runner from environment. - - Required: - - - O: build output directory - - KERNEL_HEX_NAME: name of kernel binary in HEX format - - NIOS2_CPU_SOF: location of the CPU .sof data - - ZEPHYR_BASE: zephyr Git repository base directory - ''' - hex_ = path.join(get_env_or_bail('O'), - get_env_or_bail('KERNEL_HEX_NAME')) - cpu_sof = get_env_or_bail('NIOS2_CPU_SOF') - zephyr_base = get_env_or_bail('ZEPHYR_BASE') - - return Nios2BinaryRunner(hex_, cpu_sof, zephyr_base, debug=debug) - - def run(self, command, **kwargs): - if command not in {'flash', 'debug', 'debugserver'}: - raise ValueError('{} is not supported'.format(command)) - - if command == 'flash': - self.flash(**kwargs) - else: - self.debug_debugserver(command, **kwargs) - - def flash(self, **kwargs): - cmd = [path.join(self.zephyr_base, 'scripts', 'support', - 'quartus-flash.py'), - '--sof', self.cpu_sof, - '--kernel', self.hex_] - - check_call(cmd, self.debug) - - def debug_debugserver(command, **kwargs): - raise NotImplementedError() - - -class NrfJprogBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for nrfjprog.''' - - def __init__(self, hex_, family, board, debug=False): - super(NrfJprogBinaryRunner, self).__init__(debug=debug) - self.hex_ = hex_ - self.family = family - self.board = board - - def replaces_shell_script(shell_script, command): - return command == 'flash' and shell_script == 'nrf_flash.sh' - - def create_from_env(command, debug): - '''Create flasher from environment. - - Required: - - - O: build output directory - - KERNEL_HEX_NAME: name of kernel binary in ELF format - - NRF_FAMILY: e.g. NRF51 or NRF52 - - BOARD: Zephyr board name - ''' - hex_ = path.join(get_env_or_bail('O'), - get_env_or_bail('KERNEL_HEX_NAME')) - family = get_env_or_bail('NRF_FAMILY') - board = get_env_or_bail('BOARD') - - return NrfJprogBinaryRunner(hex_, family, board, debug=debug) - - def get_board_snr_from_user(self): - snrs = check_output(['nrfjprog', '--ids'], self.debug) - snrs = snrs.decode(sys.getdefaultencoding()).strip().splitlines() - - if len(snrs) == 1: - return snrs[0] - - print('There are multiple boards connected.') - for i, snr in enumerate(snrs, 1): - print('{}. {}'.format(i, snr)) - - p = 'Please select one with desired serial number (1-{}): '.format( - len(snrs)) - while True: - value = input(p) - try: - value = int(value) - except ValueError: - continue - if 1 <= value <= len(snrs): - break - - return snrs[value - 1] - - def run(self, command, **kwargs): - if command != 'flash': - raise ValueError('only flash is supported') - - board_snr = self.get_board_snr_from_user() - - print('Flashing file: {}'.format(self.hex_)) - commands = [ - ['nrfjprog', '--eraseall', '-f', self.family, '--snr', board_snr], - ['nrfjprog', '--program', self.hex_, '-f', self.family, '--snr', - board_snr], - ] - if self.family == 'NRF52': - commands.extend([ - # Set reset pin - ['nrfjprog', '--memwr', '0x10001200', '--val', '0x00000015', - '-f', self.family, '--snr', board_snr], - ['nrfjprog', '--memwr', '0x10001204', '--val', '0x00000015', - '-f', self.family, '--snr', board_snr], - ['nrfjprog', '--reset', '-f', self.family, '--snr', board_snr], - ]) - commands.append(['nrfjprog', - '--pinreset', - '-f', self.family, - '--snr', board_snr]) - - for cmd in commands: - check_call(cmd, self.debug) - - print('{} Serial Number {} flashed with success.'.format( - self.board, board_snr)) - - -DEFAULT_OPENOCD_TCL_PORT = 6333 -DEFAULT_OPENOCD_TELNET_PORT = 4444 -DEFAULT_OPENOCD_GDB_PORT = 3333 - - -class OpenOcdBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for openocd.''' - - def __init__(self, openocd_config, - openocd='openocd', default_path=None, - bin_name=None, elf_name=None, - load_cmd=None, verify_cmd=None, pre_cmd=None, post_cmd=None, - extra_init=None, - tcl_port=DEFAULT_OPENOCD_TCL_PORT, - telnet_port=DEFAULT_OPENOCD_TELNET_PORT, - gdb_port=DEFAULT_OPENOCD_GDB_PORT, - gdb=None, tui=None, debug=False): - super(OpenOcdBinaryRunner, self).__init__(debug=debug) - self.openocd_config = openocd_config - - search_args = [] - if default_path is not None: - search_args = ['-s', default_path] - self.openocd_cmd = [openocd] + search_args - self.bin_name = bin_name - self.elf_name = elf_name - self.load_cmd = load_cmd - self.verify_cmd = verify_cmd - self.pre_cmd = pre_cmd - self.post_cmd = post_cmd - self.extra_init = extra_init if extra_init is not None else [] - self.tcl_port = tcl_port - self.telnet_port = telnet_port - self.gdb_port = gdb_port - self.gdb_cmd = [gdb] if gdb is not None else None - self.tui_arg = [tui] if tui is not None else [] - - def replaces_shell_script(shell_script, command): - return (command in {'flash', 'debug', 'debugserver'} and - shell_script == 'openocd.sh') - - def create_from_env(command, debug): - '''Create runner from environment. - - Required: - - - ZEPHYR_BASE: zephyr Git repository base directory - - ARCH: board architecture - - BOARD_NAME: zephyr name of board - - Optional: - - - OPENOCD: path to openocd, defaults to openocd - - OPENOCD_DEFAULT_PATH: openocd search path to use - - Required for 'flash': - - - O: build output directory - - KERNEL_BIN_NAME: zephyr kernel binary - - OPENOCD_LOAD_CMD: command to load binary into flash - - OPENOCD_VERIFY_CMD: command to verify flash executed correctly - - Optional for 'flash': - - - OPENOCD_PRE_CMD: command to run before any others - - OPENOCD_POST_CMD: command to run after verifying flash write - - Required for 'debug': - - - GDB: GDB executable - - O: build output directory - - KERNEL_ELF_NAME: zephyr kernel binary, ELF format - - Optional for 'debug': - - - TUI: one additional argument to GDB (e.g. -tui) - - OPENOCD_EXTRA_INIT: additional arguments to pass to openocd - - TCL_PORT: openocd TCL port, defaults to 6333 - - TELNET_PORT: openocd telnet port, defaults to 4444 - - GDB_PORT: openocd gdb port, defaults to 3333 - ''' - zephyr_base = get_env_or_bail('ZEPHYR_BASE') - arch = get_env_or_bail('ARCH') - board_name = get_env_or_bail('BOARD_NAME') - openocd_config = path.join(zephyr_base, 'boards', arch, - board_name, 'support', 'openocd.cfg') - - openocd = os.environ.get('OPENOCD', 'openocd') - default_path = os.environ.get('OPENOCD_DEFAULT_PATH', None) - - o = os.environ.get('O', None) - bin_ = os.environ.get('KERNEL_BIN_NAME', None) - elf = os.environ.get('KERNEL_ELF_NAME', None) - bin_name = None - elf_name = None - if o is not None: - if bin_ is not None: - bin_name = path.join(o, bin_) - if elf is not None: - elf_name = path.join(o, elf) - - load_cmd = get_env_strip_or('OPENOCD_LOAD_CMD', '"', None) - verify_cmd = get_env_strip_or('OPENOCD_VERIFY_CMD', '"', None) - pre_cmd = get_env_strip_or('OPENOCD_PRE_CMD', '"', None) - post_cmd = get_env_strip_or('OPENOCD_POST_CMD', '"', None) - - gdb = os.environ.get('GDB', None) - tui = os.environ.get('TUI', None) - extra_init = os.environ.get('OPENOCD_EXTRA_INIT', None) - if extra_init is not None: - extra_init = shlex.split(extra_init) - tcl_port = int(os.environ.get('TCL_PORT', - str(DEFAULT_OPENOCD_TCL_PORT))) - telnet_port = int(os.environ.get('TELNET_PORT', - str(DEFAULT_OPENOCD_TELNET_PORT))) - gdb_port = int(os.environ.get('GDB_PORT', - str(DEFAULT_OPENOCD_GDB_PORT))) - - return OpenOcdBinaryRunner(openocd_config, - openocd=openocd, default_path=default_path, - bin_name=bin_name, elf_name=elf_name, - load_cmd=load_cmd, verify_cmd=verify_cmd, - pre_cmd=pre_cmd, post_cmd=post_cmd, - extra_init=extra_init, tcl_port=tcl_port, - telnet_port=telnet_port, gdb_port=gdb_port, - gdb=gdb, tui=tui, debug=debug) - - def run(self, command, **kwargs): - if command not in {'flash', 'debug', 'debugserver'}: - raise ValueError('{} is not supported'.format(command)) - - if command == 'flash': - self.do_flash(**kwargs) - elif command == 'debug': - self.do_debug(**kwargs) - else: - self.do_debugserver(**kwargs) - - def do_flash(self, **kwargs): - if self.bin_name is None: - raise ValueError('Cannot flash; binary name is missing') - if self.load_cmd is None: - raise ValueError('Cannot flash; load command is missing') - if self.verify_cmd is None: - raise ValueError('Cannot flash; verify command is missing') - - pre_cmd = [] - if self.pre_cmd is not None: - pre_cmd = ['-c', self.pre_cmd] - - post_cmd = [] - if self.post_cmd is not None: - post_cmd = ['-c', self.post_cmd] - - cmd = (self.openocd_cmd + - ['-f', self.openocd_config, - '-c', 'init', - '-c', 'targets'] + - pre_cmd + - ['-c', 'reset halt', - '-c', self.load_cmd, - '-c', 'reset halt', - '-c', self.verify_cmd] + - post_cmd + - ['-c', 'reset run', - '-c', 'shutdown']) - check_call(cmd, self.debug) - - def do_debug(self, **kwargs): - if self.gdb_cmd is None: - raise ValueError('Cannot debug; no gdb specified') - if self.elf_name is None: - raise ValueError('Cannot debug; no .elf specified') - - server_cmd = (self.openocd_cmd + - ['-f', self.openocd_config] + - self.extra_init + - ['-c', 'tcl_port {}'.format(self.tcl_port), - '-c', 'telnet_port {}'.format(self.telnet_port), - '-c', 'gdb_port {}'.format(self.gdb_port), - '-c', 'init', - '-c', 'targets', - '-c', 'halt']) - - gdb_cmd = (self.gdb_cmd + self.tui_arg + - ['-ex', 'target remote :{}'.format(self.gdb_port), - self.elf_name]) - - self.run_server_and_client(server_cmd, gdb_cmd) - - def do_debugserver(self, **kwargs): - cmd = (self.openocd_cmd + - ['-f', self.openocd_config, - '-c', 'init', - '-c', 'targets', - '-c', 'reset halt']) - check_call(cmd, self.debug) - - -DEFAULT_PYOCD_GDB_PORT = 3333 - - -class PyOcdBinaryRunner(ZephyrBinaryRunner): - '''Runner front-end for pyocd-flashtool.''' - - def __init__(self, target, flashtool='pyocd-flashtool', - gdb=None, gdbserver='pyocd-gdbserver', - gdb_port=DEFAULT_PYOCD_GDB_PORT, tui=None, - bin_name=None, elf_name=None, - board_id=None, daparg=None, debug=False): - super(PyOcdBinaryRunner, self).__init__(debug=debug) - - self.target_args = ['-t', target] - self.flashtool = flashtool - self.gdb_cmd = [gdb] if gdb is not None else None - self.gdbserver = gdbserver - self.gdb_port = gdb_port - self.tui_args = [tui] if tui is not None else [] - self.bin_name = bin_name - self.elf_name = elf_name - - board_args = [] - if board_id is not None: - board_args = ['-b', board_id] - self.board_args = board_args - - daparg_args = [] - if daparg is not None: - daparg_args = ['-da', daparg] - self.daparg_args = daparg_args - - def replaces_shell_script(shell_script, command): - return (command in {'flash', 'debug', 'debugserver'} and - shell_script == 'pyocd.sh') - - def port_args(self): - return ['-p', str(self.gdb_port)] - - def create_from_env(command, debug): - '''Create runner from environment. - - Required: - - - PYOCD_TARGET: target override - - Optional: - - - PYOCD_DAPARG: arguments to pass to pyocd tool, default is none - - PYOCD_BOARD_ID: ID of board to flash, default is to prompt - - Required for 'flash': - - - O: build output directory - - KERNEL_BIN_NAME: name of kernel binary - - Optional for 'flash': - - - PYOCD_FLASHTOOL: flash tool path, defaults to pyocd-flashtool - - Required for 'debug': - - - O: build output directory - - KERNEL_ELF_NAME - - GDB: gdb executable - - Optional for 'debug', 'debugserver': - - - TUI: one additional argument to GDB (e.g. -tui) - - GDB_PORT: pyocd gdb port, defaults to 3333 - - PYOCD_GDBSERVER: gdb server executable, defaults to pyocd-gdbserver - ''' - target = get_env_or_bail('PYOCD_TARGET') - - o = os.environ.get('O', None) - bin_ = os.environ.get('KERNEL_BIN_NAME', None) - elf = os.environ.get('KERNEL_ELF_NAME', None) - bin_name = None - elf_name = None - if o is not None: - if bin_ is not None: - bin_name = path.join(o, bin_) - if elf is not None: - elf_name = path.join(o, elf) - - flashtool = os.environ.get('PYOCD_FLASHTOOL', 'pyocd-flashtool') - board_id = os.environ.get('PYOCD_BOARD_ID', None) - daparg = os.environ.get('PYOCD_DAPARG', None) - gdb = os.environ.get('GDB', None) - gdbserver = os.environ.get('PYOCD_GDBSERVER', 'pyocd-gdbserver') - gdb_port = os.environ.get('GDB_PORT', DEFAULT_PYOCD_GDB_PORT) - tui = os.environ.get('TUI', None) - - return PyOcdBinaryRunner(target, flashtool=flashtool, gdb=gdb, - gdbserver=gdbserver, gdb_port=gdb_port, - tui=tui, bin_name=bin_name, elf_name=elf_name, - board_id=board_id, daparg=daparg, debug=debug) - - def run(self, command, **kwargs): - if command not in {'flash', 'debug', 'debugserver'}: - raise ValueError('{} is not supported'.format(command)) - - if command == 'flash': - self.flash(**kwargs) - else: - self.debug_debugserver(command, **kwargs) - - def flash(self, **kwargs): - if self.bin_name is None: - raise ValueError('Cannot flash; bin_name is missing') - - cmd = ([self.flashtool] + - self.daparg_args + - self.target_args + - self.board_args + - [self.bin_name]) - - print('Flashing Target Device') - check_call(cmd, self.debug) - - def print_gdbserver_message(self): - print('pyOCD GDB server running on port {}'.format(self.gdb_port)) - - def debug_debugserver(self, command, **kwargs): - server_cmd = ([self.gdbserver] + - self.daparg_args + - self.port_args() + - self.target_args + - self.board_args) - - if command == 'debugserver': - self.print_gdbserver_message() - check_call(server_cmd, self.debug) - else: - if self.gdb_cmd is None: - raise ValueError('Cannot debug; gdb is missing') - if self.elf_name is None: - raise ValueError('Cannot debug; elf is missing') - client_cmd = (self.gdb_cmd + - self.tui_args + - [self.elf_name] + - ['-ex', 'target remote :{}'.format(self.gdb_port), - '-ex', 'load', - '-ex', 'monitor reset halt']) - self.print_gdbserver_message() - self.run_server_and_client(server_cmd, client_cmd) +from runner.core import ZephyrBinaryRunner, get_env_bool_or # TODO: Stop using environment variables. @@ -1044,7 +34,9 @@ debug) except ValueError: # Unsupported; fall back on shell script. - check_call([shell_script_full, command], debug) + print('Unsupported, falling back on shell script', + file=sys.stderr) + subprocess.check_call([shell_script_full, command]) return runner.run(command)