Skip to content

Commit 09213b1

Browse files
lumagizariiii9003
andauthored
Add protocol property to BusABC to determine active CAN Protocol (hardbyte#1532)
* Implement is_fd property for BusABC and PCANBus * Implement enum to represent CAN protocol * Implement CANProtocol for VirtualBus * Implement CANProtocol for UDPMulticastBus * Implement CANProtocol for the CANalystIIBus * Implement CANProtocol for the slcanBus * Rename CANProtocol to CanProtocol * Reimplement PcanBus.fd attribute as read-only property The property is scheduled for removal in v5.0 * Reimplement UdpMulticastBus.is_fd attribute as read-only property The property is superseded by BusABC.protocol and scheduled for removal in version 5.0. * Implement CanProtocol for robotellBus * Implement CanProtocol for NicanBus * Implement CanProtocol for IscanBus * Implement CanProtocol for CantactBus * Fix sphinx reference to CanProtocol * Implement CanProtocol for GsUsbBus * Implement CanProtocol for NiXNETcanBus * Implement CanProtocol for EtasBus * Implement CanProtocol for IXXATBus * Implement CanProtocol for KvaserBus * Implement CanProtocol for the SerialBus * Implement CanProtocol for UcanBus * Implement CanProtocol for VectorBus * Implement CanProtocol for NeousysBus * Implement CanProtocol for Usb2canBus * Implement CanProtocol for NeoViBus * Implement CanProtocol for SocketcanBus * Permit passthrough of protocol field for SocketCanDaemonBus * Implement CanProtocol for SeeedBus * Remove CanProtocol attribute from BusABC constructor The attribute is now set as class attribute with default value and can be overridden in the subclass constructor. * Apply suggestions from code review Fix property access and enum comparison Co-authored-by: zariiii9003 <[email protected]> * Fix syntax error * Fix more enum comparisons against BusABC.protocol --------- Co-authored-by: zariiii9003 <[email protected]>
1 parent 25fe566 commit 09213b1

38 files changed

+327
-81
lines changed

can/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"CanInitializationError",
2626
"CanInterfaceNotImplementedError",
2727
"CanOperationError",
28+
"CanProtocol",
2829
"CanTimeoutError",
2930
"CanutilsLogReader",
3031
"CanutilsLogWriter",
@@ -88,7 +89,7 @@
8889
ModifiableCyclicTaskABC,
8990
RestartableCyclicTaskABC,
9091
)
91-
from .bus import BusABC, BusState
92+
from .bus import BusABC, BusState, CanProtocol
9293
from .exceptions import (
9394
CanError,
9495
CanInitializationError,

can/bus.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ class BusState(Enum):
2626
ERROR = auto()
2727

2828

29+
class CanProtocol(Enum):
30+
"""The CAN protocol type supported by a :class:`can.BusABC` instance"""
31+
32+
CAN_20 = auto()
33+
CAN_FD = auto()
34+
CAN_XL = auto()
35+
36+
2937
class BusABC(metaclass=ABCMeta):
3038
"""The CAN Bus Abstract Base Class that serves as the basis
3139
for all concrete interfaces.
@@ -44,6 +52,7 @@ class BusABC(metaclass=ABCMeta):
4452
RECV_LOGGING_LEVEL = 9
4553

4654
_is_shutdown: bool = False
55+
_can_protocol: CanProtocol = CanProtocol.CAN_20
4756

4857
@abstractmethod
4958
def __init__(
@@ -459,6 +468,15 @@ def state(self, new_state: BusState) -> None:
459468
"""
460469
raise NotImplementedError("Property is not implemented.")
461470

471+
@property
472+
def protocol(self) -> CanProtocol:
473+
"""Return the CAN protocol used by this bus instance.
474+
475+
This value is set at initialization time and does not change
476+
during the lifetime of a bus instance.
477+
"""
478+
return self._can_protocol
479+
462480
@staticmethod
463481
def _detect_available_configs() -> List[can.typechecking.AutoDetectedConfig]:
464482
"""Detect all configurations/channels that this interface could

can/interfaces/canalystii.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import canalystii as driver
88

9-
from can import BitTiming, BitTimingFd, BusABC, Message
9+
from can import BitTiming, BitTimingFd, BusABC, CanProtocol, Message
1010
from can.exceptions import CanTimeoutError
1111
from can.typechecking import CanFilters
1212
from can.util import check_or_adjust_timing_clock, deprecated_args_alias
@@ -54,8 +54,11 @@ def __init__(
5454
raise ValueError("Either bitrate or timing argument is required")
5555

5656
# Do this after the error handling
57-
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
58-
57+
super().__init__(
58+
channel=channel,
59+
can_filters=can_filters,
60+
**kwargs,
61+
)
5962
if isinstance(channel, str):
6063
# Assume comma separated string of channels
6164
self.channels = [int(ch.strip()) for ch in channel.split(",")]
@@ -64,11 +67,11 @@ def __init__(
6467
else: # Sequence[int]
6568
self.channels = list(channel)
6669

67-
self.rx_queue: Deque[Tuple[int, driver.Message]] = deque(maxlen=rx_queue_size)
68-
6970
self.channel_info = f"CANalyst-II: device {device}, channels {self.channels}"
70-
71+
self.rx_queue: Deque[Tuple[int, driver.Message]] = deque(maxlen=rx_queue_size)
7172
self.device = driver.CanalystDevice(device_index=device)
73+
self._can_protocol = CanProtocol.CAN_20
74+
7275
for single_channel in self.channels:
7376
if isinstance(timing, BitTiming):
7477
timing = check_or_adjust_timing_clock(timing, valid_clocks=[8_000_000])

can/interfaces/cantact.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import Any, Optional, Union
88
from unittest.mock import Mock
99

10-
from can import BitTiming, BitTimingFd, BusABC, Message
10+
from can import BitTiming, BitTimingFd, BusABC, CanProtocol, Message
1111

1212
from ..exceptions import (
1313
CanInitializationError,
@@ -87,6 +87,7 @@ def __init__(
8787

8888
self.channel = int(channel)
8989
self.channel_info = f"CANtact: ch:{channel}"
90+
self._can_protocol = CanProtocol.CAN_20
9091

9192
# Configure the interface
9293
with error_check("Cannot setup the cantact.Interface", CanInitializationError):
@@ -114,7 +115,10 @@ def __init__(
114115
self.interface.start()
115116

116117
super().__init__(
117-
channel=channel, bitrate=bitrate, poll_interval=poll_interval, **kwargs
118+
channel=channel,
119+
bitrate=bitrate,
120+
poll_interval=poll_interval,
121+
**kwargs,
118122
)
119123

120124
def _recv_internal(self, timeout):

can/interfaces/etas/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import ctypes
21
import time
32
from typing import Dict, List, Optional, Tuple
43

@@ -17,9 +16,12 @@ def __init__(
1716
bitrate: int = 1000000,
1817
fd: bool = True,
1918
data_bitrate: int = 2000000,
20-
**kwargs: object,
19+
**kwargs: Dict[str, any],
2120
):
21+
super().__init__(channel=channel, **kwargs)
22+
2223
self.receive_own_messages = receive_own_messages
24+
self._can_protocol = can.CanProtocol.CAN_FD if fd else can.CanProtocol.CAN_20
2325

2426
nodeRange = CSI_NodeRange(CSI_NODE_MIN, CSI_NODE_MAX)
2527
self.tree = ctypes.POINTER(CSI_Tree)()
@@ -297,7 +299,7 @@ def _detect_available_configs() -> List[can.typechecking.AutoDetectedConfig]:
297299
tree = ctypes.POINTER(CSI_Tree)()
298300
CSI_CreateProtocolTree(ctypes.c_char_p(b""), nodeRange, ctypes.byref(tree))
299301

300-
nodes: Dict[str, str] = []
302+
nodes: List[Dict[str, str]] = []
301303

302304
def _findNodes(tree, prefix):
303305
uri = f"{prefix}/{tree.contents.item.uriName.decode()}"

can/interfaces/gs_usb.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,16 @@ def __init__(
5252

5353
self.gs_usb = gs_usb
5454
self.channel_info = channel
55+
self._can_protocol = can.CanProtocol.CAN_20
5556

5657
self.gs_usb.set_bitrate(bitrate)
5758
self.gs_usb.start()
5859

59-
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
60+
super().__init__(
61+
channel=channel,
62+
can_filters=can_filters,
63+
**kwargs,
64+
)
6065

6166
def send(self, msg: can.Message, timeout: Optional[float] = None):
6267
"""Transmit a message to the CAN bus.

can/interfaces/ics_neovi/neovi_bus.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from threading import Event
1717
from warnings import warn
1818

19-
from can import BusABC, Message
19+
from can import BusABC, CanProtocol, Message
2020

2121
from ...exceptions import (
2222
CanError,
@@ -169,7 +169,11 @@ def __init__(self, channel, can_filters=None, **kwargs):
169169
if ics is None:
170170
raise ImportError("Please install python-ics")
171171

172-
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
172+
super().__init__(
173+
channel=channel,
174+
can_filters=can_filters,
175+
**kwargs,
176+
)
173177

174178
logger.info(f"CAN Filters: {can_filters}")
175179
logger.info(f"Got configuration of: {kwargs}")
@@ -190,6 +194,9 @@ def __init__(self, channel, can_filters=None, **kwargs):
190194
serial = kwargs.get("serial")
191195
self.dev = self._find_device(type_filter, serial)
192196

197+
is_fd = kwargs.get("fd", False)
198+
self._can_protocol = CanProtocol.CAN_FD if is_fd else CanProtocol.CAN_20
199+
193200
with open_lock:
194201
ics.open_device(self.dev)
195202

@@ -198,7 +205,7 @@ def __init__(self, channel, can_filters=None, **kwargs):
198205
for channel in self.channels:
199206
ics.set_bit_rate(self.dev, kwargs.get("bitrate"), channel)
200207

201-
if kwargs.get("fd", False):
208+
if is_fd:
202209
if "data_bitrate" in kwargs:
203210
for channel in self.channels:
204211
ics.set_fd_bit_rate(

can/interfaces/iscan.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
CanInitializationError,
1414
CanInterfaceNotImplementedError,
1515
CanOperationError,
16+
CanProtocol,
1617
Message,
1718
)
1819

@@ -99,6 +100,7 @@ def __init__(
99100

100101
self.channel = ctypes.c_ubyte(int(channel))
101102
self.channel_info = f"IS-CAN: {self.channel}"
103+
self._can_protocol = CanProtocol.CAN_20
102104

103105
if bitrate not in self.BAUDRATES:
104106
raise ValueError(f"Invalid bitrate, choose one of {set(self.BAUDRATES)}")
@@ -107,7 +109,10 @@ def __init__(
107109
iscan.isCAN_DeviceInitEx(self.channel, self.BAUDRATES[bitrate])
108110

109111
super().__init__(
110-
channel=channel, bitrate=bitrate, poll_interval=poll_interval, **kwargs
112+
channel=channel,
113+
bitrate=bitrate,
114+
poll_interval=poll_interval,
115+
**kwargs,
111116
)
112117

113118
def _recv_internal(

can/interfaces/ixxat/canlib.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ def __init__(
131131
**kwargs
132132
)
133133

134+
super().__init__(channel=channel, **kwargs)
135+
self._can_protocol = self.bus.protocol
136+
134137
def flush_tx_buffer(self):
135138
"""Flushes the transmit buffer on the IXXAT"""
136139
return self.bus.flush_tx_buffer()

can/interfaces/ixxat/canlib_vcinpl.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import sys
1616
from typing import Callable, Optional, Tuple
1717

18-
from can import BusABC, Message
18+
from can import BusABC, CanProtocol, Message
1919
from can.broadcastmanager import (
2020
LimitedDurationCyclicSendTaskABC,
2121
RestartableCyclicTaskABC,
@@ -490,6 +490,7 @@ def __init__(
490490
self._channel_capabilities = structures.CANCAPABILITIES()
491491
self._message = structures.CANMSG()
492492
self._payload = (ctypes.c_byte * 8)()
493+
self._can_protocol = CanProtocol.CAN_20
493494

494495
# Search for supplied device
495496
if unique_hardware_id is None:

can/interfaces/ixxat/canlib_vcinpl2.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@
1515
import sys
1616
from typing import Callable, Optional, Tuple
1717

18-
import can.util
19-
from can import BusABC, Message
18+
from can import BusABC, CanProtocol, Message
2019
from can.broadcastmanager import (
2120
LimitedDurationCyclicSendTaskABC,
2221
RestartableCyclicTaskABC,
2322
)
2423
from can.ctypesutil import HANDLE, PHANDLE, CLibrary
2524
from can.ctypesutil import HRESULT as ctypes_HRESULT
2625
from can.exceptions import CanInitializationError, CanInterfaceNotImplementedError
27-
from can.util import deprecated_args_alias
26+
from can.util import deprecated_args_alias, dlc2len, len2dlc
2827

2928
from . import constants, structures
3029
from .exceptions import *
@@ -536,6 +535,7 @@ def __init__(
536535
self._channel_capabilities = structures.CANCAPABILITIES2()
537536
self._message = structures.CANMSG2()
538537
self._payload = (ctypes.c_byte * 64)()
538+
self._can_protocol = CanProtocol.CAN_FD
539539

540540
# Search for supplied device
541541
if unique_hardware_id is None:
@@ -865,7 +865,7 @@ def _recv_internal(self, timeout):
865865
# Timed out / can message type is not DATA
866866
return None, True
867867

868-
data_len = can.util.dlc2len(self._message.uMsgInfo.Bits.dlc)
868+
data_len = dlc2len(self._message.uMsgInfo.Bits.dlc)
869869
# The _message.dwTime is a 32bit tick value and will overrun,
870870
# so expect to see the value restarting from 0
871871
rx_msg = Message(
@@ -915,7 +915,7 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None:
915915
message.uMsgInfo.Bits.edl = 1 if msg.is_fd else 0
916916
message.dwMsgId = msg.arbitration_id
917917
if msg.dlc: # this dlc means number of bytes of payload
918-
message.uMsgInfo.Bits.dlc = can.util.len2dlc(msg.dlc)
918+
message.uMsgInfo.Bits.dlc = len2dlc(msg.dlc)
919919
data_len_dif = msg.dlc - len(msg.data)
920920
data = msg.data + bytearray(
921921
[0] * data_len_dif

can/interfaces/kvaser/canlib.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import sys
1212
import time
1313

14-
from can import BusABC, Message
14+
from can import BusABC, CanProtocol, Message
1515
from can.util import time_perfcounter_correlation
1616

1717
from ...exceptions import CanError, CanInitializationError, CanOperationError
@@ -428,11 +428,12 @@ def __init__(self, channel, can_filters=None, **kwargs):
428428
channel = int(channel)
429429
except ValueError:
430430
raise ValueError("channel must be an integer")
431-
self.channel = channel
432431

433-
log.debug("Initialising bus instance")
432+
self.channel = channel
434433
self.single_handle = single_handle
434+
self._can_protocol = CanProtocol.CAN_FD if fd else CanProtocol.CAN_20
435435

436+
log.debug("Initialising bus instance")
436437
num_channels = ctypes.c_int(0)
437438
canGetNumberOfChannels(ctypes.byref(num_channels))
438439
num_channels = int(num_channels.value)
@@ -520,7 +521,11 @@ def __init__(self, channel, can_filters=None, **kwargs):
520521
self._timestamp_offset = time.time() - (timer.value * TIMESTAMP_FACTOR)
521522

522523
self._is_filtered = False
523-
super().__init__(channel=channel, can_filters=can_filters, **kwargs)
524+
super().__init__(
525+
channel=channel,
526+
can_filters=can_filters,
527+
**kwargs,
528+
)
524529

525530
def _apply_filters(self, filters):
526531
if filters and len(filters) == 1:

can/interfaces/neousys/neousys.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@
3434
except ImportError:
3535
from ctypes import CDLL
3636

37-
from can import BusABC, Message
38-
39-
from ...exceptions import (
37+
from can import (
38+
BusABC,
4039
CanInitializationError,
4140
CanInterfaceNotImplementedError,
4241
CanOperationError,
42+
CanProtocol,
43+
Message,
4344
)
4445

4546
logger = logging.getLogger(__name__)
@@ -150,6 +151,7 @@ def __init__(self, channel, device=0, bitrate=500000, **kwargs):
150151
self.channel = channel
151152
self.device = device
152153
self.channel_info = f"Neousys Can: device {self.device}, channel {self.channel}"
154+
self._can_protocol = CanProtocol.CAN_20
153155

154156
self.queue = queue.Queue()
155157

can/interfaces/nican.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
from typing import Optional, Tuple, Type
2020

2121
import can.typechecking
22-
from can import BusABC, Message
23-
24-
from ..exceptions import (
22+
from can import (
23+
BusABC,
2524
CanError,
2625
CanInitializationError,
2726
CanInterfaceNotImplementedError,
2827
CanOperationError,
28+
CanProtocol,
29+
Message,
2930
)
3031

3132
logger = logging.getLogger(__name__)
@@ -219,6 +220,7 @@ def __init__(
219220

220221
self.channel = channel
221222
self.channel_info = f"NI-CAN: {channel}"
223+
self._can_protocol = CanProtocol.CAN_20
222224
channel_bytes = channel.encode("ascii")
223225

224226
config = [(NC_ATTR_START_ON_OPEN, True), (NC_ATTR_LOG_COMM_ERRS, log_errors)]

0 commit comments

Comments
 (0)