Skip to content

Add BLE HID Central example#566

Draft
ChocolateLoverRaj wants to merge 16 commits intoembassy-rs:mainfrom
ChocolateLoverRaj:ble_hid_central
Draft

Add BLE HID Central example#566
ChocolateLoverRaj wants to merge 16 commits intoembassy-rs:mainfrom
ChocolateLoverRaj:ble_hid_central

Conversation

@ChocolateLoverRaj
Copy link
Contributor

@ChocolateLoverRaj ChocolateLoverRaj commented Mar 21, 2026

Closes #402.

Depends on #568

My idea is to make the example be generic for connecting any BLE HID peripheral(s).

When it's ready to merge I will remove my Nix / Zed specific files.

While I was testing this with two Xbox controllers, I found some interesting things.

The controller sends a update parameters request after encrypting. If you ignore the request, the controller will terminate the connection in 55-60s no matter what you do. If you accept the requested parameters, accept different parameters than requested, or reject the request, the controller will stay connected and work as expected.

However, the second controller always disconnected after 55-60s, even if I accepted the requested parameters, but with a 15ms connection interval instead of 7.5ms (because my esp32s3 seems to not be able to do 2 simultaneous 7.5ms connections.

@ChocolateLoverRaj ChocolateLoverRaj changed the title Ble hid central Add BLE HID Central example Mar 21, 2026
Use serde + postcard to no longer have to manually serialize /
deserialize `BondInformation`.
However this is not working properly on an Xbox Series X | S controller.
@ChocolateLoverRaj
Copy link
Contributor Author

ChocolateLoverRaj commented Mar 22, 2026

I'm having TrouBLE with this example on linux. I run it with

sudo hciconfig hci0 down && systemd-run   --pty   --uid=$(id -u)   --gid=$(id -g)   --same-dir   --setenv RUST_LOG=trace   --setenv PATH --setenv RUST_BACKTRACE=1   --property "AmbientCapabilities=CAP_NET_ADMIN"  cargo run --bin ble_hid_central --features security

But after doing

conn.request_security().unwrap();

I never get the ConnectionEvent::PairingComplete event.
This is the output:

[2026-03-22T02:32:48Z INFO  trouble_example_apps::ble_hid_central] Our address = Address { kind: AddrKind(1), addr: BdAddr([255, 143, 40, 5, 228, 255]) }
[2026-03-22T02:32:48Z INFO  trouble_example_apps::ble_hid_central] Loaded bonds: []
[2026-03-22T02:32:48Z INFO  trouble_example_apps::ble_hid_central] Connecting to C8:3F:26:8D:4D:00
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] using packet pool with MTU 251 capacity 16
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] filter accept list size: 64
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] setting txq to 6, fragmenting at 251
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] configuring host buffers (1 packets of size 255)
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] initialized
[2026-03-22T02:32:48Z INFO  trouble_host::host] [host] Device Address E8:62:BE:2D:7F:52
[2026-03-22T02:32:48Z DEBUG trouble_host::host] [host] connection with handle ConnHandle(2048) established to BdAddr([00, 4d, 8d, 26, 3f, c8])
[2026-03-22T02:32:48Z DEBUG trouble_host::connection_manager] [link][poll_accept] connection accepted: state: ConnectionStorage { state: Connected, handle: Some(ConnHandle(2048)), role: Some(Central), peer_identity: Some(Identity { bd_addr: BdAddr([0, 77, 141, 38, 63, 200]), irk: None }), refcount: 0 }
[2026-03-22T02:32:48Z INFO  trouble_example_apps::ble_hid_central] Connected, pairing / bonding...
[2026-03-22T02:32:48Z TRACE trouble_host::security_manager] [security manager] Send Pairing Request 11
[2026-03-22T02:32:48Z TRACE trouble_host::host] [host] granted send packets = 1, len = 15
[2026-03-22T02:32:48Z TRACE trouble_host::host] [host] sent acl packet len = 11
[2026-03-22T02:32:48Z TRACE trouble_host::host] [host] inbound l2cap header channel = 6, fragment len = 7, total = 7
[2026-03-22T02:32:48Z INFO  trouble_host::security_manager::pairing::central] [smp] Pairing method JustWorks
[2026-03-22T02:32:48Z TRACE trouble_host::security_manager] [security manager] Send Pairing Public Key 69
[2026-03-22T02:32:48Z TRACE trouble_host::host] [host] granted send packets = 1, len = 73
[2026-03-22T02:32:48Z TRACE trouble_host::host] [host] sent acl packet len = 69
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap header channel = 6, fragment len = 20, total = 65
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap len = 24
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap len = 21
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap header channel = 6, fragment len = 17, total = 17
[2026-03-22T02:32:49Z TRACE trouble_host::security_manager] [security manager] Send Pairing Random 21
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] granted send packets = 1, len = 25
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] sent acl packet len = 21
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap header channel = 6, fragment len = 17, total = 17
[2026-03-22T02:32:49Z INFO  trouble_host::security_manager::pairing::central] [smp] Just works pairing with compare 434156
[2026-03-22T02:32:49Z TRACE trouble_host::security_manager] [security manager] Send Pairing DH Key Check 21
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] granted send packets = 1, len = 25
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] sent acl packet len = 21
[2026-03-22T02:32:49Z TRACE trouble_host::host] [host] inbound l2cap header channel = 6, fragment len = 17, total = 17
[2026-03-22T02:32:49Z INFO  trouble_host::security_manager] Enabling encryption for Identity { bd_addr: BdAddr([0, 77, 141, 38, 63, 200]), irk: None }
[2026-03-22T02:32:49Z TRACE trouble_host::security_manager] [security manager] Add bond for Identity { bd_addr: BdAddr([0, 77, 141, 38, 63, 200]), irk: None }
[2026-03-22T02:32:50Z DEBUG trouble_host::channel_manager] [l2cap][conn = ConnHandle(2048)] connection param update request: ConnParamUpdateReq { interval_min: 6, interval_max: 6, latency: 0, timeout: 300 }
[2026-03-22T02:32:50Z INFO  trouble_example_apps::ble_hid_central] [C8:3F:26:8D:4D:00] Accepting ConnectionParamsRequest { params: RequestedConnParams { min_connection_interval: Duration { ticks: 7500 }, max_connection_interval: Duration { ticks: 7500 }, max_latency: 0, min_event_length: Duration { ticks: 0 }, max_event_length: Duration { ticks: 0 }, supervision_timeout: Duration { ticks: 3000000 } }, handle: ConnHandle(2048), responded: false }
[2026-03-22T02:32:50Z TRACE trouble_host::host] [host] granted send packets = 1, len = 14
[2026-03-22T02:32:50Z TRACE trouble_host::host] [host] sent acl packet len = 10
[2026-03-22T02:32:51Z INFO  trouble_example_apps::ble_hid_central] Other connection event: ConnectionParamsUpdated { conn_interval: Duration { ticks: 7500 }, peripheral_latency: 0, supervision_timeout: Duration { ticks: 3000000 } }
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z WARN  trouble_host::host] [host] encountered error processing ACL data for ConnHandle(2048): OutOfMemory
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z WARN  trouble_host::host] [host] encountered error processing ACL data for ConnHandle(2048): OutOfMemory
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19
[2026-03-22T02:32:54Z WARN  trouble_host::host] [host] encountered error processing ACL data for ConnHandle(2048): OutOfMemory
[2026-03-22T02:32:54Z TRACE trouble_host::host] [host] inbound l2cap header channel = 4, fragment len = 19, total = 19

and it continues having the OutOfMemory error.

I think there might be another bug with trouble-host that is causing this.

On an esp32s3 this is working.

Update: The OutOfMemory error on Linux happens on my gaming desktop computer

Bus 001 Device 006: ID 8087:0032 Intel Corp. AX210 Bluetooth
Linux 6.18.18

But this example works fine on my laptop:

Bus 001 Device 003: ID 8087:0026 Intel Corp. AX201 Bluetooth
Linux 6.12.68

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.

provide example interfacing with gamepad

1 participant