@@ -120,9 +120,10 @@ def __init__(
120
120
:param timing:
121
121
An instance of :class:`~can.BitTiming` or :class:`~can.BitTimingFd`
122
122
to specify the bit timing parameters for the VectorBus interface. The
123
- `f_clock` value of the timing instance must be set to 16.000.000 (16MHz)
124
- for standard CAN or 80.000.000 (80MHz) for CAN FD. If this parameter is provided,
125
- it takes precedence over all other timing-related parameters.
123
+ `f_clock` value of the timing instance must be set to 8_000_000 (8MHz)
124
+ or 16_000_000 (16MHz) for CAN 2.0 or 80_000_000 (80MHz) for CAN FD.
125
+ If this parameter is provided, it takes precedence over all other
126
+ timing-related parameters.
126
127
Otherwise, the bit timing can be specified using the following parameters:
127
128
`bitrate` for standard CAN or `fd`, `data_bitrate`, `sjw_abr`, `tseg1_abr`,
128
129
`tseg2_abr`, `sjw_dbr`, `tseg1_dbr`, and `tseg2_dbr` for CAN FD.
@@ -252,42 +253,34 @@ def __init__(
252
253
# set CAN settings
253
254
for channel in self .channels :
254
255
if isinstance (timing , BitTiming ):
255
- timing = check_or_adjust_timing_clock (timing , [16_000_000 ])
256
- self ._set_bitrate_can (
256
+ timing = check_or_adjust_timing_clock (timing , [16_000_000 , 8_000_000 ])
257
+ self ._set_bit_timing (
257
258
channel = channel ,
258
- bitrate = timing .bitrate ,
259
- sjw = timing .sjw ,
260
- tseg1 = timing .tseg1 ,
261
- tseg2 = timing .tseg2 ,
262
- sam = timing .nof_samples ,
259
+ timing = timing ,
263
260
)
264
261
elif isinstance (timing , BitTimingFd ):
265
262
timing = check_or_adjust_timing_clock (timing , [80_000_000 ])
266
- self ._set_bitrate_canfd (
263
+ self ._set_bit_timing_fd (
267
264
channel = channel ,
268
- bitrate = timing .nom_bitrate ,
269
- data_bitrate = timing .data_bitrate ,
270
- sjw_abr = timing .nom_sjw ,
271
- tseg1_abr = timing .nom_tseg1 ,
272
- tseg2_abr = timing .nom_tseg2 ,
273
- sjw_dbr = timing .data_sjw ,
274
- tseg1_dbr = timing .data_tseg1 ,
275
- tseg2_dbr = timing .data_tseg2 ,
265
+ timing = timing ,
276
266
)
277
267
elif fd :
278
- self ._set_bitrate_canfd (
268
+ self ._set_bit_timing_fd (
279
269
channel = channel ,
280
- bitrate = bitrate ,
281
- data_bitrate = data_bitrate ,
282
- sjw_abr = sjw_abr ,
283
- tseg1_abr = tseg1_abr ,
284
- tseg2_abr = tseg2_abr ,
285
- sjw_dbr = sjw_dbr ,
286
- tseg1_dbr = tseg1_dbr ,
287
- tseg2_dbr = tseg2_dbr ,
270
+ timing = BitTimingFd .from_bitrate_and_segments (
271
+ f_clock = 80_000_000 ,
272
+ nom_bitrate = bitrate or 500_000 ,
273
+ nom_tseg1 = tseg1_abr ,
274
+ nom_tseg2 = tseg2_abr ,
275
+ nom_sjw = sjw_abr ,
276
+ data_bitrate = data_bitrate or bitrate or 500_000 ,
277
+ data_tseg1 = tseg1_dbr ,
278
+ data_tseg2 = tseg2_dbr ,
279
+ data_sjw = sjw_dbr ,
280
+ ),
288
281
)
289
282
elif bitrate :
290
- self ._set_bitrate_can (channel = channel , bitrate = bitrate )
283
+ self ._set_bitrate (channel = channel , bitrate = bitrate )
291
284
292
285
# Enable/disable TX receipts
293
286
tx_receipts = 1 if receive_own_messages else 0
@@ -404,30 +397,44 @@ def _read_bus_params(self, channel: int) -> "VectorBusParams":
404
397
f"Channel configuration for channel { channel } not found."
405
398
)
406
399
407
- def _set_bitrate_can (
408
- self ,
409
- channel : int ,
410
- bitrate : int ,
411
- sjw : Optional [int ] = None ,
412
- tseg1 : Optional [int ] = None ,
413
- tseg2 : Optional [int ] = None ,
414
- sam : int = 1 ,
415
- ) -> None :
416
- kwargs = [sjw , tseg1 , tseg2 ]
417
- if any (kwargs ) and not all (kwargs ):
418
- raise ValueError (
419
- f"Either all of sjw, tseg1, tseg2 must be set or none of them."
400
+ def _set_bitrate (self , channel : int , bitrate : int ) -> None :
401
+ # set parameters if channel has init access
402
+ if self ._has_init_access (channel ):
403
+ self .xldriver .xlCanSetChannelBitrate (
404
+ self .port_handle ,
405
+ self .channel_masks [channel ],
406
+ bitrate ,
420
407
)
408
+ LOG .info ("xlCanSetChannelBitrate: baudr.=%u" , bitrate )
421
409
410
+ if not self .__testing :
411
+ self ._check_can_settings (
412
+ channel = channel ,
413
+ bitrate = bitrate ,
414
+ )
415
+
416
+ def _set_bit_timing (self , channel : int , timing : BitTiming ) -> None :
422
417
# set parameters if channel has init access
423
418
if self ._has_init_access (channel ):
424
- if any (kwargs ):
419
+ if timing .f_clock == 8_000_000 :
420
+ self .xldriver .xlCanSetChannelParamsC200 (
421
+ self .port_handle ,
422
+ self .channel_masks [channel ],
423
+ timing .btr0 ,
424
+ timing .btr1 ,
425
+ )
426
+ LOG .info (
427
+ "xlCanSetChannelParamsC200: BTR0=%#02x, BTR1=%#02x" ,
428
+ timing .btr0 ,
429
+ timing .btr1 ,
430
+ )
431
+ elif timing .f_clock == 16_000_000 :
425
432
chip_params = xlclass .XLchipParams ()
426
- chip_params .bitRate = bitrate
427
- chip_params .sjw = sjw
428
- chip_params .tseg1 = tseg1
429
- chip_params .tseg2 = tseg2
430
- chip_params .sam = sam
433
+ chip_params .bitRate = timing . bitrate
434
+ chip_params .sjw = timing . sjw
435
+ chip_params .tseg1 = timing . tseg1
436
+ chip_params .tseg2 = timing . tseg2
437
+ chip_params .sam = timing . nof_samples
431
438
self .xldriver .xlCanSetChannelParams (
432
439
self .port_handle ,
433
440
self .channel_masks [channel ],
@@ -441,94 +448,33 @@ def _set_bitrate_can(
441
448
chip_params .tseg2 ,
442
449
)
443
450
else :
444
- self .xldriver .xlCanSetChannelBitrate (
445
- self .port_handle ,
446
- self .channel_masks [channel ],
447
- bitrate ,
451
+ raise CanInitializationError (
452
+ f"timing.f_clock must be 8_000_000 or 16_000_000 (is { timing .f_clock } )"
448
453
)
449
- LOG .info ("xlCanSetChannelBitrate: baudr.=%u" , bitrate )
450
-
451
- if self .__testing :
452
- return
453
454
454
- # Compare requested CAN settings to active settings
455
- bus_params = self ._read_bus_params (channel )
456
- settings_acceptable = True
457
-
458
- # check bus type
459
- settings_acceptable &= (
460
- bus_params .bus_type is xldefine .XL_BusTypes .XL_BUS_TYPE_CAN
461
- )
462
-
463
- # check CAN operation mode. For CANcaseXL can_op_mode remains 0
464
- if bus_params .can .can_op_mode != 0 :
465
- settings_acceptable &= bool (
466
- bus_params .can .can_op_mode
467
- & xldefine .XL_CANFD_BusParams_CanOpMode .XL_BUS_PARAMS_CANOPMODE_CAN20
468
- )
469
-
470
- # check bitrate
471
- settings_acceptable &= abs (bus_params .can .bitrate - bitrate ) < bitrate / 256
472
-
473
- # check sample point
474
- if all (kwargs ):
475
- requested_sample_point = (
476
- 100
477
- * (1 + tseg1 ) # type: ignore[operator]
478
- / (1 + tseg1 + tseg2 ) # type: ignore[operator]
479
- )
480
- actual_sample_point = (
481
- 100
482
- * (1 + bus_params .can .tseg1 )
483
- / (1 + bus_params .can .tseg1 + bus_params .can .tseg2 )
484
- )
485
- settings_acceptable &= (
486
- abs (actual_sample_point - requested_sample_point )
487
- < 1.0 # 1 percent threshold
488
- )
489
-
490
- if not settings_acceptable :
491
- active_settings = ", " .join (
492
- [
493
- f"{ key } : { getattr (val , 'name' , val )} " # print int or Enum/Flag name
494
- for key , val in bus_params .can ._asdict ().items ()
495
- ]
496
- )
497
- raise CanInitializationError (
498
- f"The requested CAN settings could not be set for channel { channel } . "
499
- f"Another application might have set incompatible settings. "
500
- f"These are the currently active settings: { active_settings } "
455
+ if not self .__testing :
456
+ self ._check_can_settings (
457
+ channel = channel ,
458
+ bitrate = timing .bitrate ,
459
+ sample_point = timing .sample_point ,
501
460
)
502
461
503
- def _set_bitrate_canfd (
462
+ def _set_bit_timing_fd (
504
463
self ,
505
464
channel : int ,
506
- bitrate : Optional [int ] = None ,
507
- data_bitrate : Optional [int ] = None ,
508
- sjw_abr : int = 2 ,
509
- tseg1_abr : int = 6 ,
510
- tseg2_abr : int = 3 ,
511
- sjw_dbr : int = 2 ,
512
- tseg1_dbr : int = 6 ,
513
- tseg2_dbr : int = 3 ,
465
+ timing : BitTimingFd ,
514
466
) -> None :
515
467
# set parameters if channel has init access
516
468
if self ._has_init_access (channel ):
517
469
canfd_conf = xlclass .XLcanFdConf ()
518
- if bitrate :
519
- canfd_conf .arbitrationBitRate = int (bitrate )
520
- else :
521
- canfd_conf .arbitrationBitRate = 500_000
522
- canfd_conf .sjwAbr = int (sjw_abr )
523
- canfd_conf .tseg1Abr = int (tseg1_abr )
524
- canfd_conf .tseg2Abr = int (tseg2_abr )
525
- if data_bitrate :
526
- canfd_conf .dataBitRate = int (data_bitrate )
527
- else :
528
- canfd_conf .dataBitRate = int (canfd_conf .arbitrationBitRate )
529
- canfd_conf .sjwDbr = int (sjw_dbr )
530
- canfd_conf .tseg1Dbr = int (tseg1_dbr )
531
- canfd_conf .tseg2Dbr = int (tseg2_dbr )
470
+ canfd_conf .arbitrationBitRate = timing .nom_bitrate
471
+ canfd_conf .sjwAbr = timing .nom_sjw
472
+ canfd_conf .tseg1Abr = timing .nom_tseg1
473
+ canfd_conf .tseg2Abr = timing .nom_tseg2
474
+ canfd_conf .dataBitRate = timing .data_bitrate
475
+ canfd_conf .sjwDbr = timing .data_sjw
476
+ canfd_conf .tseg1Dbr = timing .data_tseg1
477
+ canfd_conf .tseg2Dbr = timing .data_tseg2
532
478
self .xldriver .xlCanFdSetConfiguration (
533
479
self .port_handle , self .channel_masks [channel ], canfd_conf
534
480
)
@@ -550,11 +496,29 @@ def _set_bitrate_canfd(
550
496
canfd_conf .tseg2Dbr ,
551
497
)
552
498
553
- if self .__testing :
554
- return
499
+ if not self .__testing :
500
+ self ._check_can_settings (
501
+ channel = channel ,
502
+ bitrate = timing .nom_bitrate ,
503
+ sample_point = timing .nom_sample_point ,
504
+ fd = True ,
505
+ data_bitrate = timing .data_bitrate ,
506
+ data_sample_point = timing .data_sample_point ,
507
+ )
555
508
556
- # Compare requested CAN settings to active settings
509
+ def _check_can_settings (
510
+ self ,
511
+ channel : int ,
512
+ bitrate : int ,
513
+ sample_point : Optional [float ] = None ,
514
+ fd : bool = False ,
515
+ data_bitrate : Optional [int ] = None ,
516
+ data_sample_point : Optional [float ] = None ,
517
+ ) -> None :
518
+ """Compare requested CAN settings to active settings in driver."""
557
519
bus_params = self ._read_bus_params (channel )
520
+ # use canfd even if fd==False, bus_params.can and bus_params.canfd are a C union
521
+ bus_params_data = bus_params .canfd
558
522
settings_acceptable = True
559
523
560
524
# check bus type
@@ -563,60 +527,68 @@ def _set_bitrate_canfd(
563
527
)
564
528
565
529
# check CAN operation mode
566
- settings_acceptable &= bool (
567
- bus_params .canfd .can_op_mode
568
- & xldefine .XL_CANFD_BusParams_CanOpMode .XL_BUS_PARAMS_CANOPMODE_CANFD
569
- )
530
+ if fd :
531
+ settings_acceptable &= bool (
532
+ bus_params_data .can_op_mode
533
+ & xldefine .XL_CANFD_BusParams_CanOpMode .XL_BUS_PARAMS_CANOPMODE_CANFD
534
+ )
535
+ elif bus_params_data .can_op_mode != 0 : # can_op_mode is always 0 for cancaseXL
536
+ settings_acceptable &= bool (
537
+ bus_params_data .can_op_mode
538
+ & xldefine .XL_CANFD_BusParams_CanOpMode .XL_BUS_PARAMS_CANOPMODE_CAN20
539
+ )
570
540
571
541
# check bitrates
572
542
if bitrate :
573
543
settings_acceptable &= (
574
- abs (bus_params . canfd .bitrate - bitrate ) < bitrate / 256
544
+ abs (bus_params_data .bitrate - bitrate ) < bitrate / 256
575
545
)
576
- if data_bitrate :
546
+ if fd and data_bitrate :
577
547
settings_acceptable &= (
578
- abs (bus_params . canfd .data_bitrate - data_bitrate ) < data_bitrate / 256
548
+ abs (bus_params_data .data_bitrate - data_bitrate ) < data_bitrate / 256
579
549
)
580
550
581
551
# check sample points
582
- if bitrate :
583
- requested_nom_sample_point = (
584
- 100 * (1 + tseg1_abr ) / (1 + tseg1_abr + tseg2_abr )
585
- )
586
- actual_nom_sample_point = (
552
+ if sample_point :
553
+ nom_sample_point_act = (
587
554
100
588
- * (1 + bus_params . canfd .tseg1_abr )
589
- / (1 + bus_params . canfd . tseg1_abr + bus_params . canfd .tseg2_abr )
555
+ * (1 + bus_params_data .tseg1_abr )
556
+ / (1 + bus_params_data . tseg1_abr + bus_params_data .tseg2_abr )
590
557
)
591
558
settings_acceptable &= (
592
- abs (actual_nom_sample_point - requested_nom_sample_point )
593
- < 1.0 # 1 percent threshold
594
- )
595
- if data_bitrate :
596
- requested_data_sample_point = (
597
- 100 * (1 + tseg1_dbr ) / (1 + tseg1_dbr + tseg2_dbr )
559
+ abs (nom_sample_point_act - sample_point ) < 2.0 # 2 percent tolerance
598
560
)
599
- actual_data_sample_point = (
561
+ if fd and data_sample_point :
562
+ data_sample_point_act = (
600
563
100
601
- * (1 + bus_params . canfd .tseg1_dbr )
602
- / (1 + bus_params . canfd . tseg1_dbr + bus_params . canfd .tseg2_dbr )
564
+ * (1 + bus_params_data .tseg1_dbr )
565
+ / (1 + bus_params_data . tseg1_dbr + bus_params_data .tseg2_dbr )
603
566
)
604
567
settings_acceptable &= (
605
- abs (actual_data_sample_point - requested_data_sample_point )
606
- < 1 .0 # 1 percent threshold
568
+ abs (data_sample_point_act - data_sample_point )
569
+ < 2 .0 # 2 percent tolerance
607
570
)
608
571
609
572
if not settings_acceptable :
610
- active_settings = ", " .join (
611
- [
612
- f"{ key } : { getattr (val , 'name' , val )} " # print int or Enum/Flag name
613
- for key , val in bus_params .canfd ._asdict ().items ()
614
- ]
573
+ # The error message depends on the currently active CAN settings.
574
+ # If the active operation mode is CAN FD, show the active CAN FD timings,
575
+ # otherwise show CAN 2.0 timings.
576
+ if bool (
577
+ bus_params_data .can_op_mode
578
+ & xldefine .XL_CANFD_BusParams_CanOpMode .XL_BUS_PARAMS_CANOPMODE_CANFD
579
+ ):
580
+ active_settings = bus_params .canfd ._asdict ()
581
+ active_settings ["can_op_mode" ] = "CAN FD"
582
+ else :
583
+ active_settings = bus_params .can ._asdict ()
584
+ active_settings ["can_op_mode" ] = "CAN 2.0"
585
+ settings_string = ", " .join (
586
+ [f"{ key } : { val } " for key , val in active_settings .items ()]
615
587
)
616
588
raise CanInitializationError (
617
- f"The requested CAN FD settings could not be set for channel { channel } . "
589
+ f"The requested settings could not be set for channel { channel } . "
618
590
f"Another application might have set incompatible settings. "
619
- f"These are the currently active settings: { active_settings } ."
591
+ f"These are the currently active settings: { settings_string } ."
620
592
)
621
593
622
594
def _apply_filters (self , filters : Optional [CanFilters ]) -> None :
0 commit comments