arduino-libraries / ArduinoBLE

ArduinoBLE library for Arduino
GNU Lesser General Public License v2.1
314 stars 205 forks source link

ESP32: BLEDevice::discoverService(SERVICE_UUID) made ESP crash because runs out of memory #255

Open vsantele opened 2 years ago

vsantele commented 2 years ago

Hi,

Since ArduinoBLE is compatible with ESP32 with the latest merge, I'm trying to use it with an ESP32.

But when I run the example "PeripheralExplorer.ino", I got this exception: (I update the code to detect a peripheral with localName = "D1533286" instead of "Led")

Found 00:a0:50:61:87:06 'D1533286' 00035b03-58e6-07dd-021a-08123a000300
Connecting ...
Connected
Discovering attributes ...
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x400904c5  PS      : 0x00060030  A0      : 0x800d5c70  A1      : 0x3ffc6980  
A2      : 0x00000000  A3      : 0xfffffffc  A4      : 0x000000ff  A5      : 0x0000ff00  
A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x00000000  A9      : 0x3ffc6aa0  
A10     : 0x3ffbcadc  A11     : 0x00001800  A12     : 0x00000010  A13     : 0x3ffc29f4  
A14     : 0x3ffc6940  A15     : 0x3ffc6950  SAR     : 0x0000000f  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x400904c5  LEND    : 0x400904d5  LCOUNT  : 0xffffffff  

Backtrace:0x400904c2:0x3ffc69800x400d5c6d:0x3ffc6990 0x400d4ddf:0x3ffc69c0 0x400d3c81:0x3ffc6b20 0x400d22cb:0x3ffc6b50 0x400d16cd:0x3ffc6b70 0x400d1962:0x3ffc6bc0 0x400d99a1:0x3ffc6c80 

ELF file SHA256: 0000000000000000

I don't understand why this exception occurred.

Here is my code: ```cpp /* Peripheral Explorer This example scans for Bluetooth® Low Energy peripherals until one with a particular name ("LED") is found. Then connects, and discovers + prints all the peripheral's attributes. The circuit: - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT, Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board. You can use it with another board that is compatible with this library and the Peripherals -> LED example. This example code is in the public domain. */ #include void setup() { Serial.begin(9600); while (!Serial) ; // begin initialization if (!BLE.begin()) { Serial.println("starting Bluetooth® Low Energy module failed!"); while (1) ; } Serial.println("Bluetooth® Low Energy Central - Peripheral Explorer"); // start scanning for peripherals BLE.scan(); } void loop() { // check if a peripheral has been discovered BLEDevice peripheral = BLE.available(); if (peripheral) { // discovered a peripheral, print out address, local name, and advertised service Serial.print("Found "); Serial.print(peripheral.address()); Serial.print(" '"); Serial.print(peripheral.localName()); Serial.print("' "); Serial.print(peripheral.advertisedServiceUuid()); Serial.println(); // see if peripheral is a LED if (peripheral.localName() == "D1533286") { // stop scanning BLE.stopScan(); explorerPeripheral(peripheral); // peripheral disconnected, we are done while (1) { // do nothing } } } } void explorerPeripheral(BLEDevice peripheral) { // connect to the peripheral Serial.println("Connecting ..."); if (peripheral.connect()) { Serial.println("Connected"); } else { Serial.println("Failed to connect!"); return; } // discover peripheral attributes Serial.println("Discovering attributes ..."); if (peripheral.discoverAttributes()) { Serial.println("Attributes discovered"); } else { Serial.println("Attribute discovery failed!"); peripheral.disconnect(); return; } // read and print device name of peripheral Serial.println(); Serial.print("Device name: "); Serial.println(peripheral.deviceName()); Serial.print("Appearance: 0x"); Serial.println(peripheral.appearance(), HEX); Serial.println(); // loop the services of the peripheral and explore each for (int i = 0; i < peripheral.serviceCount(); i++) { BLEService service = peripheral.service(i); exploreService(service); } Serial.println(); // we are done exploring, disconnect Serial.println("Disconnecting ..."); peripheral.disconnect(); Serial.println("Disconnected"); } void exploreService(BLEService service) { // print the UUID of the service Serial.print("Service "); Serial.println(service.uuid()); // loop the characteristics of the service and explore each for (int i = 0; i < service.characteristicCount(); i++) { BLECharacteristic characteristic = service.characteristic(i); exploreCharacteristic(characteristic); } } void exploreCharacteristic(BLECharacteristic characteristic) { // print the UUID and properties of the characteristic Serial.print("\tCharacteristic "); Serial.print(characteristic.uuid()); Serial.print(", properties 0x"); Serial.print(characteristic.properties(), HEX); // check if the characteristic is readable if (characteristic.canRead()) { // read the characteristic value characteristic.read(); if (characteristic.valueLength() > 0) { // print out the value of the characteristic Serial.print(", value 0x"); printData(characteristic.value(), characteristic.valueLength()); } } Serial.println(); // loop the descriptors of the characteristic and explore each for (int i = 0; i < characteristic.descriptorCount(); i++) { BLEDescriptor descriptor = characteristic.descriptor(i); exploreDescriptor(descriptor); } } void exploreDescriptor(BLEDescriptor descriptor) { // print the UUID of the descriptor Serial.print("\t\tDescriptor "); Serial.print(descriptor.uuid()); // read the descriptor value descriptor.read(); // print out the value of the descriptor Serial.print(", value 0x"); printData(descriptor.value(), descriptor.valueLength()); Serial.println(); } void printData(const unsigned char data[], int length) { for (int i = 0; i < length; i++) { unsigned char b = data[i]; if (b < 16) { Serial.print("0"); } Serial.print(b, HEX); } } ```

Thanks

UPDATE 2022-08-31

BLEDevice::discoverService crashes when ATTClass::discoverAttributes discovers descriptors with ATTClass::discoverDescriptors.

The while loop inside ATTClass::discoverDescriptors is never stopped and reads the descriptors in a loop until the ESP has no more memory.

I found that for my device there are only 16 descriptors, so I managed to make my program work by stopping the loop after 16 iterations, but I don't understand why the condition if (responseBuffer[0] == ATT_OP_FIND_INFO_RESP) { is always true.

mylosvai commented 2 years ago

I'm getting the same error with .discoverAttributes(), however if I call .discoverService("uuid here") and pass in my service uuid instead it does not crash and lets me connect.

  //if (peripheral.discoverAttributes()) {   //causes an error on ESP32
    if (peripheral.discoverService(SERVICE_ATT)) {  //works fine on ESP32

I'm not sure what effect this will have down the line, but happy to see ESP32 support is being actively worked on

vsantele commented 2 years ago

Thanks for your comment! So, with your method, you can access to the characteristics of the device?

I will test that tomorrow!

mylosvai commented 2 years ago

Yes so far everything else in the BLE sample is working on the ESP32. (I'm using the LED control sample as a starting point).

vsantele commented 2 years ago

When I use peripheral.discoverService("my-service-uuid"), the ESP crashes too. Here is the backtrace:

Decoding stack results
0x400836a5: panic_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/panic.c line 402
0x40092149: esp_system_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp_system/esp_system.c line 128
0x400975c5: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/abort.c line 46
0x40102f93: __cxxabiv1::__terminate(void (*)()) at /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-esp32-elf/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc line 47
0x40102fda: std::terminate() at /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-esp32-elf/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc line 57
0x40102a79: __cxxabiv1::__cxa_allocate_exception(std::size_t) at /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-esp32-elf/src/gcc/libstdc++-v3/libsupc++/eh_alloc.cc line 300
0x401028b0: operator new(unsigned int) at /builds/idf/crosstool-NG/.build/HOST-i686-w64-mingw32/xtensa-esp32-elf/src/gcc/libstdc++-v3/libsupc++/new_op.cc line 54
0x400d5121: ATTClass::discoverDescriptors(unsigned short, BLERemoteDevice*) at C:\Users\victo\Documents\Arduino\libraries\ArduinoBLE\src\utility\ATT.cpp line 1738
0x400d3cab: ATTClass::discoverAttributes(unsigned char, unsigned char*, char const*) at C:\Users\victo\Documents\Arduino\libraries\ArduinoBLE\src\utility\ATT.cpp line 217
0x400d22d3: BLEDevice::discoverService(char const*) at C:\Users\victo\Documents\Arduino\libraries\ArduinoBLE\src\BLEDevice.cpp line 274
0x400d16d5: explorerPeripheral(BLEDevice) at C:\Users\victo\Documents\Arduino\generated_examples\PeripheralExplorer_3/PeripheralExplorer_3.ino line 90
0x400d196a: loop() at C:\Users\victo\Documents\Arduino\libraries\ArduinoBLE\src/BLEDevice.h line 39
0x400d93a1: loopTask(void*) at C:\Users\victo\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.4\cores\esp32\main.cpp line 50

The problem occurs when the function ATTClass::discoverDecriptors creates a new BLERemoteDescriptor. But I don't know why.

vsantele commented 2 years ago

After some researches, I found out that the problem occurs because of an infinite loop in the function bool ATTClass::discoverDescriptors(uint16_t connectionHandle, BLERemoteDevice* device) in src/utility/ATT.cpp

The program finds descriptors but loop to them until the ESP runs out of memory. I manage to fix this temporary with a counter that stop the loop after 16 iterations, but I suppose there is a bug hidden somewhere that prevents the condition if (responseBuffer[0] == ATT_OP_FIND_INFO_RESP) { from being false.

fpistm commented 2 years ago

Maybe linked to https://github.com/arduino-libraries/ArduinoBLE/pull/259 ?

vsantele commented 2 years ago

Maybe #259 fixed peripheral.discoverAttributes() but there is a problem after. I will rename the issue to be more accurate.