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-02-25 12:59:48 +05:30
parent 273bc6a0db
commit 432cd1ebdd
69 changed files with 1026 additions and 2059 deletions
@@ -1,2 +1,3 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS "."
PRIV_REQUIRES bt nvs_flash)
@@ -1,14 +1,4 @@
menu "Example Configuration"
config EXAMPLE_EXTENDED_ADV
bool
depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT
default y if SOC_ESP_NIMBLE_CONTROLLER
select BT_NIMBLE_EXT_ADV
prompt "Enable Extended Adv"
help
Use this option to enable extended advertising in the example.
If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
also disabled from NimBLE stack menuconfig
config EXAMPLE_PERIODIC_ADV_ENH
bool
@@ -1,3 +1,2 @@
dependencies:
nimble_central_utils:
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_central_utils
## IDF Component Manager Manifest File
dependencies: {}
@@ -1,23 +1,28 @@
/*
* 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
*/
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "esp_log.h"
#include "nvs_flash.h"
/* BLE */
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#include "services/gap/ble_svc_gap.h"
#include "periodic_sync.h"
#include "host/ble_gap.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
#include "modlog/modlog.h"
static const char *tag = "NimBLE_BLE_PERIODIC_SYNC";
static int synced = 0;
static int periodic_sync_gap_event(struct ble_gap_event *event, void *arg);
void ble_store_config_init(void);
@@ -26,7 +31,7 @@ static void
periodic_sync_scan(void)
{
uint8_t own_addr_type;
struct ble_gap_disc_params disc_params = {0};
struct ble_gap_ext_disc_params disc_params = {0};
int rc;
/* Figure out address to use while advertising (no privacy for now) */
@@ -36,25 +41,11 @@ periodic_sync_scan(void)
return;
}
/* Tell the controller to filter duplicates; we don't want to process
* repeated advertisements from the same device.
*/
disc_params.filter_duplicates = 0;
/**
* Perform a passive scan. I.e., don't send follow-up scan requests to
* each advertiser.
*/
disc_params.passive = 1;
/* Use defaults for the rest of the parameters. */
disc_params.itvl = 0;
disc_params.window = 0;
disc_params.filter_policy = 0;
disc_params.limited = 0;
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
periodic_sync_gap_event, NULL);
rc = ble_gap_ext_disc(own_addr_type, 0, 0,
0, 0, 0, &disc_params, &disc_params,
periodic_sync_gap_event, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
rc);
@@ -63,32 +54,31 @@ periodic_sync_scan(void)
void print_periodic_sync_data(struct ble_gap_event *event)
{
MODLOG_DFLT(DEBUG, "status : %d\nperiodic_sync_handle : %d\nsid : %d\n", event->periodic_sync.status, event->periodic_sync.sync_handle, event->periodic_sync.sid);
MODLOG_DFLT(DEBUG, "adv addr : ");
for (int i = 0; i < 6; i++) {
MODLOG_DFLT(DEBUG, "%d ", event->periodic_sync.adv_addr.val[i]);
}
MODLOG_DFLT(DEBUG, "\nadv_phy : %s\n", event->periodic_sync.adv_phy == 1 ? "1m" : (event->periodic_sync.adv_phy == 2 ? "2m" : "coded"));
MODLOG_DFLT(DEBUG, "per_adv_ival : %d\n", event->periodic_sync.per_adv_ival);
MODLOG_DFLT(DEBUG, "adv_clk_accuracy : %d\n", event->periodic_sync.adv_clk_accuracy);
MODLOG_DFLT(INFO, "status : %d\nperiodic_sync_handle : %d\nsid : %d\n",
event->periodic_sync.status, event->periodic_sync.sync_handle, event->periodic_sync.sid);
MODLOG_DFLT(INFO, "adv addr : ");
ESP_LOG_BUFFER_HEX("NimBLE", event->periodic_sync.adv_addr.val, 6);
MODLOG_DFLT(INFO, "adv_phy : %s\n", event->periodic_sync.adv_phy == 1 ? "1m" : (event->periodic_sync.adv_phy == 2 ? "2m" : "coded"));
MODLOG_DFLT(INFO, "per_adv_ival : %d\n", event->periodic_sync.per_adv_ival);
MODLOG_DFLT(INFO, "adv_clk_accuracy : %d\n", event->periodic_sync.adv_clk_accuracy);
}
void print_periodic_adv_data(struct ble_gap_event *event)
{
MODLOG_DFLT(DEBUG, "sync_handle : %d\n", event->periodic_report.sync_handle);
MODLOG_DFLT(DEBUG, "tx_power : %d\n", event->periodic_report.tx_power);
MODLOG_DFLT(DEBUG, "rssi : %d\n", event->periodic_report.rssi);
MODLOG_DFLT(DEBUG, "data_status : %d\n", event->periodic_report.data_status);
MODLOG_DFLT(DEBUG, "data_length : %d\n", event->periodic_report.data_length);
MODLOG_DFLT(DEBUG, "data : ");
for (int i = 0; i < event->periodic_report.data_length; i++) {
MODLOG_DFLT(DEBUG, "%c", ((char *)event->periodic_report.data)[i]);
}
MODLOG_DFLT(DEBUG, "\n");
MODLOG_DFLT(INFO, "sync_handle : %d\n", event->periodic_report.sync_handle);
MODLOG_DFLT(INFO, "tx_power : %d\n", event->periodic_report.tx_power);
MODLOG_DFLT(INFO, "rssi : %d\n", event->periodic_report.rssi);
MODLOG_DFLT(INFO, "data_status : %d\n", event->periodic_report.data_status);
MODLOG_DFLT(INFO, "data_length : %d\n", event->periodic_report.data_length);
MODLOG_DFLT(INFO, "data : ");
ESP_LOG_BUFFER_HEX("NimBLE", event->periodic_report.data, event->periodic_report.data_length);
MODLOG_DFLT(INFO, "\n");
}
void print_periodic_sync_lost_data(struct ble_gap_event *event)
{
MODLOG_DFLT(DEBUG, "sync_handle : %d\n", event->periodic_sync_lost.sync_handle);
MODLOG_DFLT(DEBUG, "reason : %s\n", event->periodic_sync_lost.reason == 13 ? "timeout" : (event->periodic_sync_lost.reason == 14 ? "terminated locally" : "Unknown reason"));
MODLOG_DFLT(INFO, "sync_handle : %d\n", event->periodic_sync_lost.sync_handle);
MODLOG_DFLT(INFO, "reason : %s\n", event->periodic_sync_lost.reason == 13 ? "timeout" : (event->periodic_sync_lost.reason == 14 ? "terminated locally" : "Unknown reason"));
}
/**
* The nimble host executes this callback when a GAP event occurs. The
@@ -107,19 +97,16 @@ void print_periodic_sync_lost_data(struct ble_gap_event *event)
static int
periodic_sync_gap_event(struct ble_gap_event *event, void *arg)
{
(void)arg;
switch (event->type) {
#if CONFIG_EXAMPLE_EXTENDED_ADV
case BLE_GAP_EVENT_EXT_DISC:
case BLE_GAP_EVENT_EXT_DISC: {
/* An advertisement report was received during GAP discovery. */
struct ble_gap_ext_disc_desc *disc = ((struct ble_gap_ext_disc_desc *)(&event->ext_disc));
const struct ble_gap_ext_disc_desc *disc = &event->ext_disc;
if (disc->sid == 2 && synced == 0) {
synced++;
ble_addr_t addr;
uint8_t adv_sid;
struct ble_gap_periodic_sync_params params;
struct ble_gap_periodic_sync_params params = {0};
int rc;
memcpy(&addr, &disc->addr, sizeof(disc->addr));
memcpy(&adv_sid, &disc->sid, sizeof(disc->sid));
synced++;
params.skip = 10;
params.sync_timeout = 1000;
@@ -129,10 +116,11 @@ periodic_sync_gap_event(struct ble_gap_event *event, void *arg)
or the Data-Id is updated by the advertiser */
params.filter_duplicates = 1;
#endif
rc = ble_gap_periodic_adv_sync_create(&addr, adv_sid, &params, periodic_sync_gap_event, NULL);
rc = ble_gap_periodic_adv_sync_create(&disc->addr, disc->sid, &params, periodic_sync_gap_event, NULL);
assert(rc == 0);
}
return 0;
}
case BLE_GAP_EVENT_PERIODIC_REPORT:
MODLOG_DFLT(INFO, "Periodic adv report event: \n");
print_periodic_adv_data(event);
@@ -141,12 +129,19 @@ periodic_sync_gap_event(struct ble_gap_event *event, void *arg)
MODLOG_DFLT(INFO, "Periodic sync lost\n");
print_periodic_sync_lost_data(event);
synced = 0;
/* Restart scanning to re-sync */
periodic_sync_scan();
return 0;
case BLE_GAP_EVENT_PERIODIC_SYNC:
case BLE_GAP_EVENT_PERIODIC_SYNC:
MODLOG_DFLT(INFO, "Periodic sync event : \n");
print_periodic_sync_data(event);
if (event->periodic_sync.status != 0) {
synced = 0;
} else {
/* Cancel scanning since sync is established */
ble_gap_disc_cancel();
}
return 0;
#endif
default:
return 0;
}
@@ -166,7 +161,7 @@ periodic_sync_on_sync(void)
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Begin scanning for a peripheral to connect to. */
/* Begin scanning for a periodic advertiser to sync with. */
periodic_sync_scan();
}
@@ -182,7 +177,6 @@ void periodic_sync_host_task(void *param)
void
app_main(void)
{
int rc;
/* Initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
@@ -202,17 +196,9 @@ app_main(void)
ble_hs_cfg.sync_cb = periodic_sync_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* Initialize data structures to track connected peers. */
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64);
assert(rc == 0);
#else
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
assert(rc == 0);
#endif
#if CONFIG_BT_NIMBLE_GAP_SERVICE
/* Set the default device name. */
rc = ble_svc_gap_device_name_set("nimble_periodic_sync");
int rc = ble_svc_gap_device_name_set("nimble_periodic_sync");
assert(rc == 0);
#endif
@@ -1,26 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef H_BLE_PERIODIC_SYNC_
#define H_BLE_PERIODIC_SYNC_
#include "modlog/modlog.h"
#include "esp_central.h"
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_adv_fields;
struct ble_gap_conn_desc;
struct ble_hs_cfg;
union ble_store_value;
union ble_store_key;
#ifdef __cplusplus
}
#endif
#endif