Skip to content

Commit

Permalink
driver/powerdriver: ykushpower: board_name support
Browse files Browse the repository at this point in the history
When 6425df9 switched from pykush to
ykushcmd, support for the YKUSH 3 and YKUSH XS was lost. Restore support
for those boards by passing the board_name argument to ykushcmd. The
board_name is determined by the USB Product ID.

Added tests for YKUSHPowerPort and YKUSHPowerPort.

Signed-off-by: Paul Vittorino <[email protected]>
  • Loading branch information
PaulVittorino committed Dec 15, 2023
1 parent c4a0867 commit 411a818
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 14 deletions.
11 changes: 6 additions & 5 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,18 @@ Used by:

YKUSHPowerPort
++++++++++++++
A YKUSHPowerPort describes a YEPKIT YKUSH USB (HID) switchable USB hub.
A YKUSHPowerPort describes a YEPKIT YKUSH family USB (HID) switchable USB hub.
Models supported include YKUSH, YKUSH 3, and YKUSH XS.

.. code-block:: yaml
YKUSHPowerPort:
serial: YK12345
serial: Y3N12345
index: 1
The example describes port 1 on the YKUSH USB hub with the
serial "YK12345".
(use "ykushcmd -l" to get your serial...)
The example describes port 1 on the YKUSH 3 USB hub with the
serial "Y3N12345".
(use "ykushcmd ykush3 -l" to get your serial...)

Arguments:
- serial (str): serial number of the YKUSH hub
Expand Down
23 changes: 23 additions & 0 deletions labgrid/driver/powerdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..util.helper import processwrapper
from .common import Driver
from .exception import ExecutionError
from ..exceptions import InvalidConfigError


@attr.s(eq=False)
Expand Down Expand Up @@ -283,11 +284,31 @@ def __attrs_post_init__(self):
else:
self.tool = 'ykushcmd'

def on_activate(self):
# Product ID (PID): 0xF0CD
# https://www.yepkit.com/uploads/documents/41cce_YKUSHXS_ProductManual_v0.0.1.pdf
if self.port.model_id == 0xf0cd:
self.board_name = "ykushxs"
# "The board USB control device can be accessed by the USB host using
# the Vendor ID (VID) and Product ID (PID), which is 0x04D8 and
# 0xF11B respectively"
# https://www.yepkit.com/uploads/documents/9f39a_ykush3-datasheet.pdf
elif self.port.model_id == 0xf11b:
self.board_name = "ykush3"
# Product ID (PID): 0xF2F7
# https://www.yepkit.com/uploads/documents/e9f11_YKUSH_ProductManual_v1.1.1.pdf
elif self.port.model_id == 0xf2f7:
self.board_name = "ykush"
else:
raise InvalidConfigError("Unknown YKUSH device {:04x}".format(self.port.model_id))


@Driver.check_active
@step()
def on(self):
cmd = [
self.tool,
f"{self.board_name}",
"-s", f"{self.port.serial}",
"-u", f"{self.port.index}"
]
Expand All @@ -298,6 +319,7 @@ def on(self):
def off(self):
cmd = [
self.tool,
f"{self.board_name}",
"-s", f"{self.port.serial}",
"-d", f"{self.port.index}"
]
Expand All @@ -314,6 +336,7 @@ def cycle(self):
def get(self):
cmd = [
self.tool,
f"{self.board_name}",
"-s", f"{self.port.serial}",
"-g", f"{self.port.index}"
]
Expand Down
41 changes: 34 additions & 7 deletions labgrid/resource/ykushpowerport.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,56 @@
import attr

from ..factory import target_factory
from .common import NetworkResource, Resource
from .remote import RemoteUSBResource
from .udev import USBResource


@target_factory.reg_resource
@attr.s(eq=False)
class YKUSHPowerPort(Resource):
class YKUSHPowerPort(USBResource):
"""This resource describes a YEPKIT YKUSH switchable USB hub.
Args:
serial (str): serial of the YKUSH device
index (int): port index"""
serial = attr.ib(validator=attr.validators.instance_of(str))
index = attr.ib(validator=attr.validators.instance_of(int),
serial = attr.ib(default=None, validator=attr.validators.instance_of(str))
index = attr.ib(default=None, validator=attr.validators.instance_of(int),
converter=int)

def filter_match(self, device):
if device.properties.get('ID_VENDOR_ID') != "04d8":
return False

# https://www.yepkit.com/uploads/documents/41cce_YKUSHXS_ProductManual_v0.0.1.pdf
# Vendor ID (VID): 0x04D8
# Product ID (PID): 0xF0CD

# https://www.yepkit.com/uploads/documents/e9f11_YKUSH_ProductManual_v1.1.1.pdf
# Vendor ID (VID): 0x04D8
# Product ID (PID): 0xF2F7

# "The board USB control device can be accessed by the USB host using
# the Vendor ID (VID) and Product ID (PID), which is 0x04D8 and
# 0xF11B respectively"
# https://www.yepkit.com/uploads/documents/9f39a_ykush3-datasheet.pdf

if device.properties.get('ID_MODEL_ID') not in ["f0cd", "f11b", "f2f7"]:
return False

if device.properties.get('ID_SERIAL_SHORT') != self.serial:
return False

return super().filter_match(device)


@target_factory.reg_resource
@attr.s(eq=False)
class NetworkYKUSHPowerPort(NetworkResource):
class NetworkYKUSHPowerPort(RemoteUSBResource):
""""This resource describes a remote YEPKIT YKUSH switchable USB hub.
Args:
serial (str): serial of the YKUSH device
index (int): port index"""
serial = attr.ib(validator=attr.validators.instance_of(str))
index = attr.ib(validator=attr.validators.instance_of(int),
serial = attr.ib(default=None, validator=attr.validators.instance_of(str))
index = attr.ib(default=None, validator=attr.validators.instance_of(int),
converter=int)
49 changes: 47 additions & 2 deletions tests/test_powerdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

import pytest

from labgrid.resource import NetworkPowerPort
from labgrid.driver.powerdriver import ExternalPowerDriver, ManualPowerDriver, NetworkPowerDriver
from labgrid.resource import NetworkPowerPort, YKUSHPowerPort
from labgrid.driver.powerdriver import (
ExternalPowerDriver,
ManualPowerDriver,
NetworkPowerDriver,
YKUSHPowerDriver,
)
from labgrid.util.helper import processwrapper


class TestManualPowerDriver:
Expand Down Expand Up @@ -264,3 +270,42 @@ def test_import_backend_tplink(self):
def test_import_backend_siglent(self):
pytest.importorskip("vxi11")
import labgrid.driver.power.siglent

class TestYKUSHPowerDriver:
FAKE_SERIAL = 'YK12345'
def test_create(self, target):
resource = YKUSHPowerPort(target, 'power', serial=self.FAKE_SERIAL, index=1)
device = YKUSHPowerDriver(target, 'power')
assert isinstance(device, YKUSHPowerDriver)

def test_default_off(self, target, mocker):
check_call_mock = mocker.patch(
'labgrid.util.helper.processwrapper.check_output'
)
model_id_mock = mocker.patch('labgrid.resource.ykushpowerport.YKUSHPowerPort.model_id', new_callable=mocker.PropertyMock)
model_id_mock.return_value = 0xf2f7
resource = YKUSHPowerPort(target, 'power', serial=self.FAKE_SERIAL, index=2)
resource.avail = True
device = YKUSHPowerDriver(target, 'power')
target.activate(device)
device.off()

check_call_mock.assert_called_with(
['ykushcmd', 'ykush', '-s', self.FAKE_SERIAL, '-d', '2']
)

def test_ykush3_on(self, target, mocker):
check_call_mock = mocker.patch(
'labgrid.util.helper.processwrapper.check_output'
)
model_id_mock = mocker.patch('labgrid.resource.ykushpowerport.YKUSHPowerPort.model_id', new_callable=mocker.PropertyMock)
model_id_mock.return_value = 0xf11b
resource = YKUSHPowerPort(target, 'power', serial=self.FAKE_SERIAL, index=3)
resource.avail = True
device = YKUSHPowerDriver(target, 'power')
target.activate(device)
device.on()

check_call_mock.assert_called_with(
['ykushcmd', 'ykush3', '-s', self.FAKE_SERIAL, '-u', '3']
)

0 comments on commit 411a818

Please sign in to comment.