NimBLE-Arduino icon indicating copy to clipboard operation
NimBLE-Arduino copied to clipboard

When device is paired on reconnect of the device not working

Open JuanJoseMoralesCalvo opened this issue 1 year ago • 25 comments

Hi im trying to create an HID Gamepad so when i first pair the device all works great but when i (for example) reset the module it doesnt work. Any suggestion on the connect CallBack?

JuanJoseMoralesCalvo avatar Oct 16 '22 21:10 JuanJoseMoralesCalvo

same here. On PC reconnect works, but on Quest2 does not work. I also use the ESP32-BLE-Gamepad library https://github.com/lemmingDev/ESP32-BLE-Gamepad It did work in summer, but now, not anymore.

CybershoesVR avatar Oct 17 '22 14:10 CybershoesVR

Can either of you share a debug log output when this occurs?

h2zero avatar Oct 17 '22 15:10 h2zero

The workaround for me was to add security to the BLE, but honestly i dont know the reason :D

Attach to setup() after advertising:

NimBLESecurity *SECURITY_MANDATORY = new BLESecurity(); SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_BOND);

JuanJoseMoralesCalvo avatar Oct 17 '22 20:10 JuanJoseMoralesCalvo

Thank you but this did not work. I tried a few other setting but decided it'll be better to go with debugging as @h2zero suggested.

from the log: GamePadPlus V3 is a BT gamepad device that reconnects successful. Cybershoes2 is our BT gamepad device that does reconnect but gamepad functionality fails upon reconnect.

Dear @h2zero, please can you hint at what makes the difference?

odh_logs_2022-10-18 13.55.53.833.txt

CybershoesVR avatar Oct 18 '22 14:10 CybershoesVR

Looks like you need to enable bonding. Try adding this after initialization: `NimBLEDevice::setSecurityAuth(true, true, true);'

Have a look at the secure client/server examples.

h2zero avatar Oct 18 '22 14:10 h2zero

yes, I did that as you see below. I am using NimBLE 1.38 with ESP32-BLE-Gamepad 0.5.1, because using NimBLE 1.40 makes my ESP32-C crash.

void BleGamepad::taskServer(void *pvParameter)
{
    BleGamepad *BleGamepadInstance = (BleGamepad *)pvParameter; // static_cast<BleGamepad *>(pvParameter);
    NimBLEDevice::init(BleGamepadInstance->deviceName);
    NimBLEServer *pServer = NimBLEDevice::createServer();
    pServer->setCallbacks(BleGamepadInstance->connectionStatus);

    BleGamepadInstance->hid = new NimBLEHIDDevice(pServer);
    BleGamepadInstance->inputGamepad = BleGamepadInstance->hid->inputReport(BleGamepadInstance->configuration.getHidReportId()); // <-- input REPORTID from report map
    BleGamepadInstance->connectionStatus->inputGamepad = BleGamepadInstance->inputGamepad;

    BleGamepadInstance->hid->manufacturer()->setValue(BleGamepadInstance->deviceManufacturer);

    BleGamepadInstance->hid->pnp(0x01, vid, pid, 0x0110);
    BleGamepadInstance->hid->hidInfo(0x00, 0x01);

    NimBLESecurity *SECURITY_MANDATORY = new BLESecurity();
    SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_BOND); // ESP_LE_AUTH_REQ_BOND_MITM,
    SECURITY_MANDATORY->setCapability(ESP_IO_CAP_NONE);

    /**
     * @brief Set the authorization mode for this device.
     * @param bonding If true we allow bonding, false no bonding will be performed.
     * @param mitm If true we are capable of man in the middle protection, false if not.
     * @param sc If true we will perform secure connection pairing, false we will use legacy pairing.
     */
    
    //NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc);
    NimBLEDevice::setSecurityAuth(true, true, true);
    
    //NimBLEDevice::setSecurityAuth( BLE_SM_PAIR_AUTHREQ_MITM); // BEST must pair again each time but no need to unpair
    //NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_SC);    //same as usual

    uint8_t *customHidReportDescriptor = new uint8_t[hidReportDescriptorSize];
    memcpy(customHidReportDescriptor, tempHidReportDescriptor, hidReportDescriptorSize);

    for (int i = 0; i < hidReportDescriptorSize; i++)
        Serial.printf("%02x", customHidReportDescriptor[i]);

    BleGamepadInstance->hid->reportMap((uint8_t *)customHidReportDescriptor, hidReportDescriptorSize);
    BleGamepadInstance->hid->startServices();

    BleGamepadInstance->onStarted(pServer);

    NimBLEAdvertising *pAdvertising = pServer->getAdvertising();
    pAdvertising->setAppearance(HID_GAMEPAD);
    pAdvertising->addServiceUUID(BleGamepadInstance->hid->hidService()->getUUID());
    pAdvertising->start();
    //https://github.com/h2zero/NimBLE-Arduino/issues/464
    //The workaround for me was to add security to the BLE, but honestly i dont know the reason :D
    //Attach to setup() after advertising:
    //NimBLESecurity *SECURITY_MANDATORY = new BLESecurity();
    //SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_BOND);
    //end of inserted code


    BleGamepadInstance->hid->setBatteryLevel(BleGamepadInstance->batteryLevel);

    ESP_LOGD(LOG_TAG, "Advertising started!");
    vTaskDelay(portMAX_DELAY); // delay(portMAX_DELAY);
}

In a variation I also tried without

    NimBLESecurity *SECURITY_MANDATORY = new BLESecurity();
    SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_BOND); // ESP_LE_AUTH_REQ_BOND_MITM,
    SECURITY_MANDATORY->setCapability(ESP_IO_CAP_NONE);

CybershoesVR avatar Oct 18 '22 14:10 CybershoesVR

reconnecting our Cybershoes gives an encryption failed:

15:55:28.310  1683  1704 D BluetoothGattServer: onConnectionUpdated() - Device=34:B4:72:00:A1:D6 interval=9 latency=0 timeout=600 status=0
15:55:28.356  1412  2092 W bt_btif       : btif_gatt_set_encryption_cb() - Encryption failed (1)
15:55:28.356  1412  2092 E bt_btif       : bta_hh_security_cmpl() - encryption failed; status=0x000e, reason=0x000a

reconnecting GamePadPlus

15:54:46.249  1683  1704 D BluetoothGattServer: onConnectionUpdated() - Device=20:21:03:07:B9:98 interval=12 latency=0 timeout=200 status=0
15:54:46.331  1412  2092 W bt_stack      : [WARNING:bta_gattc_api.cc(652)] notification already registered
15:54:46.332  1412  2092 I chatty        : uid=1002(bluetooth) bt_main_thread identical 1 line
15:54:46.332  1412  2092 W bt_stack      : [WARNING:bta_gattc_api.cc(652)] notification already registered
15:54:46.332  1412  2092 W bt_btif       : bta_hh_co_open: Found an existing device with the same handle dev_status=2, address=20:21:03:07:b9:98, attr_mask=0x0000, sub_class=0x00, app_id=255
15:54:46.332  1412  1662 W bt_btif       : btif_hh_upstreams_evt: BTA_HH_OPN_EVT: handle=16, status =0
15:54:46.332  1412  1662 W bt_btif       : BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle ... 16
15:54:46.332  1412  1662 I bt_btif_dm    : get_cod remote_cod = 0x00000504
15:54:46.332  1412  1662 I bt_btif_dm    : get_cod remote_cod = 0x00000504
15:54:46.336  1412  1412 D BluetoothAdapterService: getAdapterService() - returning com.android.bluetooth.btservice.AdapterService@590f4fe
15:54:46.336  1412  1662 W bt_btif       : btif_hh_upstreams_evt: name = GamePadPlus V3
15:54:46.336  1412  1662 W bt_btif       : bta_hh_co_send_hid_info: fd = 108, name = [GamePadPlus V3], dscp_len = 187
15:54:46.336  1412  1662 W bt_btif       : bta_hh_co_send_hid_info: vendor_id = 0x1949, product_id = 0x0402, version= 0x0111,ctry_code=0x00
15:54:46.347  1412  1412 D BluetoothAdapterService: isQuetModeEnabled() - Enabled = false

and finally

15:54:46.547  1034  1142 I InputReader   : Device added: id=15, name='GamePadPlus V3', sources=0x01000511
15:54:46.548  2020  2020 D GamepadListener: Adding Device: GamePadPlus V3 pid: 1026 sources: 16778513
15:54:46.549  3026  3026 D GamepadListener: Adding Device: GamePadPlus V3 pid: 1026 sources: 16778513
15:54:46.549  2236  2236 I [OAO] ShellOverlayServiceJNI: NativePTKServiceNotifyDeviceConnectionChanged
15:54:46.549  2236  2236 D [OAO] ShellApplication: PTKService enumerated keyboard: {vendorId: 0x1949 (0n6473), productId: 0x402 (0n1026)}
15:54:46.554  1734  1734 D GamepadListener: Adding Device: GamePadPlus V3 pid: 1026 sources: 16778513
15:54:46.577  2971  2971 D GamepadListener: Adding Device: GamePadPlus V3 pid: 1026 sources: 16778513

CybershoesVR avatar Oct 18 '22 15:10 CybershoesVR

also no success with:

    NimBLEDevice::setSecurityAuth(true, true, true);
    NimBLESecurity *SECURITY_MANDATORY = new BLESecurity();

    /**
     * @brief Set requested authentication mode
     * @param [in] auth_req A bitmask containing one or more of:
     * * ESP_LE_AUTH_NO_BOND              0x00
     * * ESP_LE_AUTH_BOND                 0x01
     * * ESP_LE_AUTH_REQ_MITM             (1 << 2)
     * * ESP_LE_AUTH_REQ_BOND_MITM        (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)
     * * ESP_LE_AUTH_REQ_SC_ONLY          (1 << 3)
     * * ESP_LE_AUTH_REQ_SC_BOND          (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY)
     * * ESP_LE_AUTH_REQ_SC_MITM          (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY)
     * * ESP_LE_AUTH_REQ_SC_MITM_BOND     (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND)
     */
    SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_REQ_BOND_MITM); // ESP_LE_AUTH_REQ_BOND_MITM,ESP_LE_AUTH_BOND
    //SECURITY_MANDATORY->setCapability(ESP_IO_CAP_NONE);


    SECURITY_MANDATORY->setInitEncryptionKey(BLE_SM_PAIR_KEY_DIST_ENC);
    SECURITY_MANDATORY->setRespEncryptionKey(BLE_SM_PAIR_KEY_DIST_ENC);

CybershoesVR avatar Oct 18 '22 15:10 CybershoesVR

sometimes (once in 5-10 attempts) connection and reconnection (but then I need to confirm pairing again) works successfully with:

NimBLEDevice::setSecurityAuth(true, true, false);

CybershoesVR avatar Oct 18 '22 15:10 CybershoesVR

I'm not too sure what the error is yet, the logs suggest an error in a value passed during pairing. What kind of pairing does the other device expect?

If not using PIN codes or any other mitm protection then try setting the last 2 parameters of the NimBLEDevice::setSecurityAuth call to false. Otherwise just set the last parameter to false if mitm is required.

h2zero avatar Oct 18 '22 16:10 h2zero

You should also remove this:


NimBLESecurity *SECURITY_MANDATORY = new BLESecurity();

    /**
     * @brief Set requested authentication mode
     * @param [in] auth_req A bitmask containing one or more of:
     * * ESP_LE_AUTH_NO_BOND              0x00
     * * ESP_LE_AUTH_BOND                 0x01
     * * ESP_LE_AUTH_REQ_MITM             (1 << 2)
     * * ESP_LE_AUTH_REQ_BOND_MITM        (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)
     * * ESP_LE_AUTH_REQ_SC_ONLY          (1 << 3)
     * * ESP_LE_AUTH_REQ_SC_BOND          (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY)
     * * ESP_LE_AUTH_REQ_SC_MITM          (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY)
     * * ESP_LE_AUTH_REQ_SC_MITM_BOND     (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND)
     */
    SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_REQ_BOND_MITM); // ESP_LE_AUTH_REQ_BOND_MITM,ESP_LE_AUTH_BOND
    //SECURITY_MANDATORY->setCapability(ESP_IO_CAP_NONE);


    SECURITY_MANDATORY->setInitEncryptionKey(BLE_SM_PAIR_KEY_DIST_ENC);
    SECURITY_MANDATORY->setRespEncryptionKey(BLE_SM_PAIR_KEY_DIST_ENC);

That is conflicting with the security settings above it.

h2zero avatar Oct 18 '22 17:10 h2zero

@CybershoesVR Try this workaround from chewara, it sounds like its happening the same:

class MyCallbacks : public BLEServerCallbacks { void onConnect(BLEServer* pServer){ Serial.println("connected"); BLEDescriptor *desc = input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); uint8_t val[] = {0x01, 0x00}; desc->setValue(val, 2); }

void onDisconnect(BLEServer* pServer){ Serial.println("disconnected"); } };

Issue Open: https://github.com/nkolban/esp32-snippets/issues/632

JuanJoseMoralesCalvo avatar Oct 19 '22 06:10 JuanJoseMoralesCalvo

You have to add something like this on the onConenct:

BLEDescriptor *desc = input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); uint8_t val[] = {0x01, 0x00}; desc->setValue(val, 2);

JuanJoseMoralesCalvo avatar Oct 19 '22 06:10 JuanJoseMoralesCalvo

I’m facing the same issue.

@JuanJoseMoralesCalvo Did your suggestion work for you?

fabdelgado avatar Nov 05 '22 14:11 fabdelgado

The workaround on comment #12 didnt work as i understand its only for the nkolban esp32 libraries. Finally by adding security it worked.

NimBLESecurity *SECURITY_MANDATORY = new NimBLESecurity(); SECURITY_MANDATORY->setAuthenticationMode(ESP_LE_AUTH_BOND); // ESP_LE_AUTH_REQ_BOND_MITM, SECURITY_MANDATORY->setCapability(ESP_IO_CAP_NONE);

JuanJoseMoralesCalvo avatar Nov 05 '22 21:11 JuanJoseMoralesCalvo

On which lines of which file should I put this?

Please explain me if I should add or replace code?

fabdelgado avatar Nov 05 '22 21:11 fabdelgado

I would encourage not to use the security class as it has been deprecated.

The equivalent call is simply:

NimBLEDevice::setSecurityAuth(true, false, false); // enable bonding, no MITM, no SC

The IO caps default to NONE. Just put that line somewhere after initializing NimBLE.

h2zero avatar Nov 05 '22 22:11 h2zero

@h2zero like this example in my gist?

https://gist.github.com/fabdelgado/60c715dec2651b46a0d342c46179fe48

fabdelgado avatar Nov 05 '22 23:11 fabdelgado

Looks good to me

h2zero avatar Nov 05 '22 23:11 h2zero

I will try that!

fabdelgado avatar Nov 05 '22 23:11 fabdelgado

It has not worked for me with my chromecast v3 Google TV. You can review the video I have recorded for you.

https://user-images.githubusercontent.com/8621547/200147816-289740df-03e3-4b02-9f8e-d16e6ccdcda3.mp4

fabdelgado avatar Nov 06 '22 00:11 fabdelgado

Hmm, please try erasing the flash of the esp32 then upload your code. Also remove any devices bonded to the TV if you can.

h2zero avatar Nov 06 '22 00:11 h2zero

@h2zero this worked for me, thanks for the help.

https://user-images.githubusercontent.com/8621547/200183433-a0bfaea0-bfe1-4ad7-8a33-ad92f576229e.mp4

This is the code that I have used, I have left it for future issues.

`void setup() {

NimBLEDevice::init("NimBLE");

NimBLEDevice::setSecurityAuth(true, false, false); // enable bonding, no MITM, no SC }`

fabdelgado avatar Nov 06 '22 16:11 fabdelgado

@h2zero I have another related problem, when I press forget device and then restart the Chromecast it unbinds the remote from Chromecast instead of ESP32. This problem happened to me before the problem of connecting and disconnecting. Do you have any idea?

fabdelgado avatar Nov 06 '22 20:11 fabdelgado

I don't have any idea why that would happen, wouldn't have anything to do with the esp32 though.

h2zero avatar Nov 07 '22 16:11 h2zero