@@ -36,6 +36,7 @@ def __init__(
36
36
tseg2 : int ,
37
37
sjw : int ,
38
38
nof_samples : int = 1 ,
39
+ strict : bool = False ,
39
40
) -> None :
40
41
"""
41
42
:param int f_clock:
@@ -56,6 +57,10 @@ def __init__(
56
57
In this case, the bit will be sampled three quanta in a row,
57
58
with the last sample being taken in the edge between TSEG1 and TSEG2.
58
59
Three samples should only be used for relatively slow baudrates.
60
+ :param bool strict:
61
+ If True, restrict bit timings to the minimum required range as defined in
62
+ ISO 11898. This can be used to ensure compatibility across a wide variety
63
+ of CAN hardware.
59
64
:raises ValueError:
60
65
if the arguments are invalid.
61
66
"""
@@ -68,19 +73,13 @@ def __init__(
68
73
"nof_samples" : nof_samples ,
69
74
}
70
75
self ._validate ()
76
+ if strict :
77
+ self ._restrict_to_minimum_range ()
71
78
72
79
def _validate (self ) -> None :
73
- if not 8 <= self .nbt <= 25 :
74
- raise ValueError (f"nominal bit time (={ self .nbt } ) must be in [8...25]." )
75
-
76
80
if not 1 <= self .brp <= 64 :
77
81
raise ValueError (f"bitrate prescaler (={ self .brp } ) must be in [1...64]." )
78
82
79
- if not 5_000 <= self .bitrate <= 2_000_000 :
80
- raise ValueError (
81
- f"bitrate (={ self .bitrate } ) must be in [5,000...2,000,000]."
82
- )
83
-
84
83
if not 1 <= self .tseg1 <= 16 :
85
84
raise ValueError (f"tseg1 (={ self .tseg1 } ) must be in [1...16]." )
86
85
@@ -104,6 +103,18 @@ def _validate(self) -> None:
104
103
if self .nof_samples not in (1 , 3 ):
105
104
raise ValueError ("nof_samples must be 1 or 3" )
106
105
106
+ def _restrict_to_minimum_range (self ) -> None :
107
+ if not 8 <= self .nbt <= 25 :
108
+ raise ValueError (f"nominal bit time (={ self .nbt } ) must be in [8...25]." )
109
+
110
+ if not 1 <= self .brp <= 32 :
111
+ raise ValueError (f"bitrate prescaler (={ self .brp } ) must be in [1...32]." )
112
+
113
+ if not 5_000 <= self .bitrate <= 1_000_000 :
114
+ raise ValueError (
115
+ f"bitrate (={ self .bitrate } ) must be in [5,000...1,000,000]."
116
+ )
117
+
107
118
@classmethod
108
119
def from_bitrate_and_segments (
109
120
cls ,
@@ -113,6 +124,7 @@ def from_bitrate_and_segments(
113
124
tseg2 : int ,
114
125
sjw : int ,
115
126
nof_samples : int = 1 ,
127
+ strict : bool = False ,
116
128
) -> "BitTiming" :
117
129
"""Create a :class:`~can.BitTiming` instance from bitrate and segment lengths.
118
130
@@ -134,6 +146,10 @@ def from_bitrate_and_segments(
134
146
In this case, the bit will be sampled three quanta in a row,
135
147
with the last sample being taken in the edge between TSEG1 and TSEG2.
136
148
Three samples should only be used for relatively slow baudrates.
149
+ :param bool strict:
150
+ If True, restrict bit timings to the minimum required range as defined in
151
+ ISO 11898. This can be used to ensure compatibility across a wide variety
152
+ of CAN hardware.
137
153
:raises ValueError:
138
154
if the arguments are invalid.
139
155
"""
@@ -149,6 +165,7 @@ def from_bitrate_and_segments(
149
165
tseg2 = tseg2 ,
150
166
sjw = sjw ,
151
167
nof_samples = nof_samples ,
168
+ strict = strict ,
152
169
)
153
170
if abs (bt .bitrate - bitrate ) > bitrate / 256 :
154
171
raise ValueError (
@@ -175,6 +192,11 @@ def from_registers(
175
192
:raises ValueError:
176
193
if the arguments are invalid.
177
194
"""
195
+ if not 0 <= btr0 < 2 ** 16 :
196
+ raise ValueError (f"Invalid btr0 value. ({ btr0 } )" )
197
+ if not 0 <= btr1 < 2 ** 16 :
198
+ raise ValueError (f"Invalid btr1 value. ({ btr1 } )" )
199
+
178
200
brp = (btr0 & 0x3F ) + 1
179
201
sjw = (btr0 >> 6 ) + 1
180
202
tseg1 = (btr1 & 0xF ) + 1
@@ -239,6 +261,7 @@ def from_sample_point(
239
261
tseg1 = tseg1 ,
240
262
tseg2 = tseg2 ,
241
263
sjw = sjw ,
264
+ strict = True ,
242
265
)
243
266
possible_solutions .append (bt )
244
267
except ValueError :
@@ -316,12 +339,12 @@ def sample_point(self) -> float:
316
339
317
340
@property
318
341
def btr0 (self ) -> int :
319
- """Bit timing register 0."""
342
+ """Bit timing register 0 for SJA1000 ."""
320
343
return (self .sjw - 1 ) << 6 | self .brp - 1
321
344
322
345
@property
323
346
def btr1 (self ) -> int :
324
- """Bit timing register 1."""
347
+ """Bit timing register 1 for SJA1000 ."""
325
348
sam = 1 if self .nof_samples == 3 else 0
326
349
return sam << 7 | (self .tseg2 - 1 ) << 4 | self .tseg1 - 1
327
350
@@ -373,6 +396,7 @@ def recreate_with_f_clock(self, f_clock: int) -> "BitTiming":
373
396
tseg2 = self .tseg2 ,
374
397
sjw = self .sjw ,
375
398
nof_samples = self .nof_samples ,
399
+ strict = True ,
376
400
)
377
401
except ValueError :
378
402
pass
@@ -474,7 +498,7 @@ class BitTimingFd(Mapping):
474
498
)
475
499
"""
476
500
477
- def __init__ (
501
+ def __init__ ( # pylint: disable=too-many-arguments
478
502
self ,
479
503
f_clock : int ,
480
504
nom_brp : int ,
@@ -485,6 +509,7 @@ def __init__(
485
509
data_tseg1 : int ,
486
510
data_tseg2 : int ,
487
511
data_sjw : int ,
512
+ strict : bool = False ,
488
513
) -> None :
489
514
"""
490
515
Initialize a BitTimingFd instance with the specified parameters.
@@ -513,6 +538,10 @@ def __init__(
513
538
:param int data_sjw:
514
539
The Synchronization Jump Width for the data phase. This value determines
515
540
the maximum number of time quanta that the controller can resynchronize every bit.
541
+ :param bool strict:
542
+ If True, restrict bit timings to the minimum required range as defined in
543
+ ISO 11898. This can be used to ensure compatibility across a wide variety
544
+ of CAN hardware.
516
545
:raises ValueError:
517
546
if the arguments are invalid.
518
547
"""
@@ -528,32 +557,23 @@ def __init__(
528
557
"data_sjw" : data_sjw ,
529
558
}
530
559
self ._validate ()
560
+ if strict :
561
+ self ._restrict_to_minimum_range ()
531
562
532
563
def _validate (self ) -> None :
533
- if self .nbt < 8 :
534
- raise ValueError (f"nominal bit time (={ self .nbt } ) must be at least 8." )
535
-
536
- if self .dbt < 8 :
537
- raise ValueError (f"data bit time (={ self .dbt } ) must be at least 8." )
538
-
539
- if not 1 <= self .nom_brp <= 256 :
540
- raise ValueError (
541
- f"nominal bitrate prescaler (={ self .nom_brp } ) must be in [1...256]."
542
- )
543
-
544
- if not 1 <= self .data_brp <= 256 :
545
- raise ValueError (
546
- f"data bitrate prescaler (={ self .data_brp } ) must be in [1...256]."
547
- )
564
+ for param , value in self ._data .items ():
565
+ if value < 0 : # type: ignore[operator]
566
+ err_msg = f"'{ param } ' (={ value } ) must not be negative."
567
+ raise ValueError (err_msg )
548
568
549
- if not 5_000 <= self .nom_bitrate <= 2_000_000 :
569
+ if self .nom_brp < 1 :
550
570
raise ValueError (
551
- f"nom_bitrate (={ self .nom_bitrate } ) must be in [5,000...2,000,000] ."
571
+ f"nominal bitrate prescaler (={ self .nom_brp } ) must be at least 1 ."
552
572
)
553
573
554
- if not 25_000 <= self .data_bitrate <= 8_000_000 :
574
+ if self .data_brp < 1 :
555
575
raise ValueError (
556
- f"data_bitrate (={ self .data_bitrate } ) must be in [25,000...8,000,000] ."
576
+ f"data bitrate prescaler (={ self .data_brp } ) must be at least 1 ."
557
577
)
558
578
559
579
if self .data_bitrate < self .nom_bitrate :
@@ -562,30 +582,12 @@ def _validate(self) -> None:
562
582
f"equal to nom_bitrate (={ self .nom_bitrate } )"
563
583
)
564
584
565
- if not 2 <= self .nom_tseg1 <= 256 :
566
- raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...256]." )
567
-
568
- if not 1 <= self .nom_tseg2 <= 128 :
569
- raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [1...128]." )
570
-
571
- if not 1 <= self .data_tseg1 <= 32 :
572
- raise ValueError (f"data_tseg1 (={ self .data_tseg1 } ) must be in [1...32]." )
573
-
574
- if not 1 <= self .data_tseg2 <= 16 :
575
- raise ValueError (f"data_tseg2 (={ self .data_tseg2 } ) must be in [1...16]." )
576
-
577
- if not 1 <= self .nom_sjw <= 128 :
578
- raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...128]." )
579
-
580
585
if self .nom_sjw > self .nom_tseg2 :
581
586
raise ValueError (
582
587
f"nom_sjw (={ self .nom_sjw } ) must not be "
583
588
f"greater than nom_tseg2 (={ self .nom_tseg2 } )."
584
589
)
585
590
586
- if not 1 <= self .data_sjw <= 16 :
587
- raise ValueError (f"data_sjw (={ self .data_sjw } ) must be in [1...128]." )
588
-
589
591
if self .data_sjw > self .data_tseg2 :
590
592
raise ValueError (
591
593
f"data_sjw (={ self .data_sjw } ) must not be "
@@ -604,8 +606,46 @@ def _validate(self) -> None:
604
606
f"(data_sample_point={ self .data_sample_point :.2f} %)."
605
607
)
606
608
609
+ def _restrict_to_minimum_range (self ) -> None :
610
+ # restrict to minimum required range as defined in ISO 11898
611
+ if not 8 <= self .nbt <= 80 :
612
+ raise ValueError (f"Nominal bit time (={ self .nbt } ) must be in [8...80]" )
613
+
614
+ if not 5 <= self .dbt <= 25 :
615
+ raise ValueError (f"Nominal bit time (={ self .dbt } ) must be in [5...25]" )
616
+
617
+ if not 1 <= self .data_tseg1 <= 16 :
618
+ raise ValueError (f"data_tseg1 (={ self .data_tseg1 } ) must be in [1...16]." )
619
+
620
+ if not 2 <= self .data_tseg2 <= 8 :
621
+ raise ValueError (f"data_tseg2 (={ self .data_tseg2 } ) must be in [2...8]." )
622
+
623
+ if not 1 <= self .data_sjw <= 8 :
624
+ raise ValueError (f"data_sjw (={ self .data_sjw } ) must be in [1...8]." )
625
+
626
+ if self .nom_brp == self .data_brp :
627
+ # shared prescaler
628
+ if not 2 <= self .nom_tseg1 <= 128 :
629
+ raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...128]." )
630
+
631
+ if not 2 <= self .nom_tseg2 <= 32 :
632
+ raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [2...32]." )
633
+
634
+ if not 1 <= self .nom_sjw <= 32 :
635
+ raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...32]." )
636
+ else :
637
+ # separate prescaler
638
+ if not 2 <= self .nom_tseg1 <= 64 :
639
+ raise ValueError (f"nom_tseg1 (={ self .nom_tseg1 } ) must be in [2...64]." )
640
+
641
+ if not 2 <= self .nom_tseg2 <= 16 :
642
+ raise ValueError (f"nom_tseg2 (={ self .nom_tseg2 } ) must be in [2...16]." )
643
+
644
+ if not 1 <= self .nom_sjw <= 16 :
645
+ raise ValueError (f"nom_sjw (={ self .nom_sjw } ) must be in [1...16]." )
646
+
607
647
@classmethod
608
- def from_bitrate_and_segments (
648
+ def from_bitrate_and_segments ( # pylint: disable=too-many-arguments
609
649
cls ,
610
650
f_clock : int ,
611
651
nom_bitrate : int ,
@@ -616,6 +656,7 @@ def from_bitrate_and_segments(
616
656
data_tseg1 : int ,
617
657
data_tseg2 : int ,
618
658
data_sjw : int ,
659
+ strict : bool = False ,
619
660
) -> "BitTimingFd" :
620
661
"""
621
662
Create a :class:`~can.BitTimingFd` instance with the bitrates and segments lengths.
@@ -644,6 +685,10 @@ def from_bitrate_and_segments(
644
685
:param int data_sjw:
645
686
The Synchronization Jump Width for the data phase. This value determines
646
687
the maximum number of time quanta that the controller can resynchronize every bit.
688
+ :param bool strict:
689
+ If True, restrict bit timings to the minimum required range as defined in
690
+ ISO 11898. This can be used to ensure compatibility across a wide variety
691
+ of CAN hardware.
647
692
:raises ValueError:
648
693
if the arguments are invalid.
649
694
"""
@@ -665,6 +710,7 @@ def from_bitrate_and_segments(
665
710
data_tseg1 = data_tseg1 ,
666
711
data_tseg2 = data_tseg2 ,
667
712
data_sjw = data_sjw ,
713
+ strict = strict ,
668
714
)
669
715
670
716
if abs (bt .nom_bitrate - nom_bitrate ) > nom_bitrate / 256 :
@@ -724,34 +770,36 @@ def from_sample_point(
724
770
725
771
possible_solutions : List [BitTimingFd ] = []
726
772
773
+ sync_seg = 1
774
+
727
775
for nom_brp in range (1 , 257 ):
728
776
nbt = round (int (f_clock / (nom_bitrate * nom_brp )))
729
- if nbt < 8 :
777
+ if nbt < 1 :
730
778
break
731
779
732
780
effective_nom_bitrate = f_clock / (nbt * nom_brp )
733
781
if abs (effective_nom_bitrate - nom_bitrate ) > nom_bitrate / 256 :
734
782
continue
735
783
736
784
nom_tseg1 = int (round (nom_sample_point / 100 * nbt )) - 1
737
- # limit tseg1, so tseg2 is at least 1 TQ
738
- nom_tseg1 = min (nom_tseg1 , nbt - 2 )
785
+ # limit tseg1, so tseg2 is at least 2 TQ
786
+ nom_tseg1 = min (nom_tseg1 , nbt - sync_seg - 2 )
739
787
nom_tseg2 = nbt - nom_tseg1 - 1
740
788
741
789
nom_sjw = min (nom_tseg2 , 128 )
742
790
743
791
for data_brp in range (1 , 257 ):
744
792
dbt = round (int (f_clock / (data_bitrate * data_brp )))
745
- if dbt < 8 :
793
+ if dbt < 1 :
746
794
break
747
795
748
796
effective_data_bitrate = f_clock / (dbt * data_brp )
749
797
if abs (effective_data_bitrate - data_bitrate ) > data_bitrate / 256 :
750
798
continue
751
799
752
800
data_tseg1 = int (round (data_sample_point / 100 * dbt )) - 1
753
- # limit tseg1, so tseg2 is at least 1 TQ
754
- data_tseg1 = min (data_tseg1 , dbt - 2 )
801
+ # limit tseg1, so tseg2 is at least 2 TQ
802
+ data_tseg1 = min (data_tseg1 , dbt - sync_seg - 2 )
755
803
data_tseg2 = dbt - data_tseg1 - 1
756
804
757
805
data_sjw = min (data_tseg2 , 16 )
@@ -767,6 +815,7 @@ def from_sample_point(
767
815
data_tseg1 = data_tseg1 ,
768
816
data_tseg2 = data_tseg2 ,
769
817
data_sjw = data_sjw ,
818
+ strict = True ,
770
819
)
771
820
possible_solutions .append (bt )
772
821
except ValueError :
@@ -971,6 +1020,7 @@ def recreate_with_f_clock(self, f_clock: int) -> "BitTimingFd":
971
1020
data_tseg1 = self .data_tseg1 ,
972
1021
data_tseg2 = self .data_tseg2 ,
973
1022
data_sjw = self .data_sjw ,
1023
+ strict = True ,
974
1024
)
975
1025
except ValueError :
976
1026
pass
0 commit comments