Skip to content
Open
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
71 changes: 69 additions & 2 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2313,6 +2313,72 @@ Implements:
Arguments:
- delay (float, default=2.0): delay in seconds between off and on

ManualButtonDriver
~~~~~~~~~~~~~~~~~~
A :any:`ManualButtonDriver` requires the user to control the taget button.
This is required if a strategy is used with the target, but no automatic
button control is available.

The driver's name will be displayed during interaction.

Binds to:
- None

Implements:
- :any:`ButtonProtocol`

.. code-block:: yaml

ManualButtonDriver:
name: 'example-board'

Arguments:
- None

ExternalButtonDriver
~~~~~~~~~~~~~~~~~~~~
An :any:`ExternalButtonDriver` is used to control a target button via an
external command.

Binds to:
- None

Implements:
- :any:`ButtonProtocol`

.. code-block:: yaml

ExternalButtonDriver:
cmd_press: 'example_command press and hold'
cmd_release: 'example_command release'
cmd_press_for: 'example_command press_for'
delay: 2.0

Arguments:
- cmd_press (str): command to press and hold the button on the board
- cmd_release (str): command to release the button on the board
- cmd_press_for (str): command to press, pause, and release the button on the board
- delay (float, default=1.0): delay in seconds when calling press_for

DigitalOutputButtonDriver
~~~~~~~~~~~~~~~~~~~~~~~~~
A :any:`DigitalOutputButtonDriver` is used to control a target button via a
DigitalOutputDriver

Binds to:
- :any:`DigitalOutputProtocol`

Implements:
- :any:`ButtonProtocol`

.. code-block:: yaml

DigitalOutputButtonDriver:
delay: 2.0

Arguments:
- delay (float, default=1.0): delay in seconds when calling press_for

GpioDigitalOutputDriver
~~~~~~~~~~~~~~~~~~~~~~~
The :any:`GpioDigitalOutputDriver` writes a digital signal to a GPIO line.
Expand All @@ -2333,10 +2399,11 @@ Implements:

.. code-block:: yaml

GpioDigitalOutputDriver: {}
GpioDigitalOutputDriver:
delay: 2.0

Arguments:
- None
- delay (float, default=1.0): delay in seconds between off and on for a power cycle or between states for button press_for

SerialPortDigitalOutputDriver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 2 additions & 0 deletions labgrid/driver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
DigitalOutputPowerDriver, YKUSHPowerDriver, \
USBPowerDriver, SiSPMPowerDriver, NetworkPowerDriver, \
PDUDaemonDriver
from .buttondriver import ManualButtonDriver, ExternalButtonDriver, \
DigitalOutputButtonDriver
from .usbloader import MXSUSBDriver, IMXUSBDriver, BDIMXUSBDriver, RKUSBDriver, UUUDriver
from .usbsdmuxdriver import USBSDMuxDriver
from .usbsdwiredriver import USBSDWireDriver
Expand Down
103 changes: 103 additions & 0 deletions labgrid/driver/buttondriver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import shlex
import time

import attr

from ..factory import target_factory
from ..protocol import ButtonProtocol, DigitalOutputProtocol
from ..step import step
from ..util.helper import processwrapper
from .common import Driver


@target_factory.reg_driver
@attr.s(eq=False)
class ManualButtonDriver(Driver, ButtonProtocol):
"""ManualButtonDriver - Driver to tell the user to control a target's button"""

@Driver.check_active
@step()
def press(self):
self.target.interact(
f"Press and hold the button on target {self.target.name} and press enter"
)

@Driver.check_active
@step()
def release(self):
self.target.interact(
f"Release the button on the target {self.target.name} press enter"
)

@Driver.check_active
@step()
def press_for(self):
self.target.interact(
f"Press and then Release the button on target {self.target.name} for {self.delay} seconds and press enter"
)

@target_factory.reg_driver
@attr.s(eq=False)
class ExternalButtonDriver(Driver, ButtonProtocol):
"""ExternalButtonDriver - Driver using an external command to control a target's button"""
cmd_press = attr.ib(validator=attr.validators.instance_of(str))
cmd_release = attr.ib(validator=attr.validators.instance_of(str))
cmd_press_for = attr.ib(validator=attr.validators.instance_of(str))
delay = attr.ib(default=1.0, validator=attr.validators.instance_of(float))

@Driver.check_active
@step()
def press(self):
cmd = shlex.split(self.cmd_press)
processwrapper.check_output(cmd)

@Driver.check_active
@step()
def release(self):
cmd = shlex.split(self.cmd_release)
processwrapper.check_output(cmd)

@Driver.check_active
@step()
def press_for(self):
if self.cmd_press_for is not None:
cmd = shlex.split(self.cmd_press_for)
processwrapper.check_output(cmd)
else:
self.press()
time.sleep(self.delay)
self.release()

@target_factory.reg_driver
@attr.s(eq=False)
class DigitalOutputButtonDriver(Driver, ButtonProtocol):
"""
DigitalOutputButtonDriver uses a DigitalOutput to control a button
"""
bindings = {"output": DigitalOutputProtocol, }
delay = attr.ib(default=1.0, validator=attr.validators.instance_of(float))

def __attrs_post_init__(self):
super().__attrs_post_init__()

@Driver.check_active
@step()
def press(self):
self.output.set(True)

@Driver.check_active
@step()
def release(self):
self.output.set(False)

@Driver.check_active
@step()
def press_for(self):
self.press()
time.sleep(self.delay)
self.release()

@Driver.check_active
@step()
def get(self):
return self.output.get()
1 change: 1 addition & 0 deletions labgrid/protocol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .consoleprotocol import ConsoleProtocol
from .linuxbootprotocol import LinuxBootProtocol
from .powerprotocol import PowerProtocol
from .buttonprotocol import ButtonProtocol
from .filetransferprotocol import FileTransferProtocol
from .infoprotocol import InfoProtocol
from .digitaloutputprotocol import DigitalOutputProtocol
Expand Down
25 changes: 25 additions & 0 deletions labgrid/protocol/buttonprotocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import abc


class ButtonProtocol(abc.ABC):
"""Abstract class providing the ButtonProtocol interface"""

@abc.abstractmethod
def press(self):
"""Implementations should "press and hold" the button."""
raise NotImplementedError

@abc.abstractmethod
def release(self):
"""Implementations should "release" the button"""
raise NotImplementedError

@abc.abstractmethod
def press_for(self, time: float):
"""Implementations should "press" the button for time seconds and then "release" the button again"""
raise NotImplementedError

@abc.abstractmethod
def get(self):
"""Implementations should return the status of the button"""
raise NotImplementedError
35 changes: 35 additions & 0 deletions labgrid/remote/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,33 @@ def power(self):
if action == "get":
print(f"power{' ' + name if name else ''} for place {place.name} is {'on' if res else 'off'}")

def button(self):
place = self.get_acquired_place()
action = self.args.action
delay = self.args.delay
name = self.args.name
target = self._get_target(place)
from ..resource.remote import NetworkSysfsGPIO

drv = None
try:
drv = target.get_driver("ButtonProtocol", name=name)
except NoDriverFoundError:
for resource in target.resources:
if isinstance(resource, NetworkSysfsGPIO):
self._get_driver_or_new(target, "GpioDigitalOutputDriver", name=name)
drv = self._get_driver_or_new(target, "DigitalOutputButtonDriver", name=name)
if drv:
break

if not drv:
raise UserError("target has no compatible resource available")
if delay is not None:
drv.delay = delay
res = getattr(drv, action)()
if action == "get":
print(f"button{' ' + name if name else ''} for place {place.name} is {'pressed' if res else 'released'}")

def digital_io(self):
place = self.get_acquired_place()
action = self.args.action
Expand Down Expand Up @@ -1868,6 +1895,14 @@ def main():
subparser.add_argument("--name", "-n", help="optional resource name")
subparser.set_defaults(func=ClientSession.power)

subparser = subparsers.add_parser("button", help="change (or get) a place's button status")
subparser.add_argument("action", choices=["press", "release", "press_for", "get"])
subparser.add_argument(
"-t", "--delay", type=float, default=None, help="wait time in seconds between the press and release during press_for"
)
subparser.add_argument("--name", "-n", help="optional resource name")
subparser.set_defaults(func=ClientSession.button)

subparser = subparsers.add_parser("io", help="change (or get) a digital IO status")
subparser.add_argument("action", choices=["high", "low", "get"], help="action")
subparser.add_argument("name", help="optional resource name", nargs="?")
Expand Down
Loading