From 0a4dfb05186d268a46db70a30b24a809aec6161a Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 12 Mar 2026 14:59:09 +0530 Subject: [PATCH 1/6] fix(nimble): Issue connect cancel in case of outstanding master connection --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 27db5fca0ee..7075927f97c 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 27db5fca0eedcb7e0e3d41b9943fbfa91b29dbf0 +Subproject commit 7075927f97c648af650a288e94a8c80dd7f00c27 From 6d43b3b0bb35e420b45e035671d137230455646d Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 17 Mar 2026 12:07:39 +0530 Subject: [PATCH 2/6] fix(nimble): Correct adv_list_init / deinit during nimble init / deinit --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 7075927f97c..697427ff39c 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 7075927f97c648af650a288e94a8c80dd7f00c27 +Subproject commit 697427ff39cbde22fc5a3fa010fe56f65fa96a71 From 63c5243ef36af0a0e33be469d30a235921538b76 Mon Sep 17 00:00:00 2001 From: Shreeyash Bhakare Date: Tue, 17 Mar 2026 15:46:37 +0530 Subject: [PATCH 3/6] fix(nimble): fix CODED PHY ext adv Packet Too Long by using min interval (20 ms) --- examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c b/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c index 81ff95800c6..4c54e8ff77c 100644 --- a/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_phy/phy_prph/main/main.c @@ -145,8 +145,13 @@ ext_bleprph_advertise(void) break; } - params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; - params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + if (s_current_phy == BLE_HCI_LE_PHY_CODED_PREF_MASK) { + params.itvl_min = BLE_GAP_ADV_ITVL_MS(20); + params.itvl_max = BLE_GAP_ADV_ITVL_MS(20); + }else{ + params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + } /* configure instance 0 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, From c9144f84ae88f8985cc371f7b0de1f292a54f7e0 Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Wed, 25 Mar 2026 22:53:27 +0530 Subject: [PATCH 4/6] fix(nimble): Fix enc adv NVS struct and add ext adv support --- .../enc_adv_data_cent/main/main.c | 131 ++++++++++++++---- .../enc_adv_data_prph/main/main.c | 95 ++++++++++++- 2 files changed, 201 insertions(+), 25 deletions(-) diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c index a31f144e120..e315ae02922 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/main/main.c @@ -101,31 +101,22 @@ enc_adv_data_cent_on_read(uint16_t conn_handle, value_ead.km_present = 1; - value_ead.km = (struct key_material *) malloc (sizeof(struct key_material)); - - if (value_ead.km == NULL) { - MODLOG_DFLT(ERROR, "Failed to allocate memory for key material"); - goto err; - } - - memset(value_ead.km, 0, sizeof(struct key_material)); + memset(&value_ead.km, 0, sizeof(struct key_material)); /* Validate mbuf has enough data before copying */ if (attr->om == NULL || OS_MBUF_PKTLEN(attr->om) < (BLE_EAD_KEY_SIZE + BLE_EAD_IV_SIZE)) { MODLOG_DFLT(ERROR, "Invalid mbuf or insufficient data size"); - free(value_ead.km); - value_ead.km = NULL; goto err; } - os_mbuf_copydata(attr->om, 0, BLE_EAD_KEY_SIZE, &value_ead.km->session_key); - os_mbuf_copydata(attr->om, BLE_EAD_KEY_SIZE, BLE_EAD_IV_SIZE, &value_ead.km->iv); + os_mbuf_copydata(attr->om, 0, BLE_EAD_KEY_SIZE, &value_ead.km.session_key); + os_mbuf_copydata(attr->om, BLE_EAD_KEY_SIZE, BLE_EAD_IV_SIZE, &value_ead.km.iv); MODLOG_DFLT(DEBUG, "Session key:"); - print_bytes(value_ead.km->session_key, BLE_EAD_KEY_SIZE); + print_bytes(value_ead.km.session_key, BLE_EAD_KEY_SIZE); MODLOG_DFLT(DEBUG, "IV:"); - print_bytes(value_ead.km->iv, BLE_EAD_IV_SIZE); + print_bytes(value_ead.km.iv, BLE_EAD_IV_SIZE); memcpy(&value_ead.peer_addr.val, &p->peer_addr, PEER_ADDR_VAL_SIZE); @@ -134,17 +125,8 @@ enc_adv_data_cent_on_read(uint16_t conn_handle, MODLOG_DFLT(INFO, "Writing of session key, iv, and peer addr to NVS success"); } - if (value_ead.km != NULL) { - free(value_ead.km); - value_ead.km = NULL; - } - err: /* Terminate the connection. */ - if (value_ead.km != NULL) { - free(value_ead.km); - value_ead.km = NULL; - } return ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); } @@ -296,8 +278,9 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_ MODLOG_DFLT(INFO, "Read session key and iv from NVS successfully"); } - rc = ble_ead_decrypt(value_ead.km->session_key, value_ead.km->iv, enc_data, + rc = ble_ead_decrypt(value_ead.km.session_key, value_ead.km.iv, enc_data, enc_payload_len, temp); + if (rc == 0) { MODLOG_DFLT(INFO, "Decryption of adv data done successfully"); } else { @@ -329,6 +312,93 @@ enc_adv_data_cent_decrypt(uint8_t length_data, const uint8_t *data, const uint8_ * advertisement. The function returns a positive result if the device * advertises connectability and support for the Key Characteristic service. */ +#if MYNEWT_VAL(BLE_EXT_ADV) +static int +enc_adv_data_cent_ext_should_connect(const struct ble_gap_ext_disc_desc *disc) +{ + int offset = 0; + int ad_struct_len = 0; +#if CONFIG_EXAMPLE_USE_CI_ADDRESS + uint32_t *addr_offset; +#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS + uint8_t test_addr[6]; + uint32_t peer_addr[6]; + + memset(peer_addr, 0x0, sizeof peer_addr); + + if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && + disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + return 0; + } + if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { +#if !CONFIG_EXAMPLE_USE_CI_ADDRESS + ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); + /* Convert string to address */ + sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%lx:%lx:%lx:%lx:%lx:%lx", + &peer_addr[5], &peer_addr[4], &peer_addr[3], + &peer_addr[2], &peer_addr[1], &peer_addr[0]); +#endif + + /* Conversion */ + for(int i=0; i<6; i++) { + test_addr[i] = (uint8_t )peer_addr[i]; + } + +#if CONFIG_EXAMPLE_USE_CI_ADDRESS + addr_offset = (uint32_t *)&test_addr[1]; + *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); + test_addr[5] = 0xC3; + test_addr[0] = TEST_CI_ADDRESS_CHIP_OFFSET; +#endif + if (memcmp(test_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { + return 0; + } + } + + /* The device has to advertise support for the Key Characteristic + * service (0x2B88) + * + * Check if custom UUID 0x2C01 is advertised + */ + while(offset < disc->length_data) { + ad_struct_len = disc->data[offset]; + + if (ad_struct_len == 0 || offset + ad_struct_len + 1 > disc->length_data) { + break; + } + + /* Search if Custom UUID 0x2C01 is advertised */ + if (ad_struct_len >= 3 && (disc->data[offset + 1] == 0x02 || disc->data[offset + 1] == 0x03)) { + for (int i = 2; i + 1 <= ad_struct_len; i+= 2) { + if (disc->data[offset + i] == 0x2C && disc->data[offset + i + 1] == 0x01) { + if (enc_adv_data_find_peer(disc->addr.val) != -1) { + MODLOG_DFLT(INFO, "Peer was already added with addr : %s", + addr_str(&disc->addr.val)); + } else { + MODLOG_DFLT(INFO, "Adding peer addr : %s", addr_str(&disc->addr.val)); + + memcpy(&kmp[counter].peer_addr, &disc->addr.val, PEER_ADDR_VAL_SIZE); + counter++; + + if (counter > CONFIG_BT_NIMBLE_MAX_CONNECTIONS) { + counter = 0; + } + } + if (enc_adv_data_check_km_exist(disc->addr.val)) { + return enc_adv_data_cent_decrypt(disc->length_data, disc->data, disc->addr.val); + } else { + return 1; + } + } + } + } + + offset += ad_struct_len + 1; + } + + return 0; +} +#else static int enc_adv_data_cent_should_connect(const struct ble_gap_disc_desc *disc) { @@ -397,6 +467,7 @@ enc_adv_data_cent_should_connect(const struct ble_gap_disc_desc *disc) return 0; } +#endif /** * Connects to the sender of the specified advertisement of it looks @@ -411,9 +482,15 @@ enc_adv_data_cent_connect_if_interesting(void *disc) ble_addr_t *addr; /* Don't do anything if we don't care about this advertiser. */ +#if MYNEWT_VAL(BLE_EXT_ADV) + if(!enc_adv_data_cent_ext_should_connect((struct ble_gap_ext_disc_desc *) disc)) { + return; + } +#else if (!enc_adv_data_cent_should_connect((struct ble_gap_disc_desc *)disc)) { return; } +#endif #if !(MYNEWT_VAL(BLE_HOST_ALLOW_CONNECT_WITH_SCAN)) /* Scanning must be stopped before a connection can be initiated. */ @@ -434,7 +511,11 @@ enc_adv_data_cent_connect_if_interesting(void *disc) /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for * timeout. */ +#if MYNEWT_VAL(BLE_EXT_ADV) + addr = &((struct ble_gap_ext_disc_desc *)disc)->addr; +#else addr = &((struct ble_gap_disc_desc *)disc)->addr; +#endif rc = ble_gap_connect(own_addr_type, addr, 30000, NULL, enc_adv_data_cent_gap_event, NULL); @@ -598,6 +679,8 @@ enc_adv_data_cent_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_EXT_DISC: /* An advertisement report was received during GAP discovery. */ ext_print_adv_report(&event->ext_disc); + + enc_adv_data_cent_connect_if_interesting(&event->ext_disc); return 0; #endif diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c index 1d162ef8691..e28495ee06a 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -21,6 +21,14 @@ static const char *tag = "ENC_ADV_DATA_PRPH"; static int enc_adv_data_prph_gap_event(struct ble_gap_event *event, void *arg); const uint8_t device_name[3] = {'k', 'e', 'y'}; +#if MYNEWT_VAL(BLE_EXT_ADV) +static uint8_t ext_adv_pattern[] = { + 0x02, BLE_HS_ADV_TYPE_FLAGS, 0x06, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0xab, 0xcd, + 0x03, BLE_HS_ADV_TYPE_COMP_UUIDS16, 0x2C, 0x01, +}; +#endif + static uint8_t unencrypted_adv_pattern[] = { 0x05, 0X09, 'p', 'r', 'p', 'h' }; @@ -102,6 +110,78 @@ enc_adv_data_prph_encrypt_set(uint8_t *out_encrypted_adv_data, return 0; } +#if MYNEWT_VAL(BLE_EXT_ADV) +/** + * Enables advertising with the following parameters: + * o General discoverable mode. + * o Undirected connectable mode. + */ +static void +enc_adv_data_prph_ext_advertise(void) +{ + struct ble_gap_ext_adv_params params; + struct os_mbuf *data; + uint8_t * temp; + uint8_t instance = 0; + int rc; + + const unsigned encrypted_adv_data_len = BLE_EAD_ENCRYPTED_PAYLOAD_SIZE(sizeof(unencrypted_adv_pattern)); + uint8_t encrypted_adv_data[encrypted_adv_data_len]; + memset(encrypted_adv_data, 0, encrypted_adv_data_len); + + /* First check if any instance is already active */ + if(ble_gap_ext_adv_active(instance)) { + return; + } + + /* use defaults for non-set params */ + memset (¶ms, 0, sizeof(params)); + + /* enable connectable advertising */ + params.connectable = 1; + + /* advertise using random addr */ + params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + + params.primary_phy = BLE_HCI_LE_PHY_1M; + params.secondary_phy = BLE_HCI_LE_PHY_2M; + params.tx_power = 127; + params.sid = 1; + + params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN; + + /* configure instance 0 */ + rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, + enc_adv_data_prph_gap_event, NULL); + assert (rc == 0); + + rc = enc_adv_data_prph_encrypt_set(encrypted_adv_data, encrypted_adv_data_len); + if (rc != 0) { + return; + } + + /* get mbuf with adv data */ + temp = malloc(sizeof(ext_adv_pattern) + 2 + encrypted_adv_data_len); + memcpy(temp, ext_adv_pattern, sizeof(ext_adv_pattern)); + temp[sizeof(ext_adv_pattern)] = 1 + encrypted_adv_data_len; + temp[sizeof(ext_adv_pattern) + 1] = BLE_GAP_ENC_ADV_DATA; + memcpy(temp + sizeof(ext_adv_pattern) + 2, encrypted_adv_data, encrypted_adv_data_len); + + data = ble_hs_mbuf_from_flat(temp, sizeof(ext_adv_pattern) + 2 + encrypted_adv_data_len); + assert(data); + + free(temp); + temp = NULL; + + rc = ble_gap_ext_adv_set_data(instance, data); + assert (rc == 0); + + /* start advertising */ + rc = ble_gap_ext_adv_start(instance, 0, 0); + assert (rc == 0); +} +#else /** * Enables advertising with the following parameters: * o General discoverable mode. @@ -165,6 +245,7 @@ enc_adv_data_prph_advertise(void) ¶ms, enc_adv_data_prph_gap_event, NULL); assert (rc == 0); } +#endif /** * The nimble host executes this callback when a GAP event occurs. The @@ -202,7 +283,11 @@ enc_adv_data_prph_gap_event(struct ble_gap_event *event, void *arg) if (event->connect.status != 0) { /* Connection failed; resume advertising. */ +#if MYNEWT_VAL(BLE_EXT_ADV) + enc_adv_data_prph_ext_advertise(); +#else enc_adv_data_prph_advertise(); +#endif } return 0; @@ -213,7 +298,11 @@ enc_adv_data_prph_gap_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "\n"); /* Connection terminated; resume advertising. */ +#if MYNEWT_VAL(BLE_EXT_ADV) + enc_adv_data_prph_ext_advertise(); +#else enc_adv_data_prph_advertise(); +#endif return 0; case BLE_GAP_EVENT_CONN_UPDATE: @@ -356,7 +445,11 @@ enc_adv_data_prph_on_sync(void) MODLOG_DFLT(INFO, "\n"); /* Begin advertising. */ +#if MYNEWT_VAL(BLE_EXT_ADV) + enc_adv_data_prph_ext_advertise(); +#else enc_adv_data_prph_advertise(); +#endif } void enc_adv_data_prph_host_task(void *param) From 534bbfd6f13a884bd6f82b427eb815cc1f1be24e Mon Sep 17 00:00:00 2001 From: Astha Verma Date: Wed, 18 Mar 2026 11:44:26 +0530 Subject: [PATCH 5/6] fix(nimble): fix missing gatt caching header in examples --- components/bt/host/nimble/nimble | 2 +- examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c | 3 +++ examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c | 3 +++ .../ble_proximity_sensor/proximity_sensor_cent/main/main.c | 6 +++++- .../ble_proximity_sensor/proximity_sensor_prph/main/main.c | 4 ++++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 697427ff39c..40997ca6eee 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 697427ff39cbde22fc5a3fa010fe56f65fa96a71 +Subproject commit 40997ca6eee2c3a7e9488b22c335fa8947b43be0 diff --git a/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c b/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c index d8c5840ec8d..bd765009ea2 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_cts/cts_cent/main/main.c @@ -15,6 +15,9 @@ #include "services/gap/ble_svc_gap.h" #include "ble_cts_cent.h" #include "services/cts/ble_svc_cts.h" +#if MYNEWT_VAL(BLE_GATT_CACHING) +#include "host/ble_esp_gattc_cache.h" +#endif static const char *tag = "NimBLE_CTS_CENT"; static int ble_cts_cent_gap_event(struct ble_gap_event *event, void *arg); diff --git a/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c b/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c index bc2668d5304..fdc49361be5 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_htp/htp_cent/main/main.c @@ -14,6 +14,9 @@ #include "console/console.h" #include "services/gap/ble_svc_gap.h" #include "ble_htp_cent.h" +#if MYNEWT_VAL(BLE_GATT_CACHING) +#include "host/ble_esp_gattc_cache.h" +#endif static const char *tag = "NimBLE_HTP_CENT"; static int ble_htp_cent_gap_event(struct ble_gap_event *event, void *arg); diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c index 4b4bf0d0583..e7029e278d4 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/main.c @@ -14,6 +14,9 @@ #include "console/console.h" #include "services/gap/ble_svc_gap.h" #include "ble_prox_cent.h" +#if MYNEWT_VAL(BLE_GATT_CACHING) +#include "host/ble_esp_gattc_cache.h" +#endif static const char *tag = "NimBLE_PROX_CENT"; static uint8_t link_supervision_timeout; @@ -499,8 +502,9 @@ ble_prox_cent_gap_event(struct ble_gap_event *event, void *arg) /* Connection attempt failed; resume scanning. */ MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n", event->connect.status); + + ble_prox_cent_scan(); } - ble_prox_cent_scan(); return 0; case BLE_GAP_EVENT_DISCONNECT: diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c index 9b2190e83dd..684758be33c 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/main.c @@ -14,6 +14,7 @@ #include "host/util/util.h" #include "console/console.h" #include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" #include "ble_prox_prph.h" #if CONFIG_EXAMPLE_EXTENDED_ADV @@ -300,6 +301,9 @@ void app_main(void) ble_hs_cfg.sm_sc = 1; ble_hs_cfg.sm_mitm = 1; + ble_svc_gap_init(); + ble_svc_gatt_init(); + int rc; /* Set the default device name */ rc = ble_svc_gap_device_name_set(device_name); From e8b0e8ac581d39cd536651fed5cdfe96a0c046d4 Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Mon, 16 Mar 2026 17:26:03 +0530 Subject: [PATCH 6/6] feat(nimble): Update blecent example README.md with EATT documentation --- components/bt/host/nimble/nimble | 2 +- examples/bluetooth/nimble/blecent/README.md | 49 +++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 40997ca6eee..23bfcada3e7 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 40997ca6eee2c3a7e9488b22c335fa8947b43be0 +Subproject commit 23bfcada3e7719d4c3817e949d05751ac2cf72b3 diff --git a/examples/bluetooth/nimble/blecent/README.md b/examples/bluetooth/nimble/blecent/README.md index a2103fc242f..0dd20b111a7 100644 --- a/examples/bluetooth/nimble/blecent/README.md +++ b/examples/bluetooth/nimble/blecent/README.md @@ -78,6 +78,22 @@ Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects. +### Configuration Option - EATT + +There are two key configurations that control the flow of this example regarding EATT: + +* `MYNEWT_VAL(BLE_EATT_CHAN_NUM)`: This value is the number of EATT channels the user wants to create. +* `Enable Link Encryption` (`EXAMPLE_ENCRYPTION`): This option, found in `Example Configuration` -> `Enable Link Encryption`, determines whether to enable encryption before performing GATT operations. + +These configurations affect when the GATT operations (initiated by `peer_disc_all`) begin: + +1. **Encryption off, EATT off**: GATT operations resume immediately after connection establishment in `BLE_GAP_EVENT_CONNECT`. +2. **Encryption on, EATT off**: GATT operations resume after encryption is established in `BLE_GAP_EVENT_ENC_CHANGE`. +3. **Encryption off, EATT on**: GATT operations resume after connection. EATT establishment requires encryption, so with encryption off, EATT bearers cannot be created. +4. **Encryption on, EATT on**: This is the correct way to use EATT. GATT operations resume in `BLE_GAP_EVENT_EATT`. After connection, the application waits for encryption. Once encrypted, the host automatically attempts to establish EATT bearers. Upon success, the `BLE_GAP_EVENT_EATT` event is triggered, and GATT operations resume. + +The example uses `ble_att_set_default_bearer_using_cid` to set the CID for upcoming GATT operations. A similar API, `ble_att_get_default_bearer_cid`, can be used to retrieve the current default bearer CID. + ## Example Output This is the console output on successful connection: @@ -168,6 +184,39 @@ The following configuration flags can be adjusted to significantly reduce RAM us | CONFIG_ESP_TASK_WDT_EN | y → n | 528 | | CONFIG_LOG_DEFAULT_LEVEL_NONE | n → y | 2592 | +## Enhanced Attribute Protocol (EATT) + +The Enhanced Attribute Protocol (EATT) is an updated version of the Attribute Protocol (ATT) introduced in Bluetooth 5.2. It upgrades the transport mechanism for GATT operations. + +### How EATT Works in NimBLE +Unlike legacy ATT, which forces all GATT transactions to be serialized over a single fixed L2CAP channel (CID 4), EATT runs over multiple **L2CAP Enhanced Credit Based Flow Control (ECFC)** channels. + +1. **Multiple Bearers**: The `MYNEWT_VAL(BLE_EATT_CHAN_NUM)` configuration determines how many parallel L2CAP channels the host will attempt to establish with the peer. +2. **Concurrency**: In the NimBLE host (`ble_eatt.c`), the `ble_eatt_get_available_chan_cid()` function dynamically selects an idle channel for outgoing GATT requests. This means if Channel A is blocked waiting for a Read Response, the application can still send a Notification immediately on Channel B. +3. **L2CAP Independence**: Each EATT channel has its own flow control credits and MTU. A stall or large transfer on one channel does not block operations on others. + +### Implementation Flow +The setup process in this example follows the logic in `ble_eatt.c`: +1. **Encryption Trigger**: EATT strictly requires an encrypted link. The host listens for `BLE_GAP_EVENT_ENC_CHANGE`. +2. **Handshake**: Once encrypted, the host automatically reads the peer's "Server Supported Features" and writes its own "Client Supported Features" to verify EATT support. +3. **Connection**: The host then initiates L2CAP connections for the number of channels defined in `BLE_EATT_CHAN_NUM`. +4. **Ready State**: When the channels are established, the application receives `BLE_GAP_EVENT_EATT`, signaling that high-performance, concurrent GATT operations can begin. +5. **Channel Selection**: The application can direct GATT operations to specific channels using `ble_att_set_default_bearer_using_cid()` or retrieve the current bearer with `ble_att_get_default_bearer_cid()`. This allows precise control over which L2CAP channel executes a transaction. + +### NimBLE Documentation +For more detailed information, refer to the NimBLE documentation located in `components/bt/host/nimble/nimble/docs`. + +To build the documentation with Doxygen: +```bash +make clean +make preview +``` + +To host the generated documentation locally: +```bash +cd _build/html && python3 -m http.server 8080 +``` + ## Troubleshooting For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.