From 2541838fa3e91207328526efebf7f81a18b19702 Mon Sep 17 00:00:00 2001 From: zariiii9003 Date: Sat, 20 Jul 2019 19:54:51 +0200 Subject: [PATCH 1/4] add bit-timing class compatibility for vector interface --- can/interfaces/vector/canlib.py | 63 +++++++++++++++++++++++++-------- can/interfaces/vector/vxlapi.py | 16 +++++++++ 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 970994c56..a377d8072 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -55,6 +55,8 @@ def __init__( poll_interval=0.01, receive_own_messages=False, bitrate=None, + timing=None, + data_timing=None, rx_queue_size=2 ** 14, app_name="CANalyzer", serial=None, @@ -76,6 +78,11 @@ def __init__( Poll interval in seconds. :param int bitrate: Bitrate in bits/s. + :param can.BitTiming timing: + Bit timing configuration. + For CAN-FD this also applies to arbitration/nominal phase. + :param can.BitTiming data_timing: + Bit timing configuration for data phase. :param int rx_queue_size: Number of messages in receive queue (power of 2). CAN: range 16…32768 @@ -175,7 +182,7 @@ def __init__( permission_mask = vxlapi.XLaccess() # Set mask to request channel init permission if needed - if bitrate or fd: + if bitrate or fd or timing: permission_mask.value = self.mask if fd: vxlapi.xlOpenPort( @@ -206,20 +213,36 @@ def __init__( if permission_mask.value == self.mask: if fd: self.canFdConf = vxlapi.XLcanFdConf() - if bitrate: - self.canFdConf.arbitrationBitRate = ctypes.c_uint(bitrate) + if timing: + self.canFdConf.arbitrationBitRate = ctypes.c_uint(timing.bitrate) + self.canFdConf.sjwAbr = ctypes.c_uint(timing.sjw) + self.canFdConf.tseg1Abr = ctypes.c_uint(timing.tseg1) + self.canFdConf.tseg2Abr = ctypes.c_uint(timing.tseg2) + if data_timing: + self.canFdConf.dataBitRate = ctypes.c_uint(data_timing.bitrate) + self.canFdConf.sjwDbr = ctypes.c_uint(data_timing.sjw) + self.canFdConf.tseg1Dbr = ctypes.c_uint(data_timing.tseg1) + self.canFdConf.tseg2Dbr = ctypes.c_uint(data_timing.tseg2) + else: + self.canFdConf.dataBitRate = ctypes.c_uint(timing.bitrate) + self.canFdConf.sjwDbr = ctypes.c_uint(timing.sjw) + self.canFdConf.tseg1Dbr = ctypes.c_uint(timing.tseg1) + self.canFdConf.tseg2Dbr = ctypes.c_uint(timing.tseg2) else: - self.canFdConf.arbitrationBitRate = ctypes.c_uint(500000) - self.canFdConf.sjwAbr = ctypes.c_uint(sjwAbr) - self.canFdConf.tseg1Abr = ctypes.c_uint(tseg1Abr) - self.canFdConf.tseg2Abr = ctypes.c_uint(tseg2Abr) - if data_bitrate: - self.canFdConf.dataBitRate = ctypes.c_uint(data_bitrate) - else: - self.canFdConf.dataBitRate = self.canFdConf.arbitrationBitRate - self.canFdConf.sjwDbr = ctypes.c_uint(sjwDbr) - self.canFdConf.tseg1Dbr = ctypes.c_uint(tseg1Dbr) - self.canFdConf.tseg2Dbr = ctypes.c_uint(tseg2Dbr) + if bitrate: + self.canFdConf.arbitrationBitRate = ctypes.c_uint(bitrate) + else: + self.canFdConf.arbitrationBitRate = ctypes.c_uint(500000) + self.canFdConf.sjwAbr = ctypes.c_uint(sjwAbr) + self.canFdConf.tseg1Abr = ctypes.c_uint(tseg1Abr) + self.canFdConf.tseg2Abr = ctypes.c_uint(tseg2Abr) + if data_bitrate: + self.canFdConf.dataBitRate = ctypes.c_uint(data_bitrate) + else: + self.canFdConf.dataBitRate = self.canFdConf.arbitrationBitRate + self.canFdConf.sjwDbr = ctypes.c_uint(sjwDbr) + self.canFdConf.tseg1Dbr = ctypes.c_uint(tseg1Dbr) + self.canFdConf.tseg2Dbr = ctypes.c_uint(tseg2Dbr) vxlapi.xlCanFdSetConfiguration( self.port_handle, self.mask, self.canFdConf @@ -242,7 +265,17 @@ def __init__( self.canFdConf.tseg2Dbr, ) else: - if bitrate: + if timing: + self.chipParams = vxlapi.XLchipParams() + self.chipParams.bitRate = ctypes.c_ulong(timing.bitrate) + self.chipParams.sjw = ctypes.c_ubyte(timing.sjw) + self.chipParams.tseg1 = ctypes.c_ubyte(timing.tseg1) + self.chipParams.tseg2 = ctypes.c_ubyte(timing.tseg2) + self.chipParams.sam = ctypes.c_ubyte(timing.nof_samples) + vxlapi.xlCanSetChannelParams( + self.port_handle, self.mask, self.chipParams + ) + elif bitrate: vxlapi.xlCanSetChannelBitrate( self.port_handle, permission_mask, bitrate ) diff --git a/can/interfaces/vector/vxlapi.py b/can/interfaces/vector/vxlapi.py index b631923f2..198205576 100644 --- a/can/interfaces/vector/vxlapi.py +++ b/can/interfaces/vector/vxlapi.py @@ -252,6 +252,17 @@ class XLcanTxEvent(ctypes.Structure): ] +# CAN configuration structure +class XLchipParams(ctypes.Structure): + _fields_ = [ + ("bitRate", ctypes.c_ulong), + ("sjw", ctypes.c_ubyte), + ("tseg1", ctypes.c_ubyte), + ("tseg2", ctypes.c_ubyte), + ("sam", ctypes.c_ubyte), + ] + + # CAN FD configuration structure class XLcanFdConf(ctypes.Structure): _fields_ = [ @@ -438,6 +449,11 @@ def check_status(result, function, arguments): xlCanSetChannelBitrate.restype = XLstatus xlCanSetChannelBitrate.errcheck = check_status +xlCanSetChannelParams = _xlapi_dll.xlCanSetChannelParams +xlCanSetChannelParams.argtypes = [XLportHandle, XLaccess, ctypes.POINTER(XLchipParams)] +xlCanSetChannelParams.restype = XLstatus +xlCanSetChannelParams.errcheck = check_status + xlCanTransmit = _xlapi_dll.xlCanTransmit xlCanTransmit.argtypes = [ XLportHandle, From 0a4ed7f2447c231e68748f3bfe395ab4038af7db Mon Sep 17 00:00:00 2001 From: zariiii9003 Date: Wed, 24 Jul 2019 02:23:27 +0200 Subject: [PATCH 2/4] add test for CAN FD without data_timing input --- test/test_vector.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/test_vector.py b/test/test_vector.py index f978b4d68..62ca5273a 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -172,6 +172,38 @@ def test_bus_creation_bittiming_class_fd(self) -> None: self.assertEqual(canFdConf.tseg1Dbr, 29) self.assertEqual(canFdConf.tseg2Dbr, 10) + def test_bus_creation_bittiming_class_fd_2(self) -> None: + timing = can.BitTiming( + f_clock=8000000, bitrate=250000, tseg1=13, tseg2=2, sjw=1 + ) + self.bus = self.bus = can.Bus( + channel=0, bustype="vector", timing=timing, fd=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, 250000) + self.assertEqual(canFdConf.dataBitRate, 250000) + self.assertEqual(canFdConf.sjwAbr, 1) + self.assertEqual(canFdConf.tseg1Abr, 13) + self.assertEqual(canFdConf.tseg2Abr, 2) + self.assertEqual(canFdConf.sjwDbr, 1) + self.assertEqual(canFdConf.tseg1Dbr, 13) + self.assertEqual(canFdConf.tseg2Dbr, 2) + def test_bus_creation_fd(self) -> None: self.bus = can.Bus(channel=0, bustype="vector", fd=True) self.assertIsInstance(self.bus, canlib.VectorBus) From c5ecb4498f5dc7ef401b2f02f574a870e69481d0 Mon Sep 17 00:00:00 2001 From: zariiii9003 Date: Sun, 4 Aug 2019 15:22:15 +0200 Subject: [PATCH 3/4] add _testing flag to new tests --- test/test_vector.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/test_vector.py b/test/test_vector.py index 9f1f15830..8140367b1 100644 --- a/test/test_vector.py +++ b/test/test_vector.py @@ -118,7 +118,9 @@ def test_bus_creation_bittiming_class(self) -> None: timing = can.BitTiming( f_clock=8000000, bitrate=250000, tseg1=13, tseg2=2, sjw=1 ) - self.bus = self.bus = can.Bus(channel=0, bustype="vector", timing=timing) + self.bus = self.bus = can.Bus( + channel=0, bustype="vector", timing=timing, _testing=True + ) self.assertIsInstance(self.bus, canlib.VectorBus) can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called() @@ -146,7 +148,12 @@ def test_bus_creation_bittiming_class_fd(self) -> None: f_clock=80000000, bitrate=2000000, tseg1=29, tseg2=10, sjw=10 ) self.bus = self.bus = can.Bus( - channel=0, bustype="vector", timing=timing, data_timing=data_timing, fd=True + channel=0, + bustype="vector", + timing=timing, + data_timing=data_timing, + fd=True, + _testing=True, ) self.assertIsInstance(self.bus, canlib.VectorBus) can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() @@ -178,7 +185,7 @@ def test_bus_creation_bittiming_class_fd_2(self) -> None: f_clock=8000000, bitrate=250000, tseg1=13, tseg2=2, sjw=1 ) self.bus = self.bus = can.Bus( - channel=0, bustype="vector", timing=timing, fd=True + channel=0, bustype="vector", timing=timing, fd=True, _testing=True ) self.assertIsInstance(self.bus, canlib.VectorBus) can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called() From 25a6c4e2a3b35d7b467ce7cf2382d0e40f9eb395 Mon Sep 17 00:00:00 2001 From: zariiii9003 Date: Thu, 24 Oct 2019 21:36:04 +0200 Subject: [PATCH 4/4] Vector - refactor XLcanFdConf out of __init__, add type hints, use f-strings --- can/interfaces/vector/canlib.py | 192 +++++++++++++++++++------------- 1 file changed, 115 insertions(+), 77 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 1314b0572..6b93f9f96 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -10,6 +10,7 @@ import logging import time import os +from typing import Any, Dict, List, Optional, Union try: # Try builtin Python 3 Windows API @@ -31,6 +32,7 @@ from can import BusABC, Message from can.util import len2dlc, dlc2len from .exceptions import VectorError +from can.bit_timing import BitTiming # Define Module Logger # ==================== @@ -53,24 +55,24 @@ class VectorBus(BusABC): def __init__( self, - channel, - can_filters=None, - poll_interval=0.01, - receive_own_messages=False, - bitrate=None, - timing=None, - data_timing=None, - rx_queue_size=2 ** 14, - app_name="CANalyzer", - serial=None, - fd=False, - data_bitrate=None, - sjwAbr=2, - tseg1Abr=6, - tseg2Abr=3, - sjwDbr=2, - tseg1Dbr=6, - tseg2Dbr=3, + channel: Union[int, List[int]], + can_filters: Optional[List[Dict[str, int]]] = None, + poll_interval: float = 0.01, + receive_own_messages: bool = False, + bitrate: Optional[int] = None, + timing: Optional[BitTiming] = None, + data_timing: Optional[BitTiming] = None, + rx_queue_size: int = 2 ** 14, + app_name: str = "CANalyzer", + serial: Optional[int] = None, + fd: bool = False, + data_bitrate: Optional[int] = None, + sjwAbr: int = 2, + tseg1Abr: int = 6, + tseg2Abr: int = 3, + sjwDbr: int = 2, + tseg1Dbr: int = 6, + tseg2Dbr: int = 3, **kwargs, ): """ @@ -167,7 +169,7 @@ def __init__( hw_channel, xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value, ) - LOG.debug("Channel index %d found", channel) + LOG.debug(f"Channel index {channel} found") idx = xldriver.xlGetChannelIndex( hw_type.value, hw_index.value, hw_channel.value ) @@ -214,81 +216,60 @@ def __init__( xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value, ) LOG.debug( - "Open Port: PortHandle: %d, PermissionMask: 0x%X", - self.port_handle.value, - permission_mask.value, + f"xlOpenPort: " + f"PortHandle={self.port_handle.value}, " + f"PermissionMask={permission_mask.value}" ) + # If application has init access, set CAN settings if permission_mask.value == self.mask: if fd: - self.canFdConf = xlclass.XLcanFdConf() - if timing: - self.canFdConf.arbitrationBitRate = ctypes.c_uint(timing.bitrate) - self.canFdConf.sjwAbr = ctypes.c_uint(timing.sjw) - self.canFdConf.tseg1Abr = ctypes.c_uint(timing.tseg1) - self.canFdConf.tseg2Abr = ctypes.c_uint(timing.tseg2) - if data_timing: - self.canFdConf.dataBitRate = ctypes.c_uint(data_timing.bitrate) - self.canFdConf.sjwDbr = ctypes.c_uint(data_timing.sjw) - self.canFdConf.tseg1Dbr = ctypes.c_uint(data_timing.tseg1) - self.canFdConf.tseg2Dbr = ctypes.c_uint(data_timing.tseg2) - else: - self.canFdConf.dataBitRate = ctypes.c_uint(timing.bitrate) - self.canFdConf.sjwDbr = ctypes.c_uint(timing.sjw) - self.canFdConf.tseg1Dbr = ctypes.c_uint(timing.tseg1) - self.canFdConf.tseg2Dbr = ctypes.c_uint(timing.tseg2) - else: - if bitrate: - self.canFdConf.arbitrationBitRate = ctypes.c_uint(bitrate) - else: - self.canFdConf.arbitrationBitRate = ctypes.c_uint(500000) - self.canFdConf.sjwAbr = ctypes.c_uint(sjwAbr) - self.canFdConf.tseg1Abr = ctypes.c_uint(tseg1Abr) - self.canFdConf.tseg2Abr = ctypes.c_uint(tseg2Abr) - if data_bitrate: - self.canFdConf.dataBitRate = ctypes.c_uint(data_bitrate) - else: - self.canFdConf.dataBitRate = self.canFdConf.arbitrationBitRate - self.canFdConf.sjwDbr = ctypes.c_uint(sjwDbr) - self.canFdConf.tseg1Dbr = ctypes.c_uint(tseg1Dbr) - self.canFdConf.tseg2Dbr = ctypes.c_uint(tseg2Dbr) + self.canFdConf = self._get_canfdconf( + timing, + data_timing, + bitrate, + sjwAbr, + tseg1Abr, + tseg2Abr, + data_bitrate, + sjwDbr, + tseg1Dbr, + tseg2Dbr, + ) xldriver.xlCanFdSetConfiguration( self.port_handle, self.mask, self.canFdConf ) LOG.info( - "SetFdConfig.: ABaudr.=%u, DBaudr.=%u", - self.canFdConf.arbitrationBitRate, - self.canFdConf.dataBitRate, - ) - LOG.info( - "SetFdConfig.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u", - self.canFdConf.sjwAbr, - self.canFdConf.tseg1Abr, - self.canFdConf.tseg2Abr, - ) - LOG.info( - "SetFdConfig.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u", - self.canFdConf.sjwDbr, - self.canFdConf.tseg1Dbr, - self.canFdConf.tseg2Dbr, + f"xlCanFdSetConfiguration: " + f"arbitrationBitRate={self.canFdConf.arbitrationBitRate}, " + f"sjwAbr={self.canFdConf.sjwAbr}, " + f"tseg1Abr={self.canFdConf.tseg1Abr}, " + f"tseg2Abr={self.canFdConf.tseg2Abr}, " + f"dataBitRate={self.canFdConf.dataBitRate}, " + f"sjwDbr={self.canFdConf.sjwDbr}, " + f"tseg1Dbr={self.canFdConf.tseg1Dbr}, " + f"tseg2Dbr={self.canFdConf.tseg2Dbr}" ) else: if timing: - self.chipParams = xlclass.XLchipParams() - self.chipParams.bitRate = ctypes.c_ulong(timing.bitrate) - self.chipParams.sjw = ctypes.c_ubyte(timing.sjw) - self.chipParams.tseg1 = ctypes.c_ubyte(timing.tseg1) - self.chipParams.tseg2 = ctypes.c_ubyte(timing.tseg2) - self.chipParams.sam = ctypes.c_ubyte(timing.nof_samples) + self.chipParams = self._get_chipparams(timing) xldriver.xlCanSetChannelParams( self.port_handle, self.mask, self.chipParams ) + LOG.info( + f"xlCanSetChannelParams: " + f"bitRate={self.chipParams.bitRate}, " + f"sjwAbr={self.chipParams.sjw}, " + f"tseg1={self.chipParams.tseg1}, " + f"tseg2={self.chipParams.tseg2}, " + f"sam={self.chipParams.sam}" + ) elif bitrate: xldriver.xlCanSetChannelBitrate( self.port_handle, permission_mask, bitrate ) - LOG.info("SetChannelBitrate: baudr.=%u", bitrate) + LOG.info(f"xlCanSetChannelBitrate: bitrate={bitrate}") else: LOG.info("No init access!") @@ -321,7 +302,64 @@ def __init__( self._is_filtered = False super().__init__(channel=channel, can_filters=can_filters, **kwargs) - def _apply_filters(self, filters): + @staticmethod + def _get_canfdconf( + timing: Optional[BitTiming] = None, + data_timing: Optional[BitTiming] = None, + bitrate: Optional[int] = None, + sjwAbr: Optional[int] = None, + tseg1Abr: Optional[int] = None, + tseg2Abr: Optional[int] = None, + data_bitrate: Optional[int] = None, + sjwDbr: Optional[int] = None, + tseg1Dbr: Optional[int] = None, + tseg2Dbr: Optional[int] = None, + ) -> xlclass.XLcanFdConf: + canFdConf = xlclass.XLcanFdConf() + if timing: + canFdConf.arbitrationBitRate = ctypes.c_uint(timing.bitrate) + canFdConf.sjwAbr = ctypes.c_uint(timing.sjw) + canFdConf.tseg1Abr = ctypes.c_uint(timing.tseg1) + canFdConf.tseg2Abr = ctypes.c_uint(timing.tseg2) + if data_timing: + canFdConf.dataBitRate = ctypes.c_uint(data_timing.bitrate) + canFdConf.sjwDbr = ctypes.c_uint(data_timing.sjw) + canFdConf.tseg1Dbr = ctypes.c_uint(data_timing.tseg1) + canFdConf.tseg2Dbr = ctypes.c_uint(data_timing.tseg2) + else: + canFdConf.dataBitRate = ctypes.c_uint(timing.bitrate) + canFdConf.sjwDbr = ctypes.c_uint(timing.sjw) + canFdConf.tseg1Dbr = ctypes.c_uint(timing.tseg1) + canFdConf.tseg2Dbr = ctypes.c_uint(timing.tseg2) + else: + if bitrate: + canFdConf.arbitrationBitRate = ctypes.c_uint(bitrate) + else: + canFdConf.arbitrationBitRate = ctypes.c_uint(500000) + canFdConf.sjwAbr = ctypes.c_uint(sjwAbr) + canFdConf.tseg1Abr = ctypes.c_uint(tseg1Abr) + canFdConf.tseg2Abr = ctypes.c_uint(tseg2Abr) + if data_bitrate: + canFdConf.dataBitRate = ctypes.c_uint(data_bitrate) + else: + canFdConf.dataBitRate = canFdConf.arbitrationBitRate + canFdConf.sjwDbr = ctypes.c_uint(sjwDbr) + canFdConf.tseg1Dbr = ctypes.c_uint(tseg1Dbr) + canFdConf.tseg2Dbr = ctypes.c_uint(tseg2Dbr) + + return canFdConf + + @staticmethod + def _get_chipparams(timing: BitTiming) -> xlclass.XLchipParams: + chipParams = xlclass.XLchipParams() + chipParams.bitRate = ctypes.c_ulong(timing.bitrate) + chipParams.sjw = ctypes.c_ubyte(timing.sjw) + chipParams.tseg1 = ctypes.c_ubyte(timing.tseg1) + chipParams.tseg2 = ctypes.c_ubyte(timing.tseg2) + chipParams.sam = ctypes.c_ubyte(timing.nof_samples) + return chipParams + + def _apply_filters(self, filters: List[Dict[str, int]]): if filters: # Only up to one filter per ID type allowed if len(filters) == 1 or ( @@ -547,7 +585,7 @@ def reset(self): ) @staticmethod - def _detect_available_configs(): + def _detect_available_configs() -> List[Dict[str, Any]]: configs = [] channel_configs = get_channel_configs() LOG.info("Found %d channels", len(channel_configs))