Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autostart option to BusABC.send_periodic() to fix issue #1848 #1853

Merged
merged 13 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion can/broadcastmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ def __init__(
period: float,
duration: Optional[float] = None,
on_error: Optional[Callable[[Exception], bool]] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> None:
"""Transmits `messages` with a `period` seconds for `duration` seconds on a `bus`.
Expand Down Expand Up @@ -324,7 +325,8 @@ def __init__(
stacklevel=1,
)

self.start()
if autostart:
self.start()

def stop(self) -> None:
self.stopped = True
Expand Down
13 changes: 12 additions & 1 deletion can/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def send_periodic(
period: float,
duration: Optional[float] = None,
store_task: bool = True,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> can.broadcastmanager.CyclicSendTaskABC:
"""Start sending messages at a given period on this bus.
Expand All @@ -237,6 +238,9 @@ def send_periodic(
:param store_task:
If True (the default) the task will be attached to this Bus instance.
Disable to instead manage tasks manually.
:param autostart:
If True (the default) the sending task will immediately start after creation.
Otherwise, the task has to be started by calling start() on it.
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved
:param modifier_callback:
Function which should be used to modify each message's data before
sending. The callback modifies the :attr:`~can.Message.data` of the
Expand Down Expand Up @@ -272,7 +276,9 @@ def send_periodic(
# Create a backend specific task; will be patched to a _SelfRemovingCyclicTask later
task = cast(
_SelfRemovingCyclicTask,
self._send_periodic_internal(msgs, period, duration, modifier_callback),
self._send_periodic_internal(
msgs, period, duration, autostart, modifier_callback
),
)
# we wrap the task's stop method to also remove it from the Bus's list of tasks
periodic_tasks = self._periodic_tasks
Expand All @@ -299,6 +305,7 @@ def _send_periodic_internal(
msgs: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> can.broadcastmanager.CyclicSendTaskABC:
"""Default implementation of periodic message sending using threading.
Expand All @@ -312,6 +319,9 @@ def _send_periodic_internal(
:param duration:
The duration between sending each message at the given rate. If
no duration is provided, the task will continue indefinitely.
:param autostart:
If True (the default) the sending task will immediately start after creation.
Otherwise, the task has to be started by calling start() on it.
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved
:return:
A started task instance. Note the task can be stopped (and
depending on the backend modified) by calling the
Expand All @@ -328,6 +338,7 @@ def _send_periodic_internal(
messages=msgs,
period=period,
duration=duration,
autostart=autostart,
modifier_callback=modifier_callback,
)
return task
Expand Down
3 changes: 2 additions & 1 deletion can/interfaces/ixxat/canlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ def _send_periodic_internal(
msgs: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> CyclicSendTaskABC:
return self.bus._send_periodic_internal(
msgs, period, duration, modifier_callback
msgs, period, duration, autostart, modifier_callback
)

def shutdown(self) -> None:
Expand Down
22 changes: 19 additions & 3 deletions can/interfaces/ixxat/canlib_vcinpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ def _send_periodic_internal(
msgs: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> CyclicSendTaskABC:
"""Send a message using built-in cyclic transmit list functionality."""
Expand All @@ -807,7 +808,12 @@ def _send_periodic_internal(
self._scheduler_resolution = caps.dwClockFreq / caps.dwCmsDivisor
_canlib.canSchedulerActivate(self._scheduler, constants.TRUE)
return CyclicSendTask(
self._scheduler, msgs, period, duration, self._scheduler_resolution
self._scheduler,
msgs,
period,
duration,
self._scheduler_resolution,
autostart=autostart,
)

# fallback to thread based cyclic task
Expand All @@ -821,6 +827,7 @@ def _send_periodic_internal(
msgs=msgs,
period=period,
duration=duration,
autostart=autostart,
modifier_callback=modifier_callback,
)

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

def __init__(self, scheduler, msgs, period, duration, resolution):
def __init__(
self,
scheduler,
msgs,
period,
duration,
resolution,
autostart: bool = True,
):
super().__init__(msgs, period, duration)
if len(self.messages) != 1:
raise ValueError(
Expand All @@ -883,7 +898,8 @@ def __init__(self, scheduler, msgs, period, duration, resolution):
self._msg.uMsgInfo.Bits.dlc = self.messages[0].dlc
for i, b in enumerate(self.messages[0].data):
self._msg.abData[i] = b
self.start()
if autostart:
self.start()

def start(self):
"""Start transmitting message (add to list if needed)."""
Expand Down
22 changes: 19 additions & 3 deletions can/interfaces/ixxat/canlib_vcinpl2.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ def _send_periodic_internal(
msgs: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> CyclicSendTaskABC:
"""Send a message using built-in cyclic transmit list functionality."""
Expand All @@ -953,7 +954,12 @@ def _send_periodic_internal(
) # TODO: confirm
_canlib.canSchedulerActivate(self._scheduler, constants.TRUE)
return CyclicSendTask(
self._scheduler, msgs, period, duration, self._scheduler_resolution
self._scheduler,
msgs,
period,
duration,
self._scheduler_resolution,
autostart=autostart,
)

# fallback to thread based cyclic task
Expand All @@ -967,6 +973,7 @@ def _send_periodic_internal(
msgs=msgs,
period=period,
duration=duration,
autostart=autostart,
modifier_callback=modifier_callback,
)

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

def __init__(self, scheduler, msgs, period, duration, resolution):
def __init__(
self,
scheduler,
msgs,
period,
duration,
resolution,
autostart: bool = True,
):
super().__init__(msgs, period, duration)
if len(self.messages) != 1:
raise ValueError(
Expand All @@ -1003,7 +1018,8 @@ def __init__(self, scheduler, msgs, period, duration, resolution):
self._msg.uMsgInfo.Bits.dlc = self.messages[0].dlc
for i, b in enumerate(self.messages[0].data):
self._msg.abData[i] = b
self.start()
if autostart:
self.start()

def start(self):
"""Start transmitting message (add to list if needed)."""
Expand Down
23 changes: 18 additions & 5 deletions can/interfaces/socketcan/socketcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ def __init__(
messages: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
) -> None:
"""Construct and :meth:`~start` a task.

Expand All @@ -349,10 +350,13 @@ def __init__(

self.bcm_socket = bcm_socket
self.task_id = task_id
self._tx_setup(self.messages)
self._tx_setup(self.messages, send=autostart)

def _tx_setup(
self, messages: Sequence[Message], raise_if_task_exists: bool = True
self,
messages: Sequence[Message],
raise_if_task_exists: bool = True,
send: bool = True,
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
# Create a low level packed frame to pass to the kernel
body = bytearray()
Expand All @@ -376,7 +380,9 @@ def _tx_setup(
for message in messages:
body += build_can_frame(message)
log.debug("Sending BCM command")
send_bcm(self.bcm_socket, header + body)

if send:
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved
send_bcm(self.bcm_socket, header + body)

def _check_bcm_task(self) -> None:
# Do a TX_READ on a task ID, and check if we get EINVAL. If so,
Expand Down Expand Up @@ -813,6 +819,7 @@ def _send_periodic_internal(
msgs: Union[Sequence[Message], Message],
period: float,
duration: Optional[float] = None,
autostart: bool = True,
modifier_callback: Optional[Callable[[Message], None]] = None,
) -> can.broadcastmanager.CyclicSendTaskABC:
"""Start sending messages at a given period on this bus.
Expand All @@ -823,13 +830,16 @@ def _send_periodic_internal(
:class:`CyclicSendTask` within BCM provides flexibility to schedule
CAN messages sending with the same CAN ID, but different CAN data.

:param messages:
:param msgs:
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved
The message(s) to be sent periodically.
:param period:
The rate in seconds at which to send the messages.
:param duration:
Approximate duration in seconds to continue sending messages. If
no duration is provided, the task will continue indefinitely.
:param autostart:
If True (the default) the sending task will immediately start after creation.
Otherwise, the task has to be started by calling start() on it.
SWolfSchunk marked this conversation as resolved.
Show resolved Hide resolved

:raises ValueError:
If task identifier passed to :class:`CyclicSendTask` can't be used
Expand All @@ -854,7 +864,9 @@ def _send_periodic_internal(
msgs_channel = str(msgs[0].channel) if msgs[0].channel else None
bcm_socket = self._get_bcm_socket(msgs_channel or self.channel)
task_id = self._get_next_task_id()
task = CyclicSendTask(bcm_socket, task_id, msgs, period, duration)
task = CyclicSendTask(
bcm_socket, task_id, msgs, period, duration, autostart=autostart
)
return task

# fallback to thread based cyclic task
Expand All @@ -868,6 +880,7 @@ def _send_periodic_internal(
msgs=msgs,
period=period,
duration=duration,
autostart=autostart,
modifier_callback=modifier_callback,
)

Expand Down
Loading