Skip to content

bledev.hid: BLE keyboards and gamepads into events, both ways - #83

Merged
bdbarnett merged 6 commits into
mainfrom
bledev-hid
Sep 25, 2026
Merged

bdbarnett merged 6 commits into
mainfrom
bledev-hid

Conversation

@bdbarnett

@bdbarnett bdbarnett commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

BLE keyboards, remotes and gamepads now feed events and keys the way USB ones do through usbif, and a board can be a BLE keyboard and gamepad itself. Stacked on #81 (bledev-host).

  • bledev.hidreport: a HID report-descriptor parser and decoder with no Bluetooth in it. Keyboard events match usbif's boot-keyboard decoder event for event (3,000 random reports compared in the tests).
  • bledev.hid: the HOGP host (reads the Report Map, pairs when the device asks, subscribes to every input report) and a peripheral serving a keyboard, consumer control and gamepad, with its identity derived from which of those it offers.
  • The contract gains descriptors, encrypted characteristics, Connection.pair() and a long_read capability; fake, mpble and bleak implement them. Two mpble MTU bugs fixed on the way (the board as central to a peripheral that exchanges first).

The guide is the new section in docs/bledev.md; how it works and what it found is docs/bledev-internals.md, "How HID gets there".

Gates

  • Parser vectors (the HID spec's boot keyboard, ESP32-BLE-Keyboard, CircuitPython's consumer control, adafruit_ble's map and gamepad, the Xbox Series BLE controller): pass on CPython, unix micropython and the P4. Each of six planted faults fails them.
  • Fake radio end to end, on both interpreters: pass. Each of four planted faults fails it.
  • Board to board over the air, both role directions (LCD-7 and T-Embed, and the P4 with the LCD-7): 112 of 112 events and the typed text exact, and a planted lost Shift fails. The one exception is the P4 as host, which loses reports below Python (P4 as BLE central loses notifications below MicroPython when Python is busy #87). The S3s never lost one.
  • Pairing and bonding, both directions: the first connect pairs "just works" and bonds. Reconnecting after both boards reset reuses the stored keys. A host that lost its keys re-pairs. A host that won't pair can't read an encrypted device.
  • Latency, as a key-press round trip: median 68-70 ms at the default interval and 29-30 ms at 7.5-15 ms, so roughly 35 and 15 ms one way. Decoding adds 1.7-2.8 ms.
  • Laptop (bleak) host against the P4 under a vendor UUID, since Windows hides 0x1812 from apps: 112 of 112, and the plant fails.
  • bless works as a laptop peripheral, with workarounds (see bless_peripheral.py).

All the numbers are in docs/bledev-internals.md, "HID, board to board and from the laptop".

… parser

bledev.hidreport parses HID report descriptors and decodes input reports into
events.Key and events.Joy* records, matching usbif's boot-keyboard decoder
event for event. bledev.hid is the HOGP host (reads the Report Map, pairs when
the device demands it, subscribes to every input report) and a peripheral that
serves a keyboard, consumer control and gamepad.

The contract gains descriptors (server and client), encrypted characteristics,
Connection.pair()/encrypted and a long_read capability; fake, mpble and bleak
implement them.
…ss probed; two mpble MTU fixes

Windows hides the HID service from apps, so Peripheral and Host take a
service_uuid and hid.INSPECT_SERVICE serves the same characteristics where
bleak can read them. The bless probe (the board as central, Windows as
peripheral) found mpble missing an MTU exchanged before aioble records a
central-role connection, and exchange_mtu() raising EALREADY when the peer
already exchanged.
Base automatically changed from bledev-host to main September 25, 2026 05:37
@bdbarnett
bdbarnett merged commit d347625 into main Sep 25, 2026
3 checks passed
@bdbarnett
bdbarnett deleted the bledev-hid 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