From b89010375459d0a905462a03724cae1c7a6a6da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 26 May 2026 10:18:58 +0200 Subject: [PATCH] emcy: Fix maximum timeout logic errors in EmcyConsumer.wait(). If an EMCY package was received, but filtered out by the emcy_code matching, the condition waiting is started again with the same timeout. Thus the actual maximum waiting time is not correctly limited to the given argument, as the docstring promises. Track the remaining time until the initial deadline instead, as basis for the condition wait. Further, spurious wake-ups from the condition wait on the OS level are not handled correctly. The threading.Condition docs explicitly recommend checking the shared state (number of logged entries in this case) in the while loop, because the wait() call may abort early. The current code assumes that this necessarily indicates a timeout, without checking the actually passed time again. Reorder the check against end_time in the loop to avoid this. --- canopen/emcy.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/canopen/emcy.py b/canopen/emcy.py index 6a860f07..f690fba3 100644 --- a/canopen/emcy.py +++ b/canopen/emcy.py @@ -69,16 +69,19 @@ def wait( while True: with self.emcy_received: prev_log_size = len(self.log) - self.emcy_received.wait(timeout) + remaining = end_time - time.time() + if remaining <= 0: + return None # Actual timeout reached + self.emcy_received.wait(remaining) if len(self.log) == prev_log_size: - # Resumed due to timeout - return None + if time.time() >= end_time: + # Resumed due to timeout + return None + else: + continue # Get last logged EMCY emcy = self.log[-1] logger.info("Got %s", emcy) - if time.time() > end_time: - # No valid EMCY received on time - return None if emcy_code is None or emcy.code == emcy_code: # This is the one we're interested in return emcy