From 96c30dbd3a4f31a2748a2bc9c5e4758305be5ced Mon Sep 17 00:00:00 2001 From: x01dc Date: Thu, 29 Oct 2026 13:31:10 +0100 Subject: [PATCH] fix(panda): ignored trigger edges logged per line as info, not as a growing warning wait_lines_done warned after every line with the total of ignored edges since arm (20/10, 23/11, 26/13 ... in a 2026-10-29 scan), which read like an escalating trigger error. These edges are harmless (encoder noise at the PSO window entry while the line runs; lines and pulses are checked and raise on a mismatch), so only the edges new since the last line are logged, at info level. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv --- .../devices/panda_box/panda_line_trigger.py | 16 +++++++++---- .../tests_devices/test_panda_line_trigger.py | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/csaxs_bec/devices/panda_box/panda_line_trigger.py b/csaxs_bec/devices/panda_box/panda_line_trigger.py index 5cf85a09..6bd4a9e4 100644 --- a/csaxs_bec/devices/panda_box/panda_line_trigger.py +++ b/csaxs_bec/devices/panda_box/panda_line_trigger.py @@ -163,6 +163,7 @@ class PandaLineTrigger(Device): self.trigger_edge = trigger_edge self._pulse_params = None # parameters written to the PULSE blocks self._dropped_at_arm = 0 # DROPPED is only zeroed by ENABLE, which is never toggled + self._ignored_reported = 0 # ignored edges since arm() already logged self.device_manager = device_manager super().__init__(prefix, name=name, **kwargs) @@ -359,6 +360,7 @@ class PandaLineTrigger(Device): self.panda.set(f"{counter}.ENABLE", "ZERO") self.panda.set(f"{counter}.ENABLE", "ONE") self._dropped_at_arm = int(self.panda.get(f"{self.DETECTOR_PULSE}.DROPPED")) + self._ignored_reported = 0 self.panda.set(f"{gate}.FORCE_SET", "") def disarm(self) -> None: @@ -415,9 +417,15 @@ class PandaLineTrigger(Device): f"{self.name}: expected {n_lines} line(s) with {n_lines * n_pulses} pulses," f" got {status['lines']} with {status['pulses']}." ) - if status["triggers"] != status["lines"]: - logger.warning( - f"{self.name}: {status['triggers'] - status['lines']} trigger edge(s) ignored" - f" (edge while a line was running or while not armed): {status}." + # Ignored edges are harmless (lines and pulses are checked above): typically encoder + # noise at the PSO window entry, one extra edge per line while the line runs. Log only + # the new ones, as info, so a scan does not print a growing warning after each line. + ignored = status["triggers"] - status["lines"] + if ignored > self._ignored_reported: + logger.info( + f"{self.name}: {ignored - self._ignored_reported} trigger edge(s) ignored in" + f" line {n_lines} (edge while a line was running or while not armed)," + f" {ignored} since arm." ) + self._ignored_reported = ignored return status diff --git a/tests/tests_devices/test_panda_line_trigger.py b/tests/tests_devices/test_panda_line_trigger.py index 65edee41..95feadef 100644 --- a/tests/tests_devices/test_panda_line_trigger.py +++ b/tests/tests_devices/test_panda_line_trigger.py @@ -274,3 +274,26 @@ def test_user_access_names_not_protected_by_bec(device_cls): module, name = device_cls.rsplit(".", 1) cls = getattr(importlib.import_module(module), name) assert not set(cls.USER_ACCESS) & set(get_protected_class_methods()) + + +def test_ignored_edges_logged_once_per_line_as_info(trigger): + from unittest import mock + + from csaxs_bec.devices.panda_box import panda_line_trigger + + trigger.configure_line(5, exp_time=0.01) + trigger.arm() + with mock.patch.object(panda_line_trigger, "logger") as logger: + for n_lines in (1, 2): + trigger.soft_line_trigger() + trigger.panda.busy = True + trigger.soft_line_trigger() # entry noise during the line + trigger.panda.busy = False + trigger.wait_lines_done(n_lines, timeout=1) + trigger.soft_line_trigger() + trigger.wait_lines_done(3, timeout=1) # clean line: nothing logged + logger.warning.assert_not_called() + messages = [call.args[0] for call in logger.info.call_args_list] + assert len(messages) == 2 + assert "1 trigger edge(s) ignored in line 1" in messages[0] + assert "1 trigger edge(s) ignored in line 2" in messages[1] and "2 since arm" in messages[1]