Hid startServices results in missing onDisconnect
I've had this curious issue on ESP32-S3 (on a proprietary board) not disconnecting correctly when device exits the range of bluetooth with NimBLE-Arduino 2.1.2. Also seems to happen on 2.2.3.
Took a good while to replicate, but it turns out the issue only appears if NimBLEHIDDevice::startServices gets called after a call to NimBLEHIDDevice::getInputReport.
To replicate,
- upload the minimal code to esp32-s3,
- open the serial port to observe connection,
- pair a device (Im testing with an android phone),
- walk out of bluetooth range,
- come back and find out the esp32-s3 still thinks it is connected. Now, move the startServices and repeat to find that the disconnection works.
main.cpp:
#include "NimBLEDevice.h"
#include <Arduino.h>
#include <NimBLEHIDDevice.h>
#include <NimBLEServer.h>
struct Cbs : public NimBLEServerCallbacks {
void onDisconnect(NimBLEServer *pServer, NimBLEConnInfo &, int i) override {
Serial.printf("Disconnected due to %d\n", i);
NimBLEDevice::startAdvertising();
}
void onConnect(NimBLEServer *pServer, NimBLEConnInfo &) override {
Serial.printf("onConnect\n");
NimBLEDevice::stopAdvertising();
}
};
NimBLEServer *server;
HardwareSerial mySerial(0);
NimBLECharacteristic *charac0;
void setup() {
Serial.begin(115200);
NimBLEDevice::init(":)");
server = NimBLEDevice::createServer();
static Cbs cbs{};
server->setCallbacks(&cbs);
// Low power so its easy to disconnect
NimBLEDevice::setPower(-21);
static NimBLEHIDDevice hidDevice{server};
hidDevice.setManufacturer("myself");
// hidDevice.startServices();
NimBLEAdvertising *pAdvertising = server->getAdvertising();
pAdvertising->setAppearance(HID_MOUSE);
pAdvertising->setName(":)");
pAdvertising->addServiceUUID(hidDevice.getHidService()->getUUID());
hidDevice.setBatteryLevel(100);
charac0 = hidDevice.getInputReport(1);
// Here lies the issue
hidDevice.startServices();
charac0->setValue(":)");
NimBLEDevice::startAdvertising();
}
void loop() {
delay(1000);
charac0->notify();
Serial.printf("connected: %d\n", server->getConnectedCount());
}
platformio.ini:
[env:default]
monitor_speed=115200
platform = espressif32 @ 6.2.0
board = esp32-s3-devkitc-1
framework = arduino
build_flags =
-std=gnu++17
board_build.f_cpu = 160000000L
build_src_filter =
+<main.cpp>
lib_deps =
h2zero/[email protected]
build_unflags =
-std=gnu++11
Looks like the HID does not work at all if startServices is called before getInputReport, so it is not a fix to just move the startServices.
startServices must be called after the first call to getInputReport in order to create the characteristic and have it added to the service, otherwise it will just create it but not register it with the GATT stack. The disconnect issue is something unrelated to the HID class and my be an upstream problem.
Fair, and we did since found more issues with gatt on esp s3 that were fixed by reverting to 1.4.3.
An additional quirk is that calling startServices both before and after getInputReport did not enable the characteristics, despite my quick read of the source hinting that the characteristics would be reinitialized.
Could you share the updated source code that isn't working?
@VisaJE any update on this?
No, but I'll test today.
Okay, I tested on nimble-arduino 2.3.5 and platformio/platform-espressif32 @ 6.12.0: The issue is fixed.