Skip to content

Commit 856fd11

Browse files
authored
Add BitTiming/BitTimingFd support to slcanBus (#1512)
* add BitTiming parameter to slcanBus * remove btr argument, rename ttyBaudrate
1 parent 33a1ec7 commit 856fd11

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

can/interfaces/slcan.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
import io
66
import logging
77
import time
8-
from typing import Any, Optional, Tuple
8+
import warnings
9+
from typing import Any, Optional, Tuple, Union
910

10-
from can import BusABC, CanProtocol, Message, typechecking
11-
12-
from ..exceptions import (
11+
from can import BitTiming, BitTimingFd, BusABC, CanProtocol, Message, typechecking
12+
from can.exceptions import (
1313
CanInitializationError,
1414
CanInterfaceNotImplementedError,
1515
CanOperationError,
1616
error_check,
1717
)
18+
from can.util import check_or_adjust_timing_clock, deprecated_args_alias
1819

1920
logger = logging.getLogger(__name__)
2021

@@ -54,12 +55,17 @@ class slcanBus(BusABC):
5455

5556
LINE_TERMINATOR = b"\r"
5657

58+
@deprecated_args_alias(
59+
deprecation_start="4.5.0",
60+
deprecation_end="5.0.0",
61+
ttyBaudrate="tty_baudrate",
62+
)
5763
def __init__(
5864
self,
5965
channel: typechecking.ChannelStr,
60-
ttyBaudrate: int = 115200,
66+
tty_baudrate: int = 115200,
6167
bitrate: Optional[int] = None,
62-
btr: Optional[str] = None,
68+
timing: Optional[Union[BitTiming, BitTimingFd]] = None,
6369
sleep_after_open: float = _SLEEP_AFTER_SERIAL_OPEN,
6470
rtscts: bool = False,
6571
listen_only: bool = False,
@@ -70,12 +76,16 @@ def __init__(
7076
:param str channel:
7177
port of underlying serial or usb device (e.g. ``/dev/ttyUSB0``, ``COM8``, ...)
7278
Must not be empty. Can also end with ``@115200`` (or similarly) to specify the baudrate.
73-
:param int ttyBaudrate:
79+
:param int tty_baudrate:
7480
baudrate of underlying serial or usb device (Ignored if set via the ``channel`` parameter)
7581
:param bitrate:
7682
Bitrate in bit/s
77-
:param btr:
78-
BTR register value to set custom can speed
83+
:param timing:
84+
Optional :class:`~can.BitTiming` instance to use for custom bit timing setting.
85+
If this argument is set then it overrides the bitrate and btr arguments. The
86+
`f_clock` value of the timing instance must be set to 8_000_000 (8MHz)
87+
for standard CAN.
88+
CAN FD and the :class:`~can.BitTimingFd` class are not supported.
7989
:param poll_interval:
8090
Poll interval in seconds when reading messages
8191
:param sleep_after_open:
@@ -97,16 +107,26 @@ def __init__(
97107
if serial is None:
98108
raise CanInterfaceNotImplementedError("The serial module is not installed")
99109

110+
btr: Optional[str] = kwargs.get("btr", None)
111+
if btr is not None:
112+
warnings.warn(
113+
"The 'btr' argument is deprecated since python-can v4.5.0 "
114+
"and scheduled for removal in v5.0.0. "
115+
"Use the 'timing' argument instead.",
116+
DeprecationWarning,
117+
stacklevel=1,
118+
)
119+
100120
if not channel: # if None or empty
101121
raise ValueError("Must specify a serial port.")
102122
if "@" in channel:
103123
(channel, baudrate) = channel.split("@")
104-
ttyBaudrate = int(baudrate)
124+
tty_baudrate = int(baudrate)
105125

106126
with error_check(exception_type=CanInitializationError):
107127
self.serialPortOrig = serial.serial_for_url(
108128
channel,
109-
baudrate=ttyBaudrate,
129+
baudrate=tty_baudrate,
110130
rtscts=rtscts,
111131
timeout=timeout,
112132
)
@@ -117,21 +137,23 @@ def __init__(
117137
time.sleep(sleep_after_open)
118138

119139
with error_check(exception_type=CanInitializationError):
120-
if bitrate is not None and btr is not None:
121-
raise ValueError("Bitrate and btr mutually exclusive.")
122-
if bitrate is not None:
123-
self.set_bitrate(bitrate)
124-
if btr is not None:
125-
self.set_bitrate_reg(btr)
140+
if isinstance(timing, BitTiming):
141+
timing = check_or_adjust_timing_clock(timing, valid_clocks=[8_000_000])
142+
self.set_bitrate_reg(f"{timing.btr0:02X}{timing.btr1:02X}")
143+
elif isinstance(timing, BitTimingFd):
144+
raise NotImplementedError(
145+
f"CAN FD is not supported by {self.__class__.__name__}."
146+
)
147+
else:
148+
if bitrate is not None and btr is not None:
149+
raise ValueError("Bitrate and btr mutually exclusive.")
150+
if bitrate is not None:
151+
self.set_bitrate(bitrate)
152+
if btr is not None:
153+
self.set_bitrate_reg(btr)
126154
self.open()
127155

128-
super().__init__(
129-
channel,
130-
ttyBaudrate=115200,
131-
bitrate=None,
132-
rtscts=False,
133-
**kwargs,
134-
)
156+
super().__init__(channel, **kwargs)
135157

136158
def set_bitrate(self, bitrate: int) -> None:
137159
"""
@@ -153,7 +175,8 @@ def set_bitrate(self, bitrate: int) -> None:
153175
def set_bitrate_reg(self, btr: str) -> None:
154176
"""
155177
:param btr:
156-
BTR register value to set custom can speed
178+
BTR register value to set custom can speed as a string `xxyy` where
179+
xx is the BTR0 value in hex and yy is the BTR1 value in hex.
157180
"""
158181
self.close()
159182
self._write("s" + btr)

0 commit comments

Comments
 (0)