a2f203dd1a
This is a partial revert of commit
2cee5ff519
("scripts: west_commands: runners: remove deprecated options").
I remarked at the time that the removal of the older way of writing
things from the runners themselves seemed gratuitous since they are
easy to continue to support indefinitely and people may have been used
to the old way of doing things. It didn't seem worth the fight to push
for a revert at the time, though.
Since then I've run into real problems that their removal has caused
in the wild and I am convinced that this part of that patch was wrong.
Restore the original, undeprecated forms of these options, but make it
clear in the command line help that they're just obsolete alternative
spellings at this point.
Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
216 lines
7.7 KiB
Python
216 lines
7.7 KiB
Python
# Copyright (c) 2017 Linaro Limited.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
'''Runner for pyOCD .'''
|
|
|
|
import os
|
|
from os import path
|
|
|
|
from runners.core import ZephyrBinaryRunner, RunnerCaps, BuildConfiguration
|
|
|
|
DEFAULT_PYOCD_GDB_PORT = 3333
|
|
DEFAULT_PYOCD_TELNET_PORT = 4444
|
|
|
|
|
|
class PyOcdBinaryRunner(ZephyrBinaryRunner):
|
|
'''Runner front-end for pyOCD.'''
|
|
|
|
def __init__(self, cfg, target,
|
|
pyocd='pyocd',
|
|
dev_id=None, flash_addr=0x0, erase=False, flash_opts=None,
|
|
gdb_port=DEFAULT_PYOCD_GDB_PORT,
|
|
telnet_port=DEFAULT_PYOCD_TELNET_PORT, tui=False,
|
|
pyocd_config=None,
|
|
daparg=None, frequency=None, tool_opt=None):
|
|
super().__init__(cfg)
|
|
|
|
default = path.join(cfg.board_dir, 'support', 'pyocd.yaml')
|
|
if path.exists(default):
|
|
self.pyocd_config = default
|
|
else:
|
|
self.pyocd_config = None
|
|
|
|
|
|
self.target_args = ['-t', target]
|
|
self.pyocd = pyocd
|
|
self.flash_addr_args = ['-a', hex(flash_addr)] if flash_addr else []
|
|
self.erase = erase
|
|
self.gdb_cmd = [cfg.gdb] if cfg.gdb is not None else None
|
|
self.gdb_port = gdb_port
|
|
self.telnet_port = telnet_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
|
|
|
|
pyocd_config_args = []
|
|
|
|
if self.pyocd_config is not None:
|
|
pyocd_config_args = ['--config', self.pyocd_config]
|
|
|
|
self.pyocd_config_args = pyocd_config_args
|
|
|
|
board_args = []
|
|
if dev_id is not None:
|
|
board_args = ['-u', dev_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.tool_opt_args = tool_opt or []
|
|
|
|
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'},
|
|
dev_id=True, flash_addr=True, erase=True,
|
|
tool_opt=True)
|
|
|
|
@classmethod
|
|
def dev_id_help(cls) -> str:
|
|
return '''Device identifier. Use it to select the probe's unique ID
|
|
or substring thereof.'''
|
|
|
|
@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('--telnet-port', default=DEFAULT_PYOCD_TELNET_PORT,
|
|
help='pyocd telnet port, defaults to {}'.format(
|
|
DEFAULT_PYOCD_TELNET_PORT))
|
|
parser.add_argument('--tui', default=False, action='store_true',
|
|
help='if given, GDB uses -tui')
|
|
parser.add_argument('--board-id', dest='dev_id',
|
|
help='obsolete synonym for -i/--dev-id')
|
|
|
|
@classmethod
|
|
def tool_opt_help(cls) -> str:
|
|
return """Additional options for pyocd commander,
|
|
e.g. '--script=user.py'"""
|
|
|
|
@classmethod
|
|
def do_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, erase=args.erase, flash_opts=args.flash_opt,
|
|
gdb_port=args.gdb_port, telnet_port=args.telnet_port, tui=args.tui,
|
|
dev_id=args.dev_id, daparg=args.daparg,
|
|
frequency=args.frequency,
|
|
tool_opt=args.tool_opt)
|
|
|
|
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), '-T', str(self.telnet_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 self.hex_name is not None and os.path.isfile(self.hex_name):
|
|
fname = self.hex_name
|
|
elif self.bin_name is not None and os.path.isfile(self.bin_name):
|
|
self.logger.warning(
|
|
'hex file ({}) does not exist; falling back on .bin ({}). '.
|
|
format(self.hex_name, self.bin_name) +
|
|
'Consider enabling CONFIG_BUILD_OUTPUT_HEX.')
|
|
fname = self.bin_name
|
|
else:
|
|
raise ValueError(
|
|
'Cannot flash; no hex ({}) or bin ({}) files found. '.format(
|
|
self.hex_name, self.bin_name))
|
|
|
|
erase_method = 'chip' if self.erase else 'sector'
|
|
|
|
cmd = ([self.pyocd] +
|
|
['flash'] +
|
|
self.pyocd_config_args +
|
|
['-e', erase_method] +
|
|
self.flash_addr_args +
|
|
self.daparg_args +
|
|
self.target_args +
|
|
self.board_args +
|
|
self.frequency_args +
|
|
self.tool_opt_args +
|
|
self.flash_extra +
|
|
[fname])
|
|
|
|
self.logger.info('Flashing file: {}'.format(fname))
|
|
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 +
|
|
self.tool_opt_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)
|