Helios panel: refresh about every 0.65 s, and yield the port to the operator

Three things were making the panel feel slow, all of them waiting rather
than working.

The trailing quiet window is waited out once per query, so it set the pace
of the whole sweep: at 50 ms that was 400 ms of a 590 ms poll spent
listening to silence. A reply streams at the baud rate — ~1 ms between
bytes, no measurable gap between its lines — and the deadline restarts on
every line read, so 20 ms outlasts the gap it exists for twenty times over.
A tail that still arrives late is caught by _discard_input(), which is what
actually protects the next query. Replayed against the rig transcript, a
sweep goes from 590 ms to 356 ms.

The poll interval was 1 s on top of that, so a value could be 1.6 s stale.
At 0.3 s the panel comes round about every 0.65 s.

And a poll held the port for its whole sweep, so a button pressed during
one waited for all eight queries. _work_pending() on the worker base lets a
poll drop what is left as soon as the operator queues something: a click
now waits ~135 ms for the register read in progress instead of the full
sweep, and the rest is picked up next time round.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Thomas Ales
2026-09-08 08:36:57 -05:00
parent 76ed7828cc
commit b473aac6aa
4 changed files with 86 additions and 4 deletions
+12
View File
@@ -44,6 +44,18 @@ class QueueWorker(QObject):
def stop_worker(self):
self._cmd_q.put(_STOP)
# ── Worker-side helpers ───────────────────────────────────────────────────
def _work_pending(self) -> bool:
"""True if the operator is waiting on something.
A poll is one queue item that can hold the port for hundreds of
milliseconds; a button pressed during one should not have to wait
for the whole sweep to finish. A poll that checks this between
reads gives the port up and picks the rest up next time round.
"""
return not self._cmd_q.empty()
# ── Worker loop ───────────────────────────────────────────────────────────
@pyqtSlot()