Esp32-snippets: Delete BLEDevice and then init new one

Created on 22 Aug 2018  ·  23Comments  ·  Source: nkolban/esp32-snippets

Hello, Dear all!

I am facing a problem with creating BLE server after working as a BLE client.
Is there way to kill previously created BLEDevice and init a new one?

There is a pseudocode:
BLEDevice::init("Client");
DoSomeRandomStuff();
BLEDevice::kill("Client");
BLEDevice::init("Server");

I have tried to:
pClient->stop();

But this is not working, because:

"class BLEClient" has no member named "stop"

I have already wrote this comment, but this can be a new issue.

Thank you for your attention and huge contribution to esp society!

WIP enhancement

Most helpful comment

@chegewara thanks for the link, this information is indeed helpful. Still, the way I read it is, that as long as esp_bt_mem_release() was not called, the BT device should be reconfigurable. Only after the BT stack releases its internal memory pool, the stack cannot be used anymore until the next boot. But because there is no way to reset the initialized flag in BLEDevice, BLEDevice::init() cannot be called again.

@nkolban I propose adding a new method static BLEDevice::deinit(bool release_memory);.

/**
 * @brief de-Initialize the %BLE environment.
 * @param release_memory release the internal BT stack memory
 */
/* STATIC */ void BLEDevice::deinit(bool release_memory) {
    if (!initialized) return;

    esp_bluedroid_disable();
    esp_bluedroid_deinit();
    esp_bt_controller_disable();
    esp_bt_controller_deinit();

    if (release_memory) {
        esp_bt_mem_release(ESP_BT_MODE_BTDM);
    } else {
        initialized = false;   // Reset the initialization flag to allow reinitialization.
    }
}

Disclaimer: I did not test this.

All 23 comments

Unfortunately the API is lacking a deinit() method. The way the library is coded makes it impossible to deinitialize the device or at least allows for calling init() a second time. (well you can call init() twice but all calls to init() but the first one are ignored.)

I agree there should be a deinit() the frees all resources and cleans up to a pristine state.

Its because you cant deinit ble device. When you deinit bluedroid then you cant init it again.

 esp_bluedroid_disable();
  esp_bluedroid_deinit();
  esp_bt_controller_disable();
  esp_bt_controller_deinit();

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/bluetooth/esp_bt_main.html

When you deinit bluedroid then you cant init it again.

@chegewara: I could not find anything about this in the documentation, can you explain why this should be the case?

I only saw the global initialized flag in the Arduino BLE library that protects the init() method from being called more often then once.

It is how esp-idf bt stack is build. For the same reason all resources (ram) are reserved on esp32 start (after deinit all resources should be released).
Of course you cant believe me, thats why i posted all commands used to deinit bluetooth. You can test it in your code.

@everslick I dont want to say i do know everything, because i dont. Its possible ive been just mislead by this information:
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/bluetooth/controller_vhci.html#_CPPv218esp_bt_mem_release13esp_bt_mode_t

@chegewara thanks for the link, this information is indeed helpful. Still, the way I read it is, that as long as esp_bt_mem_release() was not called, the BT device should be reconfigurable. Only after the BT stack releases its internal memory pool, the stack cannot be used anymore until the next boot. But because there is no way to reset the initialized flag in BLEDevice, BLEDevice::init() cannot be called again.

@nkolban I propose adding a new method static BLEDevice::deinit(bool release_memory);.

/**
 * @brief de-Initialize the %BLE environment.
 * @param release_memory release the internal BT stack memory
 */
/* STATIC */ void BLEDevice::deinit(bool release_memory) {
    if (!initialized) return;

    esp_bluedroid_disable();
    esp_bluedroid_deinit();
    esp_bt_controller_disable();
    esp_bt_controller_deinit();

    if (release_memory) {
        esp_bt_mem_release(ESP_BT_MODE_BTDM);
    } else {
        initialized = false;   // Reset the initialization flag to allow reinitialization.
    }
}

Disclaimer: I did not test this.

Its a good written function, ive been thinking about writing it the same way. I will try to test it today.

@everslick I did some quick test and your code works. Thanks.

For sake of workaround and risk of my own, is there a way for us to set the initialized variable in our own code without modifying the lib's source?

Forgive my impatience but I'd love to use this right now and implement the final version of this later.

The variable isn't namespaced, which makes it harder to reference anyway.

No. The variable is declared static within the lib, and thus cannot be accessed from outside code.

Initializing, deinitializing and initializing again seems to be causing memory leak

@patlunb Some how I managed to use one ble device after another, I am not at work now, I am going to give the source after weekends.

I mean, this works fine, I've been using something like this for awhile myself (left out mem release part), but init, deinit, init again - and repeat this a few times - and you see, that part of the heap is gone. Deinit doesn't free memory, or so it seems

It is possible, it will be further investigated when i have time. If someone else is willing help with it, please do.

Seems like the issue related to esp_bluedroid_deinit() , removing it from the deinit routine stops leaks.

Just to report that

void bt_deinit ()
{
  esp_bluedroid_disable();
  esp_bluedroid_deinit();
  esp_bt_controller_disable();
  esp_bt_controller_deinit();
}

seems to work fine to me. I was able to call init and deinit several times with no problems

void bt_init ()
{
 [.....]
  nvs_flash_init();
  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);

  esp_bt_controller_init(&bt_cfg);
  esp_bt_controller_enable(ESP_BT_MODE_BLE);
  esp_bluedroid_init();
  esp_bluedroid_enable();

  esp_ble_gap_register_callback(esp_gap_cb);
  esp_ble_gap_set_scan_params(&ble_scan_params);
}

Hi.

I’ve been working on system that transfers information via BLE from an smartphone APP (Client Android) to an ESP 32 (Server), in both directions. For that I've been using the most recent Library https://github.com/nkolban/ESP32_BLE_Arduino and everything works great except with a small important detail:
. If the client (APP), that is already connected with the ESP 32, steps away without cancelling the connection the Server (ESP 32) up to a distance bigger than what the BLE can reach, the connection breaks out however the ESP 32 stays "connected" forever, which means that if another user or even the same user approaches and try to connect he is not able to do so because the ESP 32 (Server) is "busy" with a connection that does not exist.

I’ve been searching forever for a solution and this is the forum that seems to be close to solve this issue but, following your instructions I could not reach a solution. Please take into account that I might not have reach your explanations because I'm green on this matters.

Anyway I updated the Library, I tried the deinit() function and then restart all over again by following the steps on the setup stage ( BLEDevice::init…..) and for some reason the ESP 32 Blocks when it reaches:
“ BLEServer *server = BLEDevice::createServer();
server->setCallbacks(new ServerCallbacks());”

I say it blocks because on the serial it stops running.

On the otherside (APP), the ESP32 actually pops back on in the BLE List but I cannot connect again.

Maybe the answer is already here but I cannot understand what I'm doing wrong:

@everslick and @chegewara– I’m using the latest Library with your updates; Should the function deinit() by itself be enough?

@patlunb - I’ve done the experience of removing esp_bluedroid_deinit() from the BLEDevice.cpp. No luck there also. Do I need to do anything more?

@rochamorelli - Can you explain better what have you done? Have you edit the BLEDevice.cpp using your code or did you workaround in another way?

Sorry for contacting you all, but it seems that you are only the ones that can help me with this, and my programming skills are clearly limited to solve this by my own.

Thanks in advance

Hey, @Manolotrips :D

I wasn't using arduino files, but there must be a disconnect event or something like this, are you doing something with it?

@Manolotrips

Hey, you're doing things right, but you're in a same boat as once I was.

1) Removing esp_bluedroid_deinit() saves you from the memory leaks. Nothing to do with your case.
2) The thing you have, the freeze on the "connect" event, when the server is no longer available is a well known issue to me. What happens there is because there's no timeout for the events in the RTOS and it stucks there indefinitely. What I've done was added a custom timeout for (I think) 20 seconds and some checks in the freertos.c file so that would set timeout and recover from the hang.
Apart from that, before doing anything - service discovery, characteristics read / write, anything - check connection to the server. Reading / writing has the same effect as "connect", but IIRC - the module reboots because of either watchdog or illegal operation or failed assert.
I've spent a month working days and nights fixing stuff for this (I mean - only my part of the stuff which I was working with), and if you feel not very confident about your skills now - I'd suggest you scrap ESP32 and use Nordic chip for BLE. NRF51822 has decent Arduino support (I think, never tried myself) and much more stable stack and API

Hey, @Manolotrips :D
I wasn't using arduino files, but there must be a disconnect event or something like this, are you doing something with it?

Hi
The only disconnect event that I know about is the deinit() but it presents me with that issue.

@Manolotrips
Hey, you're doing things right, but you're in a same boat as once I was.

Removing esp_bluedroid_deinit() saves you from the memory leaks. Nothing to do with your case.
The thing you have, the freeze on the "connect" event, when the server is no longer available is a well known issue to me. What happens there is because there's no timeout for the events in the RTOS and it stucks there indefinitely. What I've done was added a custom timeout for (I think) 20 seconds and some checks in the freertos.c file so that would set timeout and recover from the hang.
Apart from that, before doing anything - service discovery, characteristics read / write, anything - check connection to the server. Reading / writing has the same effect as "connect", but IIRC - the module reboots because of either watchdog or illegal operation or failed assert.
I've spent a month working days and nights fixing stuff for this (I mean - only my part of the stuff which I was working with), and if you feel not very confident about your skills now - I'd suggest you scrap ESP32 and use Nordic chip for BLE. NRF51822 has decent Arduino support (I think, never tried myself) and much more stable stack and API

I've to be honest, reading your second point (which is the solution for my problem) I've understood that I'm really out of my depth :). I'm going to study what you have point out and try to go forward with this because scraping ESP 32 is out of the question (almost there in terms of product ;) ). Thank you all and specially @patlunb for the guidance.

@Manolotrips hard to say, but working with BLE without events sounds weird to me.

Please, check this code, specially line 46, disconnect event callback.

Hi,
this still happens for me. Is anybody else experiencing this? Maybe I have to update my IDF version.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Smeedy picture Smeedy  ·  5Comments

HarrisonOfTheNorth picture HarrisonOfTheNorth  ·  8Comments

frankipl picture frankipl  ·  8Comments

mkol5222 picture mkol5222  ·  5Comments

d3cline picture d3cline  ·  4Comments