Commit cd8d43b1 authored by Martí Bolívar's avatar Martí Bolívar Committed by Anas Nashif
Browse files

scripts: runner: generalize commands to "capabilities"



Some configuration options or device tree nodes affect the way that
runners ought to behave, but there's no good way for them to report
whether they can handle them.

One motivating example is CONFIG_FLASH_LOAD_OFFSET, as influenced by
the zephyr,code-partition chosen node in the DT for architectures
where CONFIG_HAS_FLASH_LOAD_OFFSET=y.

If CONFIG_FLASH_LOAD_OFFSET is nonzero, the 'flash' command ought to
place the kernel at that address offset from the device flash's start
address. Runners don't support this right now, which should be
fixed. However, we don't want to mandate support for this feature,
since not all targets need it.

We need to let runners declare what their capabilities are. Make it so
by adding a RunnerCaps class to the runner core. This currently just
states which commands a runner can handle, but can be generalized to
implement the above use case.

Signed-off-by: default avatarMarti Bolivar <marti@opensourcefoundries.com>
parent e33ec242
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ from os import path
import os
import platform

from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail

DEFAULT_BOSSAC_PORT = '/dev/ttyACM0'

@@ -28,8 +28,8 @@ class BossacBinaryRunner(ZephyrBinaryRunner):
        return 'bossac'

    @classmethod
    def handles_command(cls, command):
        return command == 'flash'
    def capabilities(cls):
        return RunnerCaps(commands={'flash'})

    def create_from_env(command, debug):
        '''Create flasher from environment.
+24 −9
Original line number Diff line number Diff line
@@ -143,6 +143,17 @@ class NetworkPortHelper:
        return {int(b) for b in used_bytes}


class RunnerCaps:
    '''This class represents a runner class's capabilities.

    The most basic capability is the set of supported commands,
    available in the commands field. This defaults to all three
    commands.'''

    def __init__(self, commands={'flash', 'debug', 'debugserver'}):
        self.commands = commands


class ZephyrBinaryRunner(abc.ABC):
    '''Abstract superclass for binary runners (flashers, debuggers).

@@ -184,7 +195,7 @@ class ZephyrBinaryRunner(abc.ABC):

    1. Define a ZephyrBinaryRunner subclass, and implement its
       abstract methods. Override any methods you need to, especially
       handles_command().
       capabilities().

    2. Make sure the Python module defining your runner class is
       imported by this package's __init__.py (otherwise,
@@ -229,7 +240,8 @@ class ZephyrBinaryRunner(abc.ABC):
        else:
            raise ValueError('no runner named {} is known'.format(runner_name))

        if not cls.handles_command(command):
        caps = cls.capabilities()
        if command not in caps.commands:
            raise ValueError('runner {} does not implement command {}'.format(
                runner_name, command))

@@ -246,13 +258,15 @@ class ZephyrBinaryRunner(abc.ABC):
        etc.).'''

    @classmethod
    def handles_command(cls, command):
        '''Return True iff this class can run the given command.
    def capabilities(cls):
        '''Returns a RunnerCaps representing this runner's capabilities.

        This implementation returns the default capabilities, which
        includes support for all three commands, but no other special
        powers.

        The default implementation returns True if the command is
        valid (i.e. is one of "flash", "debug", and "debugserver").
        Subclasses should override if they only provide a subset.'''
        return command in {'flash', 'debug', 'debugserver'}
        Subclasses should override appropriately if needed.'''
        return RunnerCaps()

    @staticmethod
    @abc.abstractmethod
@@ -263,7 +277,8 @@ class ZephyrBinaryRunner(abc.ABC):
        '''Runs command ('flash', 'debug', 'debugserver').

        This is the main entry point to this runner.'''
        if not self.handles_command(command):
        caps = self.capabilities()
        if command not in caps.commands:
            raise ValueError('runner {} does not implement command {}'.format(
                self.name(), command))
        self.do_run(command, **kwargs)
+3 −3
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ import os
import sys
import time

from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail


class DfuUtilBinaryRunner(ZephyrBinaryRunner):
@@ -30,8 +30,8 @@ class DfuUtilBinaryRunner(ZephyrBinaryRunner):
        return 'dfu-util'

    @classmethod
    def handles_command(cls, command):
        return command == 'flash'
    def capabilities(cls):
        return RunnerCaps(commands={'flash'})

    def create_from_env(command, debug):
        '''Create flasher from environment.
+3 −3
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
from os import path
import os

from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail


class Esp32BinaryRunner(ZephyrBinaryRunner):
@@ -30,8 +30,8 @@ class Esp32BinaryRunner(ZephyrBinaryRunner):
        return 'esp32'

    @classmethod
    def handles_command(cls, command):
        return command == 'flash'
    def capabilities(cls):
        return RunnerCaps(commands={'flash'})

    def create_from_env(command, debug):
        '''Create flasher from environment.
+3 −3
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
from os import path
import os

from .core import ZephyrBinaryRunner, get_env_or_bail
from .core import ZephyrBinaryRunner, RunnerCaps, get_env_or_bail

DEFAULT_JLINK_GDB_PORT = 2331

@@ -33,8 +33,8 @@ class JLinkBinaryRunner(ZephyrBinaryRunner):
        return 'jlink'

    @classmethod
    def handles_command(cls, command):
        return command in {'debug', 'debugserver'}
    def capabilities(cls):
        return RunnerCaps(commands={'debug', 'debugserver'})

    def create_from_env(command, debug):
        '''Create runner from environment.
Loading