earlephilhower / arduino-pico

Raspberry Pi Pico Arduino core, for all RP2040 boards
GNU Lesser General Public License v2.1
1.92k stars 402 forks source link

BLE can't pair to new host after initial pairing #1817

Closed Kakiharu closed 2 months ago

Kakiharu commented 9 months ago

After messing around with the auruino-pico I thought I was doing something weird, however I found that if you pair it everything will work as intended. But if you unpair it from the same device and try to pair with something else it completely stops outputting. You have to turn off the pico unpair then turn it on and pair to the new device. I figure this is not a intended function. I tried this on multiple versions. They basic code I was using to find that out is as follows:

#include <KeyboardBLE.h>

const int pin = 2; // GPIO pin number
char key = 'w'; // Key to send

void setup() {
  pinMode(pin, INPUT_PULLUP);
  KeyboardBLE.begin();
}

void loop() {
  if (digitalRead(pin) == LOW) {
    KeyboardBLE.write(key);
    delay(1000); // Add a delay to avoid key spamming
  }
}

Edit: It's almost like it needs to not be paired to anything when you turn it off if you are switching devices. It also happens if it is already connected to the pc and you update the firmware when it reboots it will auto reconnect to the what it was paired to and will not function until you unpair, then turn it off then back on and re-pair it.

earlephilhower commented 9 months ago

Interesting observation, thanks for testing and giving a succinct explanation.

What has me scratching my head is this:

...It also happens if it is already connected to the pc and you update the firmware when it reboots it will auto reconnect ...

The BLE pairing information is actually part of the application binary, so when you flash a new app it gets cleared out. So there are no shared keys available immediately after flashing. No comms would then be possible, I imagine. Maybe the PC is assuming the same BLE MAC already has the key and not negotiating a new one...

earlephilhower commented 9 months ago

This is a very good issue. Found several things already:

That was just looking during lunch. Let me implement some fixes for these two and see if that clears things up. The TLV alignment might explain why only the 1st connection works...the 2nd and subsequent ones would not be stored properly...

earlephilhower commented 9 months ago

Did some digging around and it looks like this is a BTstack internal thing, and only occurs in BLE mode.

Ths following classic BT sketch pairs with multiple computers in a row without incident:

#include <KeyboardBT.h>

void setup() {
  KeyboardBT.begin();
}

void loop() {
  if (BOOTSEL) {
    KeyboardBT.write('w');
    while (BOOTSEL) delay(100);
  }
}

Only the BLE version has an issue:

#include <KeyboardBLE.h>

void setup() {
  KeyboardBLE.begin();
}

void loop() {
  if (BOOTSEL) {
    KeyboardBLE.write('w');
    while (BOOTSEL) delay(100);
  }
}

Tracing the callbacks shows that BTStack is not calling us with a "new connection handle" event after negotiating with a new BLE host after the initial connection.

https://github.com/earlephilhower/arduino-pico/blob/39a2bbd78811be87edac56b545d8b3a3b3b5bca4/libraries/HID_Bluetooth/src/PicoBluetoothBLEHID.h#L179-L186

So the core here can't actually send or receive anything and isn't even aware things are connected.

The infinite loop potential has been removed, and the TLV database is actually okay so those two things are not part of the issue here (TLV issues would affect classic BT too).

earlephilhower commented 2 months ago

Looks like this really is in BTStack or the CYW43 chip FW as others seem to run into it even with the raw SDK (https://github.com/joba-1/PicoW_A2DP/tree/main ). Given that, there's not anything we can do other than hope for a new PicoSDK and FW...