Skip to content

Commit 7a4c6f8

Browse files
authored
Add BitTiming/BitTimingFd support to VectorBus (#1470)
* add BitTiming parameter to VectorBus * use correct interface_version * implement tests for bittiming classes with vector
1 parent d2abd34 commit 7a4c6f8

File tree

2 files changed

+194
-5
lines changed

2 files changed

+194
-5
lines changed

can/interfaces/vector/canlib.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,20 @@
3737

3838
# Import Modules
3939
# ==============
40-
from can import BusABC, Message, CanInterfaceNotImplementedError, CanInitializationError
40+
from can import (
41+
BusABC,
42+
Message,
43+
CanInterfaceNotImplementedError,
44+
CanInitializationError,
45+
BitTiming,
46+
BitTimingFd,
47+
)
4148
from can.util import (
4249
len2dlc,
4350
dlc2len,
4451
deprecated_args_alias,
4552
time_perfcounter_correlation,
53+
check_or_adjust_timing_clock,
4654
)
4755
from can.typechecking import AutoDetectedConfig, CanFilters
4856

@@ -86,6 +94,7 @@ def __init__(
8694
can_filters: Optional[CanFilters] = None,
8795
poll_interval: float = 0.01,
8896
receive_own_messages: bool = False,
97+
timing: Optional[Union[BitTiming, BitTimingFd]] = None,
8998
bitrate: Optional[int] = None,
9099
rx_queue_size: int = 2**14,
91100
app_name: Optional[str] = "CANalyzer",
@@ -108,6 +117,15 @@ def __init__(
108117
See :class:`can.BusABC`.
109118
:param receive_own_messages:
110119
See :class:`can.BusABC`.
120+
:param timing:
121+
An instance of :class:`~can.BitTiming` or :class:`~can.BitTimingFd`
122+
to specify the bit timing parameters for the VectorBus interface. The
123+
`f_clock` value of the timing instance must be set to 16.000.000 (16MHz)
124+
for standard CAN or 80.000.000 (80MHz) for CAN FD. If this parameter is provided,
125+
it takes precedence over all other timing-related parameters.
126+
Otherwise, the bit timing can be specified using the following parameters:
127+
`bitrate` for standard CAN or `fd`, `data_bitrate`, `sjw_abr`, `tseg1_abr`,
128+
`tseg2_abr`, `sjw_dbr`, `tseg1_dbr`, and `tseg2_dbr` for CAN FD.
111129
:param poll_interval:
112130
Poll interval in seconds.
113131
:param bitrate:
@@ -184,7 +202,7 @@ def __init__(
184202
channel_configs = get_channel_configs()
185203

186204
self.mask = 0
187-
self.fd = fd
205+
self.fd = isinstance(timing, BitTimingFd) if timing else fd
188206
self.channel_masks: Dict[int, int] = {}
189207
self.index_to_channel: Dict[int, int] = {}
190208

@@ -204,12 +222,12 @@ def __init__(
204222

205223
permission_mask = xlclass.XLaccess()
206224
# Set mask to request channel init permission if needed
207-
if bitrate or fd:
225+
if bitrate or fd or timing:
208226
permission_mask.value = self.mask
209227

210228
interface_version = (
211229
xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4
212-
if fd
230+
if self.fd
213231
else xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION
214232
)
215233

@@ -233,7 +251,30 @@ def __init__(
233251

234252
# set CAN settings
235253
for channel in self.channels:
236-
if fd:
254+
if isinstance(timing, BitTiming):
255+
timing = check_or_adjust_timing_clock(timing, [16_000_000])
256+
self._set_bitrate_can(
257+
channel=channel,
258+
bitrate=timing.bitrate,
259+
sjw=timing.sjw,
260+
tseg1=timing.tseg1,
261+
tseg2=timing.tseg2,
262+
sam=timing.nof_samples,
263+
)
264+
elif isinstance(timing, BitTimingFd):
265+
timing = check_or_adjust_timing_clock(timing, [80_000_000])
266+
self._set_bitrate_canfd(
267+
channel=channel,
268+
bitrate=timing.nom_bitrate,
269+
data_bitrate=timing.data_bitrate,
270+
sjw_abr=timing.nom_sjw,
271+
tseg1_abr=timing.nom_tseg1,
272+
tseg2_abr=timing.nom_tseg2,
273+
sjw_dbr=timing.data_sjw,
274+
tseg1_dbr=timing.data_tseg1,
275+
tseg2_dbr=timing.data_tseg2,
276+
)
277+
elif fd:
237278
self._set_bitrate_canfd(
238279
channel=channel,
239280
bitrate=bitrate,

test/test_vector.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,154 @@ def test_bus_creation_fd_bitrate_timings() -> None:
270270
bus.shutdown()
271271

272272

273+
def test_bus_creation_timing_mocked(mock_xldriver) -> None:
274+
timing = can.BitTiming.from_bitrate_and_segments(
275+
f_clock=16_000_000,
276+
bitrate=125_000,
277+
tseg1=13,
278+
tseg2=2,
279+
sjw=1,
280+
)
281+
bus = can.Bus(channel=0, interface="vector", timing=timing, _testing=True)
282+
assert isinstance(bus, canlib.VectorBus)
283+
can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called()
284+
can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called()
285+
286+
can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called()
287+
xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0]
288+
assert xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION.value
289+
assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value
290+
291+
can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_not_called()
292+
can.interfaces.vector.canlib.xldriver.xlCanSetChannelParams.assert_called()
293+
chip_params = (
294+
can.interfaces.vector.canlib.xldriver.xlCanSetChannelParams.call_args[0]
295+
)[2]
296+
assert chip_params.bitRate == 125_000
297+
assert chip_params.sjw == 1
298+
assert chip_params.tseg1 == 13
299+
assert chip_params.tseg2 == 2
300+
assert chip_params.sam == 1
301+
302+
303+
@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable")
304+
def test_bus_creation_timing() -> None:
305+
timing = can.BitTiming.from_bitrate_and_segments(
306+
f_clock=16_000_000,
307+
bitrate=125_000,
308+
tseg1=13,
309+
tseg2=2,
310+
sjw=1,
311+
)
312+
bus = can.Bus(
313+
channel=0,
314+
serial=_find_virtual_can_serial(),
315+
interface="vector",
316+
timing=timing,
317+
)
318+
assert isinstance(bus, canlib.VectorBus)
319+
320+
xl_channel_config = _find_xl_channel_config(
321+
serial=_find_virtual_can_serial(), channel=0
322+
)
323+
assert xl_channel_config.busParams.data.can.bitRate == 125_000
324+
assert xl_channel_config.busParams.data.can.sjw == 1
325+
assert xl_channel_config.busParams.data.can.tseg1 == 13
326+
assert xl_channel_config.busParams.data.can.tseg2 == 2
327+
328+
bus.shutdown()
329+
330+
331+
def test_bus_creation_timingfd_mocked(mock_xldriver) -> None:
332+
timing = can.BitTimingFd.from_bitrate_and_segments(
333+
f_clock=80_000_000,
334+
nom_bitrate=500_000,
335+
nom_tseg1=68,
336+
nom_tseg2=11,
337+
nom_sjw=10,
338+
data_bitrate=2_000_000,
339+
data_tseg1=10,
340+
data_tseg2=9,
341+
data_sjw=8,
342+
)
343+
bus = can.Bus(
344+
channel=0,
345+
interface="vector",
346+
timing=timing,
347+
_testing=True,
348+
)
349+
assert isinstance(bus, canlib.VectorBus)
350+
can.interfaces.vector.canlib.xldriver.xlOpenDriver.assert_called()
351+
can.interfaces.vector.canlib.xldriver.xlGetApplConfig.assert_called()
352+
353+
can.interfaces.vector.canlib.xldriver.xlOpenPort.assert_called()
354+
xlOpenPort_args = can.interfaces.vector.canlib.xldriver.xlOpenPort.call_args[0]
355+
assert (
356+
xlOpenPort_args[5] == xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4.value
357+
)
358+
359+
assert xlOpenPort_args[6] == xldefine.XL_BusTypes.XL_BUS_TYPE_CAN.value
360+
361+
can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.assert_called()
362+
can.interfaces.vector.canlib.xldriver.xlCanSetChannelBitrate.assert_not_called()
363+
364+
xlCanFdSetConfiguration_args = (
365+
can.interfaces.vector.canlib.xldriver.xlCanFdSetConfiguration.call_args[0]
366+
)
367+
canFdConf = xlCanFdSetConfiguration_args[2]
368+
assert canFdConf.arbitrationBitRate == 500_000
369+
assert canFdConf.dataBitRate == 2_000_000
370+
assert canFdConf.sjwAbr == 10
371+
assert canFdConf.tseg1Abr == 68
372+
assert canFdConf.tseg2Abr == 11
373+
assert canFdConf.sjwDbr == 8
374+
assert canFdConf.tseg1Dbr == 10
375+
assert canFdConf.tseg2Dbr == 9
376+
377+
378+
@pytest.mark.skipif(not XLDRIVER_FOUND, reason="Vector XL API is unavailable")
379+
def test_bus_creation_timingfd() -> None:
380+
timing = can.BitTimingFd.from_bitrate_and_segments(
381+
f_clock=80_000_000,
382+
nom_bitrate=500_000,
383+
nom_tseg1=68,
384+
nom_tseg2=11,
385+
nom_sjw=10,
386+
data_bitrate=2_000_000,
387+
data_tseg1=10,
388+
data_tseg2=9,
389+
data_sjw=8,
390+
)
391+
bus = can.Bus(
392+
channel=0,
393+
serial=_find_virtual_can_serial(),
394+
interface="vector",
395+
timing=timing,
396+
)
397+
398+
xl_channel_config = _find_xl_channel_config(
399+
serial=_find_virtual_can_serial(), channel=0
400+
)
401+
assert (
402+
xl_channel_config.interfaceVersion
403+
== xldefine.XL_InterfaceVersion.XL_INTERFACE_VERSION_V4
404+
)
405+
assert (
406+
xl_channel_config.busParams.data.canFD.canOpMode
407+
& xldefine.XL_CANFD_BusParams_CanOpMode.XL_BUS_PARAMS_CANOPMODE_CANFD
408+
)
409+
assert xl_channel_config.busParams.data.canFD.arbitrationBitRate == 500_000
410+
assert xl_channel_config.busParams.data.canFD.sjwAbr == 10
411+
assert xl_channel_config.busParams.data.canFD.tseg1Abr == 68
412+
assert xl_channel_config.busParams.data.canFD.tseg2Abr == 11
413+
assert xl_channel_config.busParams.data.canFD.sjwDbr == 8
414+
assert xl_channel_config.busParams.data.canFD.tseg1Dbr == 10
415+
assert xl_channel_config.busParams.data.canFD.tseg2Dbr == 9
416+
assert xl_channel_config.busParams.data.canFD.dataBitRate == 2_000_000
417+
418+
bus.shutdown()
419+
420+
273421
def test_send_mocked(mock_xldriver) -> None:
274422
bus = can.Bus(channel=0, interface="vector", _testing=True)
275423
msg = can.Message(

0 commit comments

Comments
 (0)