From 2267ba531a9a2914c914f83ec5fc6e21cb7cf019 Mon Sep 17 00:00:00 2001 From: Caleb Date: Sun, 7 Apr 2024 22:18:11 -0500 Subject: [PATCH 1/3] add silent mode support for vector --- can/interfaces/vector/canlib.py | 27 ++++++++++++++++++++++++++- test/test_vector.py | 22 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 3a25c99d8..b784fe80f 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -204,6 +204,8 @@ def __init__( self.channel_masks: Dict[int, int] = {} self.index_to_channel: Dict[int, int] = {} self._can_protocol = CanProtocol.CAN_FD if is_fd else CanProtocol.CAN_20 + + self.silent_mode = kwargs.get('silent_mode', False) for channel in self.channels: if ( @@ -232,7 +234,7 @@ def __init__( permission_mask = xlclass.XLaccess() # Set mask to request channel init permission if needed - if bitrate or fd or timing: + if bitrate or fd or timing or self.silent_mode: permission_mask.value = self.mask interface_version = ( @@ -311,6 +313,9 @@ def __init__( if assert_timing: self._check_can_settings(channel_mask=self.mask, bitrate=bitrate) + if self.silent_mode: + self._set_mode(channel_mask=self.mask, silent=True) + # Enable/disable TX receipts tx_receipts = 1 if receive_own_messages else 0 self.xldriver.xlCanSetChannelMode(self.port_handle, self.mask, tx_receipts, 0) @@ -445,6 +450,26 @@ def _read_bus_params( f"Channel configuration for channel {channel} not found." ) + def _set_mode(self, channel_mask: int, silent: bool) -> None: + # set parameters for channels with init access + channel_mask = channel_mask & self.permission_mask + + if channel_mask: + if silent: + self.xldriver.xlCanSetChannelOutput( + self.port_handle, + channel_mask, + xldefine.XL_OutputMode.XL_OUTPUT_MODE_SILENT + ) + else: + self.xldriver.xlCanSetChannelOutput( + self.port_handle, + channel_mask, + xldefine.XL_OutputMode.XL_OUTPUT_MODE_NORMAL + ) + + LOG.info("xlCanSetChannelOutput: silent_mode=%u", silent) + def _set_bitrate(self, channel_mask: int, bitrate: int) -> None: # set parameters for channels with init access channel_mask = channel_mask & self.permission_mask diff --git a/test/test_vector.py b/test/test_vector.py index 99756c41d..0b089b86d 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -78,6 +78,28 @@ def mock_xldriver() -> None: canlib.HAS_EVENTS = real_has_events +def test_silent_mode() -> None: + bus = can.Bus(channel=0, + serial=_find_virtual_can_serial(), + interface="vector", + receive_own_messages=True, + silent=True) + assert isinstance(bus, canlib.VectorBus) + assert bus.protocol == can.CanProtocol.CAN_20 + + msg = can.Message( + arbitration_id=0xC0FFEF, data=[1, 2, 3, 4, 5, 6, 7, 8], is_extended_id=True + ) + + bus.send(msg) + + received_msg = bus.recv() + + assert received_msg == msg + + bus.shutdown() + + def test_bus_creation_mocked(mock_xldriver) -> None: bus = can.Bus(channel=0, interface="vector", _testing=True) assert isinstance(bus, canlib.VectorBus) From 788e1573df469c0e5ef03aa9b7f0a2b3f7b414ca Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 19 Apr 2024 14:11:25 -0500 Subject: [PATCH 2/3] fix: address comments and test works as expected --- can/interfaces/vector/canlib.py | 21 +++++++++++++-------- test/test_vector.py | 22 +++++++++++++++++++--- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index b784fe80f..0a5287ed6 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -104,6 +104,7 @@ def __init__( sjw_dbr: int = 2, tseg1_dbr: int = 6, tseg2_dbr: int = 3, + listen_only: Optional[bool] = False, **kwargs: Any, ) -> None: """ @@ -157,6 +158,8 @@ def __init__( Bus timing value tseg1 (data) :param tseg2_dbr: Bus timing value tseg2 (data) + :param listen_only: + if the bus should be set to listen only mode. :raise ~can.exceptions.CanInterfaceNotImplementedError: If the current operating system is not supported or the driver could not be loaded. @@ -204,8 +207,8 @@ def __init__( self.channel_masks: Dict[int, int] = {} self.index_to_channel: Dict[int, int] = {} self._can_protocol = CanProtocol.CAN_FD if is_fd else CanProtocol.CAN_20 - - self.silent_mode = kwargs.get('silent_mode', False) + + self._listen_only = listen_only for channel in self.channels: if ( @@ -234,7 +237,7 @@ def __init__( permission_mask = xlclass.XLaccess() # Set mask to request channel init permission if needed - if bitrate or fd or timing or self.silent_mode: + if bitrate or fd or timing or self._listen_only: permission_mask.value = self.mask interface_version = ( @@ -313,8 +316,8 @@ def __init__( if assert_timing: self._check_can_settings(channel_mask=self.mask, bitrate=bitrate) - if self.silent_mode: - self._set_mode(channel_mask=self.mask, silent=True) + if self._listen_only: + self._set_output_mode(channel_mask=self.mask, listen_only=True) # Enable/disable TX receipts tx_receipts = 1 if receive_own_messages else 0 @@ -450,12 +453,12 @@ def _read_bus_params( f"Channel configuration for channel {channel} not found." ) - def _set_mode(self, channel_mask: int, silent: bool) -> None: + def _set_output_mode(self, channel_mask: int, listen_only: bool) -> None: # set parameters for channels with init access channel_mask = channel_mask & self.permission_mask if channel_mask: - if silent: + if listen_only: self.xldriver.xlCanSetChannelOutput( self.port_handle, channel_mask, @@ -468,7 +471,9 @@ def _set_mode(self, channel_mask: int, silent: bool) -> None: xldefine.XL_OutputMode.XL_OUTPUT_MODE_NORMAL ) - LOG.info("xlCanSetChannelOutput: silent_mode=%u", silent) + LOG.info("xlCanSetChannelOutput: listen_only=%u", listen_only) + else: + LOG.warning("No channels with init access to set listen only mode") def _set_bitrate(self, channel_mask: int, bitrate: int) -> None: # set parameters for channels with init access diff --git a/test/test_vector.py b/test/test_vector.py index 0b089b86d..4df18b5ee 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -48,6 +48,7 @@ def mock_xldriver() -> None: xldriver_mock.xlCanSetChannelAcceptance = Mock(return_value=0) xldriver_mock.xlCanSetChannelBitrate = Mock(return_value=0) xldriver_mock.xlSetNotification = Mock(side_effect=xlSetNotification) + xldriver_mock.xlCanSetChannelOutput = Mock(return_value=0) # bus deactivation functions xldriver_mock.xlDeactivateChannel = Mock(return_value=0) @@ -78,12 +79,26 @@ def mock_xldriver() -> None: canlib.HAS_EVENTS = real_has_events -def test_silent_mode() -> None: +def test_listen_only_mocked(mock_xldriver) -> None: + bus = can.Bus(channel=0, + interface="vector", + listen_only=True, + _testing=True) + assert isinstance(bus, canlib.VectorBus) + assert bus.protocol == can.CanProtocol.CAN_20 + + can.interfaces.vector.canlib.xldriver.xlCanSetChannelOutput.assert_called() + xlCanSetChannelOutput_args = can.interfaces.vector.canlib.xldriver.xlCanSetChannelOutput.call_args[0] + assert xlCanSetChannelOutput_args[2] == xldefine.XL_OutputMode.XL_OUTPUT_MODE_SILENT + + +@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") +def test_listen_only() -> None: bus = can.Bus(channel=0, serial=_find_virtual_can_serial(), interface="vector", receive_own_messages=True, - silent=True) + listen_only=True) assert isinstance(bus, canlib.VectorBus) assert bus.protocol == can.CanProtocol.CAN_20 @@ -95,7 +110,8 @@ def test_silent_mode() -> None: received_msg = bus.recv() - assert received_msg == msg + assert received_msg.arbitration_id == msg.arbitration_id + assert received_msg.data == msg.data bus.shutdown() From cc9429016bcfc273396455fbdf2a8ab2dd65a4aa Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 19 Apr 2024 15:20:30 -0500 Subject: [PATCH 3/3] formatting --- can/interfaces/vector/canlib.py | 12 +++++++----- test/test_vector.py | 21 +++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 0a5287ed6..adf7b6c5d 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -462,13 +462,13 @@ def _set_output_mode(self, channel_mask: int, listen_only: bool) -> None: self.xldriver.xlCanSetChannelOutput( self.port_handle, channel_mask, - xldefine.XL_OutputMode.XL_OUTPUT_MODE_SILENT + xldefine.XL_OutputMode.XL_OUTPUT_MODE_SILENT, ) else: self.xldriver.xlCanSetChannelOutput( self.port_handle, channel_mask, - xldefine.XL_OutputMode.XL_OUTPUT_MODE_NORMAL + xldefine.XL_OutputMode.XL_OUTPUT_MODE_NORMAL, ) LOG.info("xlCanSetChannelOutput: listen_only=%u", listen_only) @@ -673,9 +673,11 @@ def _apply_filters(self, filters: Optional[CanFilters]) -> None: self.mask, can_filter["can_id"], can_filter["can_mask"], - xldefine.XL_AcceptanceFilter.XL_CAN_EXT - if can_filter.get("extended") - else xldefine.XL_AcceptanceFilter.XL_CAN_STD, + ( + xldefine.XL_AcceptanceFilter.XL_CAN_EXT + if can_filter.get("extended") + else xldefine.XL_AcceptanceFilter.XL_CAN_STD + ), ) except VectorOperationError as exception: LOG.warning("Could not set filters: %s", exception) diff --git a/test/test_vector.py b/test/test_vector.py index 4df18b5ee..ca46526fb 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -80,25 +80,26 @@ def mock_xldriver() -> None: def test_listen_only_mocked(mock_xldriver) -> None: - bus = can.Bus(channel=0, - interface="vector", - listen_only=True, - _testing=True) + bus = can.Bus(channel=0, interface="vector", listen_only=True, _testing=True) assert isinstance(bus, canlib.VectorBus) assert bus.protocol == can.CanProtocol.CAN_20 can.interfaces.vector.canlib.xldriver.xlCanSetChannelOutput.assert_called() - xlCanSetChannelOutput_args = can.interfaces.vector.canlib.xldriver.xlCanSetChannelOutput.call_args[0] + xlCanSetChannelOutput_args = ( + can.interfaces.vector.canlib.xldriver.xlCanSetChannelOutput.call_args[0] + ) assert xlCanSetChannelOutput_args[2] == xldefine.XL_OutputMode.XL_OUTPUT_MODE_SILENT @pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable") def test_listen_only() -> None: - bus = can.Bus(channel=0, - serial=_find_virtual_can_serial(), - interface="vector", - receive_own_messages=True, - listen_only=True) + bus = can.Bus( + channel=0, + serial=_find_virtual_can_serial(), + interface="vector", + receive_own_messages=True, + listen_only=True, + ) assert isinstance(bus, canlib.VectorBus) assert bus.protocol == can.CanProtocol.CAN_20