Skip to content

Commit 356f6f9

Browse files
authored
Add code example to BitTiming docs (#1515)
* add copy button * make bittiming classes hashable * add code example to show possible bit timings * fix tests * rename variable
1 parent 7a4c6f8 commit 356f6f9

File tree

5 files changed

+64
-11
lines changed

5 files changed

+64
-11
lines changed

can/bit_timing.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,14 @@ def recreate_with_f_clock(self, f_clock: int) -> "BitTiming":
395395

396396
def __str__(self) -> str:
397397
segments = [
398-
f"BR {self.bitrate} bit/s",
398+
f"BR: {self.bitrate:_} bit/s",
399399
f"SP: {self.sample_point:.2f}%",
400400
f"BRP: {self.brp}",
401401
f"TSEG1: {self.tseg1}",
402402
f"TSEG2: {self.tseg2}",
403403
f"SJW: {self.sjw}",
404404
f"BTR: {self.btr0:02X}{self.btr1:02X}h",
405-
f"f_clock: {self.f_clock / 1e6:.0f}MHz",
405+
f"CLK: {self.f_clock / 1e6:.0f}MHz",
406406
]
407407
return ", ".join(segments)
408408

@@ -425,6 +425,9 @@ def __eq__(self, other: object) -> bool:
425425

426426
return self._data == other._data
427427

428+
def __hash__(self) -> int:
429+
return tuple(self._data.values()).__hash__()
430+
428431

429432
class BitTimingFd(Mapping):
430433
"""Representation of a bit timing configuration for a CAN FD bus.
@@ -999,19 +1002,19 @@ def recreate_with_f_clock(self, f_clock: int) -> "BitTimingFd":
9991002

10001003
def __str__(self) -> str:
10011004
segments = [
1002-
f"NBR: {self.nom_bitrate} bit/s",
1005+
f"NBR: {self.nom_bitrate:_} bit/s",
10031006
f"NSP: {self.nom_sample_point:.2f}%",
10041007
f"NBRP: {self.nom_brp}",
10051008
f"NTSEG1: {self.nom_tseg1}",
10061009
f"NTSEG2: {self.nom_tseg2}",
10071010
f"NSJW: {self.nom_sjw}",
1008-
f"DBR: {self.data_bitrate} bit/s",
1011+
f"DBR: {self.data_bitrate:_} bit/s",
10091012
f"DSP: {self.data_sample_point:.2f}%",
10101013
f"DBRP: {self.data_brp}",
10111014
f"DTSEG1: {self.data_tseg1}",
10121015
f"DTSEG2: {self.data_tseg2}",
10131016
f"DSJW: {self.data_sjw}",
1014-
f"f_clock: {self.f_clock / 1e6:.0f}MHz",
1017+
f"CLK: {self.f_clock / 1e6:.0f}MHz",
10151018
]
10161019
return ", ".join(segments)
10171020

@@ -1034,6 +1037,9 @@ def __eq__(self, other: object) -> bool:
10341037

10351038
return self._data == other._data
10361039

1040+
def __hash__(self) -> int:
1041+
return tuple(self._data.values()).__hash__()
1042+
10371043

10381044
def _oscillator_tolerance_condition_1(nom_sjw: int, nbt: int) -> float:
10391045
"""Arbitration phase - resynchronization"""

doc/bit_timing.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,38 @@ to specify custom bit timings. The :class:`~can.BitTiming` and
6363
:class:`~can.BitTimingFd` classes can be used for this purpose to specify
6464
bit timings in a relatively interface agnostic manner.
6565

66+
:class:`~can.BitTiming` or :class:`~can.BitTimingFd` can also help you to
67+
produce an overview of possible bit timings for your desired bit rate:
68+
69+
>>> import contextlib
70+
>>> import can
71+
...
72+
>>> timings = set()
73+
>>> for sample_point in range(50, 100):
74+
... with contextlib.suppress(ValueError):
75+
... timings.add(
76+
... can.BitTiming.from_sample_point(
77+
... f_clock=8_000_000,
78+
... bitrate=250_000,
79+
... sample_point=sample_point,
80+
... )
81+
... )
82+
...
83+
>>> for timing in sorted(timings, key=lambda x: x.sample_point):
84+
... print(timing)
85+
BR: 250_000 bit/s, SP: 50.00%, BRP: 2, TSEG1: 7, TSEG2: 8, SJW: 4, BTR: C176h, CLK: 8MHz
86+
BR: 250_000 bit/s, SP: 56.25%, BRP: 2, TSEG1: 8, TSEG2: 7, SJW: 4, BTR: C167h, CLK: 8MHz
87+
BR: 250_000 bit/s, SP: 62.50%, BRP: 2, TSEG1: 9, TSEG2: 6, SJW: 4, BTR: C158h, CLK: 8MHz
88+
BR: 250_000 bit/s, SP: 68.75%, BRP: 2, TSEG1: 10, TSEG2: 5, SJW: 4, BTR: C149h, CLK: 8MHz
89+
BR: 250_000 bit/s, SP: 75.00%, BRP: 2, TSEG1: 11, TSEG2: 4, SJW: 4, BTR: C13Ah, CLK: 8MHz
90+
BR: 250_000 bit/s, SP: 81.25%, BRP: 2, TSEG1: 12, TSEG2: 3, SJW: 3, BTR: 812Bh, CLK: 8MHz
91+
BR: 250_000 bit/s, SP: 87.50%, BRP: 2, TSEG1: 13, TSEG2: 2, SJW: 2, BTR: 411Ch, CLK: 8MHz
92+
BR: 250_000 bit/s, SP: 93.75%, BRP: 2, TSEG1: 14, TSEG2: 1, SJW: 1, BTR: 010Dh, CLK: 8MHz
93+
94+
6695
It is possible to specify CAN 2.0 bit timings
6796
using the config file:
6897

69-
7098
.. code-block:: none
7199
72100
[default]

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"sphinx.ext.graphviz",
5050
"sphinxcontrib.programoutput",
5151
"sphinx_inline_tabs",
52+
"sphinx_copybutton",
5253
]
5354

5455
# Now, you can use the alias name as a new role, e.g. :issue:`123`.

doc/doc-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
sphinx>=5.2.3
22
sphinxcontrib-programoutput
33
sphinx-inline-tabs
4+
sphinx-copybutton
45
furo

test/test_bit_timing.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ def test_equality():
271271
def test_string_representation():
272272
timing = can.BitTiming(f_clock=8_000_000, brp=1, tseg1=5, tseg2=2, sjw=1)
273273
assert str(timing) == (
274-
"BR 1000000 bit/s, SP: 75.00%, BRP: 1, TSEG1: 5, TSEG2: 2, SJW: 1, "
275-
"BTR: 0014h, f_clock: 8MHz"
274+
"BR: 1_000_000 bit/s, SP: 75.00%, BRP: 1, TSEG1: 5, TSEG2: 2, SJW: 1, "
275+
"BTR: 0014h, CLK: 8MHz"
276276
)
277277

278278
fd_timing = can.BitTimingFd(
@@ -287,9 +287,9 @@ def test_string_representation():
287287
data_sjw=10,
288288
)
289289
assert str(fd_timing) == (
290-
"NBR: 500000 bit/s, NSP: 75.00%, NBRP: 1, NTSEG1: 119, NTSEG2: 40, NSJW: 40, "
291-
"DBR: 2000000 bit/s, DSP: 75.00%, DBRP: 1, DTSEG1: 29, DTSEG2: 10, DSJW: 10, "
292-
"f_clock: 80MHz"
290+
"NBR: 500_000 bit/s, NSP: 75.00%, NBRP: 1, NTSEG1: 119, NTSEG2: 40, NSJW: 40, "
291+
"DBR: 2_000_000 bit/s, DSP: 75.00%, DBRP: 1, DTSEG1: 29, DTSEG2: 10, DSJW: 10, "
292+
"CLK: 80MHz"
293293
)
294294

295295

@@ -316,6 +316,23 @@ def test_repr():
316316
)
317317

318318

319+
def test_hash():
320+
_timings = {
321+
can.BitTiming(f_clock=8_000_000, brp=1, tseg1=5, tseg2=2, sjw=1, nof_samples=1),
322+
can.BitTimingFd(
323+
f_clock=80_000_000,
324+
nom_brp=1,
325+
nom_tseg1=119,
326+
nom_tseg2=40,
327+
nom_sjw=40,
328+
data_brp=1,
329+
data_tseg1=29,
330+
data_tseg2=10,
331+
data_sjw=10,
332+
),
333+
}
334+
335+
319336
def test_mapping():
320337
timing = can.BitTiming(f_clock=8_000_000, brp=1, tseg1=5, tseg2=2, sjw=1)
321338
timing_dict = dict(timing)

0 commit comments

Comments
 (0)