Pressing Disconnect with the instruments powered off froze the GUI
(apparent crash, 2026-07-06 15:52): worker.join(5) expired while the
worker sat in multi-second VISA timeouts, then bench.close() ran on the
GUI thread -- each driver close() first writes local() to the dead
device (stacked timeouts) and closing a session under an in-flight read
can also take NI-VISA down natively.
_disconnect now detaches the UI immediately and runs all instrument
teardown on a background thread; if the worker is still stuck in I/O
after a 15s join the sessions are deliberately left open (OS reclaims
them at exit) instead of being closed under a live read. Reconnecting
while a teardown is still releasing the instruments is refused with a
console hint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Run 2026-07-06 13:08: stepping 78->80V released the 46A load mid-ramp,
the supply output overshot to 80.46V and a protection (OVP by all log
evidence) shut it down; the sweep then logged garbage rows for the rest
of the grid. Three fixes:
- release the load down to l_start BEFORE each supply voltage step
(down-steps only; descending load sweeps keep the gated path)
- OVP preflight: query the programmed OVP level at sweep start, abort
under 2V margin above the sweep max, warn under 5V
- dead-supply abort: supply readback ~0V mid-sweep drops the garbage
point, queries which protection fired (OVP/OV/OC/OP/OT) via
_supply_trip_cause, reports it, and stops -- collected points are
still ramped down and saved
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 20A PSU ceiling was hardcoded and clamped user entries, which breaks
benches with a different supply. Now the sweep I limit field IS the max
input current allowed for the test environment: used verbatim as the
supply CC limit and as the step-rejection / measured-backstop ceiling.
Manual supply-current clamp removed; manual CC/CP load gate now checks
against the I limit field value. PSU_MAX_CURRENT_A is reduced to
INPUT_LIMIT_DEFAULT_A (initial field value only).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- stm32_link.py: port to the live 114-byte broadcast protocol (magic
0xAA55AA55, odd parity 8-O-1, 100 Hz publish, repetition-validated,
no CRC); 39 params incl. adc4_trig_phase/iin_zero_sum, CLEAR_FLAGS,
30-bit flag table; commands stay CRC-16 framed; Telemetry aliases
BroadcastData, efficiency uses iout_slow and eff_net subtracts P_sys
- gui_workers.py: STM32Worker reader thread with counter dedup, rate/
loss counters, 20 s graph history, full-rate telemetry CSV writer
- gui.py: right-side telemetry panel (link state, power + EFF net,
heatsink/board temps, Vfly group, control, HRTIM, status-flag
checkboxes, fault registers), Vfly + selectable corr/phase-ofs
graphs, 20 s rolling window on all plots, dual CSV logging (merged
stm_* columns + <stem>_telem.csv), logging on by default into
logs/data_<timestamp>.csv, Plot Eff button
- sweep guards: PSU 20 A input-current gate (conservative estimate +
measured backstop + I-limit clamp), thermal pause at 57/77 C holding
the load at 1 A until cooled 5 C below threshold, CC range pinned to
R2 for the whole run with empirical range-max readback rejection
- plot_eff.py + bench-plot entry point: efficiency vs Vin vs current
maps from any logged CSV (sweep / data log / telem autodetect), file
dialog when launched without args
- bench.py: HIOKI FAST response speed, 5 s settle defaults; cli.py
stm32-read prints the full broadcast; README + .gitignore updates
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the port migration (CLI already defaults to COM11/COM4); the
GUI toolbar field still hardcoded COM1. Supply/meter stay "auto".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add offline `plot-sweep` CLI command: generates efficiency overlay,
heatmap, and power loss plots from sweep CSV (no instruments needed)
- Add degauss buttons to CH5/CH6 in GUI (sends :DEMAg SCPI command)
- Gradual load ramp-down at end of 2D sweep to avoid transients
- Live sweep time estimate in GUI based on grid size × settle time
- Update HIOKI submodule to include degauss CLI command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The worker thread was signaled to stop but never joined, causing bus
collisions when the sweep thread started talking to instruments while
the worker was still mid-query. Now:
- worker.join(timeout=10) before sweep starts
- 0.5s delay + clear supply error queue before first command
- join sweep thread before restarting worker after sweep completes
- Also join worker on disconnect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CP=500W at V=50V needs 10A on the load side — if the supply I_limit
is only 20A and the MPPT has conversion losses, this can cause the
supply to current-limit and timeout. The check now catches this upfront:
CP check: 500W / 50V = 10.0A (limit 20.0A) OK
Also raises ValueError if the worst-case current exceeds the limit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Python 3.13 deletes exception variables after the except block.
Capture the error string before passing to the lambda.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 2D sweep now supports CC (constant current) and CP (constant power)
load modes via --load-mode flag (CLI) and combobox (GUI)
- Supply capability check before all sweeps: validates max voltage
against supply range and prints V/I/P summary
- Renamed sweep-vi args from --i-start/stop/step to --l-start/stop/step
to reflect that the load setpoint can be current or power
- GUI labels update dynamically based on selected load mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GUI: voltage/current range selectors for Ch5 and Ch6 with AUTO option
- Worker: queries current V/I ranges each poll cycle, pushes to GUI
- Setting a fixed range automatically disables auto-range for that channel
- Live display shows current range values below each channel's readout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>