Skip to content

west: runners: Add new -i/--dev-id device identifier common runner option #37509

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions scripts/west_commands/runners/canopen_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def __call__(self, parser, namespace, values, option_string=None):

class CANopenBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for CANopen.'''
def __init__(self, cfg, node_id, can_context=DEFAULT_CAN_CONTEXT,
def __init__(self, cfg, dev_id, can_context=DEFAULT_CAN_CONTEXT,
program_number=1, confirm=True,
confirm_only=True, timeout=10):
if MISSING_REQUIREMENTS:
Expand All @@ -48,12 +48,13 @@ def __init__(self, cfg, node_id, can_context=DEFAULT_CAN_CONTEXT,
"how to fix")

super().__init__(cfg)
self.dev_id = dev_id # Only use for error checking in do_run()
self.bin_file = cfg.bin_file
self.confirm = confirm
self.confirm_only = confirm_only
self.timeout = timeout
self.downloader = CANopenProgramDownloader(logger=self.logger,
node_id=node_id,
node_id=dev_id,
can_context=can_context,
program_number=program_number)

Expand All @@ -63,14 +64,18 @@ def name(cls):

@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash'}, flash_addr=False)
return RunnerCaps(commands={'flash'}, dev_id=True, flash_addr=False)

@classmethod
def do_add_parser(cls, parser):
# Required:
parser.add_argument('--node-id', required=True, help='Node ID')
def dev_id_help(cls) -> str:
return 'CANopen Node ID.'

@classmethod
def do_add_parser(cls, parser):
# Optional:
parser.add_argument('--node-id', dest='dev_id',
help=cls.dev_id_help())

parser.add_argument('--can-context', default=DEFAULT_CAN_CONTEXT,
help='Custom Python-CAN context to use')
parser.add_argument('--program-number', default=1,
Expand All @@ -88,14 +93,17 @@ def do_add_parser(cls, parser):

@classmethod
def do_create(cls, cfg, args):
return CANopenBinaryRunner(cfg, int(args.node_id),
return CANopenBinaryRunner(cfg, int(args.dev_id),
can_context=args.can_context,
program_number=int(args.program_number),
confirm=args.confirm,
confirm_only=args.confirm_only,
timeout=int(args.timeout))

def do_run(self, command, **kwargs):
if not self.dev_id:
raise RuntimeError('Please specify a CANopen node ID with the '
'-i/--dev-id or --node-id command-line switch.')
if command == 'flash':
self.flash(**kwargs)

Expand Down
36 changes: 36 additions & 0 deletions scripts/west_commands/runners/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ class RunnerCaps:
- commands: set of supported commands; default is {'flash',
'debug', 'debugserver', 'attach'}.

- dev_id: whether the runner supports device identifiers, in the form of an
-i, --dev-id option. This is useful when the user has multiple debuggers
connected to a single computer, in order to select which one will be used
with the command provided.

- flash_addr: whether the runner supports flashing to an
arbitrary address. Default is False. If true, the runner
must honor the --dt-flash option.
Expand All @@ -225,14 +230,17 @@ class RunnerCaps:
def __init__(self,
commands: Set[str] = {'flash', 'debug',
'debugserver', 'attach'},
dev_id: bool = False,
flash_addr: bool = False,
erase: bool = False):
self.commands = commands
self.dev_id = dev_id
self.flash_addr = bool(flash_addr)
self.erase = bool(erase)

def __str__(self):
return (f'RunnerCaps(commands={self.commands}, '
f'dev_id={self.dev_id}, '
f'flash_addr={self.flash_addr}, '
f'erase={self.erase}'
')')
Expand Down Expand Up @@ -280,6 +288,17 @@ class _ToggleAction(argparse.Action):
def __call__(self, parser, args, ignored, option):
setattr(args, self.dest, not option.startswith('--no-'))

class DeprecatedAction(argparse.Action):

def __call__(self, parser, namespace, values, option_string=None):
_logger.warning(f'Argument {self.option_strings[0]} is deprecated, '
f'use {self._replacement} instead.')
setattr(namespace, self.dest, values)

def depr_action(*args, replacement=None, **kwargs):
action = DeprecatedAction(*args, **kwargs)
setattr(action, '_replacement', replacement)
return action

class ZephyrBinaryRunner(abc.ABC):
'''Abstract superclass for binary runners (flashers, debuggers).
Expand Down Expand Up @@ -423,6 +442,13 @@ def add_parser(cls, parser):
# using them to mean something else.
caps = cls.capabilities()

if caps.dev_id:
parser.add_argument('-i', '--dev-id',
dest='dev_id',
help=cls.dev_id_help())
else:
parser.add_argument('-i', '--dev-id', help=argparse.SUPPRESS)

if caps.flash_addr:
parser.add_argument('--dt-flash', default='n', choices=_YN_CHOICES,
action=_DTFlashAction,
Expand Down Expand Up @@ -454,6 +480,8 @@ def create(cls, cfg: RunnerConfig,
- ``args``: arguments parsed from execution environment, as
specified by ``add_parser()``.'''
caps = cls.capabilities()
if args.dev_id and not caps.dev_id:
_missing_cap(cls, '--dev-id')
if args.dt_flash and not caps.flash_addr:
_missing_cap(cls, '--dt-flash')
if args.erase and not caps.erase:
Expand Down Expand Up @@ -530,6 +558,14 @@ def thread_info_enabled(self) -> bool:
return (self.build_conf.getboolean('CONFIG_DEBUG_THREAD_INFO') or
self.build_conf.getboolean('CONFIG_OPENOCD_SUPPORT'))

@classmethod
def dev_id_help(cls) -> str:
''' Get the ArgParse help text for the --dev-id option.'''
return '''Device identifier. Use it to select
which debugger, device, node or instance to
target when multiple ones are available or
connected.'''

@staticmethod
def require(program: str) -> str:
'''Require that a program is installed before proceeding.
Expand Down
22 changes: 15 additions & 7 deletions scripts/west_commands/runners/dfu.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
class DfuUtilBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for dfu-util.'''

def __init__(self, cfg, pid, alt, img, exe='dfu-util',
def __init__(self, cfg, dev_id, alt, img, exe='dfu-util',
dfuse_config=None):

super().__init__(cfg)
self.dev_id = dev_id # Used only for error checking in do_run
self.alt = alt
self.img = img
self.cmd = [exe, '-d,{}'.format(pid)]
self.cmd = [exe, '-d,{}'.format(dev_id)]
try:
self.list_pattern = ', alt={},'.format(int(self.alt))
except ValueError:
Expand All @@ -42,17 +44,20 @@ def name(cls):

@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash'}, flash_addr=True)
return RunnerCaps(commands={'flash'}, dev_id=True, flash_addr=True)

@classmethod
def dev_id_help(cls) -> str:
return 'USB VID:PID of the connected device.'

@classmethod
def do_add_parser(cls, parser):
# Required:
parser.add_argument("--pid", required=True,
help="USB VID:PID of the board")
parser.add_argument("--alt", required=True,
help="interface alternate setting number or name")

# Optional:
parser.add_argument("--pid", dest='dev_id',
help=cls.dev_id_help())
parser.add_argument("--img",
help="binary to flash, default is --bin-file")
parser.add_argument("--dfuse", default=False, action='store_true',
Expand Down Expand Up @@ -86,7 +91,7 @@ def do_create(cls, cfg, args):
else:
dcfg = None

ret = DfuUtilBinaryRunner(cfg, args.pid, args.alt, args.img,
ret = DfuUtilBinaryRunner(cfg, args.dev_id, args.alt, args.img,
exe=args.dfu_util, dfuse_config=dcfg)
ret.ensure_device()
return ret
Expand All @@ -105,6 +110,9 @@ def find_device(self):
return self.list_pattern in output

def do_run(self, command, **kwargs):
if not self.dev_id:
raise RuntimeError('Please specify a USB VID:PID with the '
'-i/--dev-id or --pid command-line switch.')
self.require(self.cmd[0])
self.ensure_output('bin')

Expand Down
28 changes: 18 additions & 10 deletions scripts/west_commands/runners/jlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
'''Runner for debugging with J-Link.'''

import argparse
from functools import partial
import logging
import os
from pathlib import Path
Expand All @@ -13,7 +14,7 @@
import sys
import tempfile

from runners.core import ZephyrBinaryRunner, RunnerCaps
from runners.core import ZephyrBinaryRunner, RunnerCaps, depr_action

try:
from pylink.library import Library
Expand All @@ -32,7 +33,7 @@ def __call__(self, parser, args, ignored, option):
class JLinkBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for the J-Link GDB server.'''

def __init__(self, cfg, device, did=None,
def __init__(self, cfg, device, dev_id=None,
commander=DEFAULT_JLINK_EXE,
dt_flash=True, erase=True, reset_after_load=False,
iface='swd', speed='auto',
Expand All @@ -46,7 +47,7 @@ def __init__(self, cfg, device, did=None,
self.elf_name = cfg.elf_file
self.gdb_cmd = [cfg.gdb] if cfg.gdb else None
self.device = device
self.did = did # Debugger Identifier
self.dev_id = dev_id
self.commander = commander
self.dt_flash = dt_flash
self.erase = erase
Expand All @@ -69,17 +70,23 @@ def name(cls):
@classmethod
def capabilities(cls):
return RunnerCaps(commands={'flash', 'debug', 'debugserver', 'attach'},
flash_addr=True, erase=True)
dev_id=True, flash_addr=True, erase=True)

@classmethod
def dev_id_help(cls) -> str:
return '''Device identifier. Use it to select the J-Link Serial Number
of the device connected over USB.'''

@classmethod
def do_add_parser(cls, parser):
# Required:
parser.add_argument('--device', required=True, help='device name')

# Optional:
parser.add_argument('--id', required=False,
dest='did',
help='Serial number of J-Link to use')
parser.add_argument('--id', required=False, dest='dev_id',
action=partial(depr_action,
replacement='-i/--dev-id'),
help='Deprecated: use -i/--dev-id instead')
parser.add_argument('--iface', default='swd',
help='interface to use, default is swd')
parser.add_argument('--speed', default='auto',
Expand Down Expand Up @@ -110,7 +117,7 @@ def do_add_parser(cls, parser):
@classmethod
def do_create(cls, cfg, args):
return JLinkBinaryRunner(cfg, args.device,
did=args.did,
dev_id=args.dev_id,
commander=args.commander,
dt_flash=args.dt_flash,
erase=args.erase,
Expand Down Expand Up @@ -201,7 +208,8 @@ def do_run(self, command, **kwargs):

server_cmd = ([self.gdbserver] +
# only USB connections supported
['-select', 'usb' + (f'={self.did}' if self.did else ''),
['-select', 'usb' + (f'={self.dev_id}'
if self.dev_id else ''),
'-port', str(self.gdb_port),
'-if', self.iface,
'-speed', self.speed,
Expand Down Expand Up @@ -293,7 +301,7 @@ def flash(self, **kwargs):
f.writelines(bytes(line + '\n', 'utf-8') for line in lines)
cmd = ([self.commander] +
# only USB connections supported
(['-USB', f'{self.did}'] if self.did else []) +
(['-USB', f'{self.dev_id}'] if self.dev_id else []) +
(['-nogui', '1'] if self.supports_nogui else []) +
['-if', self.iface,
'-speed', self.speed,
Expand Down
Loading