h2zero / NimBLE-Arduino

A fork of the NimBLE library structured for compilation with Arduino, for use with ESP32, nRF5x.
https://h2zero.github.io/NimBLE-Arduino/
Apache License 2.0
700 stars 145 forks source link

Client reconnect failed after light sleep #616

Closed flynny75 closed 4 months ago

flynny75 commented 9 months ago

I am attempting to put a client to light sleep and when it wakes reconnect to a known server. Connections after a light sleep always seem to fail and I cant figure it out - the only difference between the iterations of the loops is light sleep. I have attached a sample Platformio project that configures both the client and server. NimBLE_light_sleep.zip

Light sleep makes this awkward because the serial connection is lost. The client ESP will need to be externally powered and the USB disconnected and reconnected at certain times to see the logs. The code indicates when to do this (this is easiest in VSCode using the Serial Monitor extension as it reconnects to the same serial port when the device reappears)

Connections following DELAY are made after a task delay, the connections made after LIGHT SLEEP are made after a light sleep

[ 10143][E][main.cpp:75] loop(): ===== DELAY =====
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=574 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[ 17493][E][main.cpp:75] loop(): ===== DELAY =====
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
I NimBLEClient: mtu update event; conn_handle=1 mtu=255
I NimBLEClient: Connection established
D NimBLEClient: >> deleteServices
D NimBLEClient: << deleteServices
D NimBLEClientCallbacks: onConnect: default
D NimBLEClient: << connect()
D NimBLEClient: >> disconnect()
D NimBLEClient: << disconnect()
[ 24556][E][main.cpp:75] loop(): ===== DELAY =====
D NimBLEClient: Got Client event 
I NimBLEClient: disconnect; reason=534, 
D NimBLEClientCallbacks: onDisconnect: default
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
I NimBLEClient: mtu update event; conn_handle=1 mtu=255
I NimBLEClient: Connection established
D NimBLEClient: >> deleteServices
D NimBLEClient: << deleteServices
D NimBLEClientCallbacks: onConnect: default
D NimBLEClient: << connect()
D NimBLEClient: >> disconnect()
D NimBLEClient: << disconnect()
[ 31656][E][main.cpp:75] loop(): ===== DELAY =====
D NimBLEClient: Got Client event 
I NimBLEClient: disconnect; reason=534, 
D NimBLEClientCallbacks: onDisconnect: default
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
I NimBLEClient: mtu update event; conn_handle=1 mtu=255
I NimBLEClient: Connection established
D NimBLEClient: >> deleteServices
D NimBLEClient: << deleteServices
D NimBLEClientCallbacks: onConnect: default
D NimBLEClient: << connect()
D NimBLEClient: >> disconnect()
D NimBLEClient: << disconnect()
[ 38706][E][main.cpp:75] loop(): ===== DELAY =====
D NimBLEClient: Got Client event 
I NimBLEClient: disconnect; reason=534, 
D NimBLEClientCallbacks: onDisconnect: default
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
I NimBLEClient: mtu update event; conn_handle=1 mtu=255
I NimBLEClient: Connection established
D NimBLEClient: >> deleteServices
D NimBLEClient: << deleteServices
D NimBLEClientCallbacks: onConnect: default
D NimBLEClient: << connect()
D NimBLEClient: >> disconnect()
D NimBLEClient: << disconnect()
[ 45806][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=13 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[ 67808][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
I NimBLEClient: Connected event
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=574 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[ 81142][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=13 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[103146][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
**** Failed to open the serial port COM5 ****
---- Opened the serial port COM5 ----
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=13 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[147207][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=13 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[169211][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
---- Reopened serial port COM5 ----
D NimBLEClient: >> connect(dc:54:75:cd:bf:9d)
D NimBLEClient: Got Client event 
E NimBLEClient: Connection failed; status=13 
D NimBLEClient: >> disconnect()
D NimBLEClient: Not connected to any peers
D NimBLEClient: << disconnect()
[191215][E][main.cpp:55] loop(): ===== LIGHT SLEEP =====
---- Closed serial port COM5 due to disconnection from the machine ----
h2zero commented 9 months ago

Is the device you are connecting to advertising when you attempt to connect? If not, then it will fail since it will not be listening for connections.

flynny75 commented 9 months ago

Yes, the server is advertising. The entirety of the server code for this scenario is

        NimBLEDevice::init("NimBLE_light_sleep");
        auto bleServer = NimBLEDevice::createServer();
        auto advertising = NimBLEDevice::getAdvertising();
        auto service = bleServer->createService("1111");
        auto c = service->createCharacteristic("2222");
        c->setValue("3333");

        service->start();
        advertising->start();

There is no change in server behaviour between the delay loops and the light sleep loops

flynny75 commented 9 months ago

I am sure this used to work, so I went back through every version of the espressif32 platform. The most recent version that works is 5.1.1, 5.2.0 and onwards do not work, it never reconnects after light sleep. 5.1.1 reconnects with much more reliability (although not 100%, I assume the failed connections are an impact of default connection parameters) after light sleep.

I have uploaded a better sample that uses the neopixel to show if the connection works NimBLE_light_sleep.zip

flynny75 commented 9 months ago

Should I also open an issue in the espressif platform repo https://github.com/platformio/platform-espressif32 ?

h2zero commented 9 months ago

Yes, I would assume that if the platform change is what affected the operation in this situation that is a bug there and not here.