mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50: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 takes the **TMAP Call Gateway (CG)** and **Unicast Media Sender (UMS)** roles, registered together via `esp_ble_audio_tmap_register(ESP_BLE_AUDIO_TMAP_ROLE_CG | ESP_BLE_AUDIO_TMAP_ROLE_UMS)`. It scans for connectable extended advertising that carries TMAS service data with the **UMR** role bit set, connects to the first match, pairs, exchanges MTU, and then drives TMAP and VCP discovery before bringing up unicast audio.
|
||||
|
||||
The host stack is NimBLE. The example uses the ESP-BLE-AUDIO library pieces for: CAP initiator with the BAP Unicast Client (LC3 preset 48_2_1, sink direction, FRONT_LEFT, MEDIA context), VCP Volume Controller, MCP server backed by the media proxy player, and CCP server registering a single GTBS bearer (`Generic TBS`, UCI `un000`, `tel,wechat` URI schemes, 5G technology). A periodic TX scheduler in the ISO task feeds dummy ISO SDUs filled with the sequence number. Device name is set to `TMAP Central`.
|
||||
The example uses the ESP-BLE-AUDIO library pieces for: CAP initiator with the BAP Unicast Client (LC3 preset 48_2_1, sink direction, FRONT_LEFT, MEDIA context), VCP Volume Controller, MCP server backed by the media proxy player, and CCP server registering a single GTBS bearer (`Generic TBS`, UCI `un000`, `tel,wechat` URI schemes, 5G technology). A periodic TX scheduler in the ISO task feeds dummy ISO SDUs filled with the sequence number. Device name is set to `TMAP Central`.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -30,11 +30,24 @@ Just-Works pairing (LE Secure Connections, no MITM, no I/O capability) with bond
|
||||
|
||||
## 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
|
||||
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
|
||||
|
||||
@@ -4,5 +4,12 @@ set(srcs "cap_initiator.c"
|
||||
"vcp_vol_ctlr.c"
|
||||
"main.c")
|
||||
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND srcs "bluedroid/central.c")
|
||||
else()
|
||||
list(APPEND srcs "nimble/central.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES bt nvs_flash)
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gattc_api.h"
|
||||
|
||||
#include "esp_ble_audio_common_api.h"
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
static SemaphoreHandle_t scan_sem;
|
||||
|
||||
/* Controller status latched by gap_event_handler for EXAMPLE_WAIT_API_CHECK. */
|
||||
static esp_bt_status_t scan_op_status;
|
||||
|
||||
#define WAIT_API(_call) EXAMPLE_WAIT_API_CHECK(_call, scan_sem, portMAX_DELAY, scan_op_status)
|
||||
|
||||
/* Cached peer address. Bluedroid's pairing and disconnect APIs key off
|
||||
* bd_addr rather than conn_handle, so we stash the addr at conn_create
|
||||
* time and reuse it in pairing_start / security_failed_recover. */
|
||||
static esp_bd_addr_t peer_bda;
|
||||
|
||||
static esp_ble_ext_scan_params_t ext_scan_params = {
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE,
|
||||
.cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK,
|
||||
.uncoded_cfg = {
|
||||
.scan_type = BLE_SCAN_TYPE_PASSIVE,
|
||||
.scan_interval = SCAN_INTERVAL,
|
||||
.scan_window = SCAN_WINDOW,
|
||||
},
|
||||
};
|
||||
|
||||
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_SET_EXT_SCAN_PARAMS_COMPLETE_EVT:
|
||||
scan_op_status = param->set_ext_scan_params.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT:
|
||||
scan_op_status = param->ext_scan_start.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT:
|
||||
scan_op_status = param->ext_scan_stop.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
|
||||
/* SMP request handling for Just Works pairing (IO_CAP=NONE). NC_REQ
|
||||
* still fires under LE Secure Connections — auto-accept. We never get
|
||||
* SEC_REQ here because the central initiates via esp_ble_set_encryption. */
|
||||
case ESP_GAP_BLE_NC_REQ_EVT:
|
||||
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);
|
||||
break;
|
||||
|
||||
/* AUTH_CMPL has no BTA channel — app must forward it. EXT_ADV_REPORT
|
||||
* is forwarded by adapter's BTA path, don't re-post here. */
|
||||
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
||||
esp_ble_audio_gap_app_post_event(event, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
scan_sem = xSemaphoreCreateBinary();
|
||||
if (scan_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create scan 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(scan_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_device_name(void)
|
||||
{
|
||||
return esp_ble_gap_set_device_name(LOCAL_DEVICE_NAME);
|
||||
}
|
||||
|
||||
int ext_scan_start(void)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_set_ext_scan_params(&ext_scan_params));
|
||||
WAIT_API(esp_ble_gap_start_ext_scan(0, 0));
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for peripheral...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_scan_stop(void)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_stop_ext_scan());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conn_create(uint8_t addr_type, const uint8_t addr[6])
|
||||
{
|
||||
/* Values shared with NimBLE side via tmap_central.h for behavioral parity.
|
||||
* Without prefer_ext_connect_params_set, L2CAP falls back to defaults
|
||||
* and logs "No extend connection parameters set". */
|
||||
const esp_ble_gap_conn_params_t conn_params = {
|
||||
.scan_interval = INIT_SCAN_INTERVAL,
|
||||
.scan_window = INIT_SCAN_WINDOW,
|
||||
.interval_min = CONN_INTERVAL,
|
||||
.interval_max = CONN_INTERVAL,
|
||||
.latency = CONN_LATENCY,
|
||||
.supervision_timeout = CONN_TIMEOUT,
|
||||
.min_ce_len = CONN_MIN_CE_LEN,
|
||||
.max_ce_len = CONN_MAX_CE_LEN,
|
||||
};
|
||||
esp_gatt_if_t gattc_if;
|
||||
esp_err_t err;
|
||||
|
||||
memcpy(peer_bda, addr, sizeof(peer_bda));
|
||||
|
||||
err = esp_ble_gap_prefer_ext_connect_params_set(
|
||||
peer_bda, ESP_BLE_GAP_PHY_1M_PREF_MASK, &conn_params, NULL, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set ext conn params, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Use the audio engine's GATTC if so OPEN/CONNECT events route back to
|
||||
* the engine. aux_open initiates an ACL against an extended advertiser.
|
||||
*
|
||||
* engine returns ESP_GATT_IF_NONE (0xFF) when GATTC is not yet registered;
|
||||
* feeding that into aux_open silently no-ops in BTC and no acl_connect
|
||||
* event ever fires, leaving the caller in a no-scan / no-conn dead state. */
|
||||
gattc_if = esp_ble_audio_bluedroid_get_gattc_if();
|
||||
if (gattc_if == ESP_GATT_IF_NONE) {
|
||||
ESP_LOGE(TAG, "GATTC not registered");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
return esp_ble_gattc_aux_open(gattc_if, peer_bda,
|
||||
(esp_ble_addr_type_t)addr_type, true);
|
||||
}
|
||||
|
||||
int pairing_start(uint16_t conn_handle)
|
||||
{
|
||||
(void)conn_handle;
|
||||
return esp_ble_set_encryption(peer_bda, ESP_BLE_SEC_ENCRYPT_NO_MITM);
|
||||
}
|
||||
|
||||
int exchange_mtu(uint16_t conn_handle)
|
||||
{
|
||||
(void)conn_handle;
|
||||
/* The Bluedroid GATTC adapter exchanges MTU automatically when aux_open
|
||||
* brings up the ACL — the MTU_UPDATED event arrives without an explicit
|
||||
* kick-off. NimBLE has no such auto-exchange, so this wrapper is a no-op
|
||||
* on bluedroid and a real ble_gattc_exchange_mtu on nimble. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void security_failed_recover(uint16_t conn_handle, uint8_t status)
|
||||
{
|
||||
(void)conn_handle;
|
||||
|
||||
/* Asymmetric bond state: we still hold an LTK for this peer but it
|
||||
* cleared its side, so encrypt-with-cached-key times out. Drop the bond
|
||||
* and tear down the link; the next reconnect runs fresh pairing. */
|
||||
ESP_LOGE(TAG, "Security change failed, status %u, clearing local bond and reconnecting", status);
|
||||
|
||||
esp_ble_remove_bond_device(peer_bda);
|
||||
esp_ble_gap_disconnect(peer_bda);
|
||||
}
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "esp_ble_audio_bap_lc3_preset_defs.h"
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
|
||||
@@ -7,36 +7,14 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
#include "ble_audio_example_init.h"
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define SCAN_INTERVAL 160 /* 100ms */
|
||||
#define SCAN_WINDOW 160 /* 100ms */
|
||||
|
||||
#define INIT_SCAN_INTERVAL 16 /* 10ms */
|
||||
#define INIT_SCAN_WINDOW 16 /* 10ms */
|
||||
#define CONN_INTERVAL 64 /* 64 * 1.25 = 80ms */
|
||||
#define CONN_LATENCY 0
|
||||
#define CONN_TIMEOUT 500 /* 500 * 10ms = 5s */
|
||||
#define CONN_MAX_CE_LEN 0xFFFF
|
||||
#define CONN_MIN_CE_LEN 0xFFFF
|
||||
#define CONN_DURATION 10000 /* 10s */
|
||||
|
||||
static uint16_t default_conn_handle = CONN_HANDLE_INIT;
|
||||
static bool disc_completed;
|
||||
static bool disc_cancelled;
|
||||
static bool mtu_exchanged;
|
||||
|
||||
uint16_t default_conn_handle_get(void)
|
||||
@@ -68,80 +46,10 @@ static esp_ble_audio_tmap_cb_t tmap_callbacks = {
|
||||
.discovery_complete = tmap_discovery_complete,
|
||||
};
|
||||
|
||||
static void ext_scan_start(void)
|
||||
{
|
||||
struct ble_gap_disc_params params = {0};
|
||||
uint8_t own_addr_type;
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
params.passive = 1;
|
||||
params.itvl = SCAN_INTERVAL;
|
||||
params.window = SCAN_WINDOW;
|
||||
|
||||
err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start scanning, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for peripheral...");
|
||||
}
|
||||
|
||||
static int conn_create(ble_addr_t *dst)
|
||||
{
|
||||
struct ble_gap_conn_params params = {0};
|
||||
uint8_t own_addr_type = 0;
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine address type, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_disc_cancel();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to stop scanning, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
disc_cancelled = true;
|
||||
|
||||
params.scan_itvl = INIT_SCAN_INTERVAL;
|
||||
params.scan_window = INIT_SCAN_WINDOW;
|
||||
params.itvl_min = CONN_INTERVAL;
|
||||
params.itvl_max = CONN_INTERVAL;
|
||||
params.latency = CONN_LATENCY;
|
||||
params.supervision_timeout = CONN_TIMEOUT;
|
||||
params.max_ce_len = CONN_MAX_CE_LEN;
|
||||
params.min_ce_len = CONN_MIN_CE_LEN;
|
||||
|
||||
return ble_gap_connect(own_addr_type, dst, CONN_DURATION, ¶ms,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
}
|
||||
|
||||
static int pairing_start(uint16_t conn_handle)
|
||||
{
|
||||
return ble_gap_security_initiate(conn_handle);
|
||||
}
|
||||
|
||||
static int exchange_mtu(uint16_t conn_handle)
|
||||
{
|
||||
return ble_gattc_exchange_mtu(conn_handle, NULL, NULL);
|
||||
}
|
||||
|
||||
static bool check_and_connect(uint8_t type, const uint8_t *data,
|
||||
uint8_t data_len, void *user_data)
|
||||
{
|
||||
esp_ble_audio_gap_app_event_t *event;
|
||||
ble_addr_t dst = {0};
|
||||
uint16_t tmap_role;
|
||||
uint16_t uuid_val;
|
||||
int err;
|
||||
@@ -179,17 +87,17 @@ static bool check_and_connect(uint8_t type, const uint8_t *data,
|
||||
return false; /* Stop parsing */
|
||||
}
|
||||
|
||||
dst.type = event->ext_scan_recv.addr.type;
|
||||
memcpy(dst.val, event->ext_scan_recv.addr.val, sizeof(dst.val));
|
||||
err = ext_scan_stop();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to stop scanning, err %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
err = conn_create(&dst);
|
||||
err = conn_create(event->ext_scan_recv.addr.type,
|
||||
event->ext_scan_recv.addr.val);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to create conn, err %d", err);
|
||||
|
||||
if (disc_cancelled) {
|
||||
disc_cancelled = false;
|
||||
ext_scan_start();
|
||||
}
|
||||
ext_scan_start();
|
||||
}
|
||||
|
||||
return false; /* Stop parsing */
|
||||
@@ -220,9 +128,7 @@ static void acl_connect(esp_ble_audio_gap_app_event_t *event)
|
||||
|
||||
ESP_LOGI(TAG, "Connected: handle %u role %u peer %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
event->acl_connect.conn_handle, event->acl_connect.role,
|
||||
event->acl_connect.dst.val[5], event->acl_connect.dst.val[4],
|
||||
event->acl_connect.dst.val[3], event->acl_connect.dst.val[2],
|
||||
event->acl_connect.dst.val[1], event->acl_connect.dst.val[0]);
|
||||
EXAMPLE_BT_ADDR_PRINT_ARGS(event->acl_connect.dst.val));
|
||||
|
||||
default_conn_handle = event->acl_connect.conn_handle;
|
||||
|
||||
@@ -240,7 +146,6 @@ static void acl_disconnect(esp_ble_audio_gap_app_event_t *event)
|
||||
|
||||
default_conn_handle = CONN_HANDLE_INIT;
|
||||
disc_completed = false;
|
||||
disc_cancelled = false;
|
||||
mtu_exchanged = false;
|
||||
|
||||
unicast_group_delete();
|
||||
@@ -253,8 +158,8 @@ static void security_change(esp_ble_iso_gap_app_event_t *event)
|
||||
int err;
|
||||
|
||||
if (event->security_change.status) {
|
||||
example_audio_security_failed_recover(TAG, event->security_change.conn_handle,
|
||||
event->security_change.status);
|
||||
security_failed_recover(event->security_change.conn_handle,
|
||||
event->security_change.status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -393,6 +298,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(&init_info);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio, err %d", err);
|
||||
@@ -431,7 +342,7 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
err = ble_svc_gap_device_name_set("TMAP Central");
|
||||
err = set_device_name();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set device name, err %d", err);
|
||||
return;
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
int mcp_server_init(void)
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_store.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "esp_ble_audio_common_api.h"
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
/* Init/conn parameters are shared with the bluedroid wrapper via tmap_central.h.
|
||||
* CONN_DURATION is NimBLE-specific (ble_gap_connect's discovery timeout). */
|
||||
#define CONN_DURATION 10000 /* 10s */
|
||||
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_EXT_DISC:
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
case BLE_GAP_EVENT_ENC_CHANGE:
|
||||
esp_ble_audio_gap_app_post_event(event->type, event);
|
||||
break;
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
case BLE_GAP_EVENT_NOTIFY_RX:
|
||||
case BLE_GAP_EVENT_NOTIFY_TX:
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
esp_ble_audio_gatt_app_post_event(event->type, event);
|
||||
break;
|
||||
case BLE_GAP_EVENT_REPEAT_PAIRING: {
|
||||
struct ble_gap_conn_desc desc = {0};
|
||||
int rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
|
||||
if (rc == 0) {
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
}
|
||||
return BLE_GAP_REPEAT_PAIRING_RETRY;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_device_name(void)
|
||||
{
|
||||
return ble_svc_gap_device_name_set(LOCAL_DEVICE_NAME);
|
||||
}
|
||||
|
||||
int ext_scan_start(void)
|
||||
{
|
||||
struct ble_gap_disc_params params = {0};
|
||||
uint8_t own_addr_type;
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine address type, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
params.passive = 1;
|
||||
params.itvl = SCAN_INTERVAL;
|
||||
params.window = SCAN_WINDOW;
|
||||
|
||||
err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms,
|
||||
gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start scanning, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for peripheral...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_scan_stop(void)
|
||||
{
|
||||
return ble_gap_disc_cancel();
|
||||
}
|
||||
|
||||
int conn_create(uint8_t addr_type, const uint8_t addr[6])
|
||||
{
|
||||
struct ble_gap_conn_params params = {0};
|
||||
uint8_t own_addr_type = 0;
|
||||
ble_addr_t dst = {0};
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine address type, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
params.scan_itvl = INIT_SCAN_INTERVAL;
|
||||
params.scan_window = INIT_SCAN_WINDOW;
|
||||
params.itvl_min = CONN_INTERVAL;
|
||||
params.itvl_max = CONN_INTERVAL;
|
||||
params.latency = CONN_LATENCY;
|
||||
params.supervision_timeout = CONN_TIMEOUT;
|
||||
params.max_ce_len = CONN_MAX_CE_LEN;
|
||||
params.min_ce_len = CONN_MIN_CE_LEN;
|
||||
|
||||
dst.type = addr_type;
|
||||
memcpy(dst.val, addr, sizeof(dst.val));
|
||||
|
||||
return ble_gap_connect(own_addr_type, &dst, CONN_DURATION,
|
||||
¶ms, gap_event_cb, NULL);
|
||||
}
|
||||
|
||||
int pairing_start(uint16_t conn_handle)
|
||||
{
|
||||
return ble_gap_security_initiate(conn_handle);
|
||||
}
|
||||
|
||||
int exchange_mtu(uint16_t conn_handle)
|
||||
{
|
||||
return ble_gattc_exchange_mtu(conn_handle, NULL, NULL);
|
||||
}
|
||||
|
||||
void security_failed_recover(uint16_t conn_handle, uint8_t status)
|
||||
{
|
||||
struct ble_gap_conn_desc desc = {0};
|
||||
int rc;
|
||||
|
||||
ESP_LOGE(TAG, "Security change failed, status %u, clearing local bond and reconnecting", status);
|
||||
|
||||
rc = ble_gap_conn_find(conn_handle, &desc);
|
||||
if (rc == 0) {
|
||||
ble_store_util_delete_peer(&desc.peer_id_addr);
|
||||
}
|
||||
|
||||
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -27,11 +28,42 @@
|
||||
#include "esp_ble_audio_vocs_api.h"
|
||||
#include "esp_ble_audio_tbs_api.h"
|
||||
|
||||
#include "ble_audio_example_init.h"
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "TMAP_CEN"
|
||||
|
||||
#define CONN_HANDLE_INIT 0xFFFF
|
||||
#define CONN_HANDLE_INIT 0xFFFF
|
||||
|
||||
#define LOCAL_DEVICE_NAME "TMAP Central"
|
||||
|
||||
#define SCAN_INTERVAL 160 /* 100ms */
|
||||
#define SCAN_WINDOW 160 /* 100ms */
|
||||
|
||||
/* ACL init parameters shared between bluedroid and nimble host wrappers.
|
||||
* Raw HCI units (scan: 0.625ms; conn interval: 1.25ms; timeout: 10ms). */
|
||||
#define INIT_SCAN_INTERVAL 16 /* 10ms */
|
||||
#define INIT_SCAN_WINDOW 16 /* 10ms */
|
||||
#define CONN_INTERVAL 24 /* 30ms */
|
||||
#define CONN_LATENCY 0
|
||||
#define CONN_TIMEOUT 500 /* 5s */
|
||||
#define CONN_MIN_CE_LEN 0xFFFF
|
||||
#define CONN_MAX_CE_LEN 0xFFFF
|
||||
|
||||
int app_host_init(void);
|
||||
|
||||
int set_device_name(void);
|
||||
|
||||
int ext_scan_start(void);
|
||||
int ext_scan_stop(void);
|
||||
|
||||
int conn_create(uint8_t addr_type, const uint8_t addr[6]);
|
||||
|
||||
int pairing_start(uint16_t conn_handle);
|
||||
|
||||
int exchange_mtu(uint16_t conn_handle);
|
||||
|
||||
void security_failed_recover(uint16_t conn_handle, uint8_t status);
|
||||
|
||||
uint16_t default_conn_handle_get(void);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tmap_central.h"
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=40
|
||||
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_GATT_MAX_SR_PROFILES=12
|
||||
CONFIG_BT_GATTC_NOTIF_REG_MAX=64
|
||||
CONFIG_BT_BLE_FEAT_ISO_EN=y
|
||||
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
@@ -32,4 +31,6 @@ CONFIG_BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL=y
|
||||
CONFIG_BT_TBS=y
|
||||
CONFIG_BT_TBS_SUPPORTED_FEATURES=3
|
||||
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# 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_NVS_PERSIST=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=64
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
Reference in New Issue
Block a user