Skip to content

BLEClient heap memory exhausted after some disconnect/connect ricycle #786

Closed
@qrpfun

Description

@qrpfun

Hi all,
I'm actually using official Arduino ESP32 library available from inside the Arduino IDE.
I need to connect via BT from an ESP32 to a peripheral made with an HC-08 connected to an arduino micro, all configured to sleep as much as possible to save energy (about 300uA in sleep), than read/write some info from there and close connection to get peripheral back in sleep mode, than reconnect only once needed and cycle this way over and over.

I'have started with BLE Client examples in the lib distribution but after some cycles everything crashes. After some debugging find out a problem with a heap memory exhaustion.

Just tried to do some research and some debugging but I would appreciate if someone would be so kind to get me some tips to find a way out from here.

this is the output from very first cycles where you can see rapid memory exhaustion:

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4
BLE FreeHeap: 274408
Starting Arduino BLE Client application...
BLE Advertised Device found: Name: HC-08, Address: 88:4a:ea:8e:38:5d, manufacturer data: 48432d30380000000000000000000000000000000000, serviceUUID: 0000fff0-0000-1000-8000-00805f9b34fb, txPower: -6
BLE RSSI: -65
Forming a connection to 88:4a:ea:8e:38:5d
1-BLE FreeHeap: 181876
 - Created client
2-BLE FreeHeap: 181148
 - Connected to server
3-BLE FreeHeap: 177004
 - Found our service
4-BLE FreeHeap: 172504
 - Found our characteristic
5-BLE FreeHeap: 171076
We are now connected to the BLE Server.
Setting new characteristic value to "Time since boot: 2"
BLE FreeHeap: 171024
onDisconnect
BLE Advertised Device found: Name: HC-08, Address: 88:4a:ea:8e:38:5d, manufacturer data: 48432d30380000000000000000000000000000000000, serviceUUID: 0000fff0-0000-1000-8000-00805f9b34fb, txPower: -6
BLE RSSI: -66
Forming a connection to 88:4a:ea:8e:38:5d
1-BLE FreeHeap: 177236
 - Created client
2-BLE FreeHeap: 176508
 - Connected to server
3-BLE FreeHeap: 172360
 - Found our service
4-BLE FreeHeap: 167972
 - Found our characteristic
5-BLE FreeHeap: 166544
We are now connected to the BLE Server.
Setting new characteristic value to "Time since boot: 10"
BLE FreeHeap: 166492
....

and here the modified BLEClient.ino code:

/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("0000fff0-0000-1000-8000-00805f9b34fb");
static BLEUUID serviceIn_UUID("0000ffe0-0000-1000-8000-00805f9b34fb");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("0000ffe1-0000-1000-8000-00805f9b34fb");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
static BLEClient*  pClient;
static BLERemoteService* pRemoteService;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.print("Notify callback for characteristic ");
    Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
//    free(pClient);
//    free(pRemoteService);
//    free(pRemoteCharacteristic);
//    delete(myDevice);
//    delete pClient; //crash
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());

    Serial.print("1-BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
    //BLEClient*  pClient  = BLEDevice::createClient();
    pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    Serial.print("2-BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");

    Serial.print("3-BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
    // Obtain a reference to the service we are after in the remote BLE server.
    //BLERemoteService* pRemoteService = pClient->getService(serviceIn_UUID);
    
    pRemoteService = pClient->getService(serviceIn_UUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");

    Serial.print("4-BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    Serial.print("5-BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
//    // BIG CRASH HERE - Read the value of the characteristic.
//    if(pRemoteCharacteristic->canRead()) {
//      std::string value = pRemoteCharacteristic->readValue();
//      Serial.print("The characteristic value was: ");
//      Serial.println(value.c_str());
//    }
//    if(pRemoteCharacteristic->canNotify())
//      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
    return true;
}
/**
 * Scan for BLE servers and find the first one that advertises the service we are looking for.
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());
    Serial.print("BLE RSSI: ");
    Serial.println(advertisedDevice.getRSSI() );

    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


void setup() {
  Serial.begin(115200);
  Serial.print("BLE FreeHeap: ");
  Serial.println(ESP.getFreeHeap());
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // End of setup.


// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    String newValue = "Time since boot: " + String(millis()/1000);
    Serial.println("Setting new characteristic value to \"" + newValue + "\"");
    Serial.print("BLE FreeHeap: ");
    Serial.println(ESP.getFreeHeap());
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    //pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
    pRemoteCharacteristic->writeValue("LedOn", 5);
    delay(1000);
    pRemoteCharacteristic->writeValue("LedOn", 5);
    delay(2000);
    pRemoteCharacteristic->writeValue("LedOff", 6);
    delay(2000);
    pClient->disconnect();
    doConnect = false;
    
  }else if(doScan){
    BLEDevice::getScan()->start(0);  // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions