Merge "pynetlink - Add support to configure pin via Netlink"
This commit is contained in:
@@ -13,6 +13,7 @@ from ..common import NetlinkException
|
|||||||
from ..common import NetlinkFactory
|
from ..common import NetlinkFactory
|
||||||
from .constants import DeviceFields
|
from .constants import DeviceFields
|
||||||
from .constants import PinFields
|
from .constants import PinFields
|
||||||
|
from .constants import PinParentFields
|
||||||
from .devices import DpllDevice
|
from .devices import DpllDevice
|
||||||
from .devices import DpllDevices
|
from .devices import DpllDevices
|
||||||
from .pins import DpllPins
|
from .pins import DpllPins
|
||||||
@@ -23,6 +24,7 @@ class DPLLCommands:
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
DEVICE_GET = 'device-get'
|
DEVICE_GET = 'device-get'
|
||||||
PIN_GET = 'pin-get'
|
PIN_GET = 'pin-get'
|
||||||
|
PIN_SET = 'pin-set'
|
||||||
|
|
||||||
|
|
||||||
class NetlinkDPLL:
|
class NetlinkDPLL:
|
||||||
@@ -177,3 +179,73 @@ class NetlinkDPLL:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return DpllPins.loadPins(self._get_all_devices(), self._get_all_pins())
|
return DpllPins.loadPins(self._get_all_devices(), self._get_all_pins())
|
||||||
|
|
||||||
|
def _set_pin(self, pin_info: dict):
|
||||||
|
"""Change the pin configuration.
|
||||||
|
|
||||||
|
Changes the pin configuration according to the given pin information.
|
||||||
|
Not all pin field are mutable, use _get_pin_by_id() to print the pin
|
||||||
|
capabilities, and check which pin fields can be changed.
|
||||||
|
|
||||||
|
Raises NetlinkException class in case of error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = self._ynl.do(DPLLCommands.PIN_SET, pin_info)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except NlError as e:
|
||||||
|
raise NetlinkException(e)
|
||||||
|
|
||||||
|
def set_pin_direction(self, pin_id: int, pin_direction: int):
|
||||||
|
"""Change pin direction.
|
||||||
|
|
||||||
|
Change the pin direction. All pin parents are changed at the same time.
|
||||||
|
|
||||||
|
Raises NetlinkException class in case of error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pin_info = {
|
||||||
|
PinFields.ID: pin_id,
|
||||||
|
PinFields.PARENT_DEVICE: []
|
||||||
|
}
|
||||||
|
|
||||||
|
# get pin's parent ids, and set the direction in all of them.
|
||||||
|
pins = self.get_pins_by_id(pin_id)
|
||||||
|
parent_ids = list(pin.dev_id for pin in pins)
|
||||||
|
for parent_id in parent_ids:
|
||||||
|
pin_info[PinFields.PARENT_DEVICE].append(
|
||||||
|
{
|
||||||
|
PinParentFields.PARENT_ID: parent_id,
|
||||||
|
PinParentFields.DIRECTION: pin_direction
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._set_pin(pin_info)
|
||||||
|
|
||||||
|
def set_pin_priority(self, pin_id: int, pin_priority: int):
|
||||||
|
"""Change pin priority
|
||||||
|
|
||||||
|
Change the pin priority. All pin parents are changed at the same time.
|
||||||
|
|
||||||
|
Raises NetlinkException class in case of error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pin_info = {
|
||||||
|
PinFields.ID: pin_id,
|
||||||
|
PinFields.PARENT_DEVICE: []
|
||||||
|
}
|
||||||
|
|
||||||
|
# get pin's parent ids, and set the priority in all of them.
|
||||||
|
pins = self.get_pins_by_id(pin_id)
|
||||||
|
parent_ids = list(pin.dev_id for pin in pins)
|
||||||
|
for parent_id in parent_ids:
|
||||||
|
pin_info[PinFields.PARENT_DEVICE].append(
|
||||||
|
{
|
||||||
|
PinParentFields.PARENT_ID: parent_id,
|
||||||
|
PinParentFields.PRIORITY: pin_priority
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._set_pin(pin_info)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from ..dpll import DpllDevice
|
|||||||
from ..dpll import DeviceFields
|
from ..dpll import DeviceFields
|
||||||
from ..dpll import DpllPins
|
from ..dpll import DpllPins
|
||||||
from ..dpll import PinFields
|
from ..dpll import PinFields
|
||||||
|
from ..dpll import PinParentFields
|
||||||
|
|
||||||
|
|
||||||
class NetlinkDPLLTestCase(TestCase):
|
class NetlinkDPLLTestCase(TestCase):
|
||||||
@@ -157,6 +158,9 @@ class NetlinkDPLLTestCase(TestCase):
|
|||||||
f'#items: Should be {len(expected_device_ids)} Got {len(devices)}')
|
f'#items: Should be {len(expected_device_ids)} Got {len(devices)}')
|
||||||
|
|
||||||
for device in devices:
|
for device in devices:
|
||||||
|
self.assertEqual(device.dev_clock_id,
|
||||||
|
clock_id,
|
||||||
|
f"Wrong clock ID: Expected {clock_id}. Got {device.dev_clock_id}")
|
||||||
self.assertIn(device.dev_id,
|
self.assertIn(device.dev_id,
|
||||||
expected_device_ids,
|
expected_device_ids,
|
||||||
f'Contains wrong device: {device.dev_id}')
|
f'Contains wrong device: {device.dev_id}')
|
||||||
@@ -242,8 +246,8 @@ class NetlinkDPLLTestCase(TestCase):
|
|||||||
@patch.object(YnlFamily, 'dump')
|
@patch.object(YnlFamily, 'dump')
|
||||||
def test_get_pins_with_specific_id(self, mock_ynl_dump: Mock, mock_ynl_do: Mock):
|
def test_get_pins_with_specific_id(self, mock_ynl_dump: Mock, mock_ynl_do: Mock):
|
||||||
|
|
||||||
pin_pict_idx = random.randint(0, 8)
|
pin_dict_idx = random.randint(0, 8)
|
||||||
pin_dict = self.dump_get_pins[pin_pict_idx]
|
pin_dict = self.dump_get_pins[pin_dict_idx]
|
||||||
pin_id = pin_dict[PinFields.ID]
|
pin_id = pin_dict[PinFields.ID]
|
||||||
|
|
||||||
mock_ynl_dump.return_value = self.dump_get_devices
|
mock_ynl_dump.return_value = self.dump_get_devices
|
||||||
@@ -283,6 +287,9 @@ class NetlinkDPLLTestCase(TestCase):
|
|||||||
f'Should return DpllPins instance. Got {type(pins)}')
|
f'Should return DpllPins instance. Got {type(pins)}')
|
||||||
|
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
self.assertEqual(pin.dev_clock_id,
|
||||||
|
clock_id,
|
||||||
|
f"Wrong clock ID: Expected {clock_id}. Got {pin.dev_clock_id}")
|
||||||
self.assertIn(pin.pin_id,
|
self.assertIn(pin.pin_id,
|
||||||
expected_pin_ids,
|
expected_pin_ids,
|
||||||
f'Contains wrong pin: {pin.pin_id}')
|
f'Contains wrong pin: {pin.pin_id}')
|
||||||
@@ -311,3 +318,158 @@ class NetlinkDPLLTestCase(TestCase):
|
|||||||
call(DPLLCommands.DEVICE_GET, {}),
|
call(DPLLCommands.DEVICE_GET, {}),
|
||||||
call(DPLLCommands.PIN_GET, {})
|
call(DPLLCommands.PIN_GET, {})
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@patch.object(YnlFamily, 'do')
|
||||||
|
def test_set_pin(self, mock_ynl_do: Mock):
|
||||||
|
|
||||||
|
expected_result = None
|
||||||
|
mock_ynl_do.return_value = expected_result
|
||||||
|
pin_info = {
|
||||||
|
'id': 34,
|
||||||
|
'parent-device': [
|
||||||
|
{
|
||||||
|
'parent-id': 2,
|
||||||
|
'direction': 1,
|
||||||
|
'priority': 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'parent-id': 3,
|
||||||
|
'direction': 1,
|
||||||
|
'priority': 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
dpll = NetlinkDPLL()
|
||||||
|
result = dpll._set_pin(pin_info) # pylint: disable=W0212
|
||||||
|
|
||||||
|
self.assertEqual(expected_result,
|
||||||
|
result,
|
||||||
|
f'Wrong _set_pin result: '
|
||||||
|
f'Expected {expected_result}. Got {result}')
|
||||||
|
|
||||||
|
mock_ynl_do.assert_called_once_with(DPLLCommands.PIN_SET, pin_info)
|
||||||
|
|
||||||
|
@patch.object(YnlFamily, 'do')
|
||||||
|
@patch.object(YnlFamily, 'dump')
|
||||||
|
def test_set_pin_direction(self, mock_ynl_dump: Mock, mock_ynl_do: Mock):
|
||||||
|
|
||||||
|
pin_dict_idx = random.randint(0, 8)
|
||||||
|
pin_dict = self.dump_get_pins[pin_dict_idx]
|
||||||
|
pin_id = pin_dict[PinFields.ID]
|
||||||
|
pin_direction = random.randint(0, 2)
|
||||||
|
parent_ids = list(parent[PinParentFields.PARENT_ID]
|
||||||
|
for parent in pin_dict[PinFields.PARENT_DEVICE])
|
||||||
|
expected_result = None
|
||||||
|
|
||||||
|
mock_ynl_dump.return_value = self.dump_get_devices
|
||||||
|
mock_ynl_do.side_effect = [pin_dict, None]
|
||||||
|
|
||||||
|
dpll = NetlinkDPLL()
|
||||||
|
result = dpll.set_pin_direction(pin_id, pin_direction)
|
||||||
|
|
||||||
|
self.assertEqual(expected_result,
|
||||||
|
result,
|
||||||
|
f'Wrong _set_pin result: '
|
||||||
|
f'Expected {expected_result}. Got {result}')
|
||||||
|
|
||||||
|
mock_ynl_dump.assert_called_once_with(DPLLCommands.DEVICE_GET, {})
|
||||||
|
|
||||||
|
# Verify the do pin-set command call.
|
||||||
|
args, _ = mock_ynl_do.call_args
|
||||||
|
call_command = args[0]
|
||||||
|
self.assertEqual(DPLLCommands.PIN_SET,
|
||||||
|
call_command,
|
||||||
|
f'Wrong do command: '
|
||||||
|
f'Expected {DPLLCommands.PIN_SET}. Got {call_command}')
|
||||||
|
|
||||||
|
call_args = args[1]
|
||||||
|
sorted_call_args = {
|
||||||
|
PinFields.ID: call_args[PinFields.ID],
|
||||||
|
PinFields.PARENT_DEVICE: sorted(
|
||||||
|
call_args[PinFields.PARENT_DEVICE],
|
||||||
|
key=lambda x: x[PinParentFields.PARENT_ID]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
expected_call_args = {
|
||||||
|
PinFields.ID: pin_id,
|
||||||
|
PinFields.PARENT_DEVICE: list(
|
||||||
|
{
|
||||||
|
PinParentFields.PARENT_ID: id,
|
||||||
|
PinParentFields.DIRECTION: pin_direction
|
||||||
|
}
|
||||||
|
for id in sorted(parent_ids)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.assertDictEqual(sorted_call_args,
|
||||||
|
expected_call_args,
|
||||||
|
f'Wrong call arguments: '
|
||||||
|
f'Expected {expected_call_args}. Got {sorted_call_args}')
|
||||||
|
|
||||||
|
@patch.object(YnlFamily, 'do')
|
||||||
|
@patch.object(YnlFamily, 'dump')
|
||||||
|
def test_set_pin_priority(self, mock_ynl_dump: Mock, mock_ynl_do: Mock):
|
||||||
|
|
||||||
|
pin_dict_idx = random.randint(0, 8)
|
||||||
|
pin_dict = self.dump_get_pins[pin_dict_idx]
|
||||||
|
pin_id = pin_dict[PinFields.ID]
|
||||||
|
pin_priority = random.randint(0, 7)
|
||||||
|
pin_info = {
|
||||||
|
PinFields.ID: pin_id,
|
||||||
|
PinFields.PARENT_DEVICE: []
|
||||||
|
}
|
||||||
|
parent_ids = list(parent[PinParentFields.PARENT_ID]
|
||||||
|
for parent in pin_dict[PinFields.PARENT_DEVICE])
|
||||||
|
for parent_id in parent_ids:
|
||||||
|
pin_info[PinFields.PARENT_DEVICE].append(
|
||||||
|
{
|
||||||
|
PinParentFields.PARENT_ID: parent_id,
|
||||||
|
PinParentFields.PRIORITY: pin_priority
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expected_result = None
|
||||||
|
|
||||||
|
mock_ynl_dump.return_value = self.dump_get_devices
|
||||||
|
mock_ynl_do.side_effect = [pin_dict, None]
|
||||||
|
|
||||||
|
dpll = NetlinkDPLL()
|
||||||
|
result = dpll.set_pin_priority(pin_id, pin_priority)
|
||||||
|
|
||||||
|
self.assertEqual(expected_result,
|
||||||
|
result,
|
||||||
|
f'Wrong _set_pin result: '
|
||||||
|
f'Expected {expected_result}. Got {result}')
|
||||||
|
|
||||||
|
mock_ynl_dump.assert_called_once_with(DPLLCommands.DEVICE_GET, {})
|
||||||
|
|
||||||
|
# Verify the do pin-set command call.
|
||||||
|
args, _ = mock_ynl_do.call_args
|
||||||
|
call_command = args[0]
|
||||||
|
# Verify the command is pin-set
|
||||||
|
self.assertEqual(DPLLCommands.PIN_SET,
|
||||||
|
call_command,
|
||||||
|
f'Wrong do command: '
|
||||||
|
f'Expected {DPLLCommands.PIN_SET}. Got {call_command}')
|
||||||
|
# Verify the pin id
|
||||||
|
call_args = args[1]
|
||||||
|
sorted_call_args = {
|
||||||
|
PinFields.ID: call_args[PinFields.ID],
|
||||||
|
PinFields.PARENT_DEVICE: sorted(
|
||||||
|
call_args[PinFields.PARENT_DEVICE],
|
||||||
|
key=lambda x: x[PinParentFields.PARENT_ID]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
expected_call_args = {
|
||||||
|
PinFields.ID: pin_id,
|
||||||
|
PinFields.PARENT_DEVICE: list(
|
||||||
|
{
|
||||||
|
PinParentFields.PARENT_ID: id,
|
||||||
|
PinParentFields.PRIORITY: pin_priority
|
||||||
|
}
|
||||||
|
for id in sorted(parent_ids)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.assertDictEqual(sorted_call_args,
|
||||||
|
expected_call_args,
|
||||||
|
f'Wrong call arguments: '
|
||||||
|
f'Expected {expected_call_args}. Got {sorted_call_args}')
|
||||||
|
|||||||
Reference in New Issue
Block a user