diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ecab49e..5e337e0b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the chang +## Version [v4.6.2](https://github.com/hardbyte/python-can/tree/v4.6.2) - 2025-10-08 + +### Added + +- Add [python-can-coe](https://c0d3.sh/smarthome/python-can-coe) interface plugin to the documentation. ([#1987](https://github.com/hardbyte/python-can/issues/1987)) + +### Fixed + +- Keep a reference to asyncio tasks in `can.Notifier` as recommended by [python documentation](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task). ([#1938](https://github.com/hardbyte/python-can/issues/1938)) + + ## Version [v4.6.1](https://github.com/hardbyte/python-can/tree/v4.6.1) - 2025-08-12 ### Fixed diff --git a/can/bus.py b/can/bus.py index ec9eb09b7..267d445f2 100644 --- a/can/bus.py +++ b/can/bus.py @@ -211,6 +211,7 @@ def send_periodic( store_task: bool = True, autostart: bool = True, modifier_callback: Optional[Callable[[Message], None]] = None, + on_error: Optional[Callable[[Exception], bool]] = None, ) -> can.broadcastmanager.CyclicSendTaskABC: """Start sending messages at a given period on this bus. @@ -240,6 +241,11 @@ def send_periodic( Function which should be used to modify each message's data before sending. The callback modifies the :attr:`~can.Message.data` of the message and returns ``None``. + :param on_error: + Function which is called when an exception occurs during sending. The + exception is passed as the only parameter. If the function returns + True, the error is suppressed and the sending continues. If it returns + False, the sending is stopped. :return: A started task instance. Note the task can be stopped (and depending on the backend modified) by calling the task's @@ -272,7 +278,7 @@ def send_periodic( task = cast( "_SelfRemovingCyclicTask", self._send_periodic_internal( - msgs, period, duration, autostart, modifier_callback + msgs, period, duration, autostart, modifier_callback, on_error ), ) # we wrap the task's stop method to also remove it from the Bus's list of tasks @@ -302,6 +308,7 @@ def _send_periodic_internal( duration: Optional[float] = None, autostart: bool = True, modifier_callback: Optional[Callable[[Message], None]] = None, + on_error: Optional[Callable[[Exception], bool]] = None, ) -> can.broadcastmanager.CyclicSendTaskABC: """Default implementation of periodic message sending using threading. @@ -336,6 +343,7 @@ def _send_periodic_internal( duration=duration, autostart=autostart, modifier_callback=modifier_callback, + on_error=on_error, ) return task diff --git a/can/interfaces/ixxat/canlib_vcinpl.py b/can/interfaces/ixxat/canlib_vcinpl.py index 59f98417d..30cee1dad 100644 --- a/can/interfaces/ixxat/canlib_vcinpl.py +++ b/can/interfaces/ixxat/canlib_vcinpl.py @@ -10,6 +10,7 @@ """ import ctypes +import time import functools import logging import sys @@ -800,6 +801,7 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None: ) else: _canlib.canChannelPostMessage(self._channel_handle, message) + time.sleep(500e-6) # Want to log outgoing messages? # log.log(self.RECV_LOGGING_LEVEL, "Sent: %s", message) diff --git a/can/interfaces/ixxat/canlib_vcinpl2.py b/can/interfaces/ixxat/canlib_vcinpl2.py index b7698277f..b9adb47e8 100644 --- a/can/interfaces/ixxat/canlib_vcinpl2.py +++ b/can/interfaces/ixxat/canlib_vcinpl2.py @@ -944,6 +944,7 @@ def send(self, msg: Message, timeout: Optional[float] = None) -> None: else: _canlib.canChannelPostMessage(self._channel_handle, message) + time.sleep(500e-6) def _send_periodic_internal( self, diff --git a/can/interfaces/pcan/pcan.py b/can/interfaces/pcan/pcan.py index d63981580..389ce0de6 100644 --- a/can/interfaces/pcan/pcan.py +++ b/can/interfaces/pcan/pcan.py @@ -663,6 +663,7 @@ def send(self, msg, timeout=None): raise PcanCanOperationError( "Failed to send: " + self._get_formatted_error(result) ) + time.sleep(500e-6) def flash(self, flash): """ diff --git a/can/interfaces/usb2can/usb2canInterface.py b/can/interfaces/usb2can/usb2canInterface.py index adc16e8b3..1be06083c 100644 --- a/can/interfaces/usb2can/usb2canInterface.py +++ b/can/interfaces/usb2can/usb2canInterface.py @@ -3,6 +3,7 @@ """ import logging +import time from ctypes import byref from typing import Optional, Union @@ -163,6 +164,7 @@ def send(self, msg, timeout=None): status = self.can.blocking_send(self.handle, byref(tx), int(timeout * 1000)) else: status = self.can.send(self.handle, byref(tx)) + time.sleep(500e-6) if status != CanalError.SUCCESS: raise CanOperationError("could not send message", error_code=status) diff --git a/can/interfaces/vector/canlib.py b/can/interfaces/vector/canlib.py index d15b89803..da9281aa3 100644 --- a/can/interfaces/vector/canlib.py +++ b/can/interfaces/vector/canlib.py @@ -870,6 +870,7 @@ def _send_can_msg_sequence(self, msgs: Sequence[Message]) -> int: self.xldriver.xlCanTransmit( self.port_handle, mask, message_count, xl_event_array ) + time.sleep(500e-6) return message_count.value @staticmethod @@ -904,6 +905,7 @@ def _send_can_fd_msg_sequence(self, msgs: Sequence[Message]) -> int: self.xldriver.xlCanTransmitEx( self.port_handle, mask, message_count, msg_count_sent, xl_can_tx_event_array ) + time.sleep(500e-6) return msg_count_sent.value @staticmethod diff --git a/doc/changelog.d/1938.fixed.md b/doc/changelog.d/1938.fixed.md deleted file mode 100644 index f9aad1089..000000000 --- a/doc/changelog.d/1938.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Keep a reference to asyncio tasks in `can.Notifier` as recommended by [python documentation](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task). diff --git a/doc/changelog.d/1987.added.md b/doc/changelog.d/1987.added.md deleted file mode 100644 index 398add3e3..000000000 --- a/doc/changelog.d/1987.added.md +++ /dev/null @@ -1 +0,0 @@ -Add [python-can-coe](https://c0d3.sh/smarthome/python-can-coe) interface plugin to the documentation.