Goal
A hardware-in-the-loop (HIL) testing framework that runs the full integration test suite (3 basic + 3 seedkeeper + 13 RPC = 19 tests) against real hardware via serial communication.
How It Works
- HIL firmware (
make hil) — builds with HIL_ENABLED = True, which starts a UART command listener on the ST-Link debug port (9600 baud)
- HIL controller (
test/hil/controller.py) — connects to debug UART and USB VCP, automates the GUI flow (PIN entry, secret selection, popup dismissal)
- HIL test runner (
test/hil/run_integration.py) — loads test modules, auto-starts Bitcoin Core, runs all 19 tests
HIL Commands (via debug UART)
| Command |
Response |
Purpose |
TEST_WIPE |
OK:WIPED |
Wipe wallet storage + hard reset |
TEST_KEYSTORE |
OK:KEYSTORE:SeedKeeper or OK:KEYSTORE:Internal |
Detect active keystore |
TEST_SECRETS |
OK:SECRETS:id:label,... |
List BIP39 secrets on card |
TEST_FINGERPRINT |
OK:FINGERPRINT:hex |
Get current fingerprint |
TEST_MNEMONIC |
OK:MNEMONIC:words |
Get loaded mnemonic (debug only) |
TEST_STATUS |
OK:STATUS:... |
Get device status |
TEST_SCREEN |
OK:SCREEN:ClassName:... |
Get current GUI screen |
TEST_UI:value |
OK:UI |
Send GUI input |
TEST_RESET |
(resets device) |
Hard reset |
Test Results
19/19 pass (~332 seconds) on STM32F469 Discovery board with SeedKeeper card:
- 3 basic tests: fingerprint, xpub, sign_psbt
- 3 seedkeeper tests: fingerprint format, xpub, read-only error
- 13 RPC tests: legacy, legacy_sh, miniscript, no_derivation, sh_wpkh, sh_wsh, sighashes, sighashes_legacy, strange_derivation, weird_wsh, with_private, wpkh, wsh
New Files
| File |
Purpose |
src/hil.py |
HIL command handler (UART listener, commands) |
manifests/disco-hil.py |
HIL firmware build manifest |
test/hil/controller.py |
Hardware controller (serial, popup drain, keystore loading) |
test/hil/run_integration.py |
HIL test runner |
test/integration/tests/test_seedkeeper.py |
SeedKeeper-specific HIL tests |
test/integration/util/bitcoin_core.py |
BitcoinCoreManager (auto-start bitcoind) |
Modified Files
| File |
Change |
src/platform.py |
hil_test_mode flag |
src/specter.py |
HIL listener, heartbeat disable, USB auto-enable |
src/hosts/usb.py |
HIL auto-enable USB |
src/main.py |
dupterm guard, network = "regtest" override |
src/gui/tcp_gui.py |
TEST_STATUS/TEST_SCREEN/TEST_RESET for simulator |
Makefile |
hil and hil-test targets |
test/integration/util/controller.py |
SIGSEGV detection |
Known Limitations
Upstream Target
Depends on SeedKeeper PR (#2). PR to cryptoadvance/specter-diy. Does NOT touch any submodule.
Goal
A hardware-in-the-loop (HIL) testing framework that runs the full integration test suite (3 basic + 3 seedkeeper + 13 RPC = 19 tests) against real hardware via serial communication.
How It Works
make hil) — builds withHIL_ENABLED = True, which starts a UART command listener on the ST-Link debug port (9600 baud)test/hil/controller.py) — connects to debug UART and USB VCP, automates the GUI flow (PIN entry, secret selection, popup dismissal)test/hil/run_integration.py) — loads test modules, auto-starts Bitcoin Core, runs all 19 testsHIL Commands (via debug UART)
TEST_WIPEOK:WIPEDTEST_KEYSTOREOK:KEYSTORE:SeedKeeperorOK:KEYSTORE:InternalTEST_SECRETSOK:SECRETS:id:label,...TEST_FINGERPRINTOK:FINGERPRINT:hexTEST_MNEMONICOK:MNEMONIC:wordsTEST_STATUSOK:STATUS:...TEST_SCREENOK:SCREEN:ClassName:...TEST_UI:valueOK:UITEST_RESETTest Results
19/19 pass (~332 seconds) on STM32F469 Discovery board with SeedKeeper card:
New Files
src/hil.pymanifests/disco-hil.pytest/hil/controller.pytest/hil/run_integration.pytest/integration/tests/test_seedkeeper.pytest/integration/util/bitcoin_core.pyModified Files
src/platform.pyhil_test_modeflagsrc/specter.pysrc/hosts/usb.pysrc/main.pynetwork = "regtest"overridesrc/gui/tcp_gui.pyMakefilehilandhil-testtargetstest/integration/util/controller.pyKnown Limitations
_load_internal_flash()needs the correct screen flow after wipe. Currently only works with SeedKeeper card.4fd3e51inf469-disco(see ISO 7816 T=1 USART reconfig needed for smartcard support on STM32F469 [PROVEN ON HARDWARE] #1)Upstream Target
Depends on SeedKeeper PR (#2). PR to
cryptoadvance/specter-diy. Does NOT touch any submodule.