fix(panda): rename software_trigger to soft_line_trigger
CI for csaxs_bec / test (push) Successful in 3m34s

software_trigger is a DeviceBase name in BEC, so the device server refused to
load pandatrig ("User access method name {'software_trigger'} is protected").
New test: USER_ACCESS of the PandA and A3200 devices has no protected names.

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 12:50:36 +01:00
1 parent 58636421ad
commit e79314c77f
3 files changed
+30 -11

No files matched your search

+1 -1
View File
@@ -179,7 +179,7 @@ the wiring at connect.
```python
dev.pandatrig.configure_line(n_pulses=100, exp_time=0.01, readout_time=0.002, shutter_delay=0.005)
dev.pandatrig.arm() # arm(one_shot=True): only the next edge
dev.pandatrig.software_trigger() # or the PSO edges on TTLIN3, one per line
dev.pandatrig.soft_line_trigger() # or the PSO edges on TTLIN3, one per line
dev.pandatrig.wait_lines_done(n_lines=1, timeout=5)
dev.pandatrig.line_status() # triggers, lines, pulses, dropped since arm()
```
@@ -120,7 +120,7 @@ class PandaLineTrigger(Device):
"configure_line",
"arm",
"disarm",
"software_trigger",
"soft_line_trigger",
"line_status",
"wait_lines_done",
"get_readout_time",
@@ -366,7 +366,7 @@ class PandaLineTrigger(Device):
self.panda.set(f"{self.ARM_GATE}.FORCE_RST", "")
self.panda.set(self.SOFT_TRIGGER_BIT, "0")
def software_trigger(self) -> None:
def soft_line_trigger(self) -> None:
"""Line trigger edge from software (accepted like a TTLIN3 edge)."""
self.panda.set(self.SOFT_TRIGGER_BIT, "1")
self.panda.set(self.SOFT_TRIGGER_BIT, "0")
+27 -8
View File
@@ -98,7 +98,7 @@ def test_never_toggles_pulse_enable_after_setup(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.panda.writes.clear()
trigger.arm()
trigger.software_trigger()
trigger.soft_line_trigger()
trigger.wait_lines_done(1, timeout=1)
trigger.disarm()
trigger.stop()
@@ -109,7 +109,7 @@ def test_stays_armed_for_many_lines(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.arm()
for _ in range(4):
trigger.software_trigger()
trigger.soft_line_trigger()
status = trigger.wait_lines_done(4, timeout=1)
assert (status["lines"], status["pulses"], status["armed"]) == (4, 20, True)
@@ -117,9 +117,9 @@ def test_stays_armed_for_many_lines(trigger):
def test_one_shot_accepts_one_edge(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.arm(one_shot=True)
trigger.software_trigger()
trigger.soft_line_trigger()
assert trigger.wait_lines_done(1, timeout=1)["armed"] is False
trigger.software_trigger()
trigger.soft_line_trigger()
status = trigger.wait_lines_done(1, timeout=1)
assert status["triggers"] == 2 and status["lines"] == 1
@@ -127,9 +127,9 @@ def test_one_shot_accepts_one_edge(trigger):
def test_edge_during_line_is_ignored(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.arm()
trigger.software_trigger()
trigger.soft_line_trigger()
trigger.panda.busy = True
trigger.software_trigger()
trigger.soft_line_trigger()
trigger.panda.busy = False
status = trigger.wait_lines_done(1, timeout=1)
assert status["triggers"] == 2 and status["lines"] == 1 and status["pulses"] == 5
@@ -151,7 +151,7 @@ def test_wait_lines_done_reports_too_many_lines(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.arm()
for _ in range(3):
trigger.software_trigger()
trigger.soft_line_trigger()
with pytest.raises(PandaLineTriggerError, match="expected 2 line"):
trigger.wait_lines_done(2, timeout=0.1, poll=0.01)
@@ -195,7 +195,7 @@ def test_disarm_closes_the_gate(trigger):
trigger.configure_line(5, exp_time=0.01)
trigger.arm()
trigger.disarm()
trigger.software_trigger()
trigger.soft_line_trigger()
status = trigger.line_status()
assert (status["armed"], status["lines"], status["pulses"]) == (False, 0, 0)
@@ -255,3 +255,22 @@ def test_unchanged_fields_are_not_written(trigger):
again.configure_line(5, 0.01, 0.002)
values = [w for w in again.panda.writes if not w.split("=", 1)[1] == ""]
assert values == []
@pytest.mark.parametrize(
"device_cls",
[
"csaxs_bec.devices.panda_box.panda_line_trigger.PandaLineTrigger",
"csaxs_bec.devices.aerotech.a3200.A3200Motor",
"csaxs_bec.devices.aerotech.a3200.A3200PositionCapture",
],
)
def test_user_access_names_not_protected_by_bec(device_cls):
# the device server refuses to load a device whose USER_ACCESS shadows a DeviceBase name
import importlib
from bec_server.device_server.devices.device_serializer import get_protected_class_methods
module, name = device_cls.rsplit(".", 1)
cls = getattr(importlib.import_module(module), name)
assert not set(cls.USER_ACCESS) & set(get_protected_class_methods())