Skip to content

feat(console): Analog In panel — live 10 Hz readout, strip chart, AO→AI loopback sweep (S1) — Studio v0.74 - #190

Merged
mbreiser merged 3 commits into
mainfrom
feat/console-analog-in
Sep 10, 2026
Merged

feat(console): Analog In panel — live 10 Hz readout, strip chart, AO→AI loopback sweep (S1) — Studio v0.74#190
mbreiser merged 3 commits into
mainfrom
feat/console-analog-in

Conversation

@mbreiser

@mbreiser mbreiser commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Studio half S1 of docs/development/analog-input-plan.md § 4 (plan PR #189; decisions 2026-09-07). Pairs with firmware F1 (reiserlab/LED-Display_G6_Firmware_Arena#46) but works against today's io_ext firmware too — the F1 flags byte is optional on the wire.

What changed (Studio v0.74)

New Console tool: "Analog In" (left-rail button + panel)

  • Live readout of both "Analog In (±10V)" BNCs: value, ±10 V bar with a centre mark, min/max since reset, and a 30 s strip chart (green = AI1, blue = AI2). Rate 10 / 5 / 2 Hz, Live/Paused toggle, Reset.
  • The poller never floods the log. It reads GET_ANALOG_IN via session.send directly (not the logging send()), is single-flight (a tick is skipped while a read is on the wire), and pauses itself with a visible reason whenever the gate says no: panel closed, not connected, no io_ext firmware, user pause, a run in progress, or a sweep in flight. Only state transitions are logged; it parks after 5 consecutive read errors with a resume hint.
  • AO → AI loopback self-test: cable "Analog Out (0-5V)" to an input, pick the input and step size, Run sweep → steps 0→5000 mV, three reads (median) per step, least-squares slope/offset, per-step error table, verdict ok (slope within 5 %, max error ≤ 150 mV) / check / fail, Copy CSV, and the previous AO level is restored. A flat reading near +10 V at every step is called out as the LAB-209 un-reworked-board signature. The sweep is also written to the bridge run log (analog_loopback_sweep).
  • The panel's status line shows what the controller reports about its reads (12-bit / calibration state from the F1 flags byte; "10-bit (pre-F1 fw)" otherwise).

Elsewhere

  • js/arena-wire-g6.js decodeAnalogIn returns {flags, cal1, cal2, bits12} (null/false on 4-byte replies).
  • Arena Trial gain tooltip states the G3-faithful scale: ×10, so 10 = unity = 100 frames/s per volt; 2–5 = 20–50 fps/V; negative reverses.
  • The I/O panel's one-shot Read appends the flags text.
  • HELP-map entries for the rail button and panel; release notes v0.74; CLAUDE.md Console convention (periodic reads bypass send(), reuse StudioAnalogIn.createPoller).

Code

  • js/studio-analog-in.js (new, classic dual-export, DOM-free): createMonitor, createPoller, sweepPlan, fitLinear, summarizeSweep, sweepCsv, describeFlags, median, barFraction, formatMv, drawStripChart.
  • arena_studio.html: rail button, panel section, CSS, poller/sweep wiring before the handler table, four data-cmd handlers (caipoll, caireset, caisweep, caisweepcsv).

Tests

  • tests/test-studio-analog-in.js (new, in pixi run test): 105 checks — monitor (window trim, min/max persistence, rate, cap), poller (single-flight skip, gate pause reported once, error streak → park → resume, gate reopen forgives errors, injected timers start/restart/stop), sweep math (exact fit, NaN rows, saturation → fail, 10 % slope → check, channel 2, CSV), wire flags decode, and HTML wiring (script order, rail, every panel id, every handler, quiet read, run gate, io_ext gate, HELP entries, gain tooltip, footer, AO restore).
  • tests/test-arena-wire-g6.js: flags decode cases (183 → 186).
  • Full pixi run test passes; touched JS Prettier-clean; all inline Studio script blocks parse.
  • Browser-verified offline (no controller): no console errors, module loads, the rail button opens the panel, the poller status goes "panel closed" → "connect to read" and issues no reads while disconnected.
  • Not bench-tested (no hardware for a few days): live values, rate, the sweep against a real board — plan § 5.4 / T6.

🤖 Generated with Claude Code

mbreiser and others added 3 commits September 10, 2026 12:51
…rt, AO→AI loopback sweep; 0xA4 flags decode; G3 gain tooltip (S1) — Studio v0.74

Studio half S1 of docs/development/analog-input-plan.md § 4 (decisions
2026-09-07). Works against today's io_ext firmware and reads the F1 flags byte
when present.

- js/studio-analog-in.js (new; classic dual-export, DOM-free): createMonitor
  (windowed ring buffer, min/max, rate), createPoller (single-flight ticker
  gated on panel-open / connected / io_ext / user pause / session.running /
  sweep; reports state CHANGES only, parks after N consecutive read errors),
  sweepPlan / fitLinear / summarizeSweep / sweepCsv (AO 0→5000 mV loopback
  self-test with ok/check/fail verdict — a flat +10 V reading is the LAB-209
  un-reworked-board signature), describeFlags (0xA4 flags byte), drawStripChart.
- arena_studio.html: left-rail "Analog In" button + panel (values, ±10 V bars,
  min/max, 30 s canvas trace, rate 10/5/2 Hz, Live/Paused, Reset, loopback
  sweep with table + Copy CSV). The poller reads via session.send directly —
  NOT the logging send() — so the Console log is not flooded at 10 Hz; state
  transitions and the sweep are logged; the sweep is also logged to the bridge
  run log (event analog_loopback_sweep) and restores the previous AO level.
  I/O panel's one-shot Read shows the flags text. Trial-panel gain tooltip now
  states the G3-faithful scale (×10; 10 = 100 fps/V; 2–5 = 20–50 fps/V).
  HELP-map entries; footer v0.74.
- js/arena-wire-g6.js: decodeAnalogIn returns {flags, cal1, cal2, bits12}
  (null/false on 4-byte pre-F1 replies); wire tests extended.
- tests/test-studio-analog-in.js (new, in pixi run test): 105 checks — monitor,
  single-flight poller with injected timers, sweep math incl. saturation and
  10 % slope verdicts, wire flags, and the HTML wiring (script order, rail,
  panel ids, handlers, quiet read, run gate, io_ext gate, HELP, tooltip, footer).
- Release notes v0.74; CLAUDE.md Console convention: periodic reads bypass
  send() and reuse StudioAnalogIn.createPoller.

Not bench-tested (no hardware); browser-verified offline: panel renders, poller
shows the gate reason and issues no reads while disconnected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…VOLTAGE; pause the poller during the Console's FicTrac closed loop

Codex cross-review 2026-09-09. The Console send() helper returns the reply
frame even when the firmware answers a non-ok status (it logs the reason), so
the sweep's truthiness check only caught transport failures: with Analog Out in
frame_number mode every 0xA0 step is refused and the sweep would have recorded
AI readings against levels that were never applied. Decode the status, abort
with a hint naming the AO mode; report a refused/unknown restore too.

The live poller gated on session.running (runner trials) but not on the
Console's own FicTrac closed loop (bridge 'apply'), which streams 0x70 at
~100 Hz outside the runner — yield the link to it as well.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A perfectly linear channel reading AO + 1 V passed as 'ok' because the verdict
looked only at slope and scatter; for a loopback self-test the offset is the
diagnostic. Now ok = slope ±5 % AND |offset| ≤ 150 mV AND max |err| ≤ 150 mV;
'check' still means slope within ±15 %. Test added (Codex review item 4).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mbreiser
mbreiser force-pushed the feat/console-analog-in branch from 9312b56 to b3dfb8a Compare September 10, 2026 16:55
@mbreiser
mbreiser merged commit 880ffd5 into main Sep 10, 2026
3 checks passed
mbreiser added a commit that referenced this pull request Sep 10, 2026
…(fw #48), first reworked-board analog results

Merge plan: B1 rows ticked with the rig05-mr run (#188 merged f744e12, #186 closed), B2 ticked
(#190 merged 880ffd5, #191 rebased --onto and held), 12-18 bring-up + loopback numbers.
Handover: status table + Windows gotchas (Git Bash TZ prints UTC, base-retarget runs no CI,
rebase --onto after a squashed parent, PYTHONUTF8, teensy upload port/power).
Analog plan § 5.1: T1/T6 results — AI1 tolerance-class, AI2 stage-2 divider ≈ 0.26 (inspect
R179/R181). CLAUDE.md: Windows-safe ET timestamp recipe.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mbreiser added a commit that referenced this pull request Sep 10, 2026
… lab-PC handover + 2026-09-10 bench results (#192)

* docs: controller telemetry ring buffer — feasibility, design, T1–T6 + L1–L4 bench plan (no code)

Proposal for a controller-side RAM ring buffer (frame/command/state events,
analog ticks yoked to frame index) drained live over USB with an ack-cursor,
replacing the SD-card event-log shape of LAB-149. Answers the two-file vs
integrated question (sidecar first), timestamps/clock-fit, and lays out the
glass-to-glass latency measurement plan for FicTrac closed loop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(telemetry proposal): use the 0xA8/0xA9 opcodes reserved by firmware PR #47

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: merge + bench plan for 2026-09-08/09 (run-log stack, analog F1/F2 + S1/S2, cleanup)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(merge plan): #186/#188 rebased; flag gzip-blind runlog index builder

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(merge plan): #189 merged; gzip index-builder fix built + tested (PR pending)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(merge plan): #193 merged + installed in the course repo; Action rebuild green

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(merge plan): corpus gates 174/174 on rebased #188; index.json filter fix

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: Codex cross-review of the pending merge-plan work (2026-09-09) — fixed bugs, discussion items, open questions

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(merge plan): stacks rebased onto main after #193; pixi.toml test-line collision note

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(codex review + merge plan): second pass — discussion items 4/6/7/8/9/10 done

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: lab-PC handover — install list, branch state, gate B1 step-by-step, minimal analog, firmware, gotchas

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(lab-pc handover): optional bench launcher — FicTrac / configGui / bridge / Studio buttons with status

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: 2026-09-10 bench day — gates B1/B2 passed, 12-18 arena flashed (fw #48), first reworked-board analog results

Merge plan: B1 rows ticked with the rig05-mr run (#188 merged f744e12, #186 closed), B2 ticked
(#190 merged 880ffd5, #191 rebased --onto and held), 12-18 bring-up + loopback numbers.
Handover: status table + Windows gotchas (Git Bash TZ prints UTC, base-retarget runs no CI,
rebase --onto after a squashed parent, PYTHONUTF8, teensy upload port/power).
Analog plan § 5.1: T1/T6 results — AI1 tolerance-class, AI2 stage-2 divider ≈ 0.26 (inspect
R179/R181). CLAUDE.md: Windows-safe ET timestamp recipe.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant