21
21
Any ,
22
22
Dict ,
23
23
Callable ,
24
+ cast ,
24
25
)
25
26
26
27
WaitForSingleObject : Optional [Callable [[int , int ], int ]]
43
44
deprecated_args_alias ,
44
45
time_perfcounter_correlation ,
45
46
)
46
- from can .typechecking import AutoDetectedConfig , CanFilters , Channel
47
+ from can .typechecking import AutoDetectedConfig , CanFilters
47
48
48
49
# Define Module Logger
49
50
# ====================
@@ -152,6 +153,7 @@ def __init__(
152
153
if xldriver is None :
153
154
raise CanInterfaceNotImplementedError ("The Vector API has not been loaded" )
154
155
self .xldriver = xldriver # keep reference so mypy knows it is not None
156
+ self .xldriver .xlOpenDriver ()
155
157
156
158
self .poll_interval = poll_interval
157
159
@@ -165,7 +167,7 @@ def __init__(
165
167
self .channels = [int (ch ) for ch in channel ]
166
168
else :
167
169
raise TypeError (
168
- f"Invalid type for channels parameter: { type (channel ).__name__ } "
170
+ f"Invalid type for parameter 'channel' : { type (channel ).__name__ } "
169
171
)
170
172
171
173
self ._app_name = app_name .encode () if app_name is not None else b""
@@ -174,136 +176,71 @@ def __init__(
174
176
", " .join (f"CAN { ch + 1 } " for ch in self .channels ),
175
177
)
176
178
177
- if serial is not None :
178
- app_name = None
179
- channel_index = []
180
- channel_configs = get_channel_configs ()
181
- for channel_config in channel_configs :
182
- if channel_config .serialNumber == serial :
183
- if channel_config .hwChannel in self .channels :
184
- channel_index .append (channel_config .channelIndex )
185
- if channel_index :
186
- if len (channel_index ) != len (self .channels ):
187
- LOG .info (
188
- "At least one defined channel wasn't found on the specified hardware."
189
- )
190
- self .channels = channel_index
191
- else :
192
- # Is there any better way to raise the error?
193
- raise CanInitializationError (
194
- "None of the configured channels could be found on the specified hardware."
195
- )
179
+ channel_configs = get_channel_configs ()
196
180
197
- self .xldriver .xlOpenDriver ()
198
- self .port_handle = xlclass .XLportHandle (xldefine .XL_INVALID_PORTHANDLE )
199
181
self .mask = 0
200
182
self .fd = fd
201
- # Get channels masks
202
- self .channel_masks : Dict [Optional [Channel ], int ] = {}
203
- self .index_to_channel = {}
183
+ self .channel_masks : Dict [int , int ] = {}
184
+ self .index_to_channel : Dict [int , int ] = {}
204
185
205
186
for channel in self .channels :
206
- if app_name :
207
- # Get global channel index from application channel
208
- hw_type , hw_index , hw_channel = self .get_application_config (
209
- app_name , channel
210
- )
211
- LOG .debug ("Channel index %d found" , channel )
212
- idx = self .xldriver .xlGetChannelIndex (hw_type , hw_index , hw_channel )
213
- if idx < 0 :
214
- # Undocumented behavior! See issue #353.
215
- # If hardware is unavailable, this function returns -1.
216
- # Raise an exception as if the driver
217
- # would have signalled XL_ERR_HW_NOT_PRESENT.
218
- raise VectorInitializationError (
219
- xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT ,
220
- xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT .name ,
221
- "xlGetChannelIndex" ,
222
- )
223
- else :
224
- # Channel already given as global channel
225
- idx = channel
226
- mask = 1 << idx
227
- self .channel_masks [channel ] = mask
228
- self .index_to_channel [idx ] = channel
229
- self .mask |= mask
187
+ channel_index = self ._find_global_channel_idx (
188
+ channel = channel ,
189
+ serial = serial ,
190
+ app_name = app_name ,
191
+ channel_configs = channel_configs ,
192
+ )
193
+ LOG .debug ("Channel index %d found" , channel )
194
+
195
+ channel_mask = 1 << channel_index
196
+ self .channel_masks [channel ] = channel_mask
197
+ self .index_to_channel [channel_index ] = channel
198
+ self .mask |= channel_mask
230
199
231
200
permission_mask = xlclass .XLaccess ()
232
201
# Set mask to request channel init permission if needed
233
202
if bitrate or fd :
234
203
permission_mask .value = self .mask
235
- if fd :
236
- self .xldriver .xlOpenPort (
237
- self .port_handle ,
238
- self ._app_name ,
239
- self .mask ,
240
- permission_mask ,
241
- rx_queue_size ,
242
- xldefine .XL_InterfaceVersion .XL_INTERFACE_VERSION_V4 ,
243
- xldefine .XL_BusTypes .XL_BUS_TYPE_CAN ,
244
- )
245
- else :
246
- self .xldriver .xlOpenPort (
247
- self .port_handle ,
248
- self ._app_name ,
249
- self .mask ,
250
- permission_mask ,
251
- rx_queue_size ,
252
- xldefine .XL_InterfaceVersion .XL_INTERFACE_VERSION ,
253
- xldefine .XL_BusTypes .XL_BUS_TYPE_CAN ,
254
- )
204
+
205
+ interface_version = (
206
+ xldefine .XL_InterfaceVersion .XL_INTERFACE_VERSION_V4
207
+ if fd
208
+ else xldefine .XL_InterfaceVersion .XL_INTERFACE_VERSION
209
+ )
210
+
211
+ self .port_handle = xlclass .XLportHandle (xldefine .XL_INVALID_PORTHANDLE )
212
+ self .xldriver .xlOpenPort (
213
+ self .port_handle ,
214
+ self ._app_name ,
215
+ self .mask ,
216
+ permission_mask ,
217
+ rx_queue_size ,
218
+ interface_version ,
219
+ xldefine .XL_BusTypes .XL_BUS_TYPE_CAN ,
220
+ )
221
+
255
222
LOG .debug (
256
223
"Open Port: PortHandle: %d, PermissionMask: 0x%X" ,
257
224
self .port_handle .value ,
258
225
permission_mask .value ,
259
226
)
260
227
261
- if permission_mask .value == self .mask :
262
- if fd :
263
- self .canFdConf = xlclass .XLcanFdConf ()
264
- if bitrate :
265
- self .canFdConf .arbitrationBitRate = int (bitrate )
266
- else :
267
- self .canFdConf .arbitrationBitRate = 500000
268
- self .canFdConf .sjwAbr = int (sjw_abr )
269
- self .canFdConf .tseg1Abr = int (tseg1_abr )
270
- self .canFdConf .tseg2Abr = int (tseg2_abr )
271
- if data_bitrate :
272
- self .canFdConf .dataBitRate = int (data_bitrate )
273
- else :
274
- self .canFdConf .dataBitRate = self .canFdConf .arbitrationBitRate
275
- self .canFdConf .sjwDbr = int (sjw_dbr )
276
- self .canFdConf .tseg1Dbr = int (tseg1_dbr )
277
- self .canFdConf .tseg2Dbr = int (tseg2_dbr )
278
-
279
- self .xldriver .xlCanFdSetConfiguration (
280
- self .port_handle , self .mask , self .canFdConf
281
- )
282
- LOG .info (
283
- "SetFdConfig.: ABaudr.=%u, DBaudr.=%u" ,
284
- self .canFdConf .arbitrationBitRate ,
285
- self .canFdConf .dataBitRate ,
286
- )
287
- LOG .info (
288
- "SetFdConfig.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u" ,
289
- self .canFdConf .sjwAbr ,
290
- self .canFdConf .tseg1Abr ,
291
- self .canFdConf .tseg2Abr ,
292
- )
293
- LOG .info (
294
- "SetFdConfig.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u" ,
295
- self .canFdConf .sjwDbr ,
296
- self .canFdConf .tseg1Dbr ,
297
- self .canFdConf .tseg2Dbr ,
298
- )
299
- else :
300
- if bitrate :
301
- self .xldriver .xlCanSetChannelBitrate (
302
- self .port_handle , permission_mask , bitrate
228
+ for channel in self .channels :
229
+ if permission_mask .value & self .channel_masks [channel ]:
230
+ if fd :
231
+ self ._set_bitrate_canfd (
232
+ channel = channel ,
233
+ bitrate = bitrate ,
234
+ data_bitrate = data_bitrate ,
235
+ sjw_abr = sjw_abr ,
236
+ tseg1_abr = tseg1_abr ,
237
+ tseg2_abr = tseg2_abr ,
238
+ sjw_dbr = sjw_dbr ,
239
+ tseg1_dbr = tseg1_dbr ,
240
+ tseg2_dbr = tseg2_dbr ,
303
241
)
304
- LOG .info ("SetChannelBitrate: baudr.=%u" , bitrate )
305
- else :
306
- LOG .info ("No init access!" )
242
+ elif bitrate :
243
+ self ._set_bitrate_can (channel = channel , bitrate = bitrate )
307
244
308
245
# Enable/disable TX receipts
309
246
tx_receipts = 1 if receive_own_messages else 0
@@ -348,6 +285,153 @@ def __init__(
348
285
self ._is_filtered = False
349
286
super ().__init__ (channel = channel , can_filters = can_filters , ** kwargs )
350
287
288
+ def _find_global_channel_idx (
289
+ self ,
290
+ channel : int ,
291
+ serial : Optional [int ],
292
+ app_name : Optional [str ],
293
+ channel_configs : List ["VectorChannelConfig" ],
294
+ ) -> int :
295
+ if serial is not None :
296
+ hw_type : Optional [xldefine .XL_HardwareType ] = None
297
+ for channel_config in channel_configs :
298
+ if channel_config .serialNumber != serial :
299
+ continue
300
+
301
+ hw_type = xldefine .XL_HardwareType (channel_config .hwType )
302
+ if channel_config .hwChannel == channel :
303
+ return channel_config .channelIndex
304
+
305
+ if hw_type is None :
306
+ err_msg = f"No interface with serial { serial } found."
307
+ else :
308
+ err_msg = f"Channel { channel } not found on interface { hw_type .name } ({ serial } )."
309
+ raise CanInitializationError (
310
+ err_msg , error_code = xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT
311
+ )
312
+
313
+ if app_name :
314
+ hw_type , hw_index , hw_channel = self .get_application_config (
315
+ app_name , channel
316
+ )
317
+ idx = cast (
318
+ int , self .xldriver .xlGetChannelIndex (hw_type , hw_index , hw_channel )
319
+ )
320
+ if idx < 0 :
321
+ # Undocumented behavior! See issue #353.
322
+ # If hardware is unavailable, this function returns -1.
323
+ # Raise an exception as if the driver
324
+ # would have signalled XL_ERR_HW_NOT_PRESENT.
325
+ raise VectorInitializationError (
326
+ xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT ,
327
+ xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT .name ,
328
+ "xlGetChannelIndex" ,
329
+ )
330
+ return idx
331
+
332
+ # check if channel is a valid global channel index
333
+ for channel_config in channel_configs :
334
+ if channel == channel_config .channelIndex :
335
+ return channel
336
+
337
+ raise CanInitializationError (
338
+ f"Channel { channel } not found. The 'channel' parameter must be "
339
+ f"a valid global channel index if neither 'app_name' nor 'serial' were given." ,
340
+ error_code = xldefine .XL_Status .XL_ERR_HW_NOT_PRESENT ,
341
+ )
342
+
343
+ def _set_bitrate_can (
344
+ self ,
345
+ channel : int ,
346
+ bitrate : int ,
347
+ sjw : Optional [int ] = None ,
348
+ tseg1 : Optional [int ] = None ,
349
+ tseg2 : Optional [int ] = None ,
350
+ sam : int = 1 ,
351
+ ) -> None :
352
+ kwargs = [sjw , tseg1 , tseg2 ]
353
+ if any (kwargs ) and not all (kwargs ):
354
+ raise ValueError (
355
+ f"Either all of sjw, tseg1, tseg2 must be set or none of them."
356
+ )
357
+
358
+ # set parameters if channel has init access
359
+ if any (kwargs ):
360
+ chip_params = xlclass .XLchipParams ()
361
+ chip_params .bitRate = bitrate
362
+ chip_params .sjw = sjw
363
+ chip_params .tseg1 = tseg1
364
+ chip_params .tseg2 = tseg2
365
+ chip_params .sam = sam
366
+ self .xldriver .xlCanSetChannelParams (
367
+ self .port_handle ,
368
+ self .channel_masks [channel ],
369
+ chip_params ,
370
+ )
371
+ LOG .info (
372
+ "xlCanSetChannelParams: baudr.=%u, sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u" ,
373
+ chip_params .bitRate ,
374
+ chip_params .sjw ,
375
+ chip_params .tseg1 ,
376
+ chip_params .tseg2 ,
377
+ )
378
+ else :
379
+ self .xldriver .xlCanSetChannelBitrate (
380
+ self .port_handle ,
381
+ self .channel_masks [channel ],
382
+ bitrate ,
383
+ )
384
+ LOG .info ("xlCanSetChannelBitrate: baudr.=%u" , bitrate )
385
+
386
+ def _set_bitrate_canfd (
387
+ self ,
388
+ channel : int ,
389
+ bitrate : Optional [int ] = None ,
390
+ data_bitrate : Optional [int ] = None ,
391
+ sjw_abr : int = 2 ,
392
+ tseg1_abr : int = 6 ,
393
+ tseg2_abr : int = 3 ,
394
+ sjw_dbr : int = 2 ,
395
+ tseg1_dbr : int = 6 ,
396
+ tseg2_dbr : int = 3 ,
397
+ ) -> None :
398
+ # set parameters if channel has init access
399
+ canfd_conf = xlclass .XLcanFdConf ()
400
+ if bitrate :
401
+ canfd_conf .arbitrationBitRate = int (bitrate )
402
+ else :
403
+ canfd_conf .arbitrationBitRate = 500_000
404
+ canfd_conf .sjwAbr = int (sjw_abr )
405
+ canfd_conf .tseg1Abr = int (tseg1_abr )
406
+ canfd_conf .tseg2Abr = int (tseg2_abr )
407
+ if data_bitrate :
408
+ canfd_conf .dataBitRate = int (data_bitrate )
409
+ else :
410
+ canfd_conf .dataBitRate = int (canfd_conf .arbitrationBitRate )
411
+ canfd_conf .sjwDbr = int (sjw_dbr )
412
+ canfd_conf .tseg1Dbr = int (tseg1_dbr )
413
+ canfd_conf .tseg2Dbr = int (tseg2_dbr )
414
+ self .xldriver .xlCanFdSetConfiguration (
415
+ self .port_handle , self .channel_masks [channel ], canfd_conf
416
+ )
417
+ LOG .info (
418
+ "xlCanFdSetConfiguration.: ABaudr.=%u, DBaudr.=%u" ,
419
+ canfd_conf .arbitrationBitRate ,
420
+ canfd_conf .dataBitRate ,
421
+ )
422
+ LOG .info (
423
+ "xlCanFdSetConfiguration.: sjwAbr=%u, tseg1Abr=%u, tseg2Abr=%u" ,
424
+ canfd_conf .sjwAbr ,
425
+ canfd_conf .tseg1Abr ,
426
+ canfd_conf .tseg2Abr ,
427
+ )
428
+ LOG .info (
429
+ "xlCanFdSetConfiguration.: sjwDbr=%u, tseg1Dbr=%u, tseg2Dbr=%u" ,
430
+ canfd_conf .sjwDbr ,
431
+ canfd_conf .tseg1Dbr ,
432
+ canfd_conf .tseg2Dbr ,
433
+ )
434
+
351
435
def _apply_filters (self , filters : Optional [CanFilters ]) -> None :
352
436
if filters :
353
437
# Only up to one filter per ID type allowed
@@ -544,7 +628,7 @@ def _send_sequence(self, msgs: Sequence[Message]) -> int:
544
628
545
629
def _get_tx_channel_mask (self , msgs : Sequence [Message ]) -> int :
546
630
if len (msgs ) == 1 :
547
- return self .channel_masks .get (msgs [0 ].channel , self .mask )
631
+ return self .channel_masks .get (msgs [0 ].channel , self .mask ) # type: ignore[arg-type]
548
632
else :
549
633
return self .mask
550
634
0 commit comments