Description
I have a class that wraps the BLE stuff in order to connect to a HM10 bluetooth device. This is the way it works:
- creates a BLEClient
- scans 3 seconds for HM10 BLE devices
- if no device is found, it waits 10 seconds and restarts the scan
- if the device is found, it connects to it using the created BLEClient from step 1
- when the device is disconnected (due to powering off the HM10 module or other reasons), it will re-start scanning
- if the device is found again, it reuses the BLEClient instance to reconnect
It works great but I think I found one bug: upon a disconnect (due to HM10 being turned off), a scan starts. When I turn the HM10 module on, the scan discovers it and it attempts to establish a new connection using pClient->connect(deviceAddress)
.
At this point sometimes the connect call fails. What is interesting is the order of the events: BLEClient::connect
takes the m_semaphoreRegEvt
semaphore and registers the new app using esp_ble_gattc_app_register
. That works fine, then the m_semaphoreRegEvt
is given back inside the handling of the ESP_GATTC_REG_EVT
event. Next the m_semaphoreOpenEvt
semaphore is taken and esp_ble_gattc_open
is called. Ideally this should work and the m_semaphoreOpenEvt
should be given back when handling ESP_GATTC_OPEN_EVT
event.
However, what I found is that occasionally the ESP_GATTC_OPEN_EVT
event never fires, and instead the ESP_GATTC_DISCONNECT_EVT
fires. Handling the ESP_GATTC_DISCONNECT_EVT
event gives back the m_semaphoreRssiCmplEvt
and m_semaphoreSearchCmplEvt
semaphores, but not the m_semaphoreOpenEvt
one that was taken by the connect
method in the BLEClient
.
This means the BLEClient::connect
hangs forever waiting for uint32_t rc = m_semaphoreOpenEvt.wait("connect");
- https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEClient.cpp#L132
Because my call to BLEClient::connect
never returns, my class that wraps everything stops working and will never re-scan or handle this.
I am looking into a fix, I think that https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEClient.cpp#L178 should give the m_semaphoreOpenEvt
semaphore as well.
Here are the logs when the above happens (The HM10Client is my class):
[D][BLEScan.cpp:106] handleGAPEvent(): Ignoring 63:04:e2:60:c1:8b, already seen it.
[D][BLEClient.cpp:464] handleGAPEvent(): BLEClient ... handling GAP event!
[D][BLEScan.cpp:106] handleGAPEvent(): Ignoring 63:04:e2:60:c1:8b, already seen it.
[D][BLEClient.cpp:464] handleGAPEvent(): BLEClient ... handling GAP event!
[D][BLEAdvertisedDevice.cpp:424] setRSSI(): - setRSSI(): rssi: -80
[D][BLEAdvertisedDevice.cpp:253] parseAdvertisement(): Type: 0x01 (), length: 1, data: 06
[D][BLEAdvertisedDevice.cpp:253] parseAdvertisement(): Type: 0x02 (), length: 2, data: e0ff
[D][BLEAdvertisedDevice.cpp:453] setServiceUUID(): - addServiceUUID(): serviceUUID: 0000ffe0-0000-1000-8000-00805f9b34fb
[D][HM10Client.cpp:79] onResult(): BLE Advertised Device found: Name: , Address: 00:15:83:10:54:12, serviceUUID: 0000ffe0-0000-1000-8000-00805f9b34fb
[D][HM10Client.cpp:81] onResult(): Found what looks like an HM10 device, stopping scan
[D][BLEScan.cpp:259] stop(): >> stop()
[D][BLEScan.cpp:271] stop(): << stop()
[D][HM10Client.cpp:40] connect(): Starting connection
[D][BLEClient.cpp:103] connect(): >> connect(00:15:83:10:54:12)
[I][BLEDevice.cpp:596] addPeerDevice(): add conn_id: 0, GATT role: client
[D][FreeRTOS.cpp:165] take(): Semaphore taking: name: RegEvt (0x3ffd47ac), owner: <N/A> for connect
[D][BLEClient.cpp:464] handleGAPEvent(): BLEClient ... handling GAP event!
[D][FreeRTOS.cpp:174] take(): Semaphore taken: name: RegEvt (0x3ffd47ac), owner: connect
[D][BLEDevice.cpp:150] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEClient.cpp:165] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][FreeRTOS.cpp:165] take(): Semaphore taking: name: OpenEvt (0x3ffd480c), owner: <N/A> for connect
[D][FreeRTOS.cpp:174] take(): Semaphore taken: name: OpenEvt (0x3ffd480c), owner: connect
[D][BLEDevice.cpp:150] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEClient.cpp:165] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][HM10Client.cpp:95] onDisconnect(): Disconnected
[I][BLEDevice.cpp:607] removePeerDevice(): remove: 0, GATT role client
[D][BLEDevice.cpp:150] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEDevice.cpp:150] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][main.ino:50] loop(): Loop task running
[D][main.ino:50] loop(): Loop task running
[D][main.ino:50] loop(): Loop task running
[D][main.ino:50] loop(): Loop task running
[D][main.ino:50] loop(): Loop task running
[D][main.ino:50] loop(): Loop task running
You can see how scan finds the device, it stops the scan and then it attempts to connect. However, due to ::connect
never returning, it blocks everything.
This failure to connect only happens occasionally, in 50% of the time with my hm10 module. I'm not sure why it can't connect but in the log you can see that ESP_GATTC_DISCONNECT_EVT
event is fired because i have a callback on it that actually gets called ([D][HM10Client.cpp:95] onDisconnect(): Disconnected
).