fix(panda): ignored trigger edges logged per line as info, not as a growing warning
CI for csaxs_bec / test (push) Successful in 3m35s

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8zoDzDfsCTY2o5bT3J7Wv
This commit is contained in:
x01dcandClaude Opus 5.5 committed 2026-10-29 13:31:10 +01:00
1 parent 723d13d8cc
commit 96c30dbd3a
2 files changed
+35 -4

No files matched your search

@@ -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
@@ -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]