From dbf7332302d31186c93f6de4cef55b2c3b36755f Mon Sep 17 00:00:00 2001 From: TJ Date: Tue, 26 Dec 2023 12:18:03 -0800 Subject: [PATCH 1/4] Add test case --- test/back2back_test.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/back2back_test.py b/test/back2back_test.py index cd5aca6aa..d5e6f6b89 100644 --- a/test/back2back_test.py +++ b/test/back2back_test.py @@ -273,6 +273,20 @@ def test_sub_second_timestamp_resolution(self): self.bus2.recv(0) self.bus2.recv(0) + def test_perodic_tasks_do_not_exceed_duration(self): + duration, period = 2.0, 0.6 + messages = [] + + self.bus2.send_periodic(can.Message(), period, duration) + while True: + msg = self.bus1.recv(period + 0.1) + if msg is None: + break + messages.append(msg) + + delta_t = messages[-1].timestamp - messages[0].timestamp + assert delta_t <= duration + @unittest.skipUnless(TEST_INTERFACE_SOCKETCAN, "skip testing of socketcan") class BasicTestSocketCan(Back2BackTestCase): From 8e3792b6375a07d83e5ee25d02091838db546a30 Mon Sep 17 00:00:00 2001 From: TJ Date: Tue, 26 Dec 2023 12:34:35 -0800 Subject: [PATCH 2/4] Fix bug --- can/broadcastmanager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/can/broadcastmanager.py b/can/broadcastmanager.py index 0ac9b6adc..7ef583801 100644 --- a/can/broadcastmanager.py +++ b/can/broadcastmanager.py @@ -297,6 +297,12 @@ def _run(self) -> None: win32event.WaitForSingleObject(self.event.handle, 0) while not self.stopped: + 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) + # Prevent calling bus.send from multiple threads with self.send_lock: try: @@ -316,12 +322,6 @@ def _run(self) -> None: self.stop() break - 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: win32event.WaitForSingleObject( self.event.handle, From 5d18b4a6c5b3f65d6d185733386aecaa87b04962 Mon Sep 17 00:00:00 2001 From: TJ Date: Wed, 27 Dec 2023 10:05:33 -0800 Subject: [PATCH 3/4] Improve unittest --- test/back2back_test.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/back2back_test.py b/test/back2back_test.py index d5e6f6b89..d9896c19f 100644 --- a/test/back2back_test.py +++ b/test/back2back_test.py @@ -273,19 +273,22 @@ def test_sub_second_timestamp_resolution(self): self.bus2.recv(0) self.bus2.recv(0) - def test_perodic_tasks_do_not_exceed_duration(self): - duration, period = 2.0, 0.6 - messages = [] - - self.bus2.send_periodic(can.Message(), period, duration) - while True: - msg = self.bus1.recv(period + 0.1) - if msg is None: - break - messages.append(msg) - - delta_t = messages[-1].timestamp - messages[0].timestamp - assert delta_t <= duration + 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") From 3e7b06e595f13753d8f706037357f0e2d17eb288 Mon Sep 17 00:00:00 2001 From: TJ Date: Tue, 2 Jan 2024 10:28:23 -0800 Subject: [PATCH 4/4] MR feedback --- can/broadcastmanager.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/can/broadcastmanager.py b/can/broadcastmanager.py index 7ef583801..a610b7a8a 100644 --- a/can/broadcastmanager.py +++ b/can/broadcastmanager.py @@ -297,11 +297,8 @@ def _run(self) -> None: win32event.WaitForSingleObject(self.event.handle, 0) while not self.stopped: - 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) # Prevent calling bus.send from multiple threads with self.send_lock: @@ -322,6 +319,11 @@ def _run(self) -> None: self.stop() break + if not USE_WINDOWS_EVENTS: + msg_due_time_ns += self.period_ns + + msg_index = (msg_index + 1) % len(self.messages) + if USE_WINDOWS_EVENTS: win32event.WaitForSingleObject( self.event.handle,