Skip to content

Commit

Permalink
Add non-ISO CANFD support to kvaser (#1752)
Browse files Browse the repository at this point in the history
* Add basic non-iso support

* Update test_kvaser.py

Add unit test

* Update test_kvaser.py

Black to pass premerge checklist

* Made code changes

New enum for non-iso mode
Documentation sections fixes
Test update

* Update bus.py

Black cleanup
  • Loading branch information
jacobschaer authored Jun 22, 2024
1 parent 621cd7d commit 867fd92
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 3 deletions.
3 changes: 2 additions & 1 deletion can/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class CanProtocol(Enum):
"""The CAN protocol type supported by a :class:`can.BusABC` instance"""

CAN_20 = auto()
CAN_FD = auto()
CAN_FD = auto() # ISO Mode
CAN_FD_NON_ISO = auto()
CAN_XL = auto()


Expand Down
16 changes: 14 additions & 2 deletions can/interfaces/kvaser/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@ def __init__(
computer, set this to True or set single_handle to True.
:param bool fd:
If CAN-FD frames should be supported.
:param bool fd_non_iso:
Open the channel in Non-ISO (Bosch) FD mode. Only applies for FD buses.
This changes the handling of the stuff-bit counter and the CRC. Defaults
to False (ISO mode)
:param bool exclusive:
Don't allow sharing of this CANlib channel.
:param bool override_exclusive:
Expand All @@ -453,6 +457,7 @@ def __init__(
accept_virtual = kwargs.get("accept_virtual", True)
fd = isinstance(timing, BitTimingFd) if timing else kwargs.get("fd", False)
data_bitrate = kwargs.get("data_bitrate", None)
fd_non_iso = kwargs.get("fd_non_iso", False)

try:
channel = int(channel)
Expand All @@ -461,7 +466,11 @@ def __init__(

self.channel = channel
self.single_handle = single_handle
self._can_protocol = CanProtocol.CAN_FD if fd else CanProtocol.CAN_20
self._can_protocol = CanProtocol.CAN_20
if fd_non_iso:
self._can_protocol = CanProtocol.CAN_FD_NON_ISO
elif fd:
self._can_protocol = CanProtocol.CAN_FD

log.debug("Initialising bus instance")
num_channels = ctypes.c_int(0)
Expand All @@ -482,7 +491,10 @@ def __init__(
if accept_virtual:
flags |= canstat.canOPEN_ACCEPT_VIRTUAL
if fd:
flags |= canstat.canOPEN_CAN_FD
if fd_non_iso:
flags |= canstat.canOPEN_CAN_FD_NONISO
else:
flags |= canstat.canOPEN_CAN_FD

log.debug("Creating read handle to bus channel: %s", channel)
self._read_handle = canOpenChannel(channel, flags)
Expand Down
7 changes: 7 additions & 0 deletions doc/interfaces/pcan.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ Here is an example configuration file for using `PCAN-USB <https://www.peak-syst
``bitrate`` (default ``500000``)
Channel bitrate

ISO/Non-ISO CAN FD Mode
~~~~~~~~~~~~~~~~~~~~~~~

The PCAN basic driver doesn't presently allow toggling the ISO/Non-ISO FD modes directly.
The default mode is stored on the device and can be controlled using the PCANView Windows application.
See: https://forum.peak-system.com/viewtopic.php?t=6496

This restriction does not apply to the socket-can driver.

.. _pcandoc linux installation:

Expand Down
5 changes: 5 additions & 0 deletions doc/interfaces/socketcan.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ to ensure usage of SocketCAN Linux API. The most important differences are:
:members:
:inherited-members:

ISO/Non-ISO CAN FD Mode
-----------------------

Socket CAN devices can (for supported hardware) control ISO vs Non-ISO FD during creation with the ``ip`` command using the ``fd-non-iso`` flag.

.. External references
.. _Linux kernel docs: https://www.kernel.org/doc/Documentation/networking/can.txt
Expand Down
27 changes: 27 additions & 0 deletions test/test_kvaser.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def test_can_timing(self):
def test_canfd_timing(self):
canlib.canSetBusParams.reset_mock()
canlib.canSetBusParamsFd.reset_mock()
canlib.canOpenChannel.reset_mock()
timing = can.BitTimingFd.from_bitrate_and_segments(
f_clock=80_000_000,
nom_bitrate=500_000,
Expand All @@ -210,6 +211,32 @@ def test_canfd_timing(self):
can.Bus(channel=0, interface="kvaser", timing=timing)
canlib.canSetBusParams.assert_called_once_with(0, 500_000, 68, 11, 10, 1, 0)
canlib.canSetBusParamsFd.assert_called_once_with(0, 2_000_000, 10, 9, 8)
canlib.canOpenChannel.assert_called_with(
0, constants.canOPEN_CAN_FD | constants.canOPEN_ACCEPT_VIRTUAL
)

def test_canfd_non_iso(self):
canlib.canSetBusParams.reset_mock()
canlib.canSetBusParamsFd.reset_mock()
canlib.canOpenChannel.reset_mock()
timing = can.BitTimingFd.from_bitrate_and_segments(
f_clock=80_000_000,
nom_bitrate=500_000,
nom_tseg1=68,
nom_tseg2=11,
nom_sjw=10,
data_bitrate=2_000_000,
data_tseg1=10,
data_tseg2=9,
data_sjw=8,
)
bus = can.Bus(channel=0, interface="kvaser", timing=timing, fd_non_iso=True)
self.assertEqual(bus.protocol, can.CanProtocol.CAN_FD_NON_ISO)
canlib.canSetBusParams.assert_called_once_with(0, 500_000, 68, 11, 10, 1, 0)
canlib.canSetBusParamsFd.assert_called_once_with(0, 2_000_000, 10, 9, 8)
canlib.canOpenChannel.assert_called_with(
0, constants.canOPEN_CAN_FD_NONISO | constants.canOPEN_ACCEPT_VIRTUAL
)

def test_canfd_nondefault_data_bitrate(self):
canlib.canSetBusParams.reset_mock()
Expand Down

0 comments on commit 867fd92

Please sign in to comment.