fix(nimble): Improve safety, fix bugs, and update docs across NimBLE examples

- Remove unused headers from examples
- Improve periodic adv/sync example functionality and readability
- Use ble_hs_id_infer_auto() instead of hardcoded BLE_OWN_ADDR_PUBLIC/RANDOM
- Add ble_hs_util_ensure_addr() calls in on_sync for proper address setup
- Use correct ext adv instance (0 instead of 1) in phy_prph, l2cap_coc, multi_conn
- Fix struct name: ble_gap_periodic_adv_enable_params -> ble_gap_periodic_adv_start_params
- Add CONFIG_BT_NIMBLE_GAP_SERVICE guards around ble_svc_gap_device_name_set
- Fix unsafe AD data parsing with bounds checks in central examples
- Fix UUID matching bugs (off-by-one loop condition and byte order) in
  phy_cent, htp_cent, and proximity_sensor_cent
- Fix ble_multi_conn_cent address type to use dynamic inference
- Remove contradictory sm_sc=0 after sm_sc=1 in ble_multi_adv
- Add CONFIG_BT_NIMBLE_EXT_ADV=y to ble_multi_adv sdkconfig defaults
- Check return values for ble_gap_set_host_feat, nimble_port_init
- Update tutorials and READMEs to match code changes
This commit is contained in:
Rahul Tank
2026-03-20 11:06:13 +05:30
parent 77462b9f65
commit 745b7bea38
69 changed files with 1054 additions and 2091 deletions
@@ -5,7 +5,7 @@
(See the README.md file in the upper level 'examples' directory for more information about examples.)
`bleprph_throughput` demonstrates server side implementation required for NimBLE throughput example. It has characteristics supporting READ, WRITE and NOTIFY (`PTS_LONG_CHR_READ_WRITE`,`PTS_CHR_READ_WRITE`,`PTS_CHR_NOTIFY`). The data of 500 Bytes (`READ_THROUGHPUT_PAYLOAD`) and 400 Bytes (`WRITE_THROUGHPUT_PAYLOAD`) is transferred for throughput GATT read and write operations respectively.
`bleprph_throughput` demonstrates server side implementation required for NimBLE throughput example. It has characteristics supporting READ, WRITE and NOTIFY (`THRPT_LONG_CHR_READ_WRITE`, `THRPT_CHR_READ_WRITE`, `THRPT_CHR_NOTIFY`). The read characteristic holds 510 bytes (`READ_THROUGHPUT_PAYLOAD`) and the write characteristic accepts up to 509 bytes (`WRITE_THROUGHPUT_PAYLOAD`). Notifications are sent with a 509-byte payload (`NOTIFY_THROUGHPUT_PAYLOAD`). These sizes are chosen to maximize ATT PDU utilization with the default MTU of 512.
`bleprph_throughput` uses the `nimble` component as BLE host.
@@ -61,7 +61,9 @@ I (83943) bleprph_throughput: Notification test completed for stipulated time o
> Here, bps is bits per second; count is number of Notifications successfully sent.
## Example scope
## Example Scope
This demo example along with `blecent_throughput` tries to demonstrate stable implementation of GATT operations like read/write and notify. For `bleprph_throughput` app, notifications are sent almost continuously for stipulated period of time. The almost part is because we use counting semaphore (~100) to mimic continuous notifications. Here one needs to understand that notifications are sent in `os_mbufs` packets and there can always be chance of them getting full because of continuous operation, so one may need to allocate higher number of mbufs through menuconfig, whenever there is `os_mbuf` memory exhaustion, app provides delay so NimBLE host stack can breathe and free `mbuf chains`.
This demo example along with `blecent_throughput` demonstrates stable GATT read/write and notify operations at high throughput. For notifications, the peripheral uses a pipelined approach: a counting semaphore (max 100) allows multiple notifications to be queued simultaneously (pipeline depth of 15). This enables the BLE controller to pack multiple PDUs into each connection event for maximum throughput.
Notifications are sent in `os_mbufs` packets. The example is configured with `CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=50` to provide sufficient buffer space. If mbuf exhaustion occurs during continuous transfer, the app yields briefly to allow the NimBLE host stack to free completed `mbuf chains` before retrying.
@@ -33,8 +33,8 @@
#define THRPT_CHR_NOTIFY 0x000a
#define THRPT_LONG_CHR_READ_WRITE 0x000b
#define READ_THROUGHPUT_PAYLOAD 500
#define WRITE_THROUGHPUT_PAYLOAD 500
#define READ_THROUGHPUT_PAYLOAD 510 /* MTU(512) - ATT read rsp header(1) - 1 (avoid Read Blob) */
#define WRITE_THROUGHPUT_PAYLOAD 509 /* MTU(512) - ATT write cmd header(3) */
static const char *tag = "bleprph_throughput";
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -30,8 +30,9 @@ static uint8_t s_current_phy;
static const char *device_name = "nimble_prph";
#define NOTIFY_THROUGHPUT_PAYLOAD 495
#define MIN_REQUIRED_MBUF 2 /* Assuming payload of 500Bytes and each mbuf can take 292Bytes. */
#define NOTIFY_THROUGHPUT_PAYLOAD 509 /* MTU(512) - ATT notify header(3) */
#define MIN_REQUIRED_MBUF 2 /* Assuming payload of 500Bytes and each mbuf can take 292Bytes. */
#define NOTIFY_PIPELINE_DEPTH 15 /* Number of notifications to keep in flight for throughput */
#define PREFERRED_MTU_VALUE 512
#define LL_PACKET_TIME 2120
#define LL_PACKET_LENGTH 251
@@ -276,8 +277,8 @@ notify_task(void *arg)
do {
om = ble_hs_mbuf_from_flat(payload, sizeof(payload));
if (om == NULL) {
/* Memory not available for mbuf */
vTaskDelay(100 / portTICK_PERIOD_MS);
/* Memory not available for mbuf, yield briefly */
vTaskDelay(1);
}
} while (om == NULL);
@@ -286,18 +287,14 @@ notify_task(void *arg)
ESP_LOGE(tag, "Error while sending notification; rc = %d", rc);
notify_count -= 1;
xSemaphoreGive(notify_sem);
/* Most probably error is because we ran out of mbufs (rc = 6),
* increase the mbuf count/size from menuconfig. Though
* inserting delay is not good solution let us keep it
* simple for time being so that the mbufs get freed up
* (?), of course assumption is we ran out of mbufs */
vTaskDelay(10 / portTICK_PERIOD_MS);
/* Yield to let mbufs free up */
vTaskDelay(1);
}
} else {
ESP_LOGE(tag, "Not enough OS_MBUFs available; reduce notify count ");
xSemaphoreGive(notify_sem);
notify_count -= 1;
vTaskDelay(10 / portTICK_PERIOD_MS);
/* Yield briefly to let mbufs free up */
vTaskDelay(1);
}
end_time = esp_timer_get_time();
@@ -395,7 +392,14 @@ gatts_gap_event(struct ble_gap_event *event, void *arg)
ESP_LOGI(tag, "notify test time = %d", *(int *)arg);
notify_test_time = *((int *)arg);
}
xSemaphoreGive(notify_sem);
if (notify_state) {
/* Prime the notification pipeline to allow multiple in-flight
* notifications. This enables the controller to fill connection
* events with back-to-back PDUs for maximum throughput. */
for (int i = 0; i < NOTIFY_PIPELINE_DEPTH; i++) {
xSemaphoreGive(notify_sem);
}
}
} else if (event->subscribe.attr_handle != notify_handle) {
notify_state = event->subscribe.cur_notify;
}