Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth Controller Bug (IDFGH-12901) #13861

Open
3 tasks done
oganigl opened this issue May 26, 2024 · 6 comments
Open
3 tasks done

Bluetooth Controller Bug (IDFGH-12901) #13861

oganigl opened this issue May 26, 2024 · 6 comments
Assignees
Labels
Awaiting Response awaiting a response from the author Status: In Progress Work is in progress Type: Bug bugs in IDF

Comments

@oganigl
Copy link

oganigl commented May 26, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

V5.2

Espressif SoC revision.

esp32-s3

Operating System used.

Windows

How did you build your project?

VS Code IDE

If you are using Windows, please specify command line type.

None

Development Kit.

esp32-s3-wroom1

Power Supply used.

USB

What is the expected behavior?

Hi, I have this code and its giving me problems when I run because it does not initialize the Controller. This code is to use bluetooth as a port to read and send messages:#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "sdkconfig.h"

char *TAG = "BLE-Server";
uint8_t ble_addr_type;
void ble_app_advertise(void);

// Write data to ESP32 defined as server
static int device_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
printf("Data from the client: %.*s\n", ctxt->om->om_len, ctxt->om->om_data);
return 0;
}

// Read data from ESP32 defined as server
static int device_read(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
os_mbuf_append(ctxt->om, "Data from the server", strlen("Data from the server"));
return 0;
}

// Array of pointers to other service definitions
// UUID - Universal Unique Identifier
static const struct ble_gatt_svc_def gatt_svcs[] = {
{.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x180), // Define UUID for device type
.characteristics = (struct ble_gatt_chr_def[]){
{.uuid = BLE_UUID16_DECLARE(0xFEF4), // Define UUID for reading
.flags = BLE_GATT_CHR_F_READ,
.access_cb = device_read},
{.uuid = BLE_UUID16_DECLARE(0xDEAD), // Define UUID for writing
.flags = BLE_GATT_CHR_F_WRITE,
.access_cb = device_write},
{0}}},
{0}};

// BLE event handling
static int ble_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type)
{
// Advertise if connected
case BLE_GAP_EVENT_CONNECT:
ESP_LOGI("GAP", "BLE GAP EVENT CONNECT %s", event->connect.status == 0 ? "OK!" : "FAILED!");
if (event->connect.status != 0)
{
ble_app_advertise();
}
break;
// Advertise again after completion of the event
case BLE_GAP_EVENT_ADV_COMPLETE:
ESP_LOGI("GAP", "BLE GAP EVENT");
ble_app_advertise();
break;
default:
break;
}
return 0;
}

// Define the BLE connection
void ble_app_advertise(void)
{
// GAP - device name definition
struct ble_hs_adv_fields fields;
const char *device_name;
memset(&fields, 0, sizeof(fields));
device_name = ble_svc_gap_device_name(); // Read the BLE device name
fields.name = (uint8_t *)device_name;
fields.name_len = strlen(device_name);
fields.name_is_complete = 1;
ble_gap_adv_set_fields(&fields);

// GAP - device connectivity definition
struct ble_gap_adv_params adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; // connectable or non-connectable
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // discoverable or non-discoverable
ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_gap_event, NULL);

}

// The application
void ble_app_on_sync(void)
{
ble_hs_id_infer_auto(0, &ble_addr_type); // Determines the best address type automatically
ble_app_advertise(); // Define the BLE connection
}

// The infinite task
void host_task(void *param)
{
nimble_port_run(); // This function will return only when nimble_port_stop() is executed
}

void app_main()
{
esp_err_t ret;

ret = nvs_flash_init();                          // 1 - Initialize NVS flash
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Check if Bluetooth controller is already initialized
if (!esp_bt_controller_get_status()) {
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));           // Initialize the BT controller
    ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)); // Enable BLE mode for the BT controller
}

ESP_ERROR_CHECK(esp_nimble_hci_init());           // 2 - Initialize ESP HCI
nimble_port_init();                               // 3 - Initialize the host stack
ble_svc_gap_device_name_set("BLE-Server");        // 4 - Initialize NimBLE configuration - server name
ble_svc_gap_init();                               // 4 - Initialize NimBLE configuration - gap service
ble_svc_gatt_init();                              // 4 - Initialize NimBLE configuration - gatt service
ble_gatts_count_cfg(gatt_svcs);                   // 4 - Initialize NimBLE configuration - config gatt services
ble_gatts_add_svcs(gatt_svcs);                    // 4 - Initialize NimBLE configuration - queues gatt services.
ble_hs_cfg.sync_cb = ble_app_on_sync;             // 5 - Initialize application
nimble_port_freertos_init(host_task);             // 6 - Run the thread

}

What is the actual behavior?

It doesn't initialize the Bluetooth controller so is bootloading and failing all the time

Steps to reproduce.

  1. Step
  2. Step
  3. Step
    ...

Debug Logs.

.

More Information.

.

@oganigl oganigl added the Type: Bug bugs in IDF label May 26, 2024
@espressif-bot espressif-bot added the Status: Opened Issue is new label May 26, 2024
@github-actions github-actions bot changed the title Bluetooth Controller Bug Bluetooth Controller Bug (IDFGH-12901) May 26, 2024
@oganigl
Copy link
Author

oganigl commented May 26, 2024

Hi, please could someone solve my doubt, because I have a project for tomorrow and I think that is an espressif problem

@rahult-github
Copy link
Collaborator

Hi @oganigl ,

The sequence in your app_main to start controller first and then invoke esp_nimble_hci_init followed by nimble_port_init is incorrect. You can refer to existing examples to check the correct sequence.

Calling nimble_port_init should suffice.

@eriksl
Copy link

eriksl commented Jun 4, 2024

Can I add here that the documentation of Nimble in ESP-IDF is close to non-existent? And that referring to an example (that doesn't even compile without errors) is not the solution? Myself, I got it working, in the end, but with very much trial and error. This really needs improvement!

@rahult-github
Copy link
Collaborator

Hi @eriksl ,

Sorry about this, but

Can I add here that the documentation of Nimble in ESP-IDF is close to non-existent?

The documentation page here does point to official NimBLE documentation . As you are aware that esp-idf nimble is fork of upstream mynewt-nimble code, so the same documentation works.

And that referring to an example (that doesn't even compile without errors) is not the solution

May i please know which example is not compiling ? Our releases undergo QA cycles to ensure we don't have these issues. But in case you are observing this , please do let us know, Will work on fixing them on priority.

Myself, I got it working, in the end, but with very much trial and error. This really needs improvement!

IDF examples are coupled with README and tutorials with walkthrough. Do let us know what more would be good to add, and we would gladly work to make it more self explanatory.

For e.g. the issue mentioned in this example ( regarding stack initialisation process ) has information here .

@eriksl
Copy link

eriksl commented Jun 4, 2024

Hi Rahult,

Thanks for your quick response. The problems arose when I was making something like this: a BT service that would be able to send and receive somewhat larger chunks of data (for OTA). Only after some seriously obfuscated assertion aborted I found out that the ESP32-S3 does not support BT classic, which, apparently, is required for BT SPP (serial emulation profile). It might be more user friendly to have the IDF code check for this at a suitable point and then deliver a suitable message to the developer.

So I went searching for a SPP "emulation" example, and found it here: examples/bluetooth/nimble/ble_spp. This example code cannot be built successfully. Besides that, it really isn't a good starting point for exchanging large chunks of data.

After A LOT of trial and error I got it all working. You are referring to the Nimble documentation. Problem is that this documentation is really not up to par. It's just the function declarations and a few comments from the source files rearranged into something pretty looking. It does not say in any way how to do (even simple) stuff.

A nice example here is that, apparently, there is no way to queue indications. You can send one indication and every following indications returns some unclear error, until the indication has been handled completely and then, suddenly, it's working again. It would be quite obvious to use the "notification/indication sent" event handler for this. But as it appears, this callback is executed from the Nimble API entry point itself, so it says nothing about the indication actually being sent or handled. It's even worse when you turn on Nimble assertions. Then it will abort on every indications that could not be queued.

Also the documentation (...) isn't really helpful on what values to select for the memory assignment in menuconfig and about MTU sizes. I had to learn the hard way that a maximum MTU of ~576 bytes is supported (from default ~16), but only if you set it on both sides. There is no negotiation whatsoever, even though that is implied by the event callback.

The examples are nice for experimentation projects, but for real stuff they're really too simple.

Also I'd really like to see a terse how-to doc (one page) of what API functions you need to call (depending on what you're trying to achieve) and what they're doing. Not some example that may not cover my needs at all. E.g. it appears some of the API functions from the examples are actually not really needed.

Thank you.

@rahult-github
Copy link
Collaborator

Hi @eriksl,

Ok. I suggest that you open a separate issue if need be where in this can be tracked and discussed more.

Hi @oganigl ,

Does the comment here help solve your issue ?

@espressif-bot espressif-bot added Status: In Progress Work is in progress and removed Status: Opened Issue is new labels Jun 6, 2024
@rahult-github rahult-github added the Awaiting Response awaiting a response from the author label Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Response awaiting a response from the author Status: In Progress Work is in progress Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

4 participants