summaryrefslogtreecommitdiff
path: root/core/acquisition.py
diff options
context:
space:
mode:
authorChristian Kolset <christian.kolset@gmail.com>2026-09-21 00:16:15 -0600
committerChristian Kolset <christian.kolset@gmail.com>2026-09-21 00:16:15 -0600
commit4ab2eea9af5338485303d421476fa874e5af6841 (patch)
tree43aee9e91d25e854fd215a7c9ee7fdc003e1c854 /core/acquisition.py
parenta0473245f1f453bfc87ea1bc9bd479311e8a944b (diff)
Fix Buffer size setting never being applied; add Safety Switch control type
- Buffer size (samples) in Settings > Acquisition was captured into the settings dict but never read anywhere — SignalBuffer always used the hardcoded MAX_BUFFER=20_000 constant (which happens to match the dialog's default, hence it looking like the value "reverts"). Add AcquisitionEngine.set_buffer_size(), wired in on startup and on Settings apply; existing buffers are rebuilt at the new size in place, keeping their most recent samples. - New "Safety Switch" control type: an On/Off Switch that's disabled outright until acquisition is running, with a lock icon shown while disabled. AcquisitionEngine gains a run_state_changed(bool) signal (emitted from start()/stop()); ControlWidget gains a _check_safety_lock() hook (no-op by default, called uniformly by ControlPanel on every widget) that SafetySwitch overrides. engine is now threaded through to every ControlWidget for this. Persists via ControlSpec.control_type alone — no schema change needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'core/acquisition.py')
-rw-r--r--core/acquisition.py26
1 files changed, 24 insertions, 2 deletions
diff --git a/core/acquisition.py b/core/acquisition.py
index eeeb4c8..c900adf 100644
--- a/core/acquisition.py
+++ b/core/acquisition.py
@@ -77,6 +77,7 @@ class AcquisitionEngine(QObject):
# switched lb/kgF/N/ozF on its own front panel
log_started(filepath)
log_stopped(filepath)
+ run_state_changed(running) # emitted from start()/stop()
"""
new_data = pyqtSignal(float, list)
@@ -84,10 +85,14 @@ class AcquisitionEngine(QObject):
channel_unit_changed = pyqtSignal(str, str, str)
log_started = pyqtSignal(str)
log_stopped = pyqtSignal(str)
+ run_state_changed = pyqtSignal(bool) # True on start(), False on stop() —
+ # e.g. ControlPanel's safety-interlock
+ # controls listen for this
def __init__(self, poll_interval_ms: int = 100):
super().__init__()
self._interval = poll_interval_ms / 1000.0
+ self._buffer_size: int = MAX_BUFFER # see set_buffer_size()
self._devices: List[BaseDevice] = []
self._buffers: Dict[str, Dict[str, SignalBuffer]] = {}
self._last_units: Dict[Tuple[str, str], str] = {}
@@ -106,12 +111,27 @@ class AcquisitionEngine(QObject):
def add_device(self, dev: BaseDevice):
self._devices.append(dev)
self._buffers[dev.info.device_id] = {
- ch.signal_id: SignalBuffer()
+ ch.signal_id: SignalBuffer(maxlen=self._buffer_size)
for ch in dev.info.signals
}
for ch in dev.info.signals:
self._last_units[(dev.info.device_id, ch.signal_id)] = ch.unit
+ def set_buffer_size(self, n: int):
+ """Change how much history each Signal's buffer holds — settings_
+ window.py's "Buffer size (samples)" field, applied live rather than
+ only on the next device add/reconfigure. Rebuilds every existing
+ buffer at the new size, keeping its most recent samples (a maxlen
+ deque naturally drops the oldest first as it's extended past
+ capacity, so growing loses nothing and shrinking keeps the tail)."""
+ self._buffer_size = n
+ for dev_bufs in self._buffers.values():
+ for ch_id, buf in list(dev_bufs.items()):
+ new_buf = SignalBuffer(maxlen=n)
+ new_buf.times.extend(buf.times)
+ new_buf.values.extend(buf.values)
+ dev_bufs[ch_id] = new_buf
+
def on_device_reconfigured(self, device_id: str):
"""Reconcile buffers with a device's current channel list — reconfigure()
can add/remove channels (e.g. Signals count changed), and buffers keyed
@@ -125,7 +145,7 @@ class AcquisitionEngine(QObject):
bufs.pop(stale_id, None)
for ch in dev.info.signals:
if ch.signal_id not in bufs:
- bufs[ch.signal_id] = SignalBuffer()
+ bufs[ch.signal_id] = SignalBuffer(maxlen=self._buffer_size)
self._last_units[(device_id, ch.signal_id)] = ch.unit
for key in [k for k in self._last_units if k[0] == device_id and k[1] not in valid_ids]:
self._last_units.pop(key, None)
@@ -176,12 +196,14 @@ class AcquisitionEngine(QObject):
self._running = True
self._thread = threading.Thread(target=self._loop, daemon=True, name="DAQ-Acq")
self._thread.start()
+ self.run_state_changed.emit(True)
def stop(self):
self._running = False
if self._thread:
self._thread.join(timeout=3.0)
self.stop_logging()
+ self.run_state_changed.emit(False)
# ── Logging ──────────────────────────────────────────────────────────