Skip to content

fix(gui): rebuild the boards a file describes, not the ones it guesses - #133

Merged
gbradham merged 1 commit into
mainfrom
fix/board-driver-on-open
Aug 21, 2026
Merged

fix(gui): rebuild the boards a file describes, not the ones it guesses#133
gbradham merged 1 commit into
mainfrom
fix/board-driver-on-open

Conversation

@gbradham

Copy link
Copy Markdown
Member

A regression on the closed-loop feature that just shipped in #131/#132. Save an experiment with a Maimu on it, reopen it, and the stimulator stops working.

The bug

_populate_hardware_from_session guessed each board's driver:

board_type = "telemetrix" if board_config.driver_type == "arduino" else "pigpio"

Right for exactly the two driver types the shipped examples happen to use, wrong for every other one:

Saved driver_type Rebuilt as
arduino TelemetrixBoard
raspberry_pi PiGPIOBoard
bluetooth PiGPIOBoard
serial PiGPIOBoard

A Bluetooth adapter came back as a Raspberry Pi GPIO board, so the Maimu on it was parented to a driver that cannot talk to it and failed to initialise. The closed loop silently stopped working after a reload, with nothing saying why. Same for any GenericSerial device.

It also dropped board_type and auto_reconnectadd_board forwards its kwargs to the driver constructor, and board_type is applied after construction, so it had no way to set it. Every file in examples/ carries board_type: "uno".

Worth noting glider --file was already correct: load_experiment goes through the core, which builds from the BoardConfig. Only the GUI's own copy guessed.

The fix

Delete the guess. The correct implementation already existed — GliderCore._create_hardware_from_session, extracted during the file-format work — and builds from the BoardConfig, honouring driver type, board_type and auto_reconnect. The GUI now calls it instead of carrying a second copy.

Exposed as populate_hardware_from_session and made sync, because neither create_board nor create_device ever awaited anything — they were async by declaration only. Both async spellings remain as thin wrappers, so existing callers are untouched.

Clearing-before-repopulating moves into that method too, so opening a second file replaces the first one's hardware on both paths rather than only the one that remembered to do it.

Tests — 9 new

tests/unit/gui/test_open_restores_board_drivers.py: every driver type rebuilt as itself (parametrised over all four); board_type and auto_reconnect surviving; a Maimu reopened from a saved experiment landing on a BLEBoard — the regression that matters; reopening replacing rather than stacking; and a file naming a driver this install doesn't have still opening, with the other boards intact.

All nine failed before the fix.

Verification

PYTHONPATH=src QT_QPA_PLATFORM=offscreen pytest tests/3651 passed, 3 skipped, ruff and black clean.

File > Open guessed each board's driver as "telemetrix" if the saved
driver_type was "arduino" else "pigpio". That is right for exactly the two
driver types the shipped examples happen to use and wrong for every other one:
a Bluetooth adapter and a serial board both came back as Raspberry Pi GPIO
boards. The devices on them were then parented to a driver that cannot talk to
them and failed to initialise, so a saved experiment stopped working after a
reload with nothing saying why. A Maimu stimulator -- BLE, on a bluetooth
board -- was exactly this case.

It also had no way to set board_type or auto_reconnect, because add_board
passes its kwargs to the driver constructor and board_type is applied after
construction. Every example file carries board_type "uno".

The correct implementation already existed: GliderCore._create_hardware_from_
session, extracted during the file-format work, builds from the BoardConfig
and honours all three. The GUI now calls it instead of carrying a second copy.
It is exposed as populate_hardware_from_session and made sync, since neither
create_board nor create_device ever awaited anything -- the async spellings
remain as thin wrappers so existing callers are unaffected.

Clearing before repopulating moves into that method, so opening a second file
replaces the first one's hardware on both paths rather than only the one that
remembered to do it.
@gbradham
gbradham merged commit c648f82 into main Aug 21, 2026
4 checks passed
@gbradham
gbradham deleted the fix/board-driver-on-open branch August 21, 2026 02:33
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