From c2260f3881fbffb989ecb751a173cb5d6c27607a Mon Sep 17 00:00:00 2001 From: Caleb Perkinson Date: Fri, 23 Apr 2021 17:26:02 -0500 Subject: [PATCH 01/11] interface for changing bitrate implemented in vector. will add to socketcan eventually. just want to get some thoughts on this interface --- can/bus.py | 13 +++++++++++++ can/interfaces/vector/canlib.py | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/can/bus.py b/can/bus.py index 246f45d19..ca672997c 100644 --- a/can/bus.py +++ b/can/bus.py @@ -314,6 +314,19 @@ def __iter__(self) -> Iterator[Message]: if msg is not None: yield msg + @abstractmethod + def change_bitrate(self, bitrate: int) -> None: + """Changes the bitrate of the underlying bus. + + Override this method to enable runtime bitrate changes. + + :param int bitrate: the new bitrate to set. + + :raises can.CanError: + if the message could not be sent + """ + raise NotImplementedError("Device not capable of runtime bitrate change") + @property def filters(self) -> Optional[can.typechecking.CanFilters]: """ diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index c5838de21..feab47410 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -515,6 +515,12 @@ def handle_canfd_event(self, event: xlclass.XLcanRxEvent) -> None: def send(self, msg: Message, timeout: typing.Optional[float] = None): self._send_sequence([msg]) + def change_bitrate(self, bitrate: int) -> None: + xldriver.xlCanSetChannelBitrate( + self.port_handle, self.mask, bitrate + ) + LOG.info("SetChannelBitrate: baudr.=%u", bitrate) + def _send_sequence(self, msgs: typing.Sequence[Message]) -> int: """Send messages and return number of successful transmissions.""" if self.fd: From 2faf4002e73d47ab384cc11d6f5f7c8927fa2027 Mon Sep 17 00:00:00 2001 From: Caleb Perkinson Date: Fri, 23 Apr 2021 22:26:56 +0000 Subject: [PATCH 02/11] Format code with black --- can/interfaces/vector/canlib.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index feab47410..f3cb6943c 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -516,9 +516,7 @@ def send(self, msg: Message, timeout: typing.Optional[float] = None): self._send_sequence([msg]) def change_bitrate(self, bitrate: int) -> None: - xldriver.xlCanSetChannelBitrate( - self.port_handle, self.mask, bitrate - ) + xldriver.xlCanSetChannelBitrate(self.port_handle, self.mask, bitrate) LOG.info("SetChannelBitrate: baudr.=%u", bitrate) def _send_sequence(self, msgs: typing.Sequence[Message]) -> int: From 786525d4f78d6bf431f139c080b507cada746c32 Mon Sep 17 00:00:00 2001 From: Caleb Perkinson Date: Fri, 23 Apr 2021 21:00:52 -0500 Subject: [PATCH 03/11] making it a property --- can/bus.py | 8 +++++++- can/interfaces/vector/canlib.py | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/can/bus.py b/can/bus.py index ca672997c..c0691260c 100644 --- a/can/bus.py +++ b/can/bus.py @@ -314,8 +314,14 @@ def __iter__(self) -> Iterator[Message]: if msg is not None: yield msg + @property + @abstractmethod + def bitrate(self) -> int: + raise NotImplementedError("Device must implement bitrate") + + @bitrate.setter @abstractmethod - def change_bitrate(self, bitrate: int) -> None: + def bitrate(self, bitrate: int) -> None: """Changes the bitrate of the underlying bus. Override this method to enable runtime bitrate changes. diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index f3cb6943c..408da7ac5 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -233,6 +233,7 @@ def __init__( ) if permission_mask.value == self.mask: + self.bitrate = bitrate if fd: self.canFdConf = xlclass.XLcanFdConf() if bitrate: @@ -515,7 +516,12 @@ def handle_canfd_event(self, event: xlclass.XLcanRxEvent) -> None: def send(self, msg: Message, timeout: typing.Optional[float] = None): self._send_sequence([msg]) - def change_bitrate(self, bitrate: int) -> None: + @property + def bitrate(self) -> int: + return self.bitrate + + @bitrate.setter + def bitrate(self, bitrate: int) -> None: xldriver.xlCanSetChannelBitrate(self.port_handle, self.mask, bitrate) LOG.info("SetChannelBitrate: baudr.=%u", bitrate) From 6a609ef5f24a3a436dd7326f0ba629342bb0fb23 Mon Sep 17 00:00:00 2001 From: Caleb Perkinson Date: Mon, 26 Apr 2021 13:46:16 +0000 Subject: [PATCH 04/11] Format code with black --- can/interfaces/vector/canlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 408da7ac5..a2e053d51 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -519,7 +519,7 @@ def send(self, msg: Message, timeout: typing.Optional[float] = None): @property def bitrate(self) -> int: return self.bitrate - + @bitrate.setter def bitrate(self, bitrate: int) -> None: xldriver.xlCanSetChannelBitrate(self.port_handle, self.mask, bitrate) From f8fef9904ac2f2d4ffa4608ae47c7e5c3d812ee6 Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 11 May 2021 20:00:37 -0500 Subject: [PATCH 05/11] add init access handling and FD --- can/interfaces/vector/canlib.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index a2e053d51..9f57e04b7 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -163,7 +163,7 @@ def __init__( ) self.channels = channel_index else: - # Is there any better way to raise the error? + #TODO - Is there any better way to raise the error? raise Exception( "None of the configured channels could be found on the specified hardware." ) @@ -233,7 +233,8 @@ def __init__( ) if permission_mask.value == self.mask: - self.bitrate = bitrate + self._init_access = True + self._bitrate = bitrate if fd: self.canFdConf = xlclass.XLcanFdConf() if bitrate: @@ -278,6 +279,7 @@ def __init__( ) LOG.info("SetChannelBitrate: baudr.=%u", bitrate) else: + self._init_access = False LOG.info("No init access!") # Enable/disable TX receipts @@ -518,12 +520,22 @@ def send(self, msg: Message, timeout: typing.Optional[float] = None): @property def bitrate(self) -> int: - return self.bitrate + return self._bitrate @bitrate.setter def bitrate(self, bitrate: int) -> None: - xldriver.xlCanSetChannelBitrate(self.port_handle, self.mask, bitrate) - LOG.info("SetChannelBitrate: baudr.=%u", bitrate) + if self._init_access: + if self.fd: + self.canFdConf.arbitrationBitRate = bitrate + xldriver.xlCanFdSetConfiguration( + self.port_handle, self.mask, self.canFdConf + ) + else: + xldriver.xlCanSetChannelBitrate(self.port_handle, self.mask, bitrate) + self._bitrate = bitrate + LOG.info("SetChannelBitrate: baudr.=%u", bitrate) + else: + LOG.error("No init access!") def _send_sequence(self, msgs: typing.Sequence[Message]) -> int: """Send messages and return number of successful transmissions.""" From 4d305b24ec2f967c91c831720981f36dfeb15d59 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 12 May 2021 01:01:26 +0000 Subject: [PATCH 06/11] Format code with black --- can/interfaces/vector/canlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index 9f57e04b7..2a6ba00a4 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -163,7 +163,7 @@ def __init__( ) self.channels = channel_index else: - #TODO - Is there any better way to raise the error? + # TODO - Is there any better way to raise the error? raise Exception( "None of the configured channels could be found on the specified hardware." ) From 896b91583873a09035523c5eda1fd7116411a385 Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 11 May 2021 22:50:57 -0500 Subject: [PATCH 07/11] shouldn't have made this abstract --- can/bus.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/can/bus.py b/can/bus.py index c0691260c..5cafcb1a2 100644 --- a/can/bus.py +++ b/can/bus.py @@ -315,21 +315,18 @@ def __iter__(self) -> Iterator[Message]: yield msg @property - @abstractmethod def bitrate(self) -> int: + """Bitrate of the underlying bus in bits/s + """ raise NotImplementedError("Device must implement bitrate") @bitrate.setter - @abstractmethod def bitrate(self, bitrate: int) -> None: """Changes the bitrate of the underlying bus. Override this method to enable runtime bitrate changes. - :param int bitrate: the new bitrate to set. - - :raises can.CanError: - if the message could not be sent + :param int bitrate: the new bitrate to set in bits/s. """ raise NotImplementedError("Device not capable of runtime bitrate change") From 48052aed7557c58aea031581821118efee98148d Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 12 May 2021 03:51:44 +0000 Subject: [PATCH 08/11] Format code with black --- can/bus.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/can/bus.py b/can/bus.py index 5cafcb1a2..f743e3782 100644 --- a/can/bus.py +++ b/can/bus.py @@ -316,8 +316,7 @@ def __iter__(self) -> Iterator[Message]: @property def bitrate(self) -> int: - """Bitrate of the underlying bus in bits/s - """ + """Bitrate of the underlying bus in bits/s""" raise NotImplementedError("Device must implement bitrate") @bitrate.setter From 6d80f4cb6e803cbd12e5a2a6ce0adca2f9a7aa79 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 12 May 2021 21:16:46 -0500 Subject: [PATCH 09/11] only works with python versions greater than 3.3 implement bitrate for socketcan using libsocketcan2. could just use ip and parse output to reduce dependency --- can/interfaces/socketcan/constants.py | 5 --- can/interfaces/socketcan/socketcan.py | 47 +++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/can/interfaces/socketcan/constants.py b/can/interfaces/socketcan/constants.py index 37d4847c4..15932244a 100644 --- a/can/interfaces/socketcan/constants.py +++ b/can/interfaces/socketcan/constants.py @@ -43,11 +43,6 @@ MSK_ARBID = 0x1FFFFFFF MSK_FLAGS = 0xE0000000 -PF_CAN = 29 -SOCK_RAW = 3 -SOCK_DGRAM = 2 -AF_CAN = PF_CAN - SIOCGIFNAME = 0x8910 SIOCGIFINDEX = 0x8933 SIOCGSTAMP = 0x8906 diff --git a/can/interfaces/socketcan/socketcan.py b/can/interfaces/socketcan/socketcan.py index 920109581..ba18b3c8a 100644 --- a/can/interfaces/socketcan/socketcan.py +++ b/can/interfaces/socketcan/socketcan.py @@ -21,6 +21,24 @@ log_tx = log.getChild("tx") log_rx = log.getChild("rx") +can_config_lib = ctypes.util.find_library("socketcan123") +if can_config_lib: + class BitrateTiming(ctypes.Structure): + _fields_ = [("bitrate", ctypes.c_uint32), + ("sample_point", ctypes.c_uint32), + ("tq", ctypes.c_uint32), + ("prop_seg", ctypes.c_uint32), + ("phase_seg1", ctypes.c_uint32), + ("phase_seg2", ctypes.c_uint32), + ("sjw", ctypes.c_uint32), + ("brp", ctypes.c_uint32)] + + can_config = ctypes.cdll.LoadLibrary(can_config_lib) +else: + can_config = None + can_config_error = "Dynamic bitrate changes not possible. Please install libsocketcan2." + log.error(can_config_error) + try: import fcntl except ImportError: @@ -267,7 +285,7 @@ def dissect_can_frame(frame: bytes) -> Tuple[int, int, int, bytes]: def create_bcm_socket(channel: str) -> socket.socket: """create a broadcast manager socket and connect to the given interface""" - s = socket.socket(PF_CAN, socket.SOCK_DGRAM, CAN_BCM) + s = socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) s.connect((channel,)) return s @@ -491,7 +509,7 @@ def create_socket() -> socket.socket: """Creates a raw CAN socket. The socket will be returned unbound to any interface. """ - sock = socket.socket(PF_CAN, socket.SOCK_RAW, CAN_RAW) + sock = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) log.info("Created a socket") @@ -854,6 +872,31 @@ def _detect_available_configs() -> List[can.typechecking.AutoDetectedConfig]: for channel in find_available_interfaces() ] + @property + def bitrate(self) -> int: + if can_config: + bitrate_timing = BitrateTiming() + error = can_config.can_get_bittiming(self.channel.encode(), ctypes.pointer(bitrate_timing)) + if error == -1: + log.error("likely need to run as sudo to be able to set the bitrate") + return None + return bitrate_timing.bitrate + else: + #TODO - better error? + raise NotImplementedError(can_config_error) + + @bitrate.setter + def bitrate(self, bitrate: int) -> None: + if can_config: + can_config.can_do_stop(self.channel.encode()) + error = can_config.can_set_bitrate(self.channel.encode(), bitrate) + can_config.can_do_start(self.channel.encode()) + if error == -1: + log.error("likely need to run as sudo to be able to set the bitrate") + else: + #TODO - better error? + raise NotImplementedError(can_config_error) + if __name__ == "__main__": # This example demonstrates how to use the internal methods of this module. From 46365fdbe963059d6a4dde114145706994f78faa Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 14 May 2021 16:53:10 +0000 Subject: [PATCH 10/11] Format code with black --- can/interfaces/socketcan/socketcan.py | 31 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/can/interfaces/socketcan/socketcan.py b/can/interfaces/socketcan/socketcan.py index ba18b3c8a..4df37b0f8 100644 --- a/can/interfaces/socketcan/socketcan.py +++ b/can/interfaces/socketcan/socketcan.py @@ -23,20 +23,25 @@ can_config_lib = ctypes.util.find_library("socketcan123") if can_config_lib: + class BitrateTiming(ctypes.Structure): - _fields_ = [("bitrate", ctypes.c_uint32), - ("sample_point", ctypes.c_uint32), - ("tq", ctypes.c_uint32), - ("prop_seg", ctypes.c_uint32), - ("phase_seg1", ctypes.c_uint32), - ("phase_seg2", ctypes.c_uint32), - ("sjw", ctypes.c_uint32), - ("brp", ctypes.c_uint32)] + _fields_ = [ + ("bitrate", ctypes.c_uint32), + ("sample_point", ctypes.c_uint32), + ("tq", ctypes.c_uint32), + ("prop_seg", ctypes.c_uint32), + ("phase_seg1", ctypes.c_uint32), + ("phase_seg2", ctypes.c_uint32), + ("sjw", ctypes.c_uint32), + ("brp", ctypes.c_uint32), + ] can_config = ctypes.cdll.LoadLibrary(can_config_lib) else: can_config = None - can_config_error = "Dynamic bitrate changes not possible. Please install libsocketcan2." + can_config_error = ( + "Dynamic bitrate changes not possible. Please install libsocketcan2." + ) log.error(can_config_error) try: @@ -876,13 +881,15 @@ def _detect_available_configs() -> List[can.typechecking.AutoDetectedConfig]: def bitrate(self) -> int: if can_config: bitrate_timing = BitrateTiming() - error = can_config.can_get_bittiming(self.channel.encode(), ctypes.pointer(bitrate_timing)) + error = can_config.can_get_bittiming( + self.channel.encode(), ctypes.pointer(bitrate_timing) + ) if error == -1: log.error("likely need to run as sudo to be able to set the bitrate") return None return bitrate_timing.bitrate else: - #TODO - better error? + # TODO - better error? raise NotImplementedError(can_config_error) @bitrate.setter @@ -894,7 +901,7 @@ def bitrate(self, bitrate: int) -> None: if error == -1: log.error("likely need to run as sudo to be able to set the bitrate") else: - #TODO - better error? + # TODO - better error? raise NotImplementedError(can_config_error) From 48b8f8cd1c82758a56608f4626d5518b3d0aafa1 Mon Sep 17 00:00:00 2001 From: Caleb Date: Fri, 14 May 2021 12:00:38 -0500 Subject: [PATCH 11/11] removing debug info --- can/interfaces/socketcan/socketcan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/interfaces/socketcan/socketcan.py b/can/interfaces/socketcan/socketcan.py index 4df37b0f8..f9fd0e426 100644 --- a/can/interfaces/socketcan/socketcan.py +++ b/can/interfaces/socketcan/socketcan.py @@ -21,7 +21,7 @@ log_tx = log.getChild("tx") log_rx = log.getChild("rx") -can_config_lib = ctypes.util.find_library("socketcan123") +can_config_lib = ctypes.util.find_library("socketcan") if can_config_lib: class BitrateTiming(ctypes.Structure):