diff options
| author | Christian Kolset <christian.kolset@gmail.com> | 2026-09-19 17:38:07 -0600 |
|---|---|---|
| committer | Christian Kolset <christian.kolset@gmail.com> | 2026-09-19 17:38:07 -0600 |
| commit | f3327d56d48d63b21ffc03a55fa5e7db753d1707 (patch) | |
| tree | e19d4c7846dd4a434f8a18f82290597731b4a12c /core/acquisition.py | |
| parent | 00671a90bb51bfe485d98a928a456d55adbe1faf (diff) | |
Redesign Signal/Channel naming and fix pin-remap breaking references
Arduino analog Signal ids used to be the pin name itself, so fixing a
wrong pin silently changed the id and orphaned any plot trace, control,
or filter pipeline pointing at it. Analog Signal ids are now positional
(ai0, ai1, ...) and decoupled from the underlying pin, matching how
digital I/O already worked.
More broadly, formalizes a Device -> Signal -> Channel -> Plot naming
model (SignalConfig for physical device channels, Channel for derived/
computed ones) and adds core/reference_registry.py to propagate any
Signal or Channel id rename through plot traces, controls, and filter
pipelines instead of leaving them dangling. Signal ids are now editable
in the Signals tab with the same propagation.
.labui profile schema bumped to v2.0 with a transparent migration for
old files, including remapping old pin-name Signal ids to the new
positional ones. Removed six confirmed-dead files (two legacy device
classes, four superseded top-level ui/ duplicates).
Diffstat (limited to 'core/acquisition.py')
| -rw-r--r-- | core/acquisition.py | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/core/acquisition.py b/core/acquisition.py index f54f265..eeeb4c8 100644 --- a/core/acquisition.py +++ b/core/acquisition.py @@ -21,7 +21,7 @@ from devices.base_device import BaseDevice, DeviceStatus MAX_BUFFER = 20_000 -class ChannelBuffer: +class SignalBuffer: """Circular time-series buffer for one channel.""" def __init__(self, maxlen: int = MAX_BUFFER): @@ -70,10 +70,10 @@ class AcquisitionEngine(QObject): Signals ------- - new_data(timestamp, readings) # readings: list[(device_id, channel_id, value)] — + new_data(timestamp, readings) # readings: list[(device_id, signal_id, value)] — # one batched emit per poll tick, not one per channel device_status_changed(device_id, status_str) - channel_unit_changed(device_id, channel_id, new_unit) # e.g. Mark-10 gauge + channel_unit_changed(device_id, signal_id, new_unit) # e.g. Mark-10 gauge # switched lb/kgF/N/ozF on its own front panel log_started(filepath) log_stopped(filepath) @@ -89,7 +89,7 @@ class AcquisitionEngine(QObject): super().__init__() self._interval = poll_interval_ms / 1000.0 self._devices: List[BaseDevice] = [] - self._buffers: Dict[str, Dict[str, ChannelBuffer]] = {} + self._buffers: Dict[str, Dict[str, SignalBuffer]] = {} self._last_units: Dict[Tuple[str, str], str] = {} self._last_status: Dict[str, str] = {} self._running = False @@ -106,11 +106,11 @@ class AcquisitionEngine(QObject): def add_device(self, dev: BaseDevice): self._devices.append(dev) self._buffers[dev.info.device_id] = { - ch.channel_id: ChannelBuffer() - for ch in dev.info.channels + ch.signal_id: SignalBuffer() + for ch in dev.info.signals } - for ch in dev.info.channels: - self._last_units[(dev.info.device_id, ch.channel_id)] = ch.unit + for ch in dev.info.signals: + self._last_units[(dev.info.device_id, ch.signal_id)] = ch.unit def on_device_reconfigured(self, device_id: str): """Reconcile buffers with a device's current channel list — reconfigure() @@ -120,13 +120,13 @@ class AcquisitionEngine(QObject): if dev is None: return bufs = self._buffers.setdefault(device_id, {}) - valid_ids = {ch.channel_id for ch in dev.info.channels} + valid_ids = {ch.signal_id for ch in dev.info.signals} for stale_id in [cid for cid in bufs if cid not in valid_ids]: bufs.pop(stale_id, None) - for ch in dev.info.channels: - if ch.channel_id not in bufs: - bufs[ch.channel_id] = ChannelBuffer() - self._last_units[(device_id, ch.channel_id)] = ch.unit + for ch in dev.info.signals: + if ch.signal_id not in bufs: + bufs[ch.signal_id] = SignalBuffer() + 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) @@ -137,8 +137,22 @@ class AcquisitionEngine(QObject): for key in [k for k in self._last_units if k[0] == device_id]: self._last_units.pop(key, None) - def get_buffer(self, device_id: str, channel_id: str) -> Optional[ChannelBuffer]: - return self._buffers.get(device_id, {}).get(channel_id) + def get_signal_buffer(self, device_id: str, signal_id: str) -> Optional[SignalBuffer]: + return self._buffers.get(device_id, {}).get(signal_id) + + def rename_channel(self, device_id: str, old_id: str, new_id: str) -> None: + """Move a channel's buffer/unit-cache entry to a new id after a rename + — mirrors on_device_reconfigured's bookkeeping but for a single + in-place rename rather than a full channel-list diff, so history is + carried over instead of dropped.""" + if old_id == new_id: + return + bufs = self._buffers.get(device_id) + if bufs and old_id in bufs: + bufs[new_id] = bufs.pop(old_id) + key = (device_id, old_id) + if key in self._last_units: + self._last_units[(device_id, new_id)] = self._last_units.pop(key) def clear_history(self): for ch_map in self._buffers.values(): @@ -181,8 +195,8 @@ class AcquisitionEngine(QObject): self._csv_file = open(filepath, "w", newline="") headers = ["elapsed_s"] for dev in self._devices: - for ch in dev.info.channels: - headers.append(f"{dev.info.device_id}/{ch.channel_id}[{ch.unit}]") + for ch in dev.info.signals: + headers.append(f"{dev.info.device_id}/{ch.signal_id}[{ch.unit}]") self._csv_writer = csv.writer(self._csv_file) self._csv_writer.writerow(headers) self._logging = True @@ -225,21 +239,21 @@ class AcquisitionEngine(QObject): print(f"[Acq] {dev.info.device_id} read error: {e}") readings = {} - for ch in dev.info.channels: - key = (dev.info.device_id, ch.channel_id) + for ch in dev.info.signals: + key = (dev.info.device_id, ch.signal_id) if self._last_units.get(key) != ch.unit: self._last_units[key] = ch.unit - self.channel_unit_changed.emit(dev.info.device_id, ch.channel_id, ch.unit) + self.channel_unit_changed.emit(dev.info.device_id, ch.signal_id, ch.unit) - val = readings.get(ch.channel_id) + val = readings.get(ch.signal_id) if val is None or not ch.enabled: log_row.append("") continue fval = float(val) - buf = self._buffers.get(dev.info.device_id, {}).get(ch.channel_id) + buf = self._buffers.get(dev.info.device_id, {}).get(ch.signal_id) if buf is not None: buf.append(elapsed, fval) - batch.append((dev.info.device_id, ch.channel_id, fval)) + batch.append((dev.info.device_id, ch.signal_id, fval)) log_row.append(f"{fval:.5f}") if batch: |
