diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 333380a6f..ae60c5754 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -881,16 +881,25 @@ class VectorChannelConfig(NamedTuple): transceiverName: str -def get_channel_configs() -> List[VectorChannelConfig]: +def _get_xl_driver_config() -> xlclass.XLdriverConfig: if xldriver is None: - return [] + raise VectorError( + error_code=xldefine.XL_Status.XL_ERR_DLL_NOT_FOUND, + error_string="xldriver is unavailable", + function="_get_xl_driver_config", + ) driver_config = xlclass.XLdriverConfig() + xldriver.xlOpenDriver() + xldriver.xlGetDriverConfig(driver_config) + xldriver.xlCloseDriver() + return driver_config + + +def get_channel_configs() -> List[VectorChannelConfig]: try: - xldriver.xlOpenDriver() - xldriver.xlGetDriverConfig(driver_config) - xldriver.xlCloseDriver() + driver_config = _get_xl_driver_config() except VectorError: - pass + return [] channel_list: List[VectorChannelConfig] = [] for i in range(driver_config.channelCount): diff --git a/test/test_vector.py b/test/test_vector.py index 338783136..c4ae21f4e 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -5,9 +5,9 @@ """ import ctypes -import os +import functools import pickle -import unittest +import time from unittest.mock import Mock import pytest @@ -24,332 +24,792 @@ ) from test.config import IS_WINDOWS +XLDRIVER_FOUND = canlib.xldriver is not None -class TestVectorBus(unittest.TestCase): - def setUp(self) -> None: - # basic mock for XLDriver - can.interfaces.vector.canlib.xldriver = Mock() - - # bus creation functions - can.interfaces.vector.canlib.xldriver.xlOpenDriver = Mock() - can.interfaces.vector.canlib.xldriver.xlGetApplConfig = Mock( - side_effect=xlGetApplConfig - ) - can.interfaces.vector.canlib.xldriver.xlGetChannelIndex = Mock( - side_effect=xlGetChannelIndex - ) - can.interfaces.vector.canlib.xldriver.xlOpenPort = Mock(side_effect=xlOpenPort) - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration = Mock( - return_value=0 - ) - can.interfaces.vector.canlib.xldriver.xlCanSetChannelMode = Mock(return_value=0) - can.interfaces.vector.canlib.xldriver.xlActivateChannel = Mock(return_value=0) - can.interfaces.vector.canlib.xldriver.xlGetSyncTime = Mock( - side_effect=xlGetSyncTime - ) - can.interfaces.vector.canlib.xldriver.xlCanSetChannelAcceptance = Mock( - return_value=0 - ) - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate = Mock( - return_value=0 - ) - can.interfaces.vector.canlib.xldriver.xlSetNotification = Mock( - side_effect=xlSetNotification - ) - - # bus deactivation functions - can.interfaces.vector.canlib.xldriver.xlDeactivateChannel = Mock(return_value=0) - can.interfaces.vector.canlib.xldriver.xlClosePort = Mock(return_value=0) - can.interfaces.vector.canlib.xldriver.xlCloseDriver = Mock() - - # sender functions - can.interfaces.vector.canlib.xldriver.xlCanTransmit = Mock(return_value=0) - can.interfaces.vector.canlib.xldriver.xlCanTransmitEx = Mock(return_value=0) - - # various functions - can.interfaces.vector.canlib.xldriver.xlCanFlushTransmitQueue = Mock() - can.interfaces.vector.canlib.WaitForSingleObject = Mock() - - self.bus = None - - def tearDown(self) -> None: - if self.bus: - self.bus.shutdown() - self.bus = None - - def test_bus_creation(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.assertIsInstance(self.bus, canlib.VectorBus) - can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() - can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() - - can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() - xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] - self.assertEqual( - xlOpenPort_args[5], xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION.value - ) - self.assertEqual(xlOpenPort_args[6], xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value) - - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_not_called() - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() - - def test_bus_creation_bitrate(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", bitrate=200000, _testing=True) - self.assertIsInstance(self.bus, canlib.VectorBus) - can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() - can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() - - can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() - xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] - self.assertEqual( - xlOpenPort_args[5], xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION.value - ) - self.assertEqual(xlOpenPort_args[6], xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value) - - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_not_called() - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_called() - xlCanSetChannelBitrate_args = ( - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.call_args[0] - ) - self.assertEqual(xlCanSetChannelBitrate_args[2], 200000) - - def test_bus_creation_fd(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) - self.assertIsInstance(self.bus, canlib.VectorBus) - can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() - can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() - - can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() - xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] - self.assertEqual( - xlOpenPort_args[5], - xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4.value, - ) - self.assertEqual(xlOpenPort_args[6], xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value) - - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_called() - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() - - def test_bus_creation_fd_bitrate_timings(self) -> None: - self.bus = can.Bus( - channel=0, - bustype="vector", - fd=True, - bitrate=500000, - data_bitrate=2000000, - sjw_abr=10, - tseg1_abr=11, - tseg2_abr=12, - sjw_dbr=13, - tseg1_dbr=14, - tseg2_dbr=15, - _testing=True, - ) - self.assertIsInstance(self.bus, canlib.VectorBus) - can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() - can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() - - can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() - xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] - self.assertEqual( - xlOpenPort_args[5], - xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4.value, - ) - self.assertEqual(xlOpenPort_args[6], xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value) - - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_called() - can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() - - xlCanFdSetConfiguration_args = ( - can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.call_args[0] - ) - canFdConf = xlCanFdSetConfiguration_args[2] - self.assertEqual(canFdConf.arbitrationBitRate, 500000) - self.assertEqual(canFdConf.dataBitRate, 2000000) - self.assertEqual(canFdConf.sjwAbr, 10) - self.assertEqual(canFdConf.tseg1Abr, 11) - self.assertEqual(canFdConf.tseg2Abr, 12) - self.assertEqual(canFdConf.sjwDbr, 13) - self.assertEqual(canFdConf.tseg1Dbr, 14) - self.assertEqual(canFdConf.tseg2Dbr, 15) - - def test_receive(self) -> None: - can.interfaces.vector.canlib.xldriver.xlReceive = Mock(side_effect=xlReceive) - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.bus.recv(timeout=0.05) - can.interfaces.vector.canlib.xldriver.xlReceive.assert_called() - can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_not_called() - - def test_receive_fd(self) -> None: - can.interfaces.vector.canlib.xldriver.xlCanReceive = Mock( - side_effect=xlCanReceive - ) - self.bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) - self.bus.recv(timeout=0.05) - can.interfaces.vector.canlib.xldriver.xlReceive.assert_not_called() - can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_called() - - def test_receive_non_msg_event(self) -> None: - can.interfaces.vector.canlib.xldriver.xlReceive = Mock( - side_effect=xlReceive_chipstate - ) - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.bus.handle_can_event = Mock() - self.bus.recv(timeout=0.05) - can.interfaces.vector.canlib.xldriver.xlReceive.assert_called() - can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_not_called() - self.bus.handle_can_event.assert_called() - - def test_receive_fd_non_msg_event(self) -> None: - can.interfaces.vector.canlib.xldriver.xlCanReceive = Mock( - side_effect=xlCanReceive_chipstate - ) - self.bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) - self.bus.handle_canfd_event = Mock() - self.bus.recv(timeout=0.05) - can.interfaces.vector.canlib.xldriver.xlReceive.assert_not_called() - can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_called() - self.bus.handle_canfd_event.assert_called() - - def test_send(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - msg = can.Message( - arbitration_id=0xC0FFEF, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=True - ) - self.bus.send(msg) - can.interfaces.vector.canlib.xldriver.xlCanTransmit.assert_called() - can.interfaces.vector.canlib.xldriver.xlCanTransmitEx.assert_not_called() - - def test_send_fd(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) - msg = can.Message( - arbitration_id=0xC0FFEF, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=True - ) - self.bus.send(msg) - can.interfaces.vector.canlib.xldriver.xlCanTransmit.assert_not_called() - can.interfaces.vector.canlib.xldriver.xlCanTransmitEx.assert_called() - - def test_flush_tx_buffer(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.bus.flush_tx_buffer() - can.interfaces.vector.canlib.xldriver.xlCanFlushTransmitQueue.assert_called() - - def test_shutdown(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.bus.shutdown() - can.interfaces.vector.canlib.xldriver.xlDeactivateChannel.assert_called() - can.interfaces.vector.canlib.xldriver.xlClosePort.assert_called() - can.interfaces.vector.canlib.xldriver.xlCloseDriver.assert_called() - - def test_reset(self) -> None: - self.bus = can.Bus(channel=0, bustype="vector", _testing=True) - self.bus.reset() - can.interfaces.vector.canlib.xldriver.xlDeactivateChannel.assert_called() - can.interfaces.vector.canlib.xldriver.xlActivateChannel.assert_called() - - def test_popup_hw_cfg(self) -> None: - canlib.xldriver.xlPopupHwConfig = Mock() - canlib.VectorBus.popup_vector_hw_configuration(10) - assert canlib.xldriver.xlPopupHwConfig.called - args, kwargs = canlib.xldriver.xlPopupHwConfig.call_args - assert isinstance(args[0], ctypes.c_char_p) - assert isinstance(args[1], ctypes.c_uint) - - def test_get_application_config(self) -> None: - canlib.xldriver.xlGetApplConfig = Mock() - canlib.VectorBus.get_application_config(app_name="CANalyzer", app_channel=0) - assert canlib.xldriver.xlGetApplConfig.called - - def test_set_application_config(self) -> None: - canlib.xldriver.xlSetApplConfig = Mock() - canlib.VectorBus.set_application_config( - app_name="CANalyzer", - app_channel=0, - hw_type=xldefine.XL_HardwareType.XL_HWTYPE_VN1610, - hw_index=0, - hw_channel=0, - ) - assert canlib.xldriver.xlSetApplConfig.called - - def test_set_timer_rate(self) -> None: - canlib.xldriver.xlSetTimerRate = Mock() - bus: canlib.VectorBus = can.Bus( - channel=0, bustype="vector", fd=True, _testing=True - ) - bus.set_timer_rate(timer_rate_ms=1) - assert canlib.xldriver.xlSetTimerRate.called - - def test_called_without_testing_argument(self) -> None: - """This tests if an exception is thrown when we are not running on Windows.""" - if os.name != "nt": - with self.assertRaises(can.CanInterfaceNotImplementedError): - # do not set the _testing argument, since it would suppress the exception - can.Bus(channel=0, bustype="vector") - - def test_vector_error_pickle(self) -> None: - for error_type in [ - VectorError, - VectorInitializationError, - VectorOperationError, - ]: - with self.subTest(f"error_type = {error_type.__name__}"): - - error_code = 118 - error_string = "XL_ERROR" - function = "function_name" - - exc = error_type(error_code, error_string, function) - - # pickle and unpickle - p = pickle.dumps(exc) - exc_unpickled: VectorError = pickle.loads(p) - - self.assertEqual(str(exc), str(exc_unpickled)) - self.assertEqual(error_code, exc_unpickled.error_code) - - with pytest.raises(error_type): - raise exc_unpickled - - def test_vector_subtype_error_from_generic(self) -> None: - for error_type in [VectorInitializationError, VectorOperationError]: - with self.subTest(f"error_type = {error_type.__name__}"): - - error_code = 118 - error_string = "XL_ERROR" - function = "function_name" - - generic = VectorError(error_code, error_string, function) - - # pickle and unpickle - specific: VectorError = error_type.from_generic(generic) - - self.assertEqual(str(generic), str(specific)) - self.assertEqual(error_code, specific.error_code) - - with pytest.raises(error_type): - raise specific - - @unittest.skipUnless(IS_WINDOWS, "Windows specific test") - def test_winapi_availability(self) -> None: - self.assertIsNotNone(canlib.WaitForSingleObject) - self.assertIsNotNone(canlib.INFINITE) - - -class TestVectorChannelConfig: - def test_attributes(self): - assert hasattr(VectorChannelConfig, "name") - assert hasattr(VectorChannelConfig, "hwType") - assert hasattr(VectorChannelConfig, "hwIndex") - assert hasattr(VectorChannelConfig, "hwChannel") - assert hasattr(VectorChannelConfig, "channelIndex") - assert hasattr(VectorChannelConfig, "channelMask") - assert hasattr(VectorChannelConfig, "channelCapabilities") - assert hasattr(VectorChannelConfig, "channelBusCapabilities") - assert hasattr(VectorChannelConfig, "isOnBus") - assert hasattr(VectorChannelConfig, "connectedBusType") - assert hasattr(VectorChannelConfig, "serialNumber") - assert hasattr(VectorChannelConfig, "articleNumber") - assert hasattr(VectorChannelConfig, "transceiverName") + +@pytest.fixture() +def mock_xldriver() -> None: + # basic mock for XLDriver + xldriver_mock = Mock() + + # bus creation functions + xldriver_mock.xlOpenDriver = Mock() + xldriver_mock.xlGetApplConfig = Mock(side_effect=xlGetApplConfig) + xldriver_mock.xlGetChannelIndex = Mock(side_effect=xlGetChannelIndex) + xldriver_mock.xlOpenPort = Mock(side_effect=xlOpenPort) + xldriver_mock.xlCanFdSetConfiguration = Mock(return_value=0) + xldriver_mock.xlCanSetChannelMode = Mock(return_value=0) + xldriver_mock.xlActivateChannel = Mock(return_value=0) + xldriver_mock.xlGetSyncTime = Mock(side_effect=xlGetSyncTime) + xldriver_mock.xlCanSetChannelAcceptance = Mock(return_value=0) + xldriver_mock.xlCanSetChannelBitrate = Mock(return_value=0) + xldriver_mock.xlSetNotification = Mock(side_effect=xlSetNotification) + + # bus deactivation functions + xldriver_mock.xlDeactivateChannel = Mock(return_value=0) + xldriver_mock.xlClosePort = Mock(return_value=0) + xldriver_mock.xlCloseDriver = Mock() + + # sender functions + xldriver_mock.xlCanTransmit = Mock(return_value=0) + xldriver_mock.xlCanTransmitEx = Mock(return_value=0) + + # various functions + xldriver_mock.xlCanFlushTransmitQueue = Mock() + + # backup unmodified values + real_xldriver = canlib.xldriver + real_waitforsingleobject = canlib.WaitForSingleObject + + # set mock + canlib.xldriver = xldriver_mock + canlib.HAS_EVENTS = False + + yield + + # cleanup + canlib.xldriver = real_xldriver + canlib.WaitForSingleObject = real_waitforsingleobject + + +def test_bus_creation_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", _testing=True) + assert isinstance(bus, canlib.VectorBus) + can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() + can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() + + can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() + xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] + assert xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION.value + assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value + + can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_not_called() + can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_bus_creation() -> None: + bus = can.Bus(channel=0, serial=_find_virtual_can_serial(), bustype="vector") + assert isinstance(bus, canlib.VectorBus) + bus.shutdown() + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert bus.channel_masks[0] == xl_channel_config.channelMask + assert ( + xl_channel_config.busParams.data.can.canOpMode + & xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CAN20 + ) + + bus = canlib.VectorBus(channel=0, serial=_find_virtual_can_serial()) + assert isinstance(bus, canlib.VectorBus) + bus.shutdown() + + +def test_bus_creation_bitrate_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", bitrate=200_000, _testing=True) + assert isinstance(bus, canlib.VectorBus) + can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() + can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() + + can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() + xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] + assert xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION.value + assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value + + can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_not_called() + can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_called() + xlCanSetChannelBitrate_args = ( + can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.call_args[0] + ) + assert xlCanSetChannelBitrate_args[2] == 200_000 + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_bus_creation_bitrate() -> None: + bus = can.Bus( + channel=0, serial=_find_virtual_can_serial(), bustype="vector", bitrate=200_000 + ) + assert isinstance(bus, canlib.VectorBus) + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert xl_channel_config.busParams.data.can.bitRate == 200_000 + + bus.shutdown() + + +def test_bus_creation_fd_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) + assert isinstance(bus, canlib.VectorBus) + can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() + can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() + + can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() + xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] + assert ( + xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4.value + ) + assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value + + can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_called() + can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_bus_creation_fd() -> None: + bus = can.Bus( + channel=0, serial=_find_virtual_can_serial(), bustype="vector", fd=True + ) + assert isinstance(bus, canlib.VectorBus) + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert ( + xl_channel_config.interfaceVersion + == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4 + ) + assert ( + xl_channel_config.busParams.data.canFD.canOpMode + & xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CANFD + ) + bus.shutdown() + + +def test_bus_creation_fd_bitrate_timings_mocked(mock_xldriver) -> None: + bus = can.Bus( + channel=0, + bustype="vector", + fd=True, + bitrate=500_000, + data_bitrate=2_000_000, + sjw_abr=10, + tseg1_abr=11, + tseg2_abr=12, + sjw_dbr=13, + tseg1_dbr=14, + tseg2_dbr=15, + _testing=True, + ) + assert isinstance(bus, canlib.VectorBus) + can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() + can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() + + can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called() + xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0] + assert ( + xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4.value + ) + + assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value + + can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_called() + can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called() + + xlCanFdSetConfiguration_args = ( + can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.call_args[0] + ) + canFdConf = xlCanFdSetConfiguration_args[2] + assert canFdConf.arbitrationBitRate == 500000 + assert canFdConf.dataBitRate == 2000000 + assert canFdConf.sjwAbr == 10 + assert canFdConf.tseg1Abr == 11 + assert canFdConf.tseg2Abr == 12 + assert canFdConf.sjwDbr == 13 + assert canFdConf.tseg1Dbr == 14 + assert canFdConf.tseg2Dbr == 15 + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_bus_creation_fd_bitrate_timings() -> None: + bus = can.Bus( + channel=0, + serial=_find_virtual_can_serial(), + bustype="vector", + fd=True, + bitrate=500_000, + data_bitrate=2_000_000, + sjw_abr=10, + tseg1_abr=11, + tseg2_abr=12, + sjw_dbr=13, + tseg1_dbr=14, + tseg2_dbr=15, + ) + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert ( + xl_channel_config.interfaceVersion + == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4 + ) + assert ( + xl_channel_config.busParams.data.canFD.canOpMode + & xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CANFD + ) + assert xl_channel_config.busParams.data.canFD.arbitrationBitRate == 500_000 + assert xl_channel_config.busParams.data.canFD.sjwAbr == 10 + assert xl_channel_config.busParams.data.canFD.tseg1Abr == 11 + assert xl_channel_config.busParams.data.canFD.tseg2Abr == 12 + assert xl_channel_config.busParams.data.canFD.sjwDbr == 13 + assert xl_channel_config.busParams.data.canFD.tseg1Dbr == 14 + assert xl_channel_config.busParams.data.canFD.tseg2Dbr == 15 + assert xl_channel_config.busParams.data.canFD.dataBitRate == 2_000_000 + + bus.shutdown() + + +def test_send_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", _testing=True) + msg = can.Message( + arbitration_id=0xC0FFEF, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=True + ) + bus.send(msg) + can.interfaces.vector.canlib.xldriver.xlCanTransmit.assert_called() + can.interfaces.vector.canlib.xldriver.xlCanTransmitEx.assert_not_called() + + +def test_send_fd_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) + msg = can.Message( + arbitration_id=0xC0FFEF, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=True + ) + bus.send(msg) + can.interfaces.vector.canlib.xldriver.xlCanTransmit.assert_not_called() + can.interfaces.vector.canlib.xldriver.xlCanTransmitEx.assert_called() + + +def test_receive_mocked(mock_xldriver) -> None: + can.interfaces.vector.canlib.xldriver.xlReceive = Mock(side_effect=xlReceive) + bus = can.Bus(channel=0, bustype="vector", _testing=True) + bus.recv(timeout=0.05) + can.interfaces.vector.canlib.xldriver.xlReceive.assert_called() + can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_not_called() + + +def test_receive_fd_mocked(mock_xldriver) -> None: + can.interfaces.vector.canlib.xldriver.xlCanReceive = Mock(side_effect=xlCanReceive) + bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) + bus.recv(timeout=0.05) + can.interfaces.vector.canlib.xldriver.xlReceive.assert_not_called() + can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_send_and_receive() -> None: + bus1 = can.Bus(channel=0, serial=_find_virtual_can_serial(), bustype="vector") + bus2 = can.Bus(channel=0, serial=_find_virtual_can_serial(), bustype="vector") + + msg_std = can.Message( + channel=0, arbitration_id=0xFF, data=list(range(8)), is_extended_id=False + ) + msg_ext = can.Message( + channel=0, arbitration_id=0xFFFFFF, data=list(range(8)), is_extended_id=True + ) + + bus1.send(msg_std) + msg_std_recv = bus2.recv(None) + assert msg_std.equals(msg_std_recv, timestamp_delta=None) + + bus1.send(msg_ext) + msg_ext_recv = bus2.recv(None) + assert msg_ext.equals(msg_ext_recv, timestamp_delta=None) + + bus1.shutdown() + bus2.shutdown() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_send_and_receive_fd() -> None: + bus1 = can.Bus( + channel=0, serial=_find_virtual_can_serial(), fd=True, bustype="vector" + ) + bus2 = can.Bus( + channel=0, serial=_find_virtual_can_serial(), fd=True, bustype="vector" + ) + + msg_std = can.Message( + channel=0, + arbitration_id=0xFF, + data=list(range(64)), + is_extended_id=False, + is_fd=True, + ) + msg_ext = can.Message( + channel=0, + arbitration_id=0xFFFFFF, + data=list(range(64)), + is_extended_id=True, + is_fd=True, + ) + + bus1.send(msg_std) + msg_std_recv = bus2.recv(None) + assert msg_std.equals(msg_std_recv, timestamp_delta=None) + + bus1.send(msg_ext) + msg_ext_recv = bus2.recv(None) + assert msg_ext.equals(msg_ext_recv, timestamp_delta=None) + + bus1.shutdown() + bus2.shutdown() + + +def test_receive_non_msg_event_mocked(mock_xldriver) -> None: + can.interfaces.vector.canlib.xldriver.xlReceive = Mock( + side_effect=xlReceive_chipstate + ) + bus = can.Bus(channel=0, bustype="vector", _testing=True) + bus.handle_can_event = Mock() + bus.recv(timeout=0.05) + can.interfaces.vector.canlib.xldriver.xlReceive.assert_called() + can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_not_called() + bus.handle_can_event.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_receive_non_msg_event() -> None: + bus = canlib.VectorBus( + channel=0, serial=_find_virtual_can_serial(), bustype="vector" + ) + bus.handle_can_event = Mock() + bus.xldriver.xlCanRequestChipState(bus.port_handle, bus.channel_masks[0]) + bus.recv(timeout=0.5) + bus.handle_can_event.assert_called() + bus.shutdown() + + +def test_receive_fd_non_msg_event_mocked(mock_xldriver) -> None: + can.interfaces.vector.canlib.xldriver.xlCanReceive = Mock( + side_effect=xlCanReceive_chipstate + ) + bus = can.Bus(channel=0, bustype="vector", fd=True, _testing=True) + bus.handle_canfd_event = Mock() + bus.recv(timeout=0.05) + can.interfaces.vector.canlib.xldriver.xlReceive.assert_not_called() + can.interfaces.vector.canlib.xldriver.xlCanReceive.assert_called() + bus.handle_canfd_event.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_receive_fd_non_msg_event() -> None: + bus = canlib.VectorBus( + channel=0, serial=_find_virtual_can_serial(), fd=True, bustype="vector" + ) + bus.handle_canfd_event = Mock() + bus.xldriver.xlCanRequestChipState(bus.port_handle, bus.channel_masks[0]) + bus.recv(timeout=0.5) + bus.handle_canfd_event.assert_called() + bus.shutdown() + + +def test_flush_tx_buffer_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", _testing=True) + bus.flush_tx_buffer() + can.interfaces.vector.canlib.xldriver.xlCanFlushTransmitQueue.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_flush_tx_buffer() -> None: + bus = can.Bus(channel=0, serial=_find_virtual_can_serial(), bustype="vector") + bus.flush_tx_buffer() + bus.shutdown() + + +def test_shutdown_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, bustype="vector", _testing=True) + bus.shutdown() + can.interfaces.vector.canlib.xldriver.xlDeactivateChannel.assert_called() + can.interfaces.vector.canlib.xldriver.xlClosePort.assert_called() + can.interfaces.vector.canlib.xldriver.xlCloseDriver.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_shutdown() -> None: + bus = can.Bus(channel=0, serial=_find_virtual_can_serial(), bustype="vector") + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert xl_channel_config.isOnBus != 0 + bus.shutdown() + + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=0 + ) + assert xl_channel_config.isOnBus == 0 + + +def test_reset_mocked(mock_xldriver) -> None: + bus = canlib.VectorBus(channel=0, bustype="vector", _testing=True) + bus.reset() + can.interfaces.vector.canlib.xldriver.xlDeactivateChannel.assert_called() + can.interfaces.vector.canlib.xldriver.xlActivateChannel.assert_called() + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_reset_mocked() -> None: + bus = canlib.VectorBus( + channel=0, serial=_find_virtual_can_serial(), bustype="vector" + ) + bus.reset() + bus.shutdown() + + +def test_popup_hw_cfg_mocked(mock_xldriver) -> None: + canlib.xldriver.xlPopupHwConfig = Mock() + canlib.VectorBus.popup_vector_hw_configuration(10) + assert canlib.xldriver.xlPopupHwConfig.called + args, kwargs = canlib.xldriver.xlPopupHwConfig.call_args + assert isinstance(args[0], ctypes.c_char_p) + assert isinstance(args[1], ctypes.c_uint) + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_popup_hw_cfg() -> None: + with pytest.raises(VectorOperationError): + canlib.VectorBus.popup_vector_hw_configuration(1) + + +def test_get_application_config_mocked(mock_xldriver) -> None: + canlib.xldriver.xlGetApplConfig = Mock() + canlib.VectorBus.get_application_config(app_name="CANalyzer", app_channel=0) + assert canlib.xldriver.xlGetApplConfig.called + + +def test_set_application_config_mocked(mock_xldriver) -> None: + canlib.xldriver.xlSetApplConfig = Mock() + canlib.VectorBus.set_application_config( + app_name="CANalyzer", + app_channel=0, + hw_type=xldefine.XL_HardwareType.XL_HWTYPE_VN1610, + hw_index=0, + hw_channel=0, + ) + assert canlib.xldriver.xlSetApplConfig.called + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_set_and_get_application_config() -> None: + xl_channel_config = _find_xl_channel_config( + serial=_find_virtual_can_serial(), channel=1 + ) + canlib.VectorBus.set_application_config( + app_name="python-can::test_vector", + app_channel=5, + hw_channel=xl_channel_config.hwChannel, + hw_index=xl_channel_config.hwIndex, + hw_type=xldefine.XL_HardwareType(xl_channel_config.hwType), + ) + hw_type, hw_index, hw_channel = canlib.VectorBus.get_application_config( + app_name="python-can::test_vector", + app_channel=5, + ) + assert hw_type == xldefine.XL_HardwareType(xl_channel_config.hwType) + assert hw_index == xl_channel_config.hwIndex + assert hw_channel == xl_channel_config.hwChannel + + +def test_set_timer_mocked(mock_xldriver) -> None: + canlib.xldriver.xlSetTimerRate = Mock() + bus = canlib.VectorBus(channel=0, bustype="vector", fd=True, _testing=True) + bus.set_timer_rate(timer_rate_ms=1) + assert canlib.xldriver.xlSetTimerRate.called + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_set_timer() -> None: + bus = canlib.VectorBus( + channel=0, serial=_find_virtual_can_serial(), bustype="vector" + ) + bus.handle_can_event = Mock() + bus.set_timer_rate(timer_rate_ms=1) + t0 = time.perf_counter() + while time.perf_counter() - t0 < 0.5: + bus.recv(timeout=-1) + + # call_count is incorrect when using virtual bus + # assert bus.handle_can_event.call_count > 498 + # assert bus.handle_can_event.call_count < 502 + + +@pytest.mark.skipif(IS_WINDOWS, reason="Not relevant for Windows.") +def test_called_without_testing_argument() -> None: + """This tests if an exception is thrown when we are not running on Windows.""" + with pytest.raises(can.CanInterfaceNotImplementedError): + # do not set the _testing argument, since it would suppress the exception + can.Bus(channel=0, bustype="vector") + + +def test_vector_error_pickle() -> None: + for error_type in [ + VectorError, + VectorInitializationError, + VectorOperationError, + ]: + error_code = 118 + error_string = "XL_ERROR" + function = "function_name" + + exc = error_type(error_code, error_string, function) + + # pickle and unpickle + p = pickle.dumps(exc) + exc_unpickled: VectorError = pickle.loads(p) + + assert str(exc) == str(exc_unpickled) + assert error_code == exc_unpickled.error_code + + with pytest.raises(error_type): + raise exc_unpickled + + +def test_vector_subtype_error_from_generic() -> None: + for error_type in [VectorInitializationError, VectorOperationError]: + error_code = 118 + error_string = "XL_ERROR" + function = "function_name" + + generic = VectorError(error_code, error_string, function) + + # pickle and unpickle + specific: VectorError = error_type.from_generic(generic) + + assert str(generic) == str(specific) + assert error_code == specific.error_code + + with pytest.raises(error_type): + raise specific + + +def test_get_channel_configs() -> None: + _original_func = canlib._get_xl_driver_config + canlib._get_xl_driver_config = _get_predefined_xl_driver_config + + channel_configs = canlib.get_channel_configs() + assert len(channel_configs) == 12 + + canlib._get_xl_driver_config = _original_func + + +@pytest.mark.skipif(not IS_WINDOWS, reason="Windows specific test") +def test_winapi_availability() -> None: + assert canlib.WaitForSingleObject is not None + assert canlib.INFINITE is not None + + +def test_vector_channel_config_attributes(): + assert hasattr(VectorChannelConfig, "name") + assert hasattr(VectorChannelConfig, "hwType") + assert hasattr(VectorChannelConfig, "hwIndex") + assert hasattr(VectorChannelConfig, "hwChannel") + assert hasattr(VectorChannelConfig, "channelIndex") + assert hasattr(VectorChannelConfig, "channelMask") + assert hasattr(VectorChannelConfig, "channelCapabilities") + assert hasattr(VectorChannelConfig, "channelBusCapabilities") + assert hasattr(VectorChannelConfig, "isOnBus") + assert hasattr(VectorChannelConfig, "connectedBusType") + assert hasattr(VectorChannelConfig, "serialNumber") + assert hasattr(VectorChannelConfig, "articleNumber") + assert hasattr(VectorChannelConfig, "transceiverName") + + +# ***************************************************************************** +# Utility functions +# ***************************************************************************** + + +def _find_xl_channel_config(serial: int, channel: int) -> xlclass.XLchannelConfig: + """Helper function""" + xl_driver_config = xlclass.XLdriverConfig() + canlib.xldriver.xlOpenDriver() + canlib.xldriver.xlGetDriverConfig(xl_driver_config) + canlib.xldriver.xlCloseDriver() + + for i in range(xl_driver_config.channelCount): + xl_channel_config: xlclass.XLchannelConfig = xl_driver_config.channel[i] + + if xl_channel_config.serialNumber != serial: + continue + + if xl_channel_config.hwChannel != channel: + continue + + return xl_channel_config + + raise LookupError("XLchannelConfig not found.") + + +@functools.lru_cache() +def _find_virtual_can_serial() -> int: + """Serial number might be 0 or 100 depending on driver version.""" + xl_driver_config = xlclass.XLdriverConfig() + canlib.xldriver.xlOpenDriver() + canlib.xldriver.xlGetDriverConfig(xl_driver_config) + canlib.xldriver.xlCloseDriver() + + for i in range(xl_driver_config.channelCount): + xl_channel_config: xlclass.XLchannelConfig = xl_driver_config.channel[i] + + if xl_channel_config.transceiverName.decode() == "Virtual CAN": + return xl_channel_config.serialNumber + + raise LookupError("Vector virtual CAN not found") + + +XL_DRIVER_CONFIG_EXAMPLE = ( + b"\x0E\x00\x1E\x14\x0C\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61\x6E\x6E" + b"\x65\x6C\x20\x53\x74\x72\x65\x61\x6D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x2D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x04" + b"\x0A\x40\x00\x02\x00\x02\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x04\x00\x00\x00\x00\x00\x00\x00\x8E" + b"\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00\x00\x08" + b"\x1C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39\x31" + b"\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x01\x03\x02\x00\x00\x00\x00\x01\x02\x00\x00" + b"\x00\x00\x00\x00\x00\x02\x10\x00\x08\x07\x01\x04\x00\x00\x00\x00\x00\x00\x04\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x04\x00" + b"\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x46\x52\x70\x69\x67\x67\x79\x20\x31\x30" + b"\x38\x30\x41\x6D\x61\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x05\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x32\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x02\x3C\x01\x00" + b"\x00\x00\x00\x02\x04\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\xA2\x03\x05\x01\x00" + b"\x00\x00\x04\x00\x00\x01\x00\x00\x00\x20\xA1\x07\x00\x01\x04\x03\x01\x01\x00\x00" + b"\x00\x00\x00\x00\x00\x01\x80\x00\x00\x00\x68\x89\x09\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x0C\x00\x02\x0A\x04\x00\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00\x00\x00" + b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x4F\x6E\x20" + b"\x62\x6F\x61\x72\x64\x20\x43\x41\x4E\x20\x31\x30\x35\x31\x63\x61\x70\x28\x48\x69" + b"\x67\x68\x73\x70\x65\x65\x64\x29\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03" + b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61\x6E" + b"\x6E\x65\x6C\x20\x33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x2D\x00\x03\x3C\x01\x00\x00\x00\x00\x03\x08\x00\x00\x00\x00\x00\x00\x00\x12" + b"\x00\x00\xA2\x03\x09\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x20\xA1\x07\x00" + b"\x01\x04\x03\x01\x01\x00\x00\x00\x00\x00\x00\x00\x01\x9B\x00\x00\x00\x68\x89\x09" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x04\x00\x00\x00\x00\x00\x00\x00" + b"\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00\x00" + b"\x08\x1C\x00\x00\x4F\x6E\x20\x62\x6F\x61\x72\x64\x20\x43\x41\x4E\x20\x31\x30\x35" + b"\x31\x63\x61\x70\x28\x48\x69\x67\x68\x73\x70\x65\x65\x64\x29\x00\x04\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39" + b"\x31\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x34\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x04\x33\x01\x00\x00\x00\x00\x04\x10\x00" + b"\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x09\x02\x08\x00\x00\x00\x00\x00\x02" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x03" + b"\x00\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x4C\x49\x4E\x70\x69\x67\x67\x79\x20" + b"\x37\x32\x36\x39\x6D\x61\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x07\x00\x00\x00\x70\x17\x00\x00\x0C\x09\x03\x04\x58\x02\x10\x0E\x30" + b"\x57\x05\x00\x00\x00\x00\x00\x88\x13\x88\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x35\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x05\x00\x00" + b"\x00\x00\x02\x00\x05\x20\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x0C\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00\x00" + b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61" + b"\x6E\x6E\x65\x6C\x20\x36\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x2D\x00\x06\x00\x00\x00\x00\x02\x00\x06\x40\x00\x00\x00\x00\x00\x00\x00" + b"\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00" + b"\x00\x08\x1C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38" + b"\x39\x31\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x37\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x07\x00\x00\x00\x00\x02\x00\x07\x80" + b"\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x38" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2D\x00\x08\x3C" + b"\x01\x00\x00\x00\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x12\x00\x00\xA2\x01\x00" + b"\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x20\xA1\x07\x00\x01\x04\x03\x01\x01" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x68\x89\x09\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x0C\x00\x02\x0A\x04\x00\x00\x00\x00\x00\x00\x00\x8E\x00\x02\x0A\x00" + b"\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03\x00\x00\x08\x1C\x00\x00\x4F" + b"\x6E\x20\x62\x6F\x61\x72\x64\x20\x43\x41\x4E\x20\x31\x30\x35\x31\x63\x61\x70\x28" + b"\x48\x69\x67\x68\x73\x70\x65\x65\x64\x29\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x4E\x38\x39\x31\x34\x20\x43\x68" + b"\x61\x6E\x6E\x65\x6C\x20\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x2D\x00\x09\x80\x02\x00\x00\x00\x00\x09\x00\x02\x00\x00\x00\x00\x00" + b"\x00\x02\x00\x00\x00\x40\x00\x40\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x02\x0A\x03\x00\x00\x00\x00\x00" + b"\x00\x00\x8E\x00\x02\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9\x03" + b"\x00\x00\x08\x1C\x00\x00\x44\x2F\x41\x20\x49\x4F\x70\x69\x67\x67\x79\x20\x38\x36" + b"\x34\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x69" + b"\x72\x74\x75\x61\x6C\x20\x43\x68\x61\x6E\x6E\x65\x6C\x20\x31\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x16\x00\x00\x00\x00\x00\x0A" + b"\x00\x04\x00\x00\x00\x00\x00\x00\x07\x00\x00\xA0\x01\x00\x01\x00\x00\x00\x00\x00" + b"\x00\x01\x00\x00\x00\x20\xA1\x07\x00\x01\x04\x03\x01\x01\x00\x00\x00\x00\x00\x00" + b"\x00\x01\x00\x00\x00\x00\x68\x89\x09\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x1E" + b"\x14\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x56\x69\x72\x74\x75\x61\x6C" + b"\x20\x43\x41\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x56\x69\x72\x74\x75\x61\x6C\x20\x43\x68\x61\x6E\x6E\x65\x6C" + b"\x20\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01" + b"\x16\x00\x00\x00\x00\x00\x0B\x00\x08\x00\x00\x00\x00\x00\x00\x07\x00\x00\xA0\x01" + b"\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x20\xA1\x07\x00\x01\x04\x03\x01" + b"\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x68\x89\x09\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x10\x00\x1E\x14\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x56\x69\x72\x74\x75\x61\x6C\x20\x43\x41\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x02" + 11832 * b"\x00" +) + + +def _get_predefined_xl_driver_config() -> xlclass.XLdriverConfig: + return xlclass.XLdriverConfig.from_buffer_copy(XL_DRIVER_CONFIG_EXAMPLE) + + +# ***************************************************************************** +# Mock functions/side effects +# ***************************************************************************** def xlGetApplConfig( @@ -454,7 +914,3 @@ def xlCanReceive_chipstate( event.timeStamp = 0 event.chanIndex = 2 return 0 - - -if __name__ == "__main__": - unittest.main()