I've had some requests to be able to use code in the runners package without having west installed. It turns out to be pretty easy to make this happen, as west is currently only used for west.log and some trivial helper methods: - To replace west log, use the standard logging module - Add an appropriate handler for each runner's logger in run_common.py which delegates to west.log, to keep output working as expected. Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
171 lines
5.9 KiB
Python
171 lines
5.9 KiB
Python
# Copyright (c) 2017 Linaro Limited.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
'''Runner for pyOCD .'''
|
|
|
|
import os
|
|
|
|
from runners.core import ZephyrBinaryRunner, RunnerCaps, \
|
|
BuildConfiguration
|
|
|
|
DEFAULT_PYOCD_GDB_PORT = 3333
|
|
|
|
|
|
class PyOcdBinaryRunner(ZephyrBinaryRunner):
|
|
'''Runner front-end for pyOCD.'''
|
|
|
|
def __init__(self, cfg, target,
|
|
pyocd='pyocd',
|
|
flash_addr=0x0, flash_opts=None,
|
|
gdb_port=DEFAULT_PYOCD_GDB_PORT, tui=False,
|
|
board_id=None, daparg=None, frequency=None):
|
|
super(PyOcdBinaryRunner, self).__init__(cfg)
|
|
|
|
self.target_args = ['-t', target]
|
|
self.pyocd = pyocd
|
|
self.flash_addr_args = ['-a', hex(flash_addr)] if flash_addr else []
|
|
self.gdb_cmd = [cfg.gdb] if cfg.gdb is not None else None
|
|
self.gdb_port = gdb_port
|
|
self.tui_args = ['-tui'] if tui else []
|
|
self.hex_name = cfg.hex_file
|
|
self.bin_name = cfg.bin_file
|
|
self.elf_name = cfg.elf_file
|
|
|
|
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
|
|
|
|
frequency_args = []
|
|
if frequency is not None:
|
|
frequency_args = ['-f', frequency]
|
|
self.frequency_args = frequency_args
|
|
|
|
self.flash_extra = flash_opts if flash_opts else []
|
|
|
|
@classmethod
|
|
def name(cls):
|
|
return 'pyocd'
|
|
|
|
@classmethod
|
|
def capabilities(cls):
|
|
return RunnerCaps(commands={'flash', 'debug', 'debugserver', 'attach'},
|
|
flash_addr=True)
|
|
|
|
@classmethod
|
|
def do_add_parser(cls, parser):
|
|
parser.add_argument('--target', required=True,
|
|
help='target override')
|
|
|
|
parser.add_argument('--daparg',
|
|
help='Additional -da arguments to pyocd tool')
|
|
parser.add_argument('--pyocd', default='pyocd',
|
|
help='path to pyocd tool, default is pyocd')
|
|
parser.add_argument('--flash-opt', default=[], action='append',
|
|
help='''Additional options for pyocd flash,
|
|
e.g. --flash-opt="-e=chip" to chip erase''')
|
|
parser.add_argument('--frequency',
|
|
help='SWD clock frequency in Hz')
|
|
parser.add_argument('--gdb-port', default=DEFAULT_PYOCD_GDB_PORT,
|
|
help='pyocd gdb port, defaults to {}'.format(
|
|
DEFAULT_PYOCD_GDB_PORT))
|
|
parser.add_argument('--tui', default=False, action='store_true',
|
|
help='if given, GDB uses -tui')
|
|
parser.add_argument('--board-id',
|
|
help='ID of board to flash, default is to prompt')
|
|
|
|
@classmethod
|
|
def create(cls, cfg, args):
|
|
build_conf = BuildConfiguration(cfg.build_dir)
|
|
flash_addr = cls.get_flash_address(args, build_conf)
|
|
|
|
ret = PyOcdBinaryRunner(
|
|
cfg, args.target,
|
|
pyocd=args.pyocd,
|
|
flash_addr=flash_addr, flash_opts=args.flash_opt,
|
|
gdb_port=args.gdb_port, tui=args.tui,
|
|
board_id=args.board_id, daparg=args.daparg,
|
|
frequency=args.frequency)
|
|
|
|
daparg = os.environ.get('PYOCD_DAPARG')
|
|
if not ret.daparg_args and daparg:
|
|
ret.logger.warning('PYOCD_DAPARG is deprecated; use --daparg')
|
|
ret.logger.debug('--daparg={} via PYOCD_DAPARG'.format(daparg))
|
|
ret.daparg_args = ['-da', daparg]
|
|
|
|
return ret
|
|
|
|
def port_args(self):
|
|
return ['-p', str(self.gdb_port)]
|
|
|
|
def do_run(self, command, **kwargs):
|
|
self.require(self.pyocd)
|
|
if command == 'flash':
|
|
self.flash(**kwargs)
|
|
else:
|
|
self.debug_debugserver(command, **kwargs)
|
|
|
|
def flash(self, **kwargs):
|
|
if os.path.isfile(self.hex_name):
|
|
fname = self.hex_name
|
|
elif os.path.isfile(self.bin_name):
|
|
fname = self.bin_name
|
|
else:
|
|
raise ValueError(
|
|
'Cannot flash; no hex ({}) or bin ({}) files'.format(
|
|
self.hex_name, self.bin_name))
|
|
|
|
cmd = ([self.pyocd] +
|
|
['flash'] +
|
|
['-e', 'sector'] +
|
|
self.flash_addr_args +
|
|
self.daparg_args +
|
|
self.target_args +
|
|
self.board_args +
|
|
self.frequency_args +
|
|
self.flash_extra +
|
|
[fname])
|
|
|
|
self.logger.info('Flashing Target Device')
|
|
self.check_call(cmd)
|
|
|
|
def log_gdbserver_message(self):
|
|
self.logger.info('pyOCD GDB server running on port {}'.
|
|
format(self.gdb_port))
|
|
|
|
def debug_debugserver(self, command, **kwargs):
|
|
server_cmd = ([self.pyocd] +
|
|
['gdbserver'] +
|
|
self.daparg_args +
|
|
self.port_args() +
|
|
self.target_args +
|
|
self.board_args +
|
|
self.frequency_args)
|
|
|
|
if command == 'debugserver':
|
|
self.log_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)])
|
|
if command == 'debug':
|
|
client_cmd += ['-ex', 'monitor halt',
|
|
'-ex', 'monitor reset',
|
|
'-ex', 'load']
|
|
|
|
self.require(client_cmd[0])
|
|
self.log_gdbserver_message()
|
|
self.run_server_and_client(server_cmd, client_cmd)
|