Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can registerForNotify() fail? #1032

Open
CLDiego opened this issue Dec 15, 2020 · 13 comments
Open

Can registerForNotify() fail? #1032

CLDiego opened this issue Dec 15, 2020 · 13 comments

Comments

@CLDiego
Copy link

CLDiego commented Dec 15, 2020

Hi I'm trying to develop a BLE + WiFi (MQTT) application, and I'm having a bit of trouble with notifications/indications at the moment.

What my code does is to scan for my BLE servers (RN4871 modules), create a list of the available servers, send such list to an MQTT broker and then the user sends back a command to connect to a specific BLE server. Once connected the esp32 client looks at the services, gets a specific server, gets its characteristics, gets its descriptor, registers for indications from the BLE server, gathers the data and sends it back to the MQTT broker. This process is repeated every 2 minutes.

My idea is to let these devices connected at all times, the problem comes when at some point the esp32 will find the device, the service, the characteristic and register for indications but then the callback is never called.... I've been only able to run the whole thing for 1-2 hours non-stop until this error happens.

I'm using platformio at the moment with the arduino-esp32 framework (I'm assuming it's pulling the latest stable release of this package), and I've looked at most of the similar issues in this repo and in the https://github.com/espressif/arduino-esp32 repo.

I learned a lot on how to enhance my code to avoid some memory leaks that I had, but I've trying to solve this issue without stopping for at least two weeks, and still haven't got anywhere. At the moment is hard for me to debug as for some reason the verbose mode crashes the esp32.

I've noticed that the sometimes depending on my setInterval and setWindow values for the scan, the program can work without stopping for 3 hours (but it might be my imagination).

I've also got to the point of restarting all of my devices once I gather the data just to be sure that they always start fresh. In the esp32 I unregister from the notifications using registerForNotify(nullptr), then I disconnect, I call BLEDevice::deinit() and kill my BLE task, and then force the watchdog timer to restart the esp32. I've also tried deleting the pClient but it often causes a heap error.

Does anyone can give me an idea of what to try next? Is there a reason for the registerForNotify() method to fail?

I'm happy to share some code (I just need to tidy it up).

@chegewara
Copy link
Collaborator

Hi,
this is very good observation, because you are using wifi at the same time and radio is shared, so its good to set interval much longer than window (or the other way, i never remeber that):

I've noticed that the sometimes depending on my setInterval and setWindow values for the scan, the program can work without stopping for 3 hours (but it might be my imagination).

you shouldnt have to delete pClient in your code because library should do it, thus heap corruption.

My advice is to add custom callbacks which was intended for debugging purpose mostly, and maybe when you call register for notify you could add small delay before it or read descriptor 2902 on that remote characteristic to make sure value is not 0.

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

Hi @chegewara,

thanks for the suggestions! I tried both adding a delay and reading the descriptor. Reading the descriptor would always freeze my code.

Then I added this to my code espressif/arduino-esp32#4464 and with it my code doesn't hang when reading the descriptor. However, reading the descriptor always returns a blank space (I assume that the ascii code would be 0x20) even when the indications fail. This is what I tried:

    desc =  pMyCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902));  
    Serial.println(desc->readValue().c_str());
    delay(500);

    pMyCharacteristic->registerForNotify(notifyCallback, false);
    Serial.println(desc->readValue().c_str());

Am I missing something when reading the descriptor?

UPDATE
Instead of printing the descriptor value with desc->readValue().c_str() I changed it to print the length of it desc->readValue().length(). I get 0 before writing to it, but after the register for notify I get blank, not even a 0.

@chegewara
Copy link
Collaborator

Serial.println(desc->readValue().c_str());
into
Serial.printf("0x02x\n", desc->readValue().c_str());

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

I changed the line Serial.printf("0x%02x\n", desc->readValue().c_str());

Before register for notify the value I get from the descriptor is : 0x3ffcde9c, but once I set up the notifications it returns a blank space.

@chegewara
Copy link
Collaborator

Ok, my bad, sorry.
Its expecting hex value, but c_str() returns string.
Serial.printf("value: %s\n", desc->readValue().c_str());

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

No worries, with Serial.printf("value: %s\n", desc->readValue().c_str());

I get:
value:

for both before and after registering the notification. This is one of the reasons I'm not sure if the issue is on the client's side or the server side.

@chegewara
Copy link
Collaborator

Then maybe there is no descriptor 2902 on peer device (very unlikely) or you have some other issue with code.
For sure its better to use this instead of readValue since value is in range 0 and 2 (not printable):
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLERemoteDescriptor.h#L31
Serial.printf("0x02x\n", desc->readUInt16());

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

That makes sense. Now I get 0x00 before registering the notification as it is expected. But after the registration I still get 0x00 even though the notification callback gets triggered.

The 2902 descriptor seems to be in place, this is the characteristic that I'm using:
20201216_175416.jpg

@chegewara
Copy link
Collaborator

Then my suggestion is to add extra call to write 0x01 or 0x02 to that descriptor after register for notification.

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

I've added the write and a delay before reading the descriptor value again, but nonetheless I still receive 0x00.

Despite, that the notification callback gets triggered.

I've a custom board with the RN4871 as the BLE server, and once a BLE client (esp32) sets the notification/indication an LED starts blinking in my custom board.

Even when I get the problem of the notification callbacks not triggering, I see that the client has successfully set the notification/indication because of the LED.

It is weird to me because the problem seems to happen at random, sometimes my program will successfully connect and get the data out and it will be able to repeat the same process for another 20-30 times, and sometimes the callback doesn't trigger.

@chegewara
Copy link
Collaborator

Its really hard to say with random problems. Thats why best option is to add custom GATTC callback and check all events. I know its not easy to check all events, but this is what i would do.

@CLDiego
Copy link
Author

CLDiego commented Dec 16, 2020

Well I must admit that I haven't coded any custom GATTC callback, could you point me to any resource that could help me get started?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants