Skip to content

bledev: the P4 HID-host gate, and a board typing in a passkey - #89

Merged
bdbarnett merged 2 commits into
mainfrom
bledev-pairing-hw
Sep 25, 2026
Merged

bdbarnett merged 2 commits into
mainfrom
bledev-pairing-hw

Conversation

@bdbarnett

@bdbarnett bdbarnett commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #88. Two things from the hardware proofs #83 and #88 left owed.

The P4 as HID host passes on the flow-control image. p4_hid_gate.py repeats #83's gate with the LCD-7 typing into the P4, which runs micropython-pydevices#12. At the default interval, 10 of 10 runs passed with 112 of 112 events. At 7.5-15 ms, 10 of 10 completed runs passed (one more attempt never connected). The planted lost Shift failed at event 0. Before #12 the P4 lost keystrokes in 3 of 5 and 6 of 6 runs. The numbers are on #87.

A board can't type in a passkey on stock MicroPython. The LCD-7 showed its passkey and the P4 (as central) was never asked for it: no _IRQ_PASSKEY_ACTION arrived, and pairing failed at NimBLE's 30 s timeout. MicroPython's peripheral_gap_event_cb (the callback for connections a board makes) drops BLE_GAP_EVENT_PASSKEY_ACTION. That's true on every NimBLE board, not only the P4, and upstream's draft micropython/micropython#19470 moves the event. The fake radio couldn't see this.

The first commit works around it in bledev.mpble. pair(passkey=...) waits 1.5 s for the stack to ask. If it hasn't, bledev asks the provider itself and keeps offering the passkey with gap_passkey() until NimBLE takes it (NimBLE answers EINVAL until the pairing reaches its confirm step). Proven on hardware (2026-09-24), on the P4's stock #12 image with no firmware patch. Right passkey: 3 of 3 runs paired, authenticated, bonded and moved 20 KB byte for byte. Wrong passkey: 3 of 3 refused, no bond on either board. The planted justworks run failed. The fake-radio suites pass (test_bledev, _pairing, _filetransfer, _hid).

The second commit adds the rigs:

  • uart_rig.py drives the boards' friendly REPLs over their UARTs, which keeps ESP-IDF's log visible and allows a hard reset between P4 runs (micropython-pydevices#13).
  • p4_hid_gate.py runs the HID gate with the P4 as host, and --mode connect (with connect_loop_server.py/connect_loop_client.py) counts connect timeouts.
  • passkey_gate.py carries a passkey the way a person would: it reads the digits off the serving board's console and types them into the other board's, where files_pair_client.run(passkey="console") reads them with input().

…tack never asks

MicroPython's NimBLE bindings raise _IRQ_PASSKEY_ACTION only on connections
the board accepted. peripheral_gap_event_cb, which handles the ones it made,
drops BLE_GAP_EVENT_PASSKEY_ACTION, so a board as central is never asked for
the passkey its peer shows and pairing stalls until the stack's 30 s timeout
(micropython/micropython#19470 moves the event). Seen on the P4 against the
LCD-7: the LCD-7 showed its passkey, the P4 got no IRQ.

pair(passkey=...) now waits 1.5 s for the stack to ask; if it hasn't, it asks
the provider itself and offers the passkey with gap_passkey() until NimBLE
takes it (EINVAL until the pairing reaches its confirm step). A stack that
does ask answers from the same value instead of asking twice.
… a typed passkey

uart_rig.py drives boards' friendly REPLs over their UARTs from Windows
Python, several at once, so ESP-IDF's log stays on the console and the P4 can
be hard-reset between runs (micropython-pydevices#13).

p4_hid_gate.py repeats the HID gate with an S3 as the device and the P4 as
host, counting alloc_acl_from_ll drops; --mode connect runs
connect_loop_server/client.py to count connect timeouts.

passkey_gate.py pairs two boards with a passkey carried the way a person
would: read off the serving board's console, typed into the other board's.
files_pair_client.run(passkey="console") is that other board's side.
@bdbarnett

bdbarnett commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor Author

The workaround is now proven on hardware, with the P4 on its stock #12 image and no firmware patch. Right passkey: 3 of 3 runs paired, bonded and moved 20 KB byte for byte, then reconnected from the bond with no second passkey. Wrong passkey: 3 of 3 refused, with no bond left on either board. The planted justworks run failed, as it must. The details are on #88: #88 (comment)

Base automatically changed from bledev-pairing to main September 25, 2026 05:38
@bdbarnett
bdbarnett merged commit 15ab2d4 into main Sep 25, 2026
3 checks passed
@bdbarnett
bdbarnett deleted the bledev-pairing-hw branch September 25, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant