summaryrefslogtreecommitdiff
path: root/core/signal_processor.py
diff options
context:
space:
mode:
Diffstat (limited to 'core/signal_processor.py')
-rw-r--r--core/signal_processor.py60
1 files changed, 32 insertions, 28 deletions
diff --git a/core/signal_processor.py b/core/signal_processor.py
index 4781e91..da615b6 100644
--- a/core/signal_processor.py
+++ b/core/signal_processor.py
@@ -230,7 +230,7 @@ def _make_src_names(sources: List[Tuple[str, str]],
# ══════════════════════════════════════════════════════════════════════════════
@dataclass
-class DerivedChannel:
+class Channel:
"""
A virtual channel computed from one or more physical channels.
@@ -393,7 +393,7 @@ class SignalProcessor(QObject):
def __init__(self):
super().__init__()
self._pipelines: Dict[Tuple[str, str], ChannelPipeline] = {}
- self._derived: List[DerivedChannel] = []
+ self._derived: List[Channel] = []
self._lock = threading.Lock()
# Latest raw values cache for derived evaluation
@@ -421,7 +421,7 @@ class SignalProcessor(QObject):
# ── Derived channel management ────────────────────────────────────────
- def add_derived(self, dc: DerivedChannel) -> Optional[str]:
+ def add_derived(self, dc: Channel) -> Optional[str]:
"""Add a derived channel. Returns compile error string or None."""
err = dc.compile()
if err:
@@ -437,36 +437,40 @@ class SignalProcessor(QObject):
self._derived = [d for d in self._derived if d.channel_id != channel_id]
self._derived_bufs.pop(channel_id, None)
- def rename_derived(self, old_id: str, new_id: str):
- """Propagate a Channel ID rename to every other derived channel's
- sources — otherwise anything chained from it keeps a dangling
- ("derived", old_id) reference (SignalProcessor._evaluate_derived
- looks sources up by exact match) and silently stops updating.
- Also carries the ring buffer and latest-value cache over under the
- new key so the rename doesn't reset plotted history or blank the
- Value column for a poll cycle. Does NOT touch source_names or
- expression/script text — those are display labels / user-authored
- code, out of scope for an automatic rewrite."""
- if old_id == new_id:
+ def rename_reference(self, old_ref: Tuple[str, str], new_ref: Tuple[str, str]):
+ """Propagate a (device_id, channel_id) reference rename to everything
+ this processor holds one of — otherwise anything reading it keeps a
+ dangling reference (_evaluate_derived/_process_one look sources and
+ pipelines up by exact match) and silently stops updating. Covers
+ both a physical Signal rename and a derived Channel rename with the
+ same code path — the renamed item's own identity (Channel.
+ channel_id, or a device's SignalConfig) is the caller's job; this
+ only fixes up *references to* old_ref held elsewhere.
+ Also carries the latest-value cache, and — when old_ref is itself a
+ derived Channel (device_id == "derived") — its ring buffer, over
+ under the new key so the rename doesn't reset plotted history or
+ blank the Value column for a poll cycle. Does NOT touch
+ source_names or expression/script text — those are display labels /
+ user-authored code, out of scope for an automatic rewrite."""
+ if old_ref == new_ref:
return
with self._lock:
+ if old_ref in self._pipelines:
+ self._pipelines[new_ref] = self._pipelines.pop(old_ref)
+
for dc in self._derived:
- if dc.channel_id == new_id:
- continue
- new_sources = [
- ("derived", new_id) if d == "derived" and c == old_id else (d, c)
- for d, c in dc.sources
- ]
+ new_sources = [new_ref if s == old_ref else s for s in dc.sources]
if new_sources != dc.sources:
dc.sources = new_sources
- buf = self._derived_bufs.pop(old_id, None)
- if buf is not None:
- self._derived_bufs[new_id] = buf
-
- entry = self._latest.pop(("derived", old_id), None)
+ entry = self._latest.pop(old_ref, None)
if entry is not None:
- self._latest[("derived", new_id)] = entry
+ self._latest[new_ref] = entry
+
+ if old_ref[0] == "derived":
+ buf = self._derived_bufs.pop(old_ref[1], None)
+ if buf is not None:
+ self._derived_bufs[new_ref[1]] = buf
def reorder_derived(self, src_idx: int, dst_idx: int):
"""Move the derived channel at src_idx to dst_idx — list order is
@@ -478,7 +482,7 @@ class SignalProcessor(QObject):
dc = self._derived.pop(src_idx)
self._derived.insert(dst_idx, dc)
- def get_derived(self) -> List[DerivedChannel]:
+ def get_derived(self) -> List[Channel]:
return list(self._derived)
def get_derived_buffer(self, channel_id: str):
@@ -575,7 +579,7 @@ class SignalProcessor(QObject):
self.derived_error.emit(dc.channel_id,
traceback.format_exc(limit=3))
- def _compute_derived(self, dc: DerivedChannel, inputs: List[float],
+ def _compute_derived(self, dc: Channel, inputs: List[float],
t: float, latest: dict) -> Optional[float]:
if dc.kind in ("expression", "function", "custom_script"):
if dc._fn is None: