ab82264ace
West now supports a mechanism for extension commands. Use it to move the command implementations that are tightly coupled with boards and the zephyr build system back into the Zephyr repository. This patch doesn't include test cases. Those will be moved over in a subsequent patch. Signed-off-by: Marti Bolivar <marti@foundries.io>
171 lines
6.2 KiB
Python
171 lines
6.2 KiB
Python
# Copyright (c) 2017 Linaro Limited.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
'''Runner for pyOCD .'''
|
|
|
|
import os
|
|
|
|
from west import log
|
|
|
|
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,
|
|
flashtool='pyocd-flashtool', flash_addr=0x0,
|
|
flashtool_opts=None,
|
|
gdbserver='pyocd-gdbserver',
|
|
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.flashtool = flashtool
|
|
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.gdbserver = gdbserver
|
|
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.flashtool_extra = flashtool_opts if flashtool_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('--flashtool', default='pyocd-flashtool',
|
|
help='flash tool path, default is pyocd-flashtool')
|
|
parser.add_argument('--flashtool-opt', default=[], action='append',
|
|
help='''Additional options for pyocd-flashtool,
|
|
e.g. -ce to chip erase''')
|
|
parser.add_argument('--frequency',
|
|
help='SWD clock frequency in Hz')
|
|
parser.add_argument('--gdbserver', default='pyocd-gdbserver',
|
|
help='GDB server, default is pyocd-gdbserver')
|
|
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):
|
|
daparg = os.environ.get('PYOCD_DAPARG')
|
|
if daparg:
|
|
log.wrn('Setting PYOCD_DAPARG in the environment is',
|
|
'deprecated; use the --daparg option instead.')
|
|
if args.daparg is None:
|
|
log.dbg('Missing --daparg set to {} from environment'.format(
|
|
daparg), level=log.VERBOSE_VERY)
|
|
args.daparg = daparg
|
|
|
|
build_conf = BuildConfiguration(cfg.build_dir)
|
|
flash_addr = cls.get_flash_address(args, build_conf)
|
|
|
|
return PyOcdBinaryRunner(
|
|
cfg, args.target, flashtool=args.flashtool,
|
|
flash_addr=flash_addr, flashtool_opts=args.flashtool_opt,
|
|
gdbserver=args.gdbserver, gdb_port=args.gdb_port, tui=args.tui,
|
|
board_id=args.board_id, daparg=args.daparg,
|
|
frequency=args.frequency)
|
|
|
|
def port_args(self):
|
|
return ['-p', str(self.gdb_port)]
|
|
|
|
def do_run(self, command, **kwargs):
|
|
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.flashtool] +
|
|
self.flash_addr_args +
|
|
self.daparg_args +
|
|
self.target_args +
|
|
self.board_args +
|
|
self.frequency_args +
|
|
self.flashtool_extra +
|
|
[fname])
|
|
|
|
log.inf('Flashing Target Device')
|
|
self.check_call(cmd)
|
|
|
|
def print_gdbserver_message(self):
|
|
log.inf('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 +
|
|
self.frequency_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)])
|
|
if command == 'debug':
|
|
client_cmd += ['-ex', 'monitor halt',
|
|
'-ex', 'monitor reset',
|
|
'-ex', 'load']
|
|
|
|
self.print_gdbserver_message()
|
|
self.run_server_and_client(server_cmd, client_cmd)
|