nkolban / esp32-snippets

Sample ESP32 snippets and code fragments
https://leanpub.com/kolban-ESP32
Apache License 2.0
2.37k stars 710 forks source link

assertion "head != NULL" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/multi_heap_poisoning.c", line 214, function: multi_heap_freeHi, #860

Open ASL07 opened 5 years ago

ASL07 commented 5 years ago

Hi

I am using your library to read data from the Xiaomi Temperature sensor.

My ESP32 board is crashing very frequently showing this error: assertion "head != NULL" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/multi_heap_poisoning.c", line 214, function: multi_heap_free

When I decode de the backtrace I get:

Exception Cause: Not found

0x4008d908: invoke_abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c:707
0x4008db39: abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c:707
0x40149cb7: __assert_func at /Users/ivan/e/newlib_xtensa-2.2.0-bin/newlib_xtensa-2.2.0/xtensa-esp32-elf/newlib/libc/stdlib/../../../.././newlib/libc/stdlib/assert.c:63 (discriminator 8)
0x40093065: multi_heap_free at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/multi_heap_poisoning.c:315
0x40084556: heap_caps_free at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/heap_caps.c:269
0x4008a289: _free_r at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/newlib/syscalls.c:42
0x4000bec7: ?? ??:0
0x40173321: operator delete(void*) at /Volumes/build/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/del_op.cc:46
0x40185f96: __gnu_cxx::new_allocator<char>::deallocate(char*, unsigned int) at /Volumes/build/idf/crosstool-NG/.build/xtensa-esp32-elf/build/build-cc-gcc-final/xtensa-esp32-elf/libstdc++-v3/include/bits/basic_string.h:2200
 (inlined by) std::allocator_traits<std::allocator<char> >::deallocate(std::allocator<char>&, char*, unsigned int) at /Volumes/build/idf/crosstool-NG/.build/xtensa-esp32-elf/build/build-cc-gcc-final/xtensa-esp32-elf/libstdc++-v3/include/bits/alloc_traits.h:386
 (inlined by) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(unsigned int) at /Volumes/build/idf/crosstool-NG/.build/xtensa-esp32-elf/build/build-cc-gcc-final/xtensa-esp32-elf/libstdc++-v3/include/bits/basic_string.h:185
 (inlined by) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose() at /Volumes/build/idf/crosstool-NG/.build/xtensa-esp32-elf/build/build-cc-gcc-final/xtensa-esp32-elf/libstdc++-v3/include/bits/basic_string.h:180
0x400d588a: FreeRTOS::Semaphore::give() at ??:?
0x400d3024: BLERemoteCharacteristic::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at ??:?
0x400d3a59: BLERemoteService::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at ??:?
0x400d2555: BLEClient::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at ??:?
0x400d2e51: BLEDevice::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at ??:?
0x400e269c: btc_gattc_cb_to_app at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c:596
 (inlined by) btc_gattc_reg_for_notify at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c:678
0x400e29cf: btc_gattc_call_handler at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c:743
0x400deb05: btc_task at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/bt/bluedroid/btc/core/btc_task.c:107
0x4009257d: vPortTaskWrapper at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/port.c:355 (discriminator 1)

It seems to happen when calling void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications)

I checked for memory leaks using xPortGetFreeHeapSize() and there seems to be none.

Can you help me debugging this issue in more detail?

Here is my .ino file

#include "BLEDevice.h"                                                                                       // As a starting point we get a class "BLEDevive" that consists of some Bluetooth Low Energy (LE) functions.  https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEDevice.h 
static BLEAddress *sensorAddress;                                                                  // To be able to take a connection to a BLE (server) device, one must know the 6 byte long address of that BLE device. Here we will mostly use a pointer (the * marking here) to the memory location where that address is saved.
BLERemoteService* remoteService;                                                             // Here we create a model of a services that are offered to us by the remote BLE server that we are connected to. 
static BLERemoteCharacteristic* remoteCharacteristic;                              // A service (mentioned the previous line) always contains one or more BLE variable (that are called a characteristic). Here we create a model for such characteristics.
BLERemoteDescriptor* remoteDescriptor;                          // A descriptor of a charasteristic (that was mentioned at the previous line) contains information on how to use or modify that characteristic. For instance the existence of the descriptor 0x2902 in the middle of the "readTempAsString" function tells us how to get automatic broadcasts that contain notifications of the value of the temperature-measurement-value-characteristic.
BLEClient*  bleClient;                                                                  // At teh previous lines we modelled the services that a BLE server offers. At this line we create a model of our ESP32 BLE client that is using those services.
String receivedTemperature = ""; 
std::string temperaturestring = "";
unsigned long startTime; // The string variable will contain the latest temperature measurement value that is received from the Xiaomi BLE thermometer. The other one is a timestamp.

#define LEVEL_DEBUG 0
#define DEBUG_LEVEL_BLE 1

std::string sensorAddressString = "4C:65:A8:D4:13:78";

/*
class bleEvents: public BLEAdvertisedDeviceCallbacks 
{                    
  void onResult(BLEAdvertisedDevice advertisedDevice)   // onResult() is called every time a device is found
  {                                                    
    if (advertisedDevice.getName() == "MJ_HT_V1")       // Found device, save address to sensorAddress and stop scanning
    {                                                          
      advertisedDevice.getScan()->stop();                   
      sensorAddress = new BLEAddress(advertisedDevice.getAddress()); 
    } 
  } 
};                       
*/

/**
 * Called every time a notification arrives
 */ 
static void notifyNewTemperature(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* receivedNotification, size_t length, bool isNotify)  
{ 
    if (receivedTemperature.length() >= 4) return;    
    // The notification of this particular thermometer happens to be an ASCII coded series of characters that is in a nicely readable format like "T=22.6 H=32.2�" 
    for (int i=0; i<length; i++) Serial.print((char)*(receivedNotification+i)); 
    Serial.println("");
    // The notification happens to be an ASCII coded series of characters in nicely readable format like "T=22.6 H=32.2�"
    for (int i=2; i<=5; i++) receivedTemperature += (char)*(receivedNotification+i); 
}                                                                           

String readTempAsString(void) 
{
  if (bleClient->isConnected() == false) // Connect
  {
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Connecting client");

    bleClient->disconnect(); 
    delay(20); 
    bleClient->connect(*sensorAddress); 
    startTime = millis(); 
  } 
  if( bleClient->isConnected() == false ) // Return an error 
  {
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("e4 Connection couln't be established");

    return "e4 Connection couln't be established";
  }                                                                                                
  if (remoteService == nullptr) // Get the service
  { 
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Getting service");

    remoteService = bleClient->getService("226c0000-6476-4566-7562-66734470666d"); 
  }                                            
  if (remoteService == nullptr) // Return an error and disconnect
  {
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Could not get service");

    bleClient->disconnect(); 
    return "e6 ERROR Found the thermometer, but failed to find the needed service. Try again later.";
  }                  
  if (remoteCharacteristic == nullptr) // Get characteristic
  { 
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("GEtting characteristic");

    remoteCharacteristic = remoteService->getCharacteristic("226caa55-6476-4566-7562-66734470666d"); 
  }   
  if (remoteCharacteristic == nullptr) // Disconnect and return an error
  {
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Could not get characteristic");

    bleClient->disconnect();
    return "e8 ERROR Found the thermometer and its service, but failed to find the neede characteristic. Try again later.";
  } 
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Registering");

  remoteCharacteristic->registerForNotify(notifyNewTemperature); 
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Registered");

  if (remoteDescriptor == nullptr) // Get descriptor
  { 
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Getting descriptor");

    remoteDescriptor = remoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902));
  }                                                                                
  if (remoteDescriptor == nullptr) // Disconnect and return an error
  {
    if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Could not get descriptor");

    bleClient->disconnect(); 
    return "e10 ERROR Found the thermometer, its service and its charasteristic, but failed to find othe needed descriptor at UUID = 0x2902. Try again later.";
  } 
  receivedTemperature = "";
  uint8_t startNotifications[2] = {0x01,0x00};
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Writing value on");

  if (remoteDescriptor != nullptr && bleClient->isConnected()) remoteDescriptor->writeValue(startNotifications, 2, false);      
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Wrote value on");

  startTime = millis(); 
  while( ( (millis() - startTime) < 5000) && (receivedTemperature.length() < 4) ) 
  { 
    if (bleClient->isConnected() == false) 
    {
      if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Lost connection");

      return "e12 ERROR After succesfully done all the setup we unexpectidly lost the connection. Try moving the thermometer closer to the ESP32.";
    }
  } // https://github.com/nkolban/esp32-snippets/issues/228  https://github.com/nkolban/esp32-snippets/issues/228  https://forum.arduino.cc/index.php?topic=122413.0
  remoteCharacteristic->registerForNotify(NULL);                               // Stop reacting to futher notifications...
  uint8_t endNotifications[2] = {0x00,0x00}; 
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Writing value off");

  if (remoteDescriptor != nullptr && bleClient->isConnected()) remoteDescriptor->writeValue(endNotifications, 2, false);                    // ...and ask the thermometer to stop sending notifications
  if(DEBUG_LEVEL_BLE <= LEVEL_DEBUG) Serial.println("Wrote value off");

  if (receivedTemperature.length() < 4) return "e14 No proper temperature measurement value catched.";
  return receivedTemperature; }

//  ****************************************************************************************
//  *********     PUT YOUR LIBRARIES AND GLOBAL VARIABLES HERE.  FOR INSTANCE :    *********
//  ****************************************************************************************
// Uncomment the next two lines (and declare the GPIO pins for SCL, SDA and RESET) if your ESP32 has an I2C SSD1306 128x64 OLED display:
// #include <U8g2lib.h> // To use this library you must download it by choosing at your Arduino IDE: Sketch -> Include Libraries -> Manage Libraries -> Search for "ESP32 SSD1306" -> choose "ESP8266 and ESP32 Oled Driver for SSD1306 display" -> Instal -> Close
// U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*SCL*/ 15, /*SDA*/ 4, /*RESET*/ 16); bool iso=true; // https://yoursunny.com/t/2018/happy-new-year-2018/

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(0);
  BLEDevice::init("OptionalTheNameOfTheBleEnvironmentAtOurEsp32");                                // This first BLEDevice function initializes the ESP32's local Bluetooth LE environment.
  /*
  BLEScan* myBLEScanner = BLEDevice::getScan();                                                   // And this BLEDevice function generates a tool "myBLEScanner" that we use later for searching for other Bluetooth LE devices.  https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEScan.h
  myBLEScanner->setAdvertisedDeviceCallbacks(new bleEvents()); // There are some "bleEvents()" , especially those that inform us each time when we a new Bluetooth LE device is detected. 
  myBLEScanner->setActiveScan(true);                                                              // Active scanning
  while (sensorAddress == nullptr) {
    myBLEScanner->start(30); startTime=millis();                                                  // Here we start the scan to run for 30 seconds (and blocks the program for those seconds). It returns an object that contains the information about each unique device found.
    while ( (millis()-startTime <50) && (sensorAddress == nullptr) ) { delay(1); } }    // The start-command should be a blocking call, but in my tests the address got always established only about 10ms after that call (that is << 50ms).
  */
  sensorAddress = new BLEAddress(sensorAddressString); 
  bleClient = BLEDevice::createClient();                                     // A BLE Client is medelled as the BLEClient class. Here we create an (yet unconnected) instance of that class.

  //  *************************************************************************************
  //  *********    PUT YOUR OWN SETUP CODE HERE, TO RUN ONCE.  FOR INSTANCE :     *********
  //  *************************************************************************************
  // Uncomment the next line if your ESP32 is conected to an I2C SSD1306 128x64 OLED display:
  // u8g2.begin(); // https://github.com/olikraus/u8g2/wiki/fntlistall#54-pixel-height
}

void loop() {
  //  ************************************************************************************************
  //  *********      PUT YOUR OWN MAIN CODE HERE, TO BE RUN REPEATEDLY.  FOR INSTANCE :      *********
  //  ************************************************************************************************

  readTempAsString();
  //Serial.printf("\n\r  =====>  New temperature value: %s deg C", readTempAsString());
  // For an OLED display uncomment the next line (if your ESP32 is conected to an I2C SSD1306 128x64 OLED display):
  // if (iso == true) {u8g2.setFont(u8g2_font_logisoso54_tf); iso=false;} else {u8g2.setFont(u8g2_font_osb41_tf); iso=true;} char currentTemperature[5]; readTempAsString().toCharArray(currentTemperature, 5);  u8g2.clearBuffer(); u8g2.drawStr(0, 60, currentTemperature); u8g2.sendBuffer(); // https://robotzero.one/heltec-wifi-kit-32/  // https://github.com/olikraus/u8g2/wiki/u8g2reference#drawstr
}

Regards

h2zero commented 5 years ago

I just figured out why this happens today and made a pull request on the arduino-esp32 repo here: https://github.com/espressif/arduino-esp32/pull/2728

I'll make one for this repo as well but it seems nobody wants to maintain it...

h2zero commented 5 years ago

Created PR for this repo here #861