mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(ble_audio): Support running ISO & LE Audio with Bluedroid Host
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
This example acts as a **BAP Broadcast Source**. It creates a BAP broadcast source from the LC3 `16_2_1` broadcast preset, encodes the BASE into the periodic advertising payload, places the Broadcast Audio Announcement Service UUID and a fixed 24-bit Broadcast ID (`0x123456`) in the extended advertising payload, and then starts the BIG so that BIS streams transmit synthetic SDU data on a fixed cadence.
|
||||
|
||||
The build runs on top of the NimBLE host stack and the ESP BLE Audio component set. Source-side APIs used: `esp_ble_audio_common_init` / `esp_ble_audio_common_start` (common layer), `esp_ble_audio_bap_broadcast_source_create` / `_get_base` / `_start` (BAP), `esp_ble_audio_bap_broadcast_adv_add` (BAP/ISO glue), and the BAP stream callbacks (`started`, `stopped`, `sent`, `disconnected`). PACS, GAP scanner, and the scan delegator are **not** used on this side. Encryption is enabled because the broadcast code `"1234"` is non-empty; packing is `ESP_BLE_ISO_PACKING_SEQUENTIAL`. Channel allocation per stream is hard-coded as `FRONT_LEFT` for stream 0 and `FRONT_RIGHT` for stream 1.
|
||||
The build runs on top of the selected BLE host stack (Bluedroid by default; NimBLE via the `sdkconfig.defaults.nimble` overlay) and the ESP BLE Audio component set. Source-side APIs used: `esp_ble_audio_common_init` / `esp_ble_audio_common_start` (common layer), `esp_ble_audio_bap_broadcast_source_create` / `_get_base` / `_start` (BAP), `esp_ble_audio_bap_broadcast_adv_add` (BAP/ISO glue), and the BAP stream callbacks (`started`, `stopped`, `sent`, `disconnected`). PACS, GAP scanner, and the scan delegator are **not** used on this side. Encryption is enabled because the broadcast code `"1234"` is non-empty; packing is `ESP_BLE_ISO_PACKING_SEQUENTIAL`. Channel allocation per stream is hard-coded as `FRONT_LEFT` for stream 0 and `FRONT_RIGHT` for stream 1.
|
||||
|
||||
The TX scheduler is built on `example_audio_tx_scheduler_*` helpers; the source comment notes that ESP timer resolution is not accurate enough for the SDU interval, so a `k_work_delayable`-based scheduler is used instead.
|
||||
|
||||
@@ -34,11 +34,24 @@ The example inherits a Just-Works pairing model (LE Secure Connections, no MITM,
|
||||
|
||||
## Build & Flash
|
||||
|
||||
The base `sdkconfig.defaults` defaults to the **Bluedroid** host; idf.py automatically merges the per-target overlay (`sdkconfig.defaults.$IDF_TARGET`). To build with **NimBLE** host instead, layer `sdkconfig.defaults.nimble` on top via `-DSDKCONFIG_DEFAULTS`.
|
||||
|
||||
### Bluedroid host (default)
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4 # or esp32s31
|
||||
idf.py set-target esp32h4
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
### NimBLE host
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4
|
||||
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32h4;sdkconfig.defaults.nimble" -p PORT flash monitor
|
||||
```
|
||||
|
||||
For `esp32s31`, replace the chip overlay accordingly.
|
||||
|
||||
(Exit serial monitor with `Ctrl-]`.)
|
||||
|
||||
## Example Flow
|
||||
@@ -46,7 +59,7 @@ idf.py -p PORT flash monitor
|
||||
1. `app_main` initializes NVS, calls `bluetooth_init()`, and calls `esp_ble_audio_common_init(NULL)` (no GAP callback for this role).
|
||||
2. `broadcast_source_setup()` registers `source_started` / `source_stopped` callbacks, populates per-stream channel-allocation BIS metadata (left/right), registers `stream_ops` on each stream, and calls `esp_ble_audio_bap_broadcast_source_create()` with the encrypted preset.
|
||||
3. `esp_ble_audio_common_start(NULL)` starts the audio stack; each stream's `example_audio_tx_scheduler_init()` is wired with `tx_scheduler_cb`.
|
||||
4. `ext_adv_start()` configures non-connectable extended adv (1M primary / 2M secondary, 200 ms interval), writes Broadcast Audio Service Data + Broadcast ID + complete name, configures periodic adv (100 ms), writes the BASE returned by `esp_ble_audio_bap_broadcast_source_get_base()`, then starts periodic and extended advertising.
|
||||
4. `adv_init()` performs host-specific GAP setup (Bluedroid: registers the GAP callback for `*_COMPLETE_EVT` semaphore signalling; NimBLE: no-op — adv-instance callback is passed at configure time). `ext_adv_start()` builds the extended (Broadcast Audio Service Data + Broadcast ID + complete name) and periodic (BASE from `esp_ble_audio_bap_broadcast_source_get_base()`) payloads in host-agnostic bytes, then calls `adv_start(ext_data, ext_len, per_data, per_len)`. The host-specific implementation in `main/bluedroid/adv.c` or `main/nimble/adv.c` configures non-connectable extended adv (1M primary / 2M secondary, 200 ms interval), configures periodic adv (100 ms), writes both payloads, and starts periodic and extended advertising.
|
||||
5. `broadcast_start()` calls `esp_ble_audio_bap_broadcast_adv_add()` and `esp_ble_audio_bap_broadcast_source_start()` on the same `ADV_HANDLE`, which kicks off BIGInfo + BIS creation.
|
||||
6. When each BIS stream goes streaming, `stream_started_cb` allocates an SDU-sized buffer and calls `example_audio_tx_scheduler_start()` at `preset_active.qos.interval`; the scheduler invokes `broadcast_source_tx()`, which fills the buffer with the low byte of `seq_num` and calls `esp_ble_audio_bap_stream_send()`.
|
||||
7. `stream_sent_cb` forwards completions to `example_audio_tx_scheduler_on_sent()` for drift accounting; `stream_stopped_cb` and `stream_disconnected_cb` stop the scheduler; `source_stopped_cb` frees all per-stream buffers.
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
set(srcs "main.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND srcs "bluedroid/adv.c")
|
||||
else()
|
||||
list(APPEND srcs "nimble/adv.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES bt nvs_flash)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSRC"
|
||||
|
||||
#define ADV_HANDLE 0
|
||||
#define ADV_SID 0
|
||||
#define ADV_TX_POWER 127
|
||||
#define ADV_INTERVAL_MS 200
|
||||
#define PER_ADV_INTERVAL_MS 100
|
||||
|
||||
int app_host_init(void);
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len);
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
|
||||
#include "adv.h"
|
||||
|
||||
static SemaphoreHandle_t adv_sem;
|
||||
|
||||
/* Controller status latched by gap_event_handler for EXAMPLE_WAIT_API_CHECK. */
|
||||
static esp_bt_status_t adv_op_status;
|
||||
|
||||
#define WAIT_API(_call) EXAMPLE_WAIT_API_CHECK(_call, adv_sem, portMAX_DELAY, adv_op_status)
|
||||
|
||||
static esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
.max_skip = 0,
|
||||
.secondary_phy = ESP_BLE_GAP_PHY_2M,
|
||||
.sid = ADV_SID,
|
||||
.scan_req_notif = false,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.tx_power = ADV_TX_POWER,
|
||||
};
|
||||
|
||||
static esp_ble_gap_periodic_adv_params_t periodic_adv_params = {
|
||||
.interval_min = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(PER_ADV_INTERVAL_MS),
|
||||
.interval_max = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(PER_ADV_INTERVAL_MS),
|
||||
.properties = 0,
|
||||
};
|
||||
|
||||
static esp_ble_gap_ext_adv_t ext_adv_inst[1] = {
|
||||
[0] = { ADV_HANDLE, 0, 0 },
|
||||
};
|
||||
|
||||
static void gap_event_handler(esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_set_params.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_data_set.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_start.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
adv_op_status = param->peroid_adv_set_params.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT:
|
||||
adv_op_status = param->period_adv_data_set.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT:
|
||||
adv_op_status = param->period_adv_start.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
adv_sem = xSemaphoreCreateBinary();
|
||||
if (adv_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create adv semaphore");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to register GAP callback, err %d", err);
|
||||
vSemaphoreDelete(adv_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_ext_adv_set_params(ADV_HANDLE, &ext_adv_params));
|
||||
WAIT_API(esp_ble_gap_config_ext_adv_data_raw(ADV_HANDLE, ext_len, ext_data));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_set_params(ADV_HANDLE, &periodic_adv_params));
|
||||
#if CONFIG_BT_BLE_FEAT_PERIODIC_ADV_ENH
|
||||
WAIT_API(esp_ble_gap_config_periodic_adv_data_raw(ADV_HANDLE, per_len, per_data, false));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_start(ADV_HANDLE, true));
|
||||
#else
|
||||
WAIT_API(esp_ble_gap_config_periodic_adv_data_raw(ADV_HANDLE, per_len, per_data));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_start(ADV_HANDLE));
|
||||
#endif
|
||||
WAIT_API(esp_ble_gap_ext_adv_start(1, ext_adv_inst));
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
return 0;
|
||||
}
|
||||
@@ -9,17 +9,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "esp_ble_audio_lc3_defs.h"
|
||||
#include "esp_ble_audio_bap_api.h"
|
||||
@@ -29,7 +22,7 @@
|
||||
#include "ble_audio_example_init.h"
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSRC"
|
||||
#include "adv.h"
|
||||
|
||||
ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(preset_active,
|
||||
ESP_BLE_AUDIO_LOCATION_FRONT_LEFT |
|
||||
@@ -42,16 +35,6 @@ ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(preset_active,
|
||||
#define LOCAL_BROADCAST_CODE "1234" /* Maximum length is 16 */
|
||||
#define LOCAL_BROADCAST_ID 0x123456
|
||||
|
||||
#define ADV_HANDLE 0x00
|
||||
#define ADV_SID 0
|
||||
#define ADV_TX_POWER 127
|
||||
#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC
|
||||
#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M
|
||||
#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M
|
||||
#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200)
|
||||
|
||||
#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100)
|
||||
|
||||
#define STREAM_COUNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT
|
||||
#define SUBGROUP_COUNT CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT
|
||||
|
||||
@@ -369,138 +352,55 @@ static uint8_t *per_adv_data_get(uint8_t *data_len)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int ext_adv_start(void)
|
||||
static int broadcast_start(void)
|
||||
{
|
||||
struct ble_gap_periodic_adv_params per_params = {0};
|
||||
struct ble_gap_ext_adv_params ext_params = {0};
|
||||
struct os_mbuf *data = NULL;
|
||||
esp_ble_audio_bap_broadcast_adv_info_t info = {
|
||||
.adv_handle = ADV_HANDLE,
|
||||
};
|
||||
/* BASE (per_adv_data_get) needs broadcast_source to exist — built earlier
|
||||
* by broadcast_source_setup(), so safe to call here. */
|
||||
uint8_t *ext_data = NULL;
|
||||
uint8_t *per_data = NULL;
|
||||
uint8_t data_len = 0;
|
||||
int err;
|
||||
uint8_t ext_len = 0;
|
||||
uint8_t per_len = 0;
|
||||
int err = 0;
|
||||
|
||||
ext_params.connectable = 0;
|
||||
ext_params.scannable = 0;
|
||||
ext_params.legacy_pdu = 0;
|
||||
ext_params.own_addr_type = ADV_ADDRESS;
|
||||
ext_params.primary_phy = ADV_PRIMARY_PHY;
|
||||
ext_params.secondary_phy = ADV_SECONDARY_PHY;
|
||||
ext_params.tx_power = ADV_TX_POWER;
|
||||
ext_params.sid = ADV_SID;
|
||||
ext_params.itvl_min = ADV_INTERVAL;
|
||||
ext_params.itvl_max = ADV_INTERVAL;
|
||||
|
||||
err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ext_data = ext_adv_data_get(&data_len);
|
||||
ext_data = ext_adv_data_get(&ext_len);
|
||||
if (ext_data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(data_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get ext adv mbuf");
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, ext_data, data_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
per_params.include_tx_power = 0;
|
||||
per_params.itvl_min = PER_ADV_INTERVAL;
|
||||
per_params.itvl_max = PER_ADV_INTERVAL;
|
||||
|
||||
err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
per_data = per_adv_data_get(&data_len);
|
||||
per_data = per_adv_data_get(&per_len);
|
||||
if (per_data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(data_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get per adv mbuf");
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, per_data, data_len);
|
||||
err = ext_adv_start(ext_data, ext_len, per_data, per_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append per adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set per adv data, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_start(ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start per advertising, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
|
||||
end:
|
||||
if (ext_data) {
|
||||
free(ext_data);
|
||||
}
|
||||
if (per_data) {
|
||||
free(per_data);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void broadcast_start(void)
|
||||
{
|
||||
esp_ble_audio_bap_broadcast_adv_info_t info = {
|
||||
.adv_handle = ADV_HANDLE,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = esp_ble_audio_bap_broadcast_adv_add(&info);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to add adv for broadcast source, err %d", err);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = esp_ble_audio_bap_broadcast_source_start(broadcast_source, ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start broadcast source, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ext_data != NULL) {
|
||||
free(ext_data);
|
||||
}
|
||||
if (per_data != NULL) {
|
||||
free(per_data);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
@@ -521,6 +421,12 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
err = app_host_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to init host, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_ble_audio_common_init(NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio, err %d", err);
|
||||
@@ -548,10 +454,9 @@ void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
err = ext_adv_start();
|
||||
err = broadcast_start();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start broadcast, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
broadcast_start();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "host/ble_gap.h"
|
||||
|
||||
#include "adv.h"
|
||||
|
||||
/* Non-connectable broadcaster: no GAP events for the application. */
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len)
|
||||
{
|
||||
struct ble_gap_periodic_adv_params per_params = {0};
|
||||
struct ble_gap_ext_adv_params ext_params = {0};
|
||||
struct os_mbuf *data;
|
||||
int err;
|
||||
|
||||
ext_params.connectable = 0;
|
||||
ext_params.scannable = 0;
|
||||
ext_params.legacy_pdu = 0;
|
||||
ext_params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
ext_params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
ext_params.secondary_phy = BLE_HCI_LE_PHY_2M;
|
||||
ext_params.tx_power = ADV_TX_POWER;
|
||||
ext_params.sid = ADV_SID;
|
||||
ext_params.itvl_min = BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS);
|
||||
ext_params.itvl_max = BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS);
|
||||
|
||||
err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL,
|
||||
gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(ext_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get ext adv mbuf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, ext_data, ext_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
per_params.include_tx_power = 0;
|
||||
per_params.itvl_min = BLE_GAP_PERIODIC_ITVL_MS(PER_ADV_INTERVAL_MS);
|
||||
per_params.itvl_max = BLE_GAP_PERIODIC_ITVL_MS(PER_ADV_INTERVAL_MS);
|
||||
|
||||
err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(per_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get per adv mbuf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, per_data, per_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append per adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set per adv data, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_start(ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start per advertising, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,14 +3,19 @@
|
||||
#
|
||||
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
CONFIG_BT_CLASSIC_ENABLED=n
|
||||
CONFIG_BT_CONTROLLER_ENABLED=y
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=1
|
||||
CONFIG_BT_BLE_FEAT_ISO_EN=y
|
||||
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# NimBLE host overlay for this example.
|
||||
# Use with:
|
||||
# idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.$IDF_TARGET;sdkconfig.defaults.nimble" build
|
||||
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
Reference in New Issue
Block a user