Skip to content

Commit 7a3d23f

Browse files
SWolfSchunkburesSebastian Wolf
authored
Add autostart option to BusABC.send_periodic() (#1853)
* Add autostart option (kwarg) to BusABC.send_periodic() to fix issue #1848 * Fix for #1849 (PCAN fails when PCAN_ERROR_ILLDATA is read via ReadFD) (#1850) * When there is an invalid frame on CAN bus (in our case CAN FD), PCAN first reports result PCAN_ERROR_ILLDATA and then it send the error frame. If the PCAN_ERROR_ILLDATA is not ignored, python-can throws an exception. This fix add the ignore on the PCAN_ERROR_ILLDATA. * Fix for ruff error `can/interfaces/pcan/pcan.py:5:1: I001 [*] Import block is un-sorted or un-formatted` Added comment explaining why to ignore the PCAN_ERROR_ILLDATA. * Format with black to pass checks * Do not ignore autostart parameter for Bus.send_periodic() on IXXAT devices * Do not ignore autostart parameter for Bis.send_periodic() on socketcan devices * Fix double start socketcan periodic * Fix link methods in docstring for start() methods of the tasks can.broadcastmanager.CyclicTask.start * Change the behaviour of autostart parameter in socketcan implementation of CyclicSendTask to not call _tx_setup() method instead of adding a parameter to it. * Fix code style (max 100 chars per line) Fix wrong docstring reference. --------- Co-authored-by: Tomas Bures <bures@d3s.mff.cuni.cz> Co-authored-by: Sebastian Wolf <Sebastian.Wolf@pace-systems.de>
1 parent 950e4b4 commit 7a3d23f

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

can/broadcastmanager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ def __init__(
276276
period: float,
277277
duration: Optional[float] = None,
278278
on_error: Optional[Callable[[Exception], bool]] = None,
279+
autostart: bool = True,
279280
modifier_callback: Optional[Callable[[Message], None]] = None,
280281
) -> None:
281282
"""Transmits `messages` with a `period` seconds for `duration` seconds on a `bus`.
@@ -324,7 +325,8 @@ def __init__(
324325
stacklevel=1,
325326
)
326327

327-
self.start()
328+
if autostart:
329+
self.start()
328330

329331
def stop(self) -> None:
330332
self.stopped = True

can/bus.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def send_periodic(
215215
period: float,
216216
duration: Optional[float] = None,
217217
store_task: bool = True,
218+
autostart: bool = True,
218219
modifier_callback: Optional[Callable[[Message], None]] = None,
219220
) -> can.broadcastmanager.CyclicSendTaskABC:
220221
"""Start sending messages at a given period on this bus.
@@ -237,6 +238,10 @@ def send_periodic(
237238
:param store_task:
238239
If True (the default) the task will be attached to this Bus instance.
239240
Disable to instead manage tasks manually.
241+
:param autostart:
242+
If True (the default) the sending task will immediately start after creation.
243+
Otherwise, the task has to be started by calling the
244+
tasks :meth:`~can.RestartableCyclicTaskABC.start` method on it.
240245
:param modifier_callback:
241246
Function which should be used to modify each message's data before
242247
sending. The callback modifies the :attr:`~can.Message.data` of the
@@ -272,7 +277,9 @@ def send_periodic(
272277
# Create a backend specific task; will be patched to a _SelfRemovingCyclicTask later
273278
task = cast(
274279
_SelfRemovingCyclicTask,
275-
self._send_periodic_internal(msgs, period, duration, modifier_callback),
280+
self._send_periodic_internal(
281+
msgs, period, duration, autostart, modifier_callback
282+
),
276283
)
277284
# we wrap the task's stop method to also remove it from the Bus's list of tasks
278285
periodic_tasks = self._periodic_tasks
@@ -299,6 +306,7 @@ def _send_periodic_internal(
299306
msgs: Union[Sequence[Message], Message],
300307
period: float,
301308
duration: Optional[float] = None,
309+
autostart: bool = True,
302310
modifier_callback: Optional[Callable[[Message], None]] = None,
303311
) -> can.broadcastmanager.CyclicSendTaskABC:
304312
"""Default implementation of periodic message sending using threading.
@@ -312,6 +320,10 @@ def _send_periodic_internal(
312320
:param duration:
313321
The duration between sending each message at the given rate. If
314322
no duration is provided, the task will continue indefinitely.
323+
:param autostart:
324+
If True (the default) the sending task will immediately start after creation.
325+
Otherwise, the task has to be started by calling the
326+
tasks :meth:`~can.RestartableCyclicTaskABC.start` method on it.
315327
:return:
316328
A started task instance. Note the task can be stopped (and
317329
depending on the backend modified) by calling the
@@ -328,6 +340,7 @@ def _send_periodic_internal(
328340
messages=msgs,
329341
period=period,
330342
duration=duration,
343+
autostart=autostart,
331344
modifier_callback=modifier_callback,
332345
)
333346
return task

can/interfaces/ixxat/canlib.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,11 @@ def _send_periodic_internal(
155155
msgs: Union[Sequence[Message], Message],
156156
period: float,
157157
duration: Optional[float] = None,
158+
autostart: bool = True,
158159
modifier_callback: Optional[Callable[[Message], None]] = None,
159160
) -> CyclicSendTaskABC:
160161
return self.bus._send_periodic_internal(
161-
msgs, period, duration, modifier_callback
162+
msgs, period, duration, autostart, modifier_callback
162163
)
163164

164165
def shutdown(self) -> None:

can/interfaces/ixxat/canlib_vcinpl.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,7 @@ def _send_periodic_internal(
793793
msgs: Union[Sequence[Message], Message],
794794
period: float,
795795
duration: Optional[float] = None,
796+
autostart: bool = True,
796797
modifier_callback: Optional[Callable[[Message], None]] = None,
797798
) -> CyclicSendTaskABC:
798799
"""Send a message using built-in cyclic transmit list functionality."""
@@ -807,7 +808,12 @@ def _send_periodic_internal(
807808
self._scheduler_resolution = caps.dwClockFreq / caps.dwCmsDivisor
808809
_canlib.canSchedulerActivate(self._scheduler, constants.TRUE)
809810
return CyclicSendTask(
810-
self._scheduler, msgs, period, duration, self._scheduler_resolution
811+
self._scheduler,
812+
msgs,
813+
period,
814+
duration,
815+
self._scheduler_resolution,
816+
autostart=autostart,
811817
)
812818

813819
# fallback to thread based cyclic task
@@ -821,6 +827,7 @@ def _send_periodic_internal(
821827
msgs=msgs,
822828
period=period,
823829
duration=duration,
830+
autostart=autostart,
824831
modifier_callback=modifier_callback,
825832
)
826833

@@ -863,7 +870,15 @@ def state(self) -> BusState:
863870
class CyclicSendTask(LimitedDurationCyclicSendTaskABC, RestartableCyclicTaskABC):
864871
"""A message in the cyclic transmit list."""
865872

866-
def __init__(self, scheduler, msgs, period, duration, resolution):
873+
def __init__(
874+
self,
875+
scheduler,
876+
msgs,
877+
period,
878+
duration,
879+
resolution,
880+
autostart: bool = True,
881+
):
867882
super().__init__(msgs, period, duration)
868883
if len(self.messages) != 1:
869884
raise ValueError(
@@ -883,7 +898,8 @@ def __init__(self, scheduler, msgs, period, duration, resolution):
883898
self._msg.uMsgInfo.Bits.dlc = self.messages[0].dlc
884899
for i, b in enumerate(self.messages[0].data):
885900
self._msg.abData[i] = b
886-
self.start()
901+
if autostart:
902+
self.start()
887903

888904
def start(self):
889905
"""Start transmitting message (add to list if needed)."""

can/interfaces/ixxat/canlib_vcinpl2.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,7 @@ def _send_periodic_internal(
937937
msgs: Union[Sequence[Message], Message],
938938
period: float,
939939
duration: Optional[float] = None,
940+
autostart: bool = True,
940941
modifier_callback: Optional[Callable[[Message], None]] = None,
941942
) -> CyclicSendTaskABC:
942943
"""Send a message using built-in cyclic transmit list functionality."""
@@ -953,7 +954,12 @@ def _send_periodic_internal(
953954
) # TODO: confirm
954955
_canlib.canSchedulerActivate(self._scheduler, constants.TRUE)
955956
return CyclicSendTask(
956-
self._scheduler, msgs, period, duration, self._scheduler_resolution
957+
self._scheduler,
958+
msgs,
959+
period,
960+
duration,
961+
self._scheduler_resolution,
962+
autostart=autostart,
957963
)
958964

959965
# fallback to thread based cyclic task
@@ -967,6 +973,7 @@ def _send_periodic_internal(
967973
msgs=msgs,
968974
period=period,
969975
duration=duration,
976+
autostart=autostart,
970977
modifier_callback=modifier_callback,
971978
)
972979

@@ -983,7 +990,15 @@ def shutdown(self):
983990
class CyclicSendTask(LimitedDurationCyclicSendTaskABC, RestartableCyclicTaskABC):
984991
"""A message in the cyclic transmit list."""
985992

986-
def __init__(self, scheduler, msgs, period, duration, resolution):
993+
def __init__(
994+
self,
995+
scheduler,
996+
msgs,
997+
period,
998+
duration,
999+
resolution,
1000+
autostart: bool = True,
1001+
):
9871002
super().__init__(msgs, period, duration)
9881003
if len(self.messages) != 1:
9891004
raise ValueError(
@@ -1003,7 +1018,8 @@ def __init__(self, scheduler, msgs, period, duration, resolution):
10031018
self._msg.uMsgInfo.Bits.dlc = self.messages[0].dlc
10041019
for i, b in enumerate(self.messages[0].data):
10051020
self._msg.abData[i] = b
1006-
self.start()
1021+
if autostart:
1022+
self.start()
10071023

10081024
def start(self):
10091025
"""Start transmitting message (add to list if needed)."""

can/interfaces/socketcan/socketcan.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ def __init__(
327327
messages: Union[Sequence[Message], Message],
328328
period: float,
329329
duration: Optional[float] = None,
330+
autostart: bool = True,
330331
) -> None:
331332
"""Construct and :meth:`~start` a task.
332333
@@ -349,10 +350,13 @@ def __init__(
349350

350351
self.bcm_socket = bcm_socket
351352
self.task_id = task_id
352-
self._tx_setup(self.messages)
353+
if autostart:
354+
self._tx_setup(self.messages)
353355

354356
def _tx_setup(
355-
self, messages: Sequence[Message], raise_if_task_exists: bool = True
357+
self,
358+
messages: Sequence[Message],
359+
raise_if_task_exists: bool = True,
356360
) -> None:
357361
# Create a low level packed frame to pass to the kernel
358362
body = bytearray()
@@ -813,6 +817,7 @@ def _send_periodic_internal(
813817
msgs: Union[Sequence[Message], Message],
814818
period: float,
815819
duration: Optional[float] = None,
820+
autostart: bool = True,
816821
modifier_callback: Optional[Callable[[Message], None]] = None,
817822
) -> can.broadcastmanager.CyclicSendTaskABC:
818823
"""Start sending messages at a given period on this bus.
@@ -823,13 +828,17 @@ def _send_periodic_internal(
823828
:class:`CyclicSendTask` within BCM provides flexibility to schedule
824829
CAN messages sending with the same CAN ID, but different CAN data.
825830
826-
:param messages:
831+
:param msgs:
827832
The message(s) to be sent periodically.
828833
:param period:
829834
The rate in seconds at which to send the messages.
830835
:param duration:
831836
Approximate duration in seconds to continue sending messages. If
832837
no duration is provided, the task will continue indefinitely.
838+
:param autostart:
839+
If True (the default) the sending task will immediately start after creation.
840+
Otherwise, the task has to be started by calling the
841+
tasks :meth:`~can.RestartableCyclicTaskABC.start` method on it.
833842
834843
:raises ValueError:
835844
If task identifier passed to :class:`CyclicSendTask` can't be used
@@ -854,7 +863,9 @@ def _send_periodic_internal(
854863
msgs_channel = str(msgs[0].channel) if msgs[0].channel else None
855864
bcm_socket = self._get_bcm_socket(msgs_channel or self.channel)
856865
task_id = self._get_next_task_id()
857-
task = CyclicSendTask(bcm_socket, task_id, msgs, period, duration)
866+
task = CyclicSendTask(
867+
bcm_socket, task_id, msgs, period, duration, autostart=autostart
868+
)
858869
return task
859870

860871
# fallback to thread based cyclic task
@@ -868,6 +879,7 @@ def _send_periodic_internal(
868879
msgs=msgs,
869880
period=period,
870881
duration=duration,
882+
autostart=autostart,
871883
modifier_callback=modifier_callback,
872884
)
873885

0 commit comments

Comments
 (0)