-
-
Notifications
You must be signed in to change notification settings - Fork 174
Properly find the remote characteristic end handle for descriptor discovery. #233
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
Conversation
Hi, calling me is welcome !! #include "NimBLEDevice.h"
static NimBLEUUID serviceUUID((uint16_t)0x1812);
void setup() {
Serial.begin(115200);
NimBLEDevice::init("");
auto pBLEScan = NimBLEDevice::getScan();
pBLEScan->setActiveScan(true);
Serial.println("wait 10 secs..");
auto pScanResults = pBLEScan->start(10);
for (int i = 0; i < pScanResults.getCount(); i++) {
auto advertisedDevice = pScanResults.getDevice(i);
if (advertisedDevice.haveServiceUUID()) {
Serial.println(advertisedDevice.toString().c_str());
auto pClient = NimBLEDevice::createClient();
if(pClient && pClient->connect(&advertisedDevice)) {
auto pService = pClient->getService(serviceUUID);
if(pService != NULL) {
Serial.println();
Serial.print("**");
Serial.println(pService->toString().c_str());
pService->getCharacteristic((uint16_t)0x2a4d);
auto pCharacteristics = pService->getCharacteristics();
for (auto pCharacteristic : *pCharacteristics) {
Serial.print("****");
Serial.println(pCharacteristic->toString().c_str());
auto pDescriptors = pCharacteristic->getDescriptors(true);
for (auto pDescriptor : *pDescriptors)
{
Serial.print("******");
Serial.println(pDescriptor->toString().c_str());
}
}
}
}
Serial.println();
}
}
if(NimBLEDevice::getClientListSize() == 0)
ESP.restart();
}
void loop() {
delay(1);
} I tested it with the above sources and it was a disappointing result.
In the middle of the sample source code auto pCharacteristics = pService->getCharacteristics(); When I changed this as below, Panic did not occur and it worked normally. auto pCharacteristics = pService->getCharacteristics(true);
I'll change the DebugLevel and explore a little more. |
Awesome, thank you for testing it. I knew there had to be a bug somewhere when it worked so easily on the first test 😄. Looking forward to anything you find in the logs. Looks like a nullptr issue that needs to be tracked down. |
When I changed DebugLevel to
|
Of course that would happen lol. Looking at the code you posted it seems somehow that the vector was empty when your code accessed it, might be a core/task switch timing issue? Hopefully I can reproduce and put a taskYIELD() in a couple places to track it down. |
I thought that the series of BLE operations was asynchronous (blocked). I wrote the code on the assumption that the results of auto pService = pClient->getService(serviceUUID);
if(pService != NULL) {
Serial.println();
Serial.print("**");
Serial.println(pService->toString().c_str());
pService->getCharacteristic((uint16_t)0x2a4d);
auto pCharacteristics = pService->getCharacteristics();
if(pCharacteristics != NULL)
for (auto pCharacteristic : *pCharacteristics) {
Serial.print("****");
Serial.println(pCharacteristic->toString().c_str());
auto pDescriptors = pCharacteristic->getDescriptors(true);
if(pDescriptors != NULL)
for (auto pDescriptor : *pDescriptors)
{
Serial.print("******");
Serial.println(pDescriptor->toString().c_str());
}
}
} When I use the master branch, it works fine without being nervous about timing. |
I'm not sure if this is the correct way to sprinkle auto pService = pClient->getService(serviceUUID);
if(pService != NULL) {
Serial.println();
Serial.print("**");
Serial.println(pService->toString().c_str());
pService->getCharacteristic((uint16_t)0x2a4d);
taskYIELD();
auto pCharacteristics = pService->getCharacteristics();
taskYIELD();
if(pCharacteristics != NULL)
for (auto pCharacteristic : *pCharacteristics) {
taskYIELD();
Serial.print("****");
Serial.println(pCharacteristic->toString().c_str());
auto pDescriptors = pCharacteristic->getDescriptors(true);
taskYIELD();
if(pDescriptors != NULL)
for (auto pDescriptor : *pDescriptors)
{
taskYIELD();
Serial.print("******");
Serial.println(pDescriptor->toString().c_str());
}
}
} |
src/NimBLERemoteCharacteristic.cpp
Outdated
} | ||
|
||
int rc = 0; | ||
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel that there are unfinished tasks in xTaskGetCurrentTaskHandle()
.
Just before this line
taskYIELD();
After adding, the Panic error no longer occurs.
However, I'm not sure if this fix is correct, and it's possible that the problem lurks on the side of getNextCharHandle()
, which is running just before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I will try to track this down today, that gives me somewhere to start.
Found the error, it's in the NimBLE core and has already been fixed upstream. I'll do some more testing and push the fix to this PR when satisfied. |
This will not be merged until the NimBLE core files are updated. To make this PR work for testing you will need to change:
to: return (criteria->matching_rx_entry != NULL);
|
It worked perfectly fine. |
You provided plenty of information to reproduce the error, thanks again! It was a simple matter from there to decode the backtrace which lead into the core files and I simply looked for any related commits upstream. |
By the way, apart from this case, I think it is a topic that should be set up as a new issue, but it does not work properly if you use the latest master branch of arduino-esp32. |
Thanks for the heads up. I haven't tested with the latest master yet, I wonder what changed that would break this. I'll look into it. |
@wakwak-koba I just updated master to the latest NimBLE core. If you could please test this PR with the arduino master and this master branch I would really appreciate it. |
…covery. Previously we used the service end handle or, if available, the handle of the next characteristic in the service as the end handle when retrieving the descriptors of a characteristic. This process would fail when connecting to some devices if the characteristics were retrieved individually instead of all together. The cause of failure was requesting a handle range that is out of characteristic scope which is also out of line with BLE specifications. The fix included in this is to set the end handles of the characteristics either after retrieving all the characteristics in a service by using the next charactertistic definition handle or, if the characteristic was retrieved separately, we retrieve the next characteristic just before retrieving the descriptors.
1a9f16a
to
c467231
Compare
I tested it on my device, but I haven't found any problems in combination with the master branch of arduino-esp32 ! |
Great, thanks for testing it 😄 . I did quite a bit of testing as well and found no issues. If you find something isn't working please post an issue. |
Previously we used the service end handle or, if available, the handle of the next characteristic in the service
as the end handle when retrieving the descriptors of a characteristic. This process would fail when connecting to some
devices if the characteristics were retrieved individually instead of all together. The cause of failure was requesting
a handle range that is out of characteristic scope which is also out of line with BLE
specifications.
The fix included in this is to set the end handles of the characteristics either after retrieving all the characteristics
in a service by using the next charactertistic definition handle or, if the characteristic was retrieved separately,
we retrieve the next characteristic just before retrieving the descriptors.
@wakwak-koba I'd be grateful if you could test this against the device that exposed this issue in #170