Skip to content

Commit

Permalink
examples/usbpower: extend example with local and remote resources
Browse files Browse the repository at this point in the history
This example includes the complete setup for local and remote access,
direct library use and pytest testing with a custom strategy.

Signed-off-by: Jan Luebbe <[email protected]>
  • Loading branch information
jluebbe committed Mar 20, 2018
1 parent 4c91da3 commit d31e404
Show file tree
Hide file tree
Showing 6 changed files with 418 additions and 0 deletions.
235 changes: 235 additions & 0 deletions examples/usbpower/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
USB Power and SD-Mux Example
============================

Files
-----

cycle.py
Python script which uses labgrid as a library and directly cycles power on
the USBPowerPort.

local.yaml
Environment configuration to use USBPowerPort, USBSerialPort and
USBSDMuxDevice resources which are connected locally.

examplestrategy.py
Custom strategy which controls the USB-SD-Mux and the USB port power.

test_example.py
Testsuite (based on pytest) to run a simple command in Barebox, Shell and
Barebox again.

exports.yaml
Configuration file for labgrid-exporter to export these resources over the
network.

remote.yaml
Environment configuration to use USBPowerPort, USBSerialPort and
USBSDMuxDevice resources which are connected remotely (to the place 'demo1').

Hardware Setup
--------------

This example uses a USB hub which has power control (as supported by `uhubctl
<https://github.com/mvp/uhubctl>`_), a USB serial converter, a `USB-SD-Mux
<https://www.pengutronix.de/de/2017-10-23-usb-sd-mux-automated-sd-card-juggler.html>
board`_ and a USB powered target.
The target is connected on port 1, the serial converer on port2 and the SD-Mux
on port 3.

Software Setup
--------------

The following expects that labgrid with crossbar support is installed in the
active virtualenv.
The ``uhubctl`` and ``usbsdmux`` tools need to be installed on the system.

Library Example
---------------

Ensure that the hardware is connected and run ``python cycle.py``.
You should get the following output::

Target: Target(name='main', env=None)
Resources: [USBPowerPort(target=Target(name='main', env=None), name=None, state=<BindingState.active: 2>, avail=True, timeout=5.0, match={'SUBSYSTEM': 'usb', 'DEVTYPE': 'usb_interface', 'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0', 'DRIVER': 'hub'}, device=Device('/sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0'), index=1)]
Drivers: [USBPowerDriver(target=Target(name='main', env=None), name=None, state=<BindingState.active: 2>, delay=2.0)]
Status: True

=== Switching power OFF ===
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
Sent power off request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Status: False

=== Switching power ON ===
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Sent power on request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
Status: True

Local pytest Example
--------------------

Run ``pytest --lg-env local.yaml -v``.
You should get output similar to the following::

========================================== test session starts ===========================================
platform linux -- Python 3.5.3, pytest-3.4.0, py-1.5.2, pluggy-0.6.0 -- /home/jluebbe/ptx/labgrid/venv/bin/python3
cachedir: ../.pytest_cache
rootdir: /home/jluebbe/ptx/labgrid/examples, inifile: pytest.ini
plugins: pylint-0.7.1, mock-1.6.3, isort-0.1.0, cov-2.5.1, labgrid-0.1.1.dev242+ge3d60c7
collected 3 items
test_example.py::test_barebox
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
Sent power off request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Sent power on request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
PASSED [ 33%]
test_example.py::test_shell
PASSED [ 66%]
test_example.py::test_barebox_2
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
Sent power off request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Sent power on request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
PASSED [100%]

======================================= 3 passed in 23.90 seconds ========================================

Remote Setup
------------

To access resources remotely, you first need to start the coordinator::
$ crossbar start --logformat none
[...]
Coordinator ready.

Then, you need to start the exporter::
$ labgrid-exporter exports.yaml
[...]

Now, you can use ``labgrid-client`` to show resources and configure a place::
$ labgrid-client resources
polaris/hub-p1/NetworkUSBPowerPort
polaris/hub-p2/NetworkUSBPowerPort
polaris/hub-p2/NetworkSerialPort
polaris/hub-p3/NetworkUSBPowerPort
polaris/hub-p3/NetworkUSBSDMuxDevice
polaris/hub-p4/NetworkUSBPowerPort
$ labgrid-client -p demo1 create
$ labgrid-client -p demo1 add-match polaris/hub-p1/NetworkUSBPowerPort
$ labgrid-client -p demo1 add-match polaris/hub-p2/NetworkSerialPort
$ labgrid-client -p demo1 add-match polaris/hub-p3/NetworkUSBSDMuxDevice
$ labgrid-client places
demo1
$ labgrid-client -p demo1 lock
acquired place demo1
$ labgrid-client -p demo1 show
Place 'demo1':
aliases:
comment:
matches:
polaris/hub-p1/NetworkUSBPowerPort
polaris/hub-p2/NetworkSerialPort
polaris/hub-p3/NetworkUSBSDMuxDevice
acquired: polaris/jluebbe
acquired resources:
polaris/hub-p1/NetworkUSBPowerPort/USBPowerPort
polaris/hub-p2/NetworkSerialPort/USBSerialPort
polaris/hub-p3/NetworkUSBSDMuxDevice/USBSDMuxDevice
created: 2018-03-20 10:41:07.561995
changed: 2018-03-20 15:48:25.928298
Acquired resource 'USBPowerPort' (polaris/hub-p1/NetworkUSBPowerPort/USBPowerPort):
{'acquired': None,
'avail': True,
'cls': 'NetworkUSBPowerPort',
'params': {'busnum': 1,
'devnum': 95,
'host': 'polaris',
'index': 1,
'model_id': 1544,
'path': '1-2',
'vendor_id': 1507}}
Acquired resource 'USBSerialPort' (polaris/hub-p2/NetworkSerialPort/USBSerialPort):
{'acquired': None,
'avail': True,
'cls': 'NetworkSerialPort',
'params': {'extra': {'path': '/dev/ttyUSB0'},
'host': 'polaris',
'port': 52363}}
Acquired resource 'USBSDMuxDevice' (polaris/hub-p3/NetworkUSBSDMuxDevice/USBSDMuxDevice):
{'acquired': None,
'avail': True,
'cls': 'NetworkUSBSDMuxDevice',
'params': {'busnum': 1,
'control_path': '/dev/sg1',
'devnum': 98,
'host': 'polaris',
'model_id': 16449,
'path': '/dev/sdb',
'vendor_id': 1060}}
$ labgrid-client who
User Host Place Changed
jluebbe polaris demo1 2018-03-20 15:50:18.413377
$ labgrid-client -p demo1 sd-mux dut
Success
$ labgrid-client -p demo1 power cycle
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
Sent power off request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Current status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0000 off
Sent power on request
New status for hub 1-2 [05e3:0608 USB2.0 Hub, USB 2.10, 4 ports]
Port 1: 0100 power
$ labgrid-client -p demo1 console
connecting to NetworkSerialPort(target=Target(name='demo1', env=None), name='USBSerialPort', state=<BindingState.bound: 1>, avail=True, host='polaris', port=52363, speed=115200, protocol='rfc2217') calling microcom -s 115200 -t polaris:52363
connected to 127.0.1.1 (port 52363)
Escape character: Ctrl-\
Type the escape character followed by c to get to the menu or q to quit


barebox 2018.03.0-20180308-1 #1 Thu Mar 8 17:11:54 CET 2018


Board: RaspberryPi 3 Model B
bcm2835_mci 3f300000.sdhci: registered as 3f300000.sdhci
bcm2835-gpio 3f200000.gpio: probed gpiochip-1 with base 0
pitft@0-2: setting up native-CS0 as GPIO 8
fbtft_of_value: buswidth = 8
fbtft_of_value: debug = 4294967295
fbtft_of_value: rotate = 0
fbtft_of_value: fps = 25
mci0: detected SD card version 2.0
mci0: registered disk0
state: New state registered 'state'
state: Using bucket 0@0x00000000
malloc space: 0x0fefe3c0 -> 0x1fdfc77f (size 255 MiB)
bcm2835_fb bcm2835_fb0: registered

Hit any key to stop autoboot:
barebox@RaspberryPi 3 Model B:/

Remote pytest Example
---------------------

Run ``pytest --lg-env remote.yaml -v``.
You should get output very similar to the local pytest example above.
70 changes: 70 additions & 0 deletions examples/usbpower/examplestrategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import enum

import attr

from labgrid.driver import BareboxDriver, ShellDriver, USBSDMuxDriver
from labgrid.factory import target_factory
from labgrid.protocol import PowerProtocol
from labgrid.step import step
from labgrid.strategy import Strategy


@attr.s(cmp=False)
class StrategyError(Exception):
msg = attr.ib(validator=attr.validators.instance_of(str))


class Status(enum.Enum):
unknown = 0
barebox = 1
shell = 2


@target_factory.reg_driver
@attr.s(cmp=False)
class ExampleStrategy(Strategy):
"""ExampleStrategy - Strategy to for the usbpower labgrid example"""
bindings = {
"power": PowerProtocol,
"sdmux": USBSDMuxDriver,
"barebox": BareboxDriver,
"shell": ShellDriver,
}

status = attr.ib(default=Status.unknown)

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

@step(args=['status'])
def transition(self, status, *, step):
if not isinstance(status, Status):
status = Status[status]
if status == Status.unknown:
raise StrategyError("can not transition to {}".format(status))
elif status == self.status:
step.skip("nothing to do")
return # nothing to do
elif status == Status.barebox:
self.target.activate(self.power)
self.target.activate(self.sdmux)
# power off
self.power.off()
# configure sd-mux
self.sdmux.set_mode('dut')
# cycle power
self.power.on()
# interrupt barebox
self.target.activate(self.barebox)
elif status == Status.shell:
# tansition to barebox
self.transition(Status.barebox)
self.barebox.boot("")
self.barebox.await_boot()
self.target.activate(self.shell)
else:
raise StrategyError(
"no transition found from {} to {}".
format(self.status, status)
)
self.status = status
26 changes: 26 additions & 0 deletions examples/usbpower/exports.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
hub-p1:
USBPowerPort:
match:
'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0'
index: 1
hub-p2:
USBPowerPort:
match:
'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0'
index: 2
USBSerialPort:
match:
'@ID_PATH': 'pci-0000:00:14.0-usb-0:2.2'
hub-p3:
USBPowerPort:
match:
'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0'
index: 3
USBSDMuxDevice:
match:
'@ID_PATH': 'pci-0000:00:14.0-usb-0:2.3'
hub-p4:
USBPowerPort:
match:
'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0'
index: 4
26 changes: 26 additions & 0 deletions examples/usbpower/local.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
targets:
main:
resources:
USBPowerPort:
match:
'ID_PATH': 'pci-0000:00:14.0-usb-0:2:1.0'
index: 1
USBSerialPort:
match:
'@ID_PATH': 'pci-0000:00:14.0-usb-0:2.2'
USBSDMuxDevice:
match:
'@ID_PATH': 'pci-0000:00:14.0-usb-0:2.3'
drivers:
USBPowerDriver: {}
USBSDMuxDriver: {}
SerialDriver: {}
BareboxDriver:
prompt: 'barebox@[^:]+:[^ ]+ '
ShellDriver:
prompt: 'root@\w+:[^ ]+ '
login_prompt: ' login: '
username: 'root'
ExampleStrategy: {}
imports:
- examplestrategy.py
18 changes: 18 additions & 0 deletions examples/usbpower/remote.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
targets:
main:
resources:
RemotePlace:
name: demo1
drivers:
USBPowerDriver: {}
USBSDMuxDriver: {}
SerialDriver: {}
BareboxDriver:
prompt: 'barebox@[^:]+:[^ ]+ '
ShellDriver:
prompt: 'root@\w+:[^ ]+ '
login_prompt: ' login: '
username: 'root'
ExampleStrategy: {}
imports:
- examplestrategy.py
Loading

0 comments on commit d31e404

Please sign in to comment.