nkolban / esp32-snippets

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

Delete pClient crashes everything #784

Closed copercini closed 5 years ago

copercini commented 5 years ago

Hi all,

I'm trying to free pClient memory before create another one calling BLEClient* pClient = BLEDevice::createClient(); , but when the destructor is called a crash occurs

Code:

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

    void onDisconnect(BLEClient* pClient) {
        ESP_LOGI(__func__, "onDisconnect");
        pClient->disconnect();
        delete pClient; //crash
        ESP_LOGI(__func__, "Free heap after disconnect %u", xPortGetFreeHeapSize());
    }
};

Logs:

I (9588) onDisconnect: onDisconnect
CORRUPT HEAP: multi_heap.c:474 detected at 0x3ffd5a9c
abort() was called at PC 0x400912f9 on core 0
0x400912f9: multi_heap_assert at C:/msys32/home/note/esp/esp-idf/components/heap/multi_heap.c:377
 (inlined by) multi_heap_free_impl at C:/msys32/home/note/esp/esp-idf/components/heap/multi_heap.c:474

Backtrace: 0x4008c288:0x3ffcb260 0x4008c4b5:0x3ffcb280 0x400912f9:0x3ffcb2a0 0x4008271a:0x3ffcb2c0 0x40082be1:0x3ffcb2e0 0x40
00bec7:0x3ffcb300 0x400902eb:0x3ffcb320 0x40102c9e:0x3ffcb340 0x40100a77:0x3ffcb360 0x401040a4:0x3ffcb380 0x401040de:0x3ffcb3
a0 0x401040fe:0x3ffcb3c0 0x400ff57e:0x3ffcb3e0 0x400d3f2a:0x3ffcb400 0x400ff8ae:0x3ffcb420 0x401052e1:0x3ffcb4e0 0x4011dc41:0
x3ffcb530 0x4011ac86:0x3ffcb570 0x4008f7ed:0x3ffcb5a0
0x4008c288: invoke_abort at C:/msys32/home/note/esp/esp-idf/components/esp32/panic.c:707

0x4008c4b5: abort at C:/msys32/home/note/esp/esp-idf/components/esp32/panic.c:707

0x400912f9: multi_heap_assert at C:/msys32/home/note/esp/esp-idf/components/heap/multi_heap.c:377
 (inlined by) multi_heap_free_impl at C:/msys32/home/note/esp/esp-idf/components/heap/multi_heap.c:474

0x4008271a: heap_caps_free at C:/msys32/home/note/esp/esp-idf/components/heap/heap_caps.c:231

0x40082be1: _free_r at C:/msys32/home/note/esp/esp-idf/components/newlib/syscalls.c:42

0x400902eb: vQueueDelete at C:/msys32/home/note/esp/esp-idf/components/freertos/queue.c:2037

0x40102c9e: FreeRTOS::Semaphore::~Semaphore() at c:\msys32\opt\xtensa-esp32-elf\xtensa-esp32-elf\include\c++\5.2.0\bits/char_
traits.h:243

0x40100a77: BLERemoteCharacteristic::~BLERemoteCharacteristic() at C:/msys32/home/Note/esp/DFUupdates/components/cpp_utils/BL
ERemoteCharacteristic.cpp:309

0x401040a4: BLERemoteService::removeCharacteristics() at C:/msys32/home/Note/esp/DFUupdates/components/cpp_utils/BLERemoteSer
vice.cpp:235

0x401040de: BLERemoteService::~BLERemoteService() at C:/msys32/home/Note/esp/DFUupdates/components/cpp_utils/BLERemoteService
.cpp:235

0x401040fe: BLERemoteService::~BLERemoteService() at C:/msys32/home/Note/esp/DFUupdates/components/cpp_utils/BLERemoteService
.cpp:235

0x400ff57e: BLEClient::~BLEClient() at C:/msys32/home/Note/esp/DFUupdates/components/cpp_utils/BLEClient.cpp:449

0x400d3f2a: MyClientCallback::onDisconnect(BLEClient*) at C:/msys32/home/Note/esp/DFUupdates/main/hello_world_main.cpp:122

0x400ff8ae: BLEClient::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at C:/msys32/ho
me/Note/esp/DFUupdates/components/cpp_utils/BLEClient.cpp:449

0x401052e1: BLEDevice::gattClientEventHandler(esp_gattc_cb_event_t, unsigned char, esp_ble_gattc_cb_param_t*) at C:/msys32/ho
me/Note/esp/DFUupdates/components/cpp_utils/BLEDevice.cpp:167

0x4011dc41: btc_gattc_cb_to_app at C:/msys32/home/note/esp/esp-idf/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c:3
1
 (inlined by) btc_gattc_cb_handler at C:/msys32/home/note/esp/esp-idf/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.
c:922

0x4011ac86: btc_task at C:/msys32/home/note/esp/esp-idf/components/bt/bluedroid/btc/core/btc_task.c:110

0x4008f7ed: vPortTaskWrapper at C:/msys32/home/note/esp/esp-idf/components/freertos/port.c:403
chegewara commented 5 years ago

Hi @copercini its because you are doing it from inside onDsiconnect() callback. As you can see here https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEClient.cpp#L192-L195 after onDisconnect has been called pClient needs to be also deleted from connected clients list here https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEDevice.cpp#L610

EDIT im dont remember if i tested different order and call removePeerDevice before onDisconnect():

BLEDevice::removePeerDevice(m_appId, true);
if (m_pClientCallbacks != nullptr) {
    m_pClientCallbacks->onDisconnect(this);
}
chegewara commented 5 years ago

Ok, i remember now. I changed a bit BLEClient.cpp but had no chance to create PR yet. Here is code you can try. As you can see i moved removePeerDevice()to destructor, so now you should be able to delete client from onDisconnect():

/*
 * BLEDevice.cpp
 *
 *  Created on: Mar 22, 2017
 *      Author: kolban
 */
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#include <esp_bt.h>
#include <esp_bt_main.h>
#include <esp_gap_ble_api.h>
#include <esp_gattc_api.h>
#include "BLEClient.h"
#include "BLEUtils.h"
#include "BLEService.h"
#include "GeneralUtils.h"
#include <string>
#include <sstream>
#include <unordered_set>
#include "BLEDevice.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define LOG_TAG ""
#else
#include "esp_log.h"
static const char* LOG_TAG = "BLEClient";
#endif

/*
 * Design
 * ------
 * When we perform a searchService() requests, we are asking the BLE server to return each of the services
 * that it exposes.  For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details
 * of the exposed service including its UUID.
 *
 * The objects we will invent for a BLEClient will be as follows:
 * * BLERemoteService - A model of a remote service.
 * * BLERemoteCharacteristic - A model of a remote characteristic
 * * BLERemoteDescriptor - A model of a remote descriptor.
 *
 * Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own
 * zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors.
 *
 * We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics
 * and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors.
 *
 *
 */

BLEClient::BLEClient() {
    m_pClientCallbacks = nullptr;
    m_conn_id          = ESP_GATT_IF_NONE;
    m_gattc_if         = ESP_GATT_IF_NONE;
    m_haveServices     = false;
    m_isConnected      = false;  // Initially, we are flagged as not connected.

    m_appId = BLEDevice::m_appId++;
    m_appId = m_appId%100;
    BLEDevice::addPeerDevice(this, true, m_appId);
    m_semaphoreRegEvt.take("connect");

    esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId);
    if (errRc != ESP_OK) {
        ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
        return;
    }

    m_semaphoreRegEvt.wait("connect");

} // BLEClient

/**
 * @brief Destructor.
 */
BLEClient::~BLEClient() {
    // We may have allocated service references associated with this client.  Before we are finished
    // with the client, we must release resources.
    clearServices();
    esp_ble_gattc_app_unregister(m_gattc_if);
    BLEDevice::removePeerDevice(m_appId, true);

} // ~BLEClient

/**
 * @brief Clear any existing services.
 *
 */
void BLEClient::clearServices() {
    ESP_LOGD(LOG_TAG, ">> clearServices");
    // Delete all the services.
    for (auto &myPair : m_servicesMap) {
       delete myPair.second;
    }
    m_servicesMap.clear();
    m_servicesMapByInstID.clear();
    m_haveServices = false;
    ESP_LOGD(LOG_TAG, "<< clearServices");
} // clearServices

/**
 * Add overloaded function to ease connect to peer device with not public address
 */
bool BLEClient::connect(BLEAdvertisedDevice* device) {
    BLEAddress address =  device->getAddress();
    esp_ble_addr_type_t type = device->getAddressType();
    return connect(address, type);
}

/**
 * @brief Connect to the partner (BLE Server).
 * @param [in] address The address of the partner.
 * @return True on success.
 */
bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
    ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());

    m_peerAddress = address;

    // Perform the open connection request against the target BLE Server.
    m_semaphoreOpenEvt.take("connect");
    esp_err_t errRc = ::esp_ble_gattc_open(
        m_gattc_if,
        *getPeerAddress().getNative(), // address
        type,          // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature.
        1                              // direct connection <-- maybe needs to be changed in case of direct indirect connection???
    );
    if (errRc != ESP_OK) {
        ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
        return false;
    }

    uint32_t rc = m_semaphoreOpenEvt.wait("connect");   // Wait for the connection to complete.
    ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
    return rc == ESP_GATT_OK;
} // connect

/**
 * @brief Disconnect from the peer.
 * @return N/A.
 */
void BLEClient::disconnect() {
    ESP_LOGD(LOG_TAG, ">> disconnect()");
    ESP_LOGW(__func__, "gattIf: %d, connId: %d", getGattcIf(), getConnId());
    esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId());
    if (errRc != ESP_OK) {
        ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
        return;
    }
    ESP_LOGD(LOG_TAG, "<< disconnect()");
} // disconnect

/**
 * @brief Handle GATT Client events
 */
void BLEClient::gattClientEventHandler(
    esp_gattc_cb_event_t      event,
    esp_gatt_if_t             gattc_if,
    esp_ble_gattc_cb_param_t* evtParam) {

    ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
        gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());

    // Execute handler code based on the type of event received.
    switch(event) {

        case ESP_GATTC_SRVC_CHG_EVT:
            if(getConnId() != evtParam->search_res.conn_id)
                break;

            ESP_LOGI(LOG_TAG, "SERVICE CHANGED");
            break;

        case ESP_GATTC_CLOSE_EVT: {
            break;
        }

        //
        // ESP_GATTC_DISCONNECT_EVT
        //
        // disconnect:
        // - esp_gatt_status_t status
        // - uint16_t          conn_id
        // - esp_bd_addr_t     remote_bda
        case ESP_GATTC_DISCONNECT_EVT: {
            ESP_LOGE(__func__, "disconnect event, conn_id: %d", evtParam->disconnect.conn_id);
            if(getConnId() != evtParam->disconnect.conn_id)
                break;
            m_semaphoreOpenEvt.give(evtParam->disconnect.reason);
            if(!m_isConnected)
                break;
            // If we receive a disconnect event, set the class flag that indicates that we are
            // no longer connected.
            esp_ble_gattc_close(m_gattc_if, m_conn_id);
            m_isConnected = false;
            if (m_pClientCallbacks != nullptr) {
                m_pClientCallbacks->onDisconnect(this);
            }
            break;
        } // ESP_GATTC_DISCONNECT_EVT

        //
        // ESP_GATTC_OPEN_EVT
        //
        // open:
        // - esp_gatt_status_t status
        // - uint16_t          conn_id
        // - esp_bd_addr_t     remote_bda
        //
        case ESP_GATTC_OPEN_EVT: {
            if(getConnId() != ESP_GATT_IF_NONE)
                break;
            m_conn_id = evtParam->open.conn_id;
            if (m_pClientCallbacks != nullptr) {
                m_pClientCallbacks->onConnect(this);
            }
            if (evtParam->open.status == ESP_GATT_OK) {
                m_isConnected = true;   // Flag us as connected.
                m_mtu = evtParam->open.mtu;
            }
            m_semaphoreOpenEvt.give(evtParam->open.status);
            break;
        } // ESP_GATTC_OPEN_EVT

        //
        // ESP_GATTC_REG_EVT
        //
        // reg:
        // esp_gatt_status_t status
        // uint16_t          app_id
        //
        case ESP_GATTC_REG_EVT: {
            if(m_appId == evtParam->reg.app_id){
                ESP_LOGI(__func__, "register app id: %d, %d, gattc_if: %d", m_appId, evtParam->reg.app_id, gattc_if);
                m_gattc_if = gattc_if;
                m_appId = evtParam->reg.app_id;
                m_semaphoreRegEvt.give();
            }
            break;
        } // ESP_GATTC_REG_EVT

        case ESP_GATTC_CFG_MTU_EVT:
            if(evtParam->cfg_mtu.status != ESP_GATT_OK) {
                ESP_LOGE(LOG_TAG,"Config mtu failed");
            }
            else
                m_mtu = evtParam->cfg_mtu.mtu;
            break;

        case ESP_GATTC_CONNECT_EVT: {
            if(evtParam->connect.conn_id != getConnId())
                break;
            BLEDevice::updatePeerDevice(this, true, m_gattc_if);
            esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id);
            if (errRc != ESP_OK) {
                ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
            }
#ifdef CONFIG_BLE_SMP_ENABLE   // Check that BLE SMP (security) is configured in make menuconfig
            if(BLEDevice::m_securityLevel){
                esp_ble_set_encryption(evtParam->connect.remote_bda, BLEDevice::m_securityLevel);
            }
#endif  // CONFIG_BLE_SMP_ENABLE
            break;
        } // ESP_GATTC_CONNECT_EVT

        //
        // ESP_GATTC_SEARCH_CMPL_EVT
        //
        // search_cmpl:
        // - esp_gatt_status_t status
        // - uint16_t          conn_id
        //
        case ESP_GATTC_SEARCH_CMPL_EVT: {
            if(evtParam->search_cmpl.conn_id != getConnId())
                break;
            if (evtParam->search_cmpl.status != ESP_GATT_OK){
                ESP_LOGE(LOG_TAG, "search service failed, error status = %x", evtParam->search_cmpl.status);
            }
#ifndef ARDUINO_ARCH_ESP32
// commented out just for now to keep backward compatibility            
            // if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) {
            //  ESP_LOGI(LOG_TAG, "Get service information from remote device");
            // } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) {
            //  ESP_LOGI(LOG_TAG, "Get service information from flash");
            // } else {
            //  ESP_LOGI(LOG_TAG, "unknown service source");
            // }
#endif
            m_semaphoreSearchCmplEvt.give(evtParam->search_cmpl.status);
            break;
        } // ESP_GATTC_SEARCH_CMPL_EVT

        //
        // ESP_GATTC_SEARCH_RES_EVT
        //
        // search_res:
        // - uint16_t      conn_id
        // - uint16_t      start_handle
        // - uint16_t      end_handle
        // - esp_gatt_id_t srvc_id
        //
        case ESP_GATTC_SEARCH_RES_EVT: {
            if(getConnId() != evtParam->search_res.conn_id)
                break;
            BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id);
            BLERemoteService* pRemoteService = new BLERemoteService(
                evtParam->search_res.srvc_id,
                this,
                evtParam->search_res.start_handle,
                evtParam->search_res.end_handle
            );
            m_servicesMap.insert(std::pair<std::string, BLERemoteService*>(uuid.toString(), pRemoteService));
            m_servicesMapByInstID.insert(std::pair<BLERemoteService *, uint16_t>(pRemoteService, evtParam->search_res.srvc_id.inst_id));
            break;
        } // ESP_GATTC_SEARCH_RES_EVT

        default: {
            break;
        }
    } // Switch

    // Pass the request on to all services.
    for (auto &myPair : m_servicesMap) {
       myPair.second->gattClientEventHandler(event, gattc_if, evtParam);
    }

} // gattClientEventHandler

uint16_t BLEClient::getConnId() {
    return m_conn_id;
} // getConnId

esp_gatt_if_t BLEClient::getGattcIf() {
    return m_gattc_if;
} // getGattcIf

/**
 * @brief Retrieve the address of the peer.
 *
 * Returns the Bluetooth device address of the %BLE peer to which this client is connected.
 */
BLEAddress BLEClient::getPeerAddress() {
    return m_peerAddress;
} // getAddress

/**
 * @brief Ask the BLE server for the RSSI value.
 * @return The RSSI value.
 */
int BLEClient::getRssi() {
    ESP_LOGD(LOG_TAG, ">> getRssi()");
    if (!isConnected()) {
        ESP_LOGD(LOG_TAG, "<< getRssi(): Not connected");
        return 0;
    }
    // We make the API call to read the RSSI value which is an asynchronous operation.  We expect to receive
    // an ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT to indicate completion.
    //
    m_semaphoreRssiCmplEvt.take("getRssi");
    esp_err_t rc = ::esp_ble_gap_read_rssi(*getPeerAddress().getNative());
    if (rc != ESP_OK) {
        ESP_LOGE(LOG_TAG, "<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc));
        return 0;
    }
    int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi");
    ESP_LOGD(LOG_TAG, "<< getRssi(): %d", rssiValue);
    return rssiValue;
} // getRssi

/**
 * @brief Get the service BLE Remote Service instance corresponding to the uuid.
 * @param [in] uuid The UUID of the service being sought.
 * @return A reference to the Service or nullptr if don't know about it.
 */
BLERemoteService* BLEClient::getService(const char* uuid) {
    return getService(BLEUUID(uuid));
} // getService

/**
 * @brief Get the service object corresponding to the uuid.
 * @param [in] uuid The UUID of the service being sought.
 * @return A reference to the Service or nullptr if don't know about it.
 * @throws BLEUuidNotFound
 */
BLERemoteService* BLEClient::getService(BLEUUID uuid) {
    ESP_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
// Design
// ------
// We wish to retrieve the service given its UUID.  It is possible that we have not yet asked the
// device what services it has in which case we have nothing to match against.  If we have not
// asked the device about its services, then we do that now.  Once we get the results we can then
// examine the services map to see if it has the service we are looking for.
    if (!m_haveServices) {
        getServices();
    }
    std::string uuidStr = uuid.toString();
    for (auto &myPair : m_servicesMap) {
        if (myPair.first == uuidStr) {
            ESP_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
            return myPair.second;
        }
    } // End of each of the services.
    ESP_LOGD(LOG_TAG, "<< getService: not found");
    return nullptr;
} // getService

/**
 * @brief Ask the remote %BLE server for its services.
 * A %BLE Server exposes a set of services for its partners.  Here we ask the server for its set of
 * services and wait until we have received them all.
 * @return N/A
 */
std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
/*
 * Design
 * ------
 * We invoke esp_ble_gattc_search_service.  This will request a list of the service exposed by the
 * peer BLE partner to be returned as events.  Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT
 * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received.
 */
    ESP_LOGD(LOG_TAG, ">> getServices");
// TODO implement retrieving services from cache
    clearServices(); // Clear any services that may exist.

    esp_err_t errRc = esp_ble_gattc_search_service(
        getGattcIf(),
        getConnId(),
        NULL            // Filter UUID
    );

    m_semaphoreSearchCmplEvt.take("getServices");
    if (errRc != ESP_OK) {
        ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
        return &m_servicesMap;
    }
    // If sucessfull, remember that we now have services.
    m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0);
    ESP_LOGD(LOG_TAG, "<< getServices");
    return &m_servicesMap;
} // getServices

/**
 * @brief Get the value of a specific characteristic associated with a specific service.
 * @param [in] serviceUUID The service that owns the characteristic.
 * @param [in] characteristicUUID The characteristic whose value we wish to read.
 * @throws BLEUuidNotFound
 */
std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) {
    ESP_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
    std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue();
    ESP_LOGD(LOG_TAG, "<<getValue");
    return ret;
} // getValue

/**
 * @brief Handle a received GAP event.
 *
 * @param [in] event
 * @param [in] param
 */
void BLEClient::handleGAPEvent(
        esp_gap_ble_cb_event_t  event,
        esp_ble_gap_cb_param_t* param) {
    ESP_LOGD(LOG_TAG, "BLEClient ... handling GAP event!");
    switch (event) {
        //
        // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
        //
        // read_rssi_cmpl
        // - esp_bt_status_t status
        // - int8_t rssi
        // - esp_bd_addr_t remote_addr
        //
        case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: {
            m_semaphoreRssiCmplEvt.give((uint32_t) param->read_rssi_cmpl.rssi);
            break;
        } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT

        default:
            break;
    }
} // handleGAPEvent

/**
 * @brief Are we connected to a partner?
 * @return True if we are connected and false if we are not connected.
 */
bool BLEClient::isConnected() {
    return m_isConnected;
} // isConnected

/**
 * @brief Set the callbacks that will be invoked.
 */
void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) {
    m_pClientCallbacks = pClientCallbacks;
} // setClientCallbacks

/**
 * @brief Set the value of a specific characteristic associated with a specific service.
 * @param [in] serviceUUID The service that owns the characteristic.
 * @param [in] characteristicUUID The characteristic whose value we wish to write.
 * @throws BLEUuidNotFound
 */
void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
    ESP_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
    getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value);
    ESP_LOGD(LOG_TAG, "<< setValue");
} // setValue

uint16_t BLEClient::getMTU() {
    return m_mtu;
}

/**
 * @brief Return a string representation of this client.
 * @return A string representation of this client.
 */
std::string BLEClient::toString() {
    std::ostringstream ss;
    ss << "peer address: " << m_peerAddress.toString();
    ss << "\nServices:\n";
    for (auto &myPair : m_servicesMap) {
        ss << myPair.second->toString() << "\n";
      // myPair.second is the value
    }
    return ss.str();
} // toString

#endif // CONFIG_BT_ENABLED
copercini commented 5 years ago

@chegewara Thanks for your quick reply and code, this crash seems related with this line: https://github.com/nkolban/esp32-snippets/blob/c8dea9ec9bcacdbada2b655be0621cb618eca3e8/cpp_utils/BLERemoteService.cpp#L296 just commenting this out, no more crashes occur, only a small memory leak

chegewara commented 5 years ago

Yes, it is also possible, because my internal changes looks like this:

void BLERemoteService::removeCharacteristics() {
    for (auto &myPair : m_characteristicMap) {
       delete myPair.second;
       //m_characteristicMap.erase(myPair.first);  // Should be no need to delete as it will be deleted by the clear
    }
    m_characteristicMap.clear();   // Clear the map
} // removeCharacteristics

EDIT i have a lot changes in my internal version, but i dont have time to test it and make PR. Sorry for that

copercini commented 5 years ago

it's my fault actually facepalm

I was using a global static BLERemoteCharacteristic* myCharacteristic; then it was crashing on some internal free of destructor

copercini commented 5 years ago

Additionally, using this PR: https://github.com/nkolban/esp32-snippets/pull/783 there is no problem of have global characteristics