Skip to content

Commit 2d60900

Browse files
authored
Add BitTiming/BitTimingFd support to KvaserBus (#1510)
* add BitTiming parameter to KvaserBus * implement tests for bittiming classes with kvaser * set default number of samples to 1 * undo last change
1 parent 7b353ca commit 2d60900

File tree

2 files changed

+98
-20
lines changed

2 files changed

+98
-20
lines changed

can/interfaces/kvaser/canlib.py

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import logging
1111
import sys
1212
import time
13+
from typing import Optional, Union
1314

14-
from can import BusABC, CanProtocol, Message
15-
from can.util import time_perfcounter_correlation
15+
from can import BitTiming, BitTimingFd, BusABC, CanProtocol, Message
16+
from can.exceptions import CanError, CanInitializationError, CanOperationError
17+
from can.typechecking import CanFilters
18+
from can.util import check_or_adjust_timing_clock, time_perfcounter_correlation
1619

17-
from ...exceptions import CanError, CanInitializationError, CanOperationError
1820
from . import constants as canstat
1921
from . import structures
2022

@@ -199,6 +201,17 @@ def __check_bus_handle_validity(handle, function, arguments):
199201
errcheck=__check_status_initialization,
200202
)
201203

204+
canSetBusParamsC200 = __get_canlib_function(
205+
"canSetBusParamsC200",
206+
argtypes=[
207+
c_canHandle,
208+
ctypes.c_byte,
209+
ctypes.c_byte,
210+
],
211+
restype=canstat.c_canStatus,
212+
errcheck=__check_status_initialization,
213+
)
214+
202215
canSetBusParamsFd = __get_canlib_function(
203216
"canSetBusParamsFd",
204217
argtypes=[
@@ -360,7 +373,13 @@ class KvaserBus(BusABC):
360373
The CAN Bus implemented for the Kvaser interface.
361374
"""
362375

363-
def __init__(self, channel, can_filters=None, **kwargs):
376+
def __init__(
377+
self,
378+
channel: int,
379+
can_filters: Optional[CanFilters] = None,
380+
timing: Optional[Union[BitTiming, BitTimingFd]] = None,
381+
**kwargs,
382+
):
364383
"""
365384
:param int channel:
366385
The Channel id to create this bus with.
@@ -370,6 +389,12 @@ def __init__(self, channel, can_filters=None, **kwargs):
370389
371390
Backend Configuration
372391
392+
:param timing:
393+
An instance of :class:`~can.BitTiming` or :class:`~can.BitTimingFd`
394+
to specify the bit timing parameters for the Kvaser interface. If provided, it
395+
takes precedence over the all other timing-related parameters.
396+
Note that the `f_clock` property of the `timing` instance must be 16_000_000 (16MHz)
397+
for standard CAN or 80_000_000 (80MHz) for CAN FD.
373398
:param int bitrate:
374399
Bitrate of channel in bit/s
375400
:param bool accept_virtual:
@@ -427,7 +452,7 @@ def __init__(self, channel, can_filters=None, **kwargs):
427452
exclusive = kwargs.get("exclusive", False)
428453
override_exclusive = kwargs.get("override_exclusive", False)
429454
accept_virtual = kwargs.get("accept_virtual", True)
430-
fd = kwargs.get("fd", False)
455+
fd = isinstance(timing, BitTimingFd) if timing else kwargs.get("fd", False)
431456
data_bitrate = kwargs.get("data_bitrate", None)
432457

433458
try:
@@ -468,22 +493,43 @@ def __init__(self, channel, can_filters=None, **kwargs):
468493
ctypes.byref(ctypes.c_long(TIMESTAMP_RESOLUTION)),
469494
4,
470495
)
471-
472-
if fd:
473-
if "tseg1" not in kwargs and bitrate in BITRATE_FD:
474-
# Use predefined bitrate for arbitration
475-
bitrate = BITRATE_FD[bitrate]
476-
if data_bitrate in BITRATE_FD:
477-
# Use predefined bitrate for data
478-
data_bitrate = BITRATE_FD[data_bitrate]
479-
elif not data_bitrate:
480-
# Use same bitrate for arbitration and data phase
481-
data_bitrate = bitrate
482-
canSetBusParamsFd(self._read_handle, data_bitrate, tseg1, tseg2, sjw)
496+
if isinstance(timing, BitTimingFd):
497+
timing = check_or_adjust_timing_clock(timing, [80_000_000])
498+
canSetBusParams(
499+
self._read_handle,
500+
timing.nom_bitrate,
501+
timing.nom_tseg1,
502+
timing.nom_tseg2,
503+
timing.nom_sjw,
504+
1,
505+
0,
506+
)
507+
canSetBusParamsFd(
508+
self._read_handle,
509+
timing.data_bitrate,
510+
timing.data_tseg1,
511+
timing.data_tseg2,
512+
timing.data_sjw,
513+
)
514+
elif isinstance(timing, BitTiming):
515+
timing = check_or_adjust_timing_clock(timing, [16_000_000])
516+
canSetBusParamsC200(self._read_handle, timing.btr0, timing.btr1)
483517
else:
484-
if "tseg1" not in kwargs and bitrate in BITRATE_OBJS:
485-
bitrate = BITRATE_OBJS[bitrate]
486-
canSetBusParams(self._read_handle, bitrate, tseg1, tseg2, sjw, no_samp, 0)
518+
if fd:
519+
if "tseg1" not in kwargs and bitrate in BITRATE_FD:
520+
# Use predefined bitrate for arbitration
521+
bitrate = BITRATE_FD[bitrate]
522+
if data_bitrate in BITRATE_FD:
523+
# Use predefined bitrate for data
524+
data_bitrate = BITRATE_FD[data_bitrate]
525+
elif not data_bitrate:
526+
# Use same bitrate for arbitration and data phase
527+
data_bitrate = bitrate
528+
canSetBusParamsFd(self._read_handle, data_bitrate, tseg1, tseg2, sjw)
529+
else:
530+
if "tseg1" not in kwargs and bitrate in BITRATE_OBJS:
531+
bitrate = BITRATE_OBJS[bitrate]
532+
canSetBusParams(self._read_handle, bitrate, tseg1, tseg2, sjw, no_samp, 0)
487533

488534
# By default, use local echo if single handle is used (see #160)
489535
local_echo = single_handle or receive_own_messages

test/test_kvaser.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def setUp(self):
2121
canlib.canIoCtl = Mock(return_value=0)
2222
canlib.canIoCtlInit = Mock(return_value=0)
2323
canlib.kvReadTimer = Mock()
24+
canlib.canSetBusParamsC200 = Mock()
2425
canlib.canSetBusParams = Mock()
2526
canlib.canSetBusParamsFd = Mock()
2627
canlib.canBusOn = Mock()
@@ -179,6 +180,37 @@ def test_canfd_default_data_bitrate(self):
179180
0, constants.canFD_BITRATE_500K_80P, 0, 0, 0
180181
)
181182

183+
def test_can_timing(self):
184+
canlib.canSetBusParams.reset_mock()
185+
canlib.canSetBusParamsFd.reset_mock()
186+
timing = can.BitTiming.from_bitrate_and_segments(
187+
f_clock=16_000_000,
188+
bitrate=125_000,
189+
tseg1=13,
190+
tseg2=2,
191+
sjw=1,
192+
)
193+
can.Bus(channel=0, interface="kvaser", timing=timing)
194+
canlib.canSetBusParamsC200.assert_called_once_with(0, timing.btr0, timing.btr1)
195+
196+
def test_canfd_timing(self):
197+
canlib.canSetBusParams.reset_mock()
198+
canlib.canSetBusParamsFd.reset_mock()
199+
timing = can.BitTimingFd.from_bitrate_and_segments(
200+
f_clock=80_000_000,
201+
nom_bitrate=500_000,
202+
nom_tseg1=68,
203+
nom_tseg2=11,
204+
nom_sjw=10,
205+
data_bitrate=2_000_000,
206+
data_tseg1=10,
207+
data_tseg2=9,
208+
data_sjw=8,
209+
)
210+
can.Bus(channel=0, interface="kvaser", timing=timing)
211+
canlib.canSetBusParams.assert_called_once_with(0, 500_000, 68, 11, 10, 1, 0)
212+
canlib.canSetBusParamsFd.assert_called_once_with(0, 2_000_000, 10, 9, 8)
213+
182214
def test_canfd_nondefault_data_bitrate(self):
183215
canlib.canSetBusParams.reset_mock()
184216
canlib.canSetBusParamsFd.reset_mock()

0 commit comments

Comments
 (0)