7
7
from datetime import datetime
8
8
import platform
9
9
10
- from typing import Optional
10
+ from typing import Optional , Union
11
11
12
12
from packaging import version
13
13
14
+ from ... import BitTiming , BitTimingFd
14
15
from ...message import Message
15
16
from ...bus import BusABC , BusState
16
17
from ...util import len2dlc , dlc2len
57
58
FEATURE_FD_CAPABLE ,
58
59
PCAN_DICT_STATUS ,
59
60
PCAN_BUSOFF_AUTORESET ,
61
+ TPCANBaudrate ,
60
62
)
61
63
62
64
103
105
class PcanBus (BusABC ):
104
106
def __init__ (
105
107
self ,
106
- channel = "PCAN_USBBUS1" ,
107
- device_id = None ,
108
- state = BusState .ACTIVE ,
109
- bitrate = 500000 ,
108
+ channel : str = "PCAN_USBBUS1" ,
109
+ device_id : Optional [int ] = None ,
110
+ state : BusState = BusState .ACTIVE ,
111
+ timing : Optional [Union [BitTiming , BitTimingFd ]] = None ,
112
+ bitrate : int = 500000 ,
110
113
* args ,
111
114
** kwargs ,
112
115
):
@@ -133,6 +136,18 @@ def __init__(
133
136
BusState of the channel.
134
137
Default is ACTIVE
135
138
139
+ :param timing:
140
+ An instance of :class:`~can.BitTiming` or :class:`~can.BitTimingFd`
141
+ to specify the bit timing parameters for the PCAN interface. If this parameter
142
+ is provided, it takes precedence over all other timing-related parameters.
143
+ If this parameter is not provided, the bit timing parameters can be specified
144
+ using the `bitrate` parameter for standard CAN or the `fd`, `f_clock`,
145
+ `f_clock_mhz`, `nom_brp`, `nom_tseg1`, `nom_tseg2`, `nom_sjw`, `data_brp`,
146
+ `data_tseg1`, `data_tseg2`, and `data_sjw` parameters for CAN FD.
147
+ Note that the `f_clock` value of the `timing` instance must be 8_000_000
148
+ for standard CAN or any of the following values for CAN FD: 20_000_000,
149
+ 24_000_000, 30_000_000, 40_000_000, 60_000_000, 80_000_000.
150
+
136
151
:param int bitrate:
137
152
Bitrate of channel in bit/s.
138
153
Default is 500 kbit/s.
@@ -222,8 +237,9 @@ def __init__(
222
237
raise ValueError (err_msg )
223
238
224
239
self .channel_info = str (channel )
225
- self .fd = kwargs .get ("fd" , False )
226
- pcan_bitrate = PCAN_BITRATES .get (bitrate , PCAN_BAUD_500K )
240
+ self .fd = isinstance (timing , BitTimingFd ) or (
241
+ timing is None and kwargs .get ("fd" , False )
242
+ )
227
243
228
244
hwtype = PCAN_TYPE_ISA
229
245
ioport = 0x02A0
@@ -241,28 +257,69 @@ def __init__(
241
257
else :
242
258
raise ValueError ("BusState must be Active or Passive" )
243
259
244
- if self .fd :
245
- f_clock_val = kwargs .get ("f_clock" , None )
246
- if f_clock_val is None :
247
- f_clock = "{}={}" .format ("f_clock_mhz" , kwargs .get ("f_clock_mhz" , None ))
248
- else :
249
- f_clock = "{}={}" .format ("f_clock" , kwargs .get ("f_clock" , None ))
250
-
251
- fd_parameters_values = [f_clock ] + [
252
- f"{ key } ={ kwargs .get (key , None )} "
253
- for key in PCAN_FD_PARAMETER_LIST
254
- if kwargs .get (key , None ) is not None
260
+ if isinstance (timing , BitTimingFd ):
261
+ valid_fd_clocks = [
262
+ 20000000 ,
263
+ 24000000 ,
264
+ 30000000 ,
265
+ 40000000 ,
266
+ 60000000 ,
267
+ 80000000 ,
255
268
]
256
-
257
- self .fd_bitrate = " ," .join (fd_parameters_values ).encode ("ascii" )
258
-
269
+ if timing .f_clock not in valid_fd_clocks :
270
+ raise CanInitializationError (
271
+ f"The PcanBus requires one of the following CAN clocks for CAN FD: "
272
+ f"{ ',' .join ([str (f ) for f in valid_fd_clocks ])} (timing={ timing !r} )"
273
+ )
274
+ self .fd_bitrate = (
275
+ f"f_clock={ timing .f_clock } ,"
276
+ f"nom_brp={ timing .nom_brp } ,"
277
+ f"nom_tseg1={ timing .nom_tseg1 } ,"
278
+ f"nom_tseg2={ timing .nom_tseg2 } ,"
279
+ f"nom_sjw={ timing .nom_sjw } ,"
280
+ f"data_brp={ timing .data_brp } ,"
281
+ f"data_tseg1={ timing .data_tseg1 } ,"
282
+ f"data_tseg2={ timing .data_tseg2 } ,"
283
+ f"data_sjw={ timing .data_sjw } "
284
+ ).encode ("ascii" )
259
285
result = self .m_objPCANBasic .InitializeFD (
260
286
self .m_PcanHandle , self .fd_bitrate
261
287
)
262
- else :
288
+ elif isinstance (timing , BitTiming ):
289
+ if timing .f_clock != 8_000_000 :
290
+ raise CanInitializationError (
291
+ f"The PcanBus requires a 8MHz CAN clock for CAN2.0 (timing={ timing !r} )"
292
+ )
293
+ pcan_bitrate = TPCANBaudrate (timing .btr0 << 8 | timing .btr1 )
263
294
result = self .m_objPCANBasic .Initialize (
264
295
self .m_PcanHandle , pcan_bitrate , hwtype , ioport , interrupt
265
296
)
297
+ else :
298
+ if self .fd :
299
+ f_clock_val = kwargs .get ("f_clock" , None )
300
+ if f_clock_val is None :
301
+ f_clock = "{}={}" .format (
302
+ "f_clock_mhz" , kwargs .get ("f_clock_mhz" , None )
303
+ )
304
+ else :
305
+ f_clock = "{}={}" .format ("f_clock" , kwargs .get ("f_clock" , None ))
306
+
307
+ fd_parameters_values = [f_clock ] + [
308
+ f"{ key } ={ kwargs .get (key , None )} "
309
+ for key in PCAN_FD_PARAMETER_LIST
310
+ if kwargs .get (key , None ) is not None
311
+ ]
312
+
313
+ self .fd_bitrate = " ," .join (fd_parameters_values ).encode ("ascii" )
314
+
315
+ result = self .m_objPCANBasic .InitializeFD (
316
+ self .m_PcanHandle , self .fd_bitrate
317
+ )
318
+ else :
319
+ pcan_bitrate = PCAN_BITRATES .get (bitrate , PCAN_BAUD_500K )
320
+ result = self .m_objPCANBasic .Initialize (
321
+ self .m_PcanHandle , pcan_bitrate , hwtype , ioport , interrupt
322
+ )
266
323
267
324
if result != PCAN_ERROR_OK :
268
325
raise PcanCanInitializationError (self ._get_formatted_error (result ))
0 commit comments