From 856fd115da6672cc8821b88d5d3e601ded32c662 Mon Sep 17 00:00:00 2001 From: zariiii9003 <52598363+zariiii9003@users.noreply.github.com> Date: Sat, 23 Nov 2024 15:48:55 +0100 Subject: [PATCH] Add BitTiming/BitTimingFd support to slcanBus (#1512) * add BitTiming parameter to slcanBus * remove btr argument, rename ttyBaudrate --- can/interfaces/slcan.py | 73 +++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/can/interfaces/slcan.py b/can/interfaces/slcan.py index f023e084c..4cf8b5e25 100644 --- a/can/interfaces/slcan.py +++ b/can/interfaces/slcan.py @@ -5,16 +5,17 @@ import io import logging import time -from typing import Any, Optional, Tuple +import warnings +from typing import Any, Optional, Tuple, Union -from can import BusABC, CanProtocol, Message, typechecking - -from ..exceptions import ( +from can import BitTiming, BitTimingFd, BusABC, CanProtocol, Message, typechecking +from can.exceptions import ( CanInitializationError, CanInterfaceNotImplementedError, CanOperationError, error_check, ) +from can.util import check_or_adjust_timing_clock, deprecated_args_alias logger = logging.getLogger(__name__) @@ -54,12 +55,17 @@ class slcanBus(BusABC): LINE_TERMINATOR = b"\r" + @deprecated_args_alias( + deprecation_start="4.5.0", + deprecation_end="5.0.0", + ttyBaudrate="tty_baudrate", + ) def __init__( self, channel: typechecking.ChannelStr, - ttyBaudrate: int = 115200, + tty_baudrate: int = 115200, bitrate: Optional[int] = None, - btr: Optional[str] = None, + timing: Optional[Union[BitTiming, BitTimingFd]] = None, sleep_after_open: float = _SLEEP_AFTER_SERIAL_OPEN, rtscts: bool = False, listen_only: bool = False, @@ -70,12 +76,16 @@ def __init__( :param str channel: port of underlying serial or usb device (e.g. ``/dev/ttyUSB0``, ``COM8``, ...) Must not be empty. Can also end with ``@115200`` (or similarly) to specify the baudrate. - :param int ttyBaudrate: + :param int tty_baudrate: baudrate of underlying serial or usb device (Ignored if set via the ``channel`` parameter) :param bitrate: Bitrate in bit/s - :param btr: - BTR register value to set custom can speed + :param timing: + Optional :class:`~can.BitTiming` instance to use for custom bit timing setting. + If this argument is set then it overrides the bitrate and btr arguments. The + `f_clock` value of the timing instance must be set to 8_000_000 (8MHz) + for standard CAN. + CAN FD and the :class:`~can.BitTimingFd` class are not supported. :param poll_interval: Poll interval in seconds when reading messages :param sleep_after_open: @@ -97,16 +107,26 @@ def __init__( if serial is None: raise CanInterfaceNotImplementedError("The serial module is not installed") + btr: Optional[str] = kwargs.get("btr", None) + if btr is not None: + warnings.warn( + "The 'btr' argument is deprecated since python-can v4.5.0 " + "and scheduled for removal in v5.0.0. " + "Use the 'timing' argument instead.", + DeprecationWarning, + stacklevel=1, + ) + if not channel: # if None or empty raise ValueError("Must specify a serial port.") if "@" in channel: (channel, baudrate) = channel.split("@") - ttyBaudrate = int(baudrate) + tty_baudrate = int(baudrate) with error_check(exception_type=CanInitializationError): self.serialPortOrig = serial.serial_for_url( channel, - baudrate=ttyBaudrate, + baudrate=tty_baudrate, rtscts=rtscts, timeout=timeout, ) @@ -117,21 +137,23 @@ def __init__( time.sleep(sleep_after_open) with error_check(exception_type=CanInitializationError): - if bitrate is not None and btr is not None: - raise ValueError("Bitrate and btr mutually exclusive.") - if bitrate is not None: - self.set_bitrate(bitrate) - if btr is not None: - self.set_bitrate_reg(btr) + if isinstance(timing, BitTiming): + timing = check_or_adjust_timing_clock(timing, valid_clocks=[8_000_000]) + self.set_bitrate_reg(f"{timing.btr0:02X}{timing.btr1:02X}") + elif isinstance(timing, BitTimingFd): + raise NotImplementedError( + f"CAN FD is not supported by {self.__class__.__name__}." + ) + else: + if bitrate is not None and btr is not None: + raise ValueError("Bitrate and btr mutually exclusive.") + if bitrate is not None: + self.set_bitrate(bitrate) + if btr is not None: + self.set_bitrate_reg(btr) self.open() - super().__init__( - channel, - ttyBaudrate=115200, - bitrate=None, - rtscts=False, - **kwargs, - ) + super().__init__(channel, **kwargs) def set_bitrate(self, bitrate: int) -> None: """ @@ -153,7 +175,8 @@ def set_bitrate(self, bitrate: int) -> None: def set_bitrate_reg(self, btr: str) -> None: """ :param btr: - BTR register value to set custom can speed + BTR register value to set custom can speed as a string `xxyy` where + xx is the BTR0 value in hex and yy is the BTR1 value in hex. """ self.close() self._write("s" + btr)