diff --git a/can/broadcastmanager.py b/can/broadcastmanager.py index 0ac9b6adc..a610b7a8a 100644 --- a/can/broadcastmanager.py +++ b/can/broadcastmanager.py @@ -297,6 +297,9 @@ def _run(self) -> None: win32event.WaitForSingleObject(self.event.handle, 0) while not self.stopped: + if self.end_time is not None and time.perf_counter() >= self.end_time: + break + # Prevent calling bus.send from multiple threads with self.send_lock: try: @@ -318,8 +321,7 @@ def _run(self) -> None: if not USE_WINDOWS_EVENTS: msg_due_time_ns += self.period_ns - if self.end_time is not None and time.perf_counter() >= self.end_time: - break + msg_index = (msg_index + 1) % len(self.messages) if USE_WINDOWS_EVENTS: diff --git a/test/back2back_test.py b/test/back2back_test.py index cd5aca6aa..d9896c19f 100644 --- a/test/back2back_test.py +++ b/test/back2back_test.py @@ -273,6 +273,23 @@ def test_sub_second_timestamp_resolution(self): self.bus2.recv(0) self.bus2.recv(0) + def test_send_periodic_duration(self): + """ + Verify that send_periodic only transmits for the specified duration. + + Regression test for #1713. + """ + for params in [(0.01, 0.003), (0.1, 0.011), (1, 0.4)]: + duration, period = params + messages = [] + + self.bus2.send_periodic(can.Message(), period, duration) + while (msg := self.bus1.recv(period * 1.25)) is not None: + messages.append(msg) + + delta_t = round(messages[-1].timestamp - messages[0].timestamp, 2) + assert delta_t <= duration + @unittest.skipUnless(TEST_INTERFACE_SOCKETCAN, "skip testing of socketcan") class BasicTestSocketCan(Back2BackTestCase):