16
16
CanOperationError ,
17
17
error_check ,
18
18
)
19
- from can .util import check_or_adjust_timing_clock , deprecated_args_alias
19
+ from can .util import CAN_FD_DLC , check_or_adjust_timing_clock , deprecated_args_alias
20
20
21
21
logger = logging .getLogger (__name__ )
22
22
@@ -48,6 +48,10 @@ class slcanBus(BusABC):
48
48
1000000 : "S8" ,
49
49
83300 : "S9" ,
50
50
}
51
+ _DATA_BITRATES = {
52
+ 2000000 : "Y2" ,
53
+ 5000000 : "Y5" ,
54
+ }
51
55
52
56
_SLEEP_AFTER_SERIAL_OPEN = 2 # in seconds
53
57
@@ -86,7 +90,8 @@ def __init__(
86
90
If this argument is set then it overrides the bitrate and btr arguments. The
87
91
`f_clock` value of the timing instance must be set to 8_000_000 (8MHz)
88
92
for standard CAN.
89
- CAN FD and the :class:`~can.BitTimingFd` class are not supported.
93
+ CAN FD and the :class:`~can.BitTimingFd` class have partial support according to the non-standard
94
+ slcan protocol implementation in the CANABLE 2.0 firmware: currently only data rates of 2M and 5M.
90
95
:param poll_interval:
91
96
Poll interval in seconds when reading messages
92
97
:param sleep_after_open:
@@ -143,9 +148,7 @@ def __init__(
143
148
timing = check_or_adjust_timing_clock (timing , valid_clocks = [8_000_000 ])
144
149
self .set_bitrate_reg (f"{ timing .btr0 :02X} { timing .btr1 :02X} " )
145
150
elif isinstance (timing , BitTimingFd ):
146
- raise NotImplementedError (
147
- f"CAN FD is not supported by { self .__class__ .__name__ } ."
148
- )
151
+ self .set_bitrate (timing .nom_bitrate , timing .data_bitrate )
149
152
else :
150
153
if bitrate is not None and btr is not None :
151
154
raise ValueError ("Bitrate and btr mutually exclusive." )
@@ -157,10 +160,12 @@ def __init__(
157
160
158
161
super ().__init__ (channel , ** kwargs )
159
162
160
- def set_bitrate (self , bitrate : int ) -> None :
163
+ def set_bitrate (self , bitrate : int , dbitrate : int = 0 ) -> None :
161
164
"""
162
165
:param bitrate:
163
166
Bitrate in bit/s
167
+ :param dbitrate:
168
+ Data Bitrate in bit/s for FD frames
164
169
165
170
:raise ValueError: if ``bitrate`` is not among the possible values
166
171
"""
@@ -169,9 +174,15 @@ def set_bitrate(self, bitrate: int) -> None:
169
174
else :
170
175
bitrates = ", " .join (str (k ) for k in self ._BITRATES .keys ())
171
176
raise ValueError (f"Invalid bitrate, choose one of { bitrates } ." )
177
+ if dbitrate in self ._DATA_BITRATES :
178
+ dbitrate_code = self ._DATA_BITRATES [dbitrate ]
179
+ else :
180
+ dbitrates = ", " .join (str (k ) for k in self ._DATA_BITRATES .keys ())
181
+ raise ValueError (f"Invalid data bitrate, choose one of { dbitrates } ." )
172
182
173
183
self .close ()
174
184
self ._write (bitrate_code )
185
+ self ._write (dbitrate_code )
175
186
self .open ()
176
187
177
188
def set_bitrate_reg (self , btr : str ) -> None :
@@ -235,6 +246,8 @@ def _recv_internal(
235
246
remote = False
236
247
extended = False
237
248
data = None
249
+ isFd = False
250
+ fdBrs = False
238
251
239
252
if self ._queue .qsize ():
240
253
string : Optional [str ] = self ._queue .get_nowait ()
@@ -268,13 +281,43 @@ def _recv_internal(
268
281
dlc = int (string [9 ])
269
282
extended = True
270
283
remote = True
284
+ elif string [0 ] == "d" :
285
+ # FD standard frame
286
+ canId = int (string [1 :4 ], 16 )
287
+ dlc = int (string [4 ], 16 )
288
+ isFd = True
289
+ data = bytearray .fromhex (string [5 : 5 + CAN_FD_DLC [dlc ] * 2 ])
290
+ elif string [0 ] == "D" :
291
+ # FD extended frame
292
+ canId = int (string [1 :9 ], 16 )
293
+ dlc = int (string [9 ], 16 )
294
+ extended = True
295
+ isFd = True
296
+ data = bytearray .fromhex (string [10 : 10 + CAN_FD_DLC [dlc ] * 2 ])
297
+ elif string [0 ] == "b" :
298
+ # FD with bitrate switch
299
+ canId = int (string [1 :4 ], 16 )
300
+ dlc = int (string [4 ], 16 )
301
+ isFd = True
302
+ fdBrs = True
303
+ data = bytearray .fromhex (string [5 : 5 + CAN_FD_DLC [dlc ] * 2 ])
304
+ elif string [0 ] == "B" :
305
+ # FD extended with bitrate switch
306
+ canId = int (string [1 :9 ], 16 )
307
+ dlc = int (string [9 ], 16 )
308
+ extended = True
309
+ isFd = True
310
+ fdBrs = True
311
+ data = bytearray .fromhex (string [10 : 10 + CAN_FD_DLC [dlc ] * 2 ])
271
312
272
313
if canId is not None :
273
314
msg = Message (
274
315
arbitration_id = canId ,
275
316
is_extended_id = extended ,
276
317
timestamp = time .time (), # Better than nothing...
277
318
is_remote_frame = remote ,
319
+ is_fd = isFd ,
320
+ bitrate_switch = fdBrs ,
278
321
dlc = dlc ,
279
322
data = data ,
280
323
)
@@ -289,6 +332,19 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None:
289
332
sendStr = f"R{ msg .arbitration_id :08X} { msg .dlc :d} "
290
333
else :
291
334
sendStr = f"r{ msg .arbitration_id :03X} { msg .dlc :d} "
335
+ elif msg .is_fd :
336
+ if msg .bitrate_switch :
337
+ if msg .is_extended_id :
338
+ sendStr = f"B{ msg .arbitration_id :08X} { msg .dlc :d} "
339
+ else :
340
+ sendStr = f"b{ msg .arbitration_id :03X} { msg .dlc :d} "
341
+ sendStr += msg .data .hex ().upper ()
342
+ else :
343
+ if msg .is_extended_id :
344
+ sendStr = f"D{ msg .arbitration_id :08X} { msg .dlc :d} "
345
+ else :
346
+ sendStr = f"d{ msg .arbitration_id :03X} { msg .dlc :d} "
347
+ sendStr += msg .data .hex ().upper ()
292
348
else :
293
349
if msg .is_extended_id :
294
350
sendStr = f"T{ msg .arbitration_id :08X} { msg .dlc :d} "
0 commit comments