@@ -491,7 +491,7 @@ class BitTimingFd(Mapping):
491
491
)
492
492
"""
493
493
494
- def __init__ (
494
+ def __init__ ( # pylint: disable=too-many-arguments
495
495
self ,
496
496
f_clock : int ,
497
497
nom_brp : int ,
@@ -502,6 +502,7 @@ def __init__(
502
502
data_tseg1 : int ,
503
503
data_tseg2 : int ,
504
504
data_sjw : int ,
505
+ strict : bool = False ,
505
506
) -> None :
506
507
"""
507
508
Initialize a BitTimingFd instance with the specified parameters.
@@ -530,6 +531,10 @@ def __init__(
530
531
:param int data_sjw:
531
532
The Synchronization Jump Width for the data phase. This value determines
532
533
the maximum number of time quanta that the controller can resynchronize every bit.
534
+ :param strict:
535
+ If True, restrict bit timings to the minimum required range as defined in
536
+ ISO 11898. This can be used to ensure compatibility across a wide variety
537
+ of CAN hardware.
533
538
:raises ValueError:
534
539
if the arguments are invalid.
535
540
"""
@@ -545,32 +550,23 @@ def __init__(
545
550
"data_sjw" : data_sjw ,
546
551
}
547
552
self ._validate ()
553
+ if strict :
554
+ self ._restrict_to_minimum_range ()
548
555
549
556
def _validate (self ) -> None :
550
- if self .nbt < 8 :
551
- raise ValueError (f"nominal bit time (={ self .nbt } ) must be at least 8." )
552
-
553
- if self .dbt < 8 :
554
- raise ValueError (f"data bit time (={ self .dbt } ) must be at least 8." )
557
+ for param , value in self ._data .items ():
558
+ if value < 0 : # type: ignore[operator]
559
+ err_msg = f"'{ param } ' (={ value } ) must not be negative."
560
+ raise ValueError (err_msg )
555
561
556
- if not 1 <= self .nom_brp <= 256 :
562
+ if self .nom_brp < 1 :
557
563
raise ValueError (
558
- f"nominal bitrate prescaler (={ self .nom_brp } ) must be in [1...256] ."
564
+ f"nominal bitrate prescaler (={ self .nom_brp } ) must be at least 1 ."
559
565
)
560
566
561
- if not 1 <= self .data_brp <= 256 :
567
+ if self .data_brp < 1 :
562
568
raise ValueError (
563
- f"data bitrate prescaler (={ self .data_brp } ) must be in [1...256]."
564
- )
565
-
566
- if not 5_000 <= self .nom_bitrate <= 2_000_000 :
567
- raise ValueError (
568
- f"nom_bitrate (={ self .nom_bitrate } ) must be in [5,000...2,000,000]."
569
- )
570
-
571
- if not 25_000 <= self .data_bitrate <= 8_000_000 :
572
- raise ValueError (
573
- f"data_bitrate (={ self .data_bitrate } ) must be in [25,000...8,000,000]."
569
+ f"data bitrate prescaler (={ self .data_brp } ) must be at least 1."
574
570
)
575
571
576
572
if self .data_bitrate < self .nom_bitrate :
@@ -579,30 +575,12 @@ def _validate(self) -> None:
579
575
f"equal to nom_bitrate (={ self .nom_bitrate } )"
580
576
)
581
577
582
- if not 2 <= self .nom_tseg1 <= 256 :
583
- raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...256]." )
584
-
585
- if not 1 <= self .nom_tseg2 <= 128 :
586
- raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [1...128]." )
587
-
588
- if not 1 <= self .data_tseg1 <= 32 :
589
- raise ValueError (f"data_tseg1 (={ self .data_tseg1 } ) must be in [1...32]." )
590
-
591
- if not 1 <= self .data_tseg2 <= 16 :
592
- raise ValueError (f"data_tseg2 (={ self .data_tseg2 } ) must be in [1...16]." )
593
-
594
- if not 1 <= self .nom_sjw <= 128 :
595
- raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...128]." )
596
-
597
578
if self .nom_sjw > self .nom_tseg2 :
598
579
raise ValueError (
599
580
f"nom_sjw (={ self .nom_sjw } ) must not be "
600
581
f"greater than nom_tseg2 (={ self .nom_tseg2 } )."
601
582
)
602
583
603
- if not 1 <= self .data_sjw <= 16 :
604
- raise ValueError (f"data_sjw (={ self .data_sjw } ) must be in [1...128]." )
605
-
606
584
if self .data_sjw > self .data_tseg2 :
607
585
raise ValueError (
608
586
f"data_sjw (={ self .data_sjw } ) must not be "
@@ -621,6 +599,44 @@ def _validate(self) -> None:
621
599
f"(data_sample_point={ self .data_sample_point :.2f} %)."
622
600
)
623
601
602
+ def _restrict_to_minimum_range (self ) -> None :
603
+ # restrict to minimum required range as defined in ISO 11898
604
+ if not 8 <= self .nbt <= 80 :
605
+ raise ValueError (f"Nominal bit time (={ self .nbt } ) must be in [8...80]" )
606
+
607
+ if not 5 <= self .dbt <= 25 :
608
+ raise ValueError (f"Nominal bit time (={ self .dbt } ) must be in [5...25]" )
609
+
610
+ if not 1 <= self .data_tseg1 <= 16 :
611
+ raise ValueError (f"data_tseg1 (={ self .data_tseg1 } ) must be in [1...16]." )
612
+
613
+ if not 2 <= self .data_tseg2 <= 8 :
614
+ raise ValueError (f"data_tseg2 (={ self .data_tseg2 } ) must be in [2...8]." )
615
+
616
+ if not 1 <= self .data_sjw <= 8 :
617
+ raise ValueError (f"data_sjw (={ self .data_sjw } ) must be in [1...8]." )
618
+
619
+ if self .nom_brp == self .data_brp :
620
+ # shared prescaler
621
+ if not 2 <= self .nom_tseg1 <= 128 :
622
+ raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...128]." )
623
+
624
+ if not 2 <= self .nom_tseg2 <= 32 :
625
+ raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [2...32]." )
626
+
627
+ if not 1 <= self .nom_sjw <= 32 :
628
+ raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...32]." )
629
+ else :
630
+ # separate prescaler
631
+ if not 2 <= self .nom_tseg1 <= 64 :
632
+ raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...64]." )
633
+
634
+ if not 2 <= self .nom_tseg2 <= 16 :
635
+ raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [2...16]." )
636
+
637
+ if not 1 <= self .nom_sjw <= 16 :
638
+ raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...16]." )
639
+
624
640
@classmethod
625
641
def from_bitrate_and_segments (
626
642
cls ,
@@ -741,34 +757,36 @@ def from_sample_point(
741
757
742
758
possible_solutions : List [BitTimingFd ] = []
743
759
760
+ sync_seg = 1
761
+
744
762
for nom_brp in range (1 , 257 ):
745
763
nbt = round (int (f_clock / (nom_bitrate * nom_brp )))
746
- if nbt < 8 :
764
+ if nbt < 1 :
747
765
break
748
766
749
767
effective_nom_bitrate = f_clock / (nbt * nom_brp )
750
768
if abs (effective_nom_bitrate - nom_bitrate ) > nom_bitrate / 256 :
751
769
continue
752
770
753
771
nom_tseg1 = int (round (nom_sample_point / 100 * nbt )) - 1
754
- # limit tseg1, so tseg2 is at least 1 TQ
755
- nom_tseg1 = min (nom_tseg1 , nbt - 2 )
772
+ # limit tseg1, so tseg2 is at least 2 TQ
773
+ nom_tseg1 = min (nom_tseg1 , nbt - sync_seg - 2 )
756
774
nom_tseg2 = nbt - nom_tseg1 - 1
757
775
758
776
nom_sjw = min (nom_tseg2 , 128 )
759
777
760
778
for data_brp in range (1 , 257 ):
761
779
dbt = round (int (f_clock / (data_bitrate * data_brp )))
762
- if dbt < 8 :
780
+ if dbt < 1 :
763
781
break
764
782
765
783
effective_data_bitrate = f_clock / (dbt * data_brp )
766
784
if abs (effective_data_bitrate - data_bitrate ) > data_bitrate / 256 :
767
785
continue
768
786
769
787
data_tseg1 = int (round (data_sample_point / 100 * dbt )) - 1
770
- # limit tseg1, so tseg2 is at least 1 TQ
771
- data_tseg1 = min (data_tseg1 , dbt - 2 )
788
+ # limit tseg1, so tseg2 is at least 2 TQ
789
+ data_tseg1 = min (data_tseg1 , dbt - sync_seg - 2 )
772
790
data_tseg2 = dbt - data_tseg1 - 1
773
791
774
792
data_sjw = min (data_tseg2 , 16 )
@@ -784,6 +802,7 @@ def from_sample_point(
784
802
data_tseg1 = data_tseg1 ,
785
803
data_tseg2 = data_tseg2 ,
786
804
data_sjw = data_sjw ,
805
+ strict = True ,
787
806
)
788
807
possible_solutions .append (bt )
789
808
except ValueError :
0 commit comments