Merge branch 'idf/ble_audio_past_support' into 'master'

feat(ble_audio): Support using PAST in the cap/acceptor example

See merge request espressif/esp-idf!48449
This commit is contained in:
Island
2026-05-15 10:28:08 +08:00
50 changed files with 1210 additions and 562 deletions
@@ -25,13 +25,13 @@ esp_err_t esp_ble_audio_bap_unicast_server_register(const esp_ble_audio_bap_unic
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_ascs_init();
if (err) {
bt_bap_unicast_server_unregister_safe();
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -723,13 +723,13 @@ esp_err_t esp_ble_audio_bap_scan_delegator_register(esp_ble_audio_bap_scan_deleg
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_bass_init();
if (err) {
bt_bap_scan_delegator_unregister_safe();
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -9,6 +9,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include "esp_ble_audio_common_api.h"
@@ -53,7 +54,11 @@ esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle)
int err;
err = bt_gattc_disc_start_safe(conn_handle);
if (err) {
/* -EALREADY means disc already in progress for this conn (e.g. peer sent
* MTU exchange twice triggering two gatt_mtu_change events). The
* caller's goal is already true, treat as success.
*/
if (err && err != -EALREADY) {
return ESP_FAIL;
}
@@ -133,12 +133,15 @@ esp_err_t esp_ble_audio_has_register(const esp_ble_audio_has_features_param_t *f
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_has_init();
if (err) {
/* TODO: rollback register_safe once lib exposes an unregister API;
* retry will hit -EALREADY. Only reachable on GATT alloc failure.
*/
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -566,12 +566,15 @@ esp_err_t esp_ble_audio_media_proxy_pl_init(void)
return ESP_FAIL;
}
#if CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD
#if CONFIG_BT_MCS && BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_media_proxy_pl_init();
if (err) {
/* TODO: rollback pl_init_safe once lib exposes an undo API;
* retry will hit -EALREADY. Only reachable on GATT alloc failure.
*/
return ESP_FAIL;
}
#endif /* CONFIG_BT_MCS && BLE_AUDIO_SVC_SEP_ADD */
#endif /* CONFIG_BT_MCS && BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -22,12 +22,15 @@ esp_err_t esp_ble_audio_micp_mic_dev_register(esp_ble_audio_micp_mic_dev_registe
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_micp_mic_dev_init();
if (err) {
/* TODO: rollback register_safe once lib exposes an unregister API;
* retry will hit -EALREADY. Only reachable on GATT alloc failure.
*/
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -318,12 +318,12 @@ esp_err_t esp_ble_audio_tbs_register_bearer(const esp_ble_audio_tbs_register_par
*bearer_index = ret;
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
if (bt_le_gtbs_init()) {
bt_tbs_unregister_bearer_safe(*bearer_index);
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -18,12 +18,15 @@ esp_err_t esp_ble_audio_tmap_register(esp_ble_audio_tmap_role_t role)
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_tmas_init();
if (err) {
/* TODO: rollback register_safe once lib exposes an unregister API;
* retry will hit -EALREADY. Only reachable on GATT alloc failure.
*/
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -49,12 +49,15 @@ esp_err_t esp_ble_audio_vcp_vol_rend_register(esp_ble_audio_vcp_vol_rend_registe
return ESP_FAIL;
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
err = bt_le_vcp_vol_rend_init();
if (err) {
/* TODO: rollback register_safe once lib exposes an unregister API;
* retry will hit -EALREADY. Only reachable on GATT alloc failure.
*/
return ESP_FAIL;
}
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
return ESP_OK;
}
@@ -92,6 +92,8 @@ esp_err_t esp_ble_audio_gattc_disc_start(uint16_t conn_handle);
#define ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV
/*!< Audio GAP Periodic Sync Established event */
#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC
/*!< Audio GAP Periodic Sync Transfer Received event */
#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_PAST BT_LE_GAP_APP_EVENT_PA_SYNC_PAST
/*!< Audio GAP Periodic Sync Lost event */
#define ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST
/*!< Audio GAP Connection Complete event */
@@ -168,7 +168,7 @@ int bt_le_nimble_audio_init(void)
}
#endif /* CONFIG_BT_PACS */
#if (BLE_AUDIO_SVC_SEP_ADD == 0)
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
#if CONFIG_BT_ASCS
err = bt_le_nimble_ascs_init();
if (err) {
@@ -203,7 +203,7 @@ int bt_le_nimble_audio_init(void)
return err;
}
#endif /* CONFIG_BT_HAS */
#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
return err;
}
@@ -419,7 +419,7 @@ int bt_le_nimble_audio_start(void *info)
ARG_UNUSED(inc_csis_svc);
#endif /* CONFIG_BT_CAP_ACCEPTOR */
#if (BLE_AUDIO_SVC_SEP_ADD == 0)
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
#if CONFIG_BT_MCS
err = bt_le_nimble_media_proxy_pl_init();
if (err) {
@@ -440,7 +440,7 @@ int bt_le_nimble_audio_start(void *info)
return err;
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#endif /* (BLE_AUDIO_SVC_SEP_ADD == 0) */
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
err = ble_gatts_start();
if (err) {
@@ -108,8 +108,18 @@ int bt_le_nimble_ascs_attr_handle_set(void)
{
struct bt_gatt_service *ascs_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_ASCS_VAL), NULL);
if (rc) {
LOG_DBG("[N]AscsNotInit");
return 0;
}
ascs_svc = lib_ascs_svc_get();
assert(ascs_svc);
@@ -84,8 +84,18 @@ int bt_le_nimble_bass_attr_handle_set(void)
{
struct bt_gatt_service *bass_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_BASS_VAL), NULL);
if (rc) {
LOG_DBG("[N]BassNotInit");
return 0;
}
bass_svc = lib_bap_bass_svc_get();
assert(bass_svc);
@@ -50,21 +50,19 @@ static struct ble_gatt_svc_def gatt_svc_cas[] = {
int bt_le_nimble_cas_attr_handle_set(void)
{
struct bt_gatt_service *cas_svc;
uint16_t handle;
uint16_t handle = 0;
int rc;
cas_svc = lib_cas_svc_get();
assert(cas_svc);
LOG_DBG("[N]CasAttrHdlSet[%u]", cas_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_CAS_VAL), &handle);
if (rc) {
LOG_ERR("[N]CasNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
cas_svc = lib_cas_svc_get();
assert(cas_svc);
LOG_DBG("[N]CasAttrHdlSet[%u][%u]", handle, cas_svc->attr_count);
for (size_t i = 0; i < cas_svc->attr_count; i++) {
(cas_svc->attrs + i)->handle = handle + i;
@@ -139,8 +139,8 @@ static int csis_svc_check(void)
int bt_le_nimble_csis_attr_handle_set(void)
{
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
LOG_DBG("[N]CsisAttrHdlSet[%u]", csis_svc_count);
@@ -110,21 +110,23 @@ int bt_le_nimble_has_attr_handle_set(void)
uint16_t end_handle = 0;
int rc;
has_svc = lib_has_svc_get();
assert(has_svc);
LOG_DBG("[N]HasAttrHdlSet[%u]", has_svc->attr_count);
assert(has_svc->attr_count > 0);
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_HAS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]HasNotFound[%d]", rc);
return rc;
LOG_DBG("[N]HasNotInit");
return 0;
}
has_svc = lib_has_svc_get();
assert(has_svc);
assert(has_svc->attr_count > 0);
end_handle = start_handle + has_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
LOG_DBG("[N]HasAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, has_svc->attr_count);
for (size_t i = 0; i < has_svc->attr_count; i++) {
(has_svc->attrs + i)->handle = start_handle + i;
@@ -393,20 +393,22 @@ int bt_le_nimble_gmcs_attr_handle_set(void)
uint16_t end_handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL), &start_handle);
if (rc) {
LOG_DBG("[N]GmcsNotInit");
return 0;
}
gmcs_svc = lib_mcs_svc_get();
assert(gmcs_svc);
LOG_DBG("[N]GmcsAttrHdlSet[%u]", gmcs_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GMCS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]GmcsNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + gmcs_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
LOG_DBG("[N]GmcsAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, gmcs_svc->attr_count);
for (size_t i = 0; i < gmcs_svc->attr_count; i++) {
(gmcs_svc->attrs + i)->handle = start_handle + i;
@@ -234,20 +234,22 @@ int bt_le_nimble_mics_attr_handle_set(void)
uint16_t end_handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MICS_VAL), &start_handle);
if (rc) {
LOG_DBG("[N]MicsNotInit");
return 0;
}
mics_svc = lib_mics_svc_get();
assert(mics_svc);
LOG_DBG("[N]MicsAttrHdlSet[%u]", mics_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MICS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]MicsNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + mics_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
LOG_DBG("[N]MicsAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, mics_svc->attr_count);
for (size_t i = 0; i < mics_svc->attr_count; i++) {
(mics_svc->attrs + i)->handle = start_handle + i;
@@ -162,8 +162,8 @@ int bt_le_nimble_pacs_attr_handle_set(void)
{
struct bt_gatt_service *pacs_svc;
struct bt_gatt_attr *attr;
uint16_t start_handle;
uint16_t end_handle;
uint16_t start_handle = 0;
uint16_t end_handle = 0;
pacs_svc = lib_pacs_svc_get();
assert(pacs_svc);
@@ -74,7 +74,7 @@ static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
case BLE_GATT_ACCESS_OP_READ_CHR:
attr = bt_gatts_find_attr_by_handle(attr_handle);
if (attr == NULL) {
LOG_WRN("[N]RdInvHdl[%u]", attr_handle);
LOG_WRN("[N]RdAttrNotFound[%u]", attr_handle);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE);
}
@@ -88,7 +88,7 @@ static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
rc = attr->read(conn, attr, (void *)&cb, UINT16_MAX, 0);
if (rc < 0) {
LOG_ERR("[N]RdFail[%u][%d]", attr_handle, rc);
LOG_DBG("[N]RdGattErr[%u][%d]", attr_handle, rc);
return BT_GATT_ERR(rc);
}
@@ -97,7 +97,7 @@ static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
case BLE_GATT_ACCESS_OP_WRITE_CHR:
attr = bt_gatts_find_attr_by_handle(attr_handle);
if (attr == NULL) {
LOG_WRN("[N]WrInvHdl[%u]", attr_handle);
LOG_WRN("[N]WrAttrNotFound[%u]", attr_handle);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_HANDLE);
}
@@ -118,7 +118,7 @@ static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
LOG_DBG("[N]WrBassControlPoint[%u]", alloc_len);
if (OS_MBUF_PKTLEN(ctx->om) > alloc_len) {
LOG_ERR("[N]WrBassCtrlPtTooLong[%u > %u]",
LOG_WRN("[N]WrBassCtrlPtTooLong[%u > %u]",
OS_MBUF_PKTLEN(ctx->om), alloc_len);
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
@@ -148,7 +148,7 @@ static int gatts_access_cb(uint16_t conn_handle, uint16_t attr_handle,
data = NULL;
}
if (rc < 0) {
LOG_ERR("[N]WrFail[%u][%d]", attr_handle, rc);
LOG_DBG("[N]WrGattErr[%u][%d]", attr_handle, rc);
return BT_GATT_ERR(rc);
}
@@ -165,21 +165,22 @@ static const struct ble_gatt_svc_def gatt_svc_gtbs[] = {
int bt_le_nimble_gtbs_attr_handle_set(void)
{
struct bt_gatt_service *gtbs_svc;
uint16_t handle;
uint16_t handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL), &handle);
if (rc) {
LOG_DBG("[N]GtbsNotInit");
return 0;
}
gtbs_svc = lib_gtbs_svc_get();
assert(gtbs_svc);
LOG_DBG("[N]GtbsAttrHdlSet[%u]", gtbs_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_GTBS_VAL), &handle);
if (rc) {
LOG_ERR("[N]GtbsNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
LOG_DBG("[N]GtbsAttrHdlSet[%u][%u]", handle, gtbs_svc->attr_count);
for (size_t i = 0; i < gtbs_svc->attr_count; i++) {
(gtbs_svc->attrs + i)->handle = handle + i;
@@ -58,21 +58,22 @@ static const struct ble_gatt_svc_def gatt_svc_tmas[] = {
int bt_le_nimble_tmas_attr_handle_set(void)
{
struct bt_gatt_service *tmas_svc;
uint16_t handle;
uint16_t handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL), &handle);
if (rc) {
LOG_DBG("[N]TmasNotInit");
return 0;
}
tmas_svc = lib_tmas_svc_get();
assert(tmas_svc);
LOG_DBG("[N]TmasAttrHdlSet[%u]", tmas_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_TMAS_VAL), &handle);
if (rc) {
LOG_ERR("[N]TmasNotFound[%d]", rc);
return rc;
}
LOG_DBG("[N]Hdl[%u]", handle);
LOG_DBG("[N]TmasAttrHdlSet[%u][%u]", handle, tmas_svc->attr_count);
for (size_t i = 0; i < tmas_svc->attr_count; i++) {
(tmas_svc->attrs + i)->handle = handle + i;
@@ -370,20 +370,22 @@ int bt_le_nimble_vcs_attr_handle_set(void)
uint16_t end_handle = 0;
int rc;
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
* unused capability built). Skip rather than fail audio_start.
*/
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_VCS_VAL), &start_handle);
if (rc) {
LOG_DBG("[N]VcsNotInit");
return 0;
}
vcs_svc = lib_vcs_svc_get();
assert(vcs_svc);
LOG_DBG("[N]VcsAttrHdlSet[%u]", vcs_svc->attr_count);
rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_VCS_VAL), &start_handle);
if (rc) {
LOG_ERR("[N]VcsNotFound[%d]", rc);
return rc;
}
end_handle = start_handle + vcs_svc->attr_count - 1;
LOG_DBG("[N]Hdl[%u][%u]", start_handle, end_handle);
LOG_DBG("[N]VcsAttrHdlSet[%u][%u][%u]",
start_handle, end_handle, vcs_svc->attr_count);
for (size_t i = 0; i < vcs_svc->attr_count; i++) {
(vcs_svc->attrs + i)->handle = start_handle + i;
@@ -18,13 +18,18 @@
extern "C" {
#endif
#define BLE_AUDIO_SVC_SEP_ADD 0 /* Indicate if adding LE Audio services separately */
/* Defer LE Audio service add from host init to the application
* register call (esp_ble_audio_*_register). Lets the firmware keep
* unused capabilities built in without exposing their attributes
* before the app provides backing state.
*/
#define BLE_AUDIO_SVC_DEFERRED_ADD 1
/* Minimum value required by BAP.
* 64 octets is not enough for running 4 ASEs.
* Hence use 128 as the default value here.
*/
#define BLE_AUDIO_ATT_MTU_MIN 128
#define BLE_AUDIO_ATT_MTU_MIN 128
struct bt_csip_set_member_svc_inst;
@@ -178,12 +178,13 @@ static const uint16_t ext_structs[] = {
sizeof(struct bt_bond_info),
};
#define LEA_VERSION (0x20260512)
#define LEA_VERSION (0x20260514)
struct lib_ext_cfgs {
/* BLE */
bool config_past_sender;
bool config_past_receiver;
bool config_past_check;
uint8_t config_max_conn;
uint8_t config_max_paired;
uint16_t config_max_attr_len;
@@ -439,6 +440,7 @@ static const struct lib_ext_cfgs ext_cfgs = {
/* BLE */
.config_past_sender = CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER,
.config_past_receiver = CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER,
.config_past_check = false,
.config_max_conn = CONFIG_BT_MAX_CONN,
.config_max_paired = CONFIG_BT_MAX_PAIRED,
.config_max_attr_len = 251,
@@ -2092,7 +2094,7 @@ int bt_le_audio_init(void)
return bt_le_nimble_audio_init();
}
#if BLE_AUDIO_SVC_SEP_ADD
#if BLE_AUDIO_SVC_DEFERRED_ADD
#if CONFIG_BT_ASCS
int bt_le_ascs_init(void)
{
@@ -2164,7 +2166,7 @@ int bt_le_micp_mic_dev_init(void)
return bt_le_nimble_micp_mic_dev_init();
}
#endif /* CONFIG_BT_MICP_MIC_DEV */
#endif /* BLE_AUDIO_SVC_SEP_ADD */
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
int bt_le_audio_start(void *info)
{
@@ -552,6 +552,8 @@ esp_err_t esp_ble_iso_chan_send_ts(esp_ble_iso_chan_t *chan,
#define ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV
/*!< ISO GAP Periodic Sync Established event */
#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC BT_LE_GAP_APP_EVENT_PA_SYNC
/*!< ISO GAP Periodic Sync Transfer Received event */
#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC_PAST BT_LE_GAP_APP_EVENT_PA_SYNC_PAST
/*!< ISO GAP Periodic Sync Lost event */
#define ESP_BLE_ISO_GAP_EVENT_PA_SYNC_LOST BT_LE_GAP_APP_EVENT_PA_SYNC_LOST
/*!< ISO GAP Connection Complete event */
@@ -135,6 +135,24 @@ void bt_le_nimble_gap_post_event(void *param)
qev->pa_sync.adv_ca = ev->periodic_sync.adv_clk_accuracy;
break;
case BLE_GAP_EVENT_PERIODIC_TRANSFER:
case BLE_GAP_EVENT_PERIODIC_TRANSFER_V2:
/* Both events share the same periodic_transfer union field; V2 only
* adds PAwR-specific tail fields that this handler does not consume.
*/
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_PAST;
qev->pa_sync_past.status = ev->periodic_transfer.status;
qev->pa_sync_past.sync_handle = ev->periodic_transfer.sync_handle;
qev->pa_sync_past.addr.type = ev->periodic_transfer.adv_addr.type;
memcpy(qev->pa_sync_past.addr.val, ev->periodic_transfer.adv_addr.val, BT_ADDR_SIZE);
qev->pa_sync_past.sid = ev->periodic_transfer.sid;
qev->pa_sync_past.adv_phy = ev->periodic_transfer.adv_phy;
qev->pa_sync_past.per_adv_itvl = ev->periodic_transfer.per_adv_itvl;
qev->pa_sync_past.adv_ca = ev->periodic_transfer.adv_clk_accuracy;
qev->pa_sync_past.conn_handle = ev->periodic_transfer.conn_handle;
break;
case BLE_GAP_EVENT_PERIODIC_SYNC_LOST:
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_LOST;
@@ -1411,7 +1411,10 @@ int bt_le_nimble_gattc_db_auto_disc(uint16_t conn_handle)
adb = gattc_db_find(conn_handle);
if (adb) {
LOG_WRN("[N]GattcDbExist");
/* Idempotent: caller's goal (disc running for this conn) is
* already true. -EALREADY tells the API layer to map to success.
*/
LOG_DBG("[N]GattcDbExist");
return -EALREADY;
}
@@ -168,6 +168,7 @@ static void handle_pa_sync_event_safe(struct bt_le_gap_app_param *param)
event.pa_sync.per_adv_itvl,
event.pa_sync.addr.type,
event.pa_sync.addr.val,
BT_CONN_HANDLE_INVALID,
&per_adv_sync);
if (err) {
goto end;
@@ -182,6 +183,51 @@ end:
bt_le_gap_app_cb_evt(&event);
}
static void handle_pa_sync_past_event_safe(struct bt_le_gap_app_param *param)
{
struct bt_le_gap_app_event event = {
.type = BT_LE_GAP_APP_EVENT_PA_SYNC_PAST,
};
struct bt_le_per_adv_sync *per_adv_sync;
int err;
event.pa_sync_past.status = param->pa_sync_past.status;
event.pa_sync_past.sync_handle = param->pa_sync_past.sync_handle;
event.pa_sync_past.addr.type = param->pa_sync_past.addr.type;
memcpy(event.pa_sync_past.addr.val, param->pa_sync_past.addr.val, BT_ADDR_SIZE);
event.pa_sync_past.sid = param->pa_sync_past.sid;
event.pa_sync_past.adv_phy = param->pa_sync_past.adv_phy;
event.pa_sync_past.per_adv_itvl = param->pa_sync_past.per_adv_itvl;
event.pa_sync_past.adv_ca = param->pa_sync_past.adv_ca;
event.pa_sync_past.conn_handle = param->pa_sync_past.conn_handle;
bt_le_host_lock();
if (event.pa_sync_past.status) {
goto end;
}
err = bt_le_per_adv_sync_new(event.pa_sync_past.sync_handle,
event.pa_sync_past.sid,
event.pa_sync_past.adv_phy,
event.pa_sync_past.per_adv_itvl,
event.pa_sync_past.addr.type,
event.pa_sync_past.addr.val,
event.pa_sync_past.conn_handle,
&per_adv_sync);
if (err) {
goto end;
}
err = bt_le_per_adv_sync_establish_listener(event.pa_sync_past.sync_handle);
assert(err == 0);
end:
bt_le_host_unlock();
bt_le_gap_app_cb_evt(&event);
}
static void handle_pa_sync_lost_event_safe(struct bt_le_gap_app_param *param)
{
struct bt_le_gap_app_event event = {
@@ -437,6 +483,9 @@ void bt_le_gap_handle_event(uint8_t *data, size_t data_len)
case BT_LE_GAP_APP_PARAM_PA_SYNC:
handle_pa_sync_event_safe(param);
break;
case BT_LE_GAP_APP_PARAM_PA_SYNC_PAST:
handle_pa_sync_past_event_safe(param);
break;
case BT_LE_GAP_APP_PARAM_PA_SYNC_LOST:
handle_pa_sync_lost_event_safe(param);
break;
+3 -4
View File
@@ -128,10 +128,9 @@ struct bt_gatt_attr *bt_gatts_find_attr_by_handle(uint16_t handle)
break;
}
}
}
if (attr == NULL) {
LOG_WRN("AttrNotFound[%u]", handle);
if (attr != NULL) {
break;
}
}
return attr;
+12 -4
View File
@@ -72,10 +72,15 @@ int bt_le_host_init(void)
k_mutex_create(&host_mutex);
err = bt_le_scan_init();
if (err) {
goto delete_mutex;
}
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
err = bt_le_l2cap_init();
if (err) {
goto delete_mutex;
goto deinit_scan;
}
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
@@ -96,8 +101,10 @@ deinit_iso:
deinit_l2cap:
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
bt_le_l2cap_deinit();
delete_mutex:
deinit_scan: /* only reachable when OTS path is compiled in */
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
bt_le_scan_deinit();
delete_mutex:
k_mutex_delete(&host_mutex);
return err;
@@ -107,11 +114,12 @@ void bt_le_host_deinit(void)
{
LOG_DBG("HostDeinit");
bt_le_iso_task_deinit();
bt_le_iso_deinit();
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
bt_le_l2cap_deinit();
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
bt_le_iso_deinit();
bt_le_iso_task_deinit();
bt_le_scan_deinit();
k_mutex_delete(&host_mutex);
}
@@ -45,6 +45,18 @@ struct bt_le_gap_app_pa_sync_param {
uint8_t adv_ca;
};
struct bt_le_gap_app_pa_sync_past_param {
uint8_t status;
uint16_t sync_handle;
struct bt_le_addr addr;
uint8_t sid;
uint8_t adv_phy;
uint16_t per_adv_itvl;
uint8_t adv_ca;
/* ACL conn that delivered the PAST. */
uint16_t conn_handle;
};
struct bt_le_gap_app_pa_sync_lost_param {
uint16_t sync_handle;
uint8_t reason;
@@ -113,6 +125,7 @@ struct bt_le_gap_app_param {
union {
struct bt_le_gap_app_ext_scan_recv_param ext_scan_recv;
struct bt_le_gap_app_pa_sync_param pa_sync;
struct bt_le_gap_app_pa_sync_past_param pa_sync_past;
struct bt_le_gap_app_pa_sync_lost_param pa_sync_lost;
struct bt_le_gap_app_pa_sync_recv_param pa_sync_recv;
struct bt_le_gap_app_acl_connect_param acl_connect;
@@ -126,6 +139,7 @@ struct bt_le_gap_app_param {
enum bt_le_gap_app_param_type {
BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV,
BT_LE_GAP_APP_PARAM_PA_SYNC,
BT_LE_GAP_APP_PARAM_PA_SYNC_PAST,
BT_LE_GAP_APP_PARAM_PA_SYNC_LOST,
BT_LE_GAP_APP_PARAM_PA_SYNC_RECV,
BT_LE_GAP_APP_PARAM_ACL_CONNECT,
@@ -160,6 +174,18 @@ struct bt_le_gap_app_event_pa_sync {
uint8_t adv_ca;
};
struct bt_le_gap_app_event_pa_sync_past {
uint8_t status;
uint16_t sync_handle;
struct bt_le_addr addr;
uint8_t sid;
uint8_t adv_phy;
uint16_t per_adv_itvl;
uint8_t adv_ca;
/* ACL conn that delivered the PAST. */
uint16_t conn_handle;
};
struct bt_le_gap_app_event_pa_sync_lost {
uint16_t sync_handle;
uint8_t reason;
@@ -228,6 +254,7 @@ struct bt_le_gap_app_event {
union {
struct bt_le_gap_app_event_ext_scan_recv ext_scan_recv;
struct bt_le_gap_app_event_pa_sync pa_sync;
struct bt_le_gap_app_event_pa_sync_past pa_sync_past;
struct bt_le_gap_app_event_pa_sync_lost pa_sync_lost;
struct bt_le_gap_app_event_pa_sync_recv pa_sync_recv;
struct bt_le_gap_app_event_acl_connect acl_connect;
@@ -242,6 +269,7 @@ struct bt_le_gap_app_event {
enum bt_le_gap_app_event_type {
BT_LE_GAP_APP_EVENT_EXT_SCAN_RECV,
BT_LE_GAP_APP_EVENT_PA_SYNC,
BT_LE_GAP_APP_EVENT_PA_SYNC_PAST,
BT_LE_GAP_APP_EVENT_PA_SYNC_LOST,
BT_LE_GAP_APP_EVENT_PA_SYNC_RECV,
BT_LE_GAP_APP_EVENT_ACL_CONNECT,
@@ -39,6 +39,7 @@ int bt_le_per_adv_sync_new(uint16_t sync_handle,
uint16_t interval,
uint8_t addr_type,
const uint8_t addr[6],
uint16_t conn_handle,
struct bt_le_per_adv_sync **out_sync);
int bt_le_per_adv_sync_delete(uint16_t sync_handle);
@@ -51,6 +52,10 @@ int bt_le_per_adv_sync_report_recv_listener(uint16_t sync_handle,
const uint8_t *data,
size_t data_length);
int bt_le_scan_init(void);
void bt_le_scan_deinit(void);
#ifdef __cplusplus
}
#endif
@@ -36,9 +36,6 @@ LOG_MODULE_REGISTER(ISO_SHIM, CONFIG_BT_ISO_LOG_LEVEL);
#define ISO_PKT_COMP_SDU (0b10)
#define ISO_PKT_LAST_FRAG (0b11)
#define BT_LE_FEAT_SET(feat, n) (feat[(n) >> 3] |= BIT((n) & 7))
#define BT_LE_FEAT_UNSET(feat, n) (feat[(n) >> 3] &= ~BIT((n) & 7))
static sys_slist_t iso_cbs = SYS_SLIST_STATIC_INIT(&iso_cbs);
#if CONFIG_BT_ISO_UNICAST
+65 -4
View File
@@ -14,8 +14,10 @@
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/common/bt_str.h>
#include <../host/conn_internal.h>
#include <../host/hci_core.h>
#include "common/host.h"
@@ -220,8 +222,7 @@ static struct bt_le_per_adv_sync *per_adv_sync_find(uint16_t handle)
struct bt_le_per_adv_sync *per_adv_sync = NULL;
for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) {
if (atomic_test_bit(per_adv_sync_pool[i].flags,
BT_PER_ADV_SYNC_SYNCED) &&
if (atomic_test_bit(per_adv_sync_pool[i].flags, BT_PER_ADV_SYNC_SYNCED) &&
per_adv_sync_pool[i].handle == handle) {
per_adv_sync = &per_adv_sync_pool[i];
break;
@@ -269,11 +270,13 @@ int bt_le_per_adv_sync_new(uint16_t sync_handle,
uint16_t interval,
uint8_t addr_type,
const uint8_t addr[6],
uint16_t conn_handle,
struct bt_le_per_adv_sync **out_sync)
{
struct bt_le_per_adv_sync *per_adv_sync;
LOG_DBG("PaSyncNew[%u][%u][%u][%u]", sync_handle, sid, phy, interval);
LOG_DBG("PaSyncNew[%u][%u][%u][%u][%u]",
sync_handle, sid, phy, interval, conn_handle);
if (addr_type > BT_ADDR_LE_RANDOM_ID || addr == NULL) {
LOG_ERR("InvAddr[%02x][%p]", addr_type, addr);
@@ -296,6 +299,7 @@ int bt_le_per_adv_sync_new(uint16_t sync_handle,
per_adv_sync->sid = sid;
per_adv_sync->phy = phy;
per_adv_sync->interval = interval;
per_adv_sync->conn_handle = conn_handle;
per_adv_sync->addr.type = addr_type;
memcpy(per_adv_sync->addr.a.val, addr, BT_ADDR_SIZE);
@@ -345,7 +349,16 @@ int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle)
info.sid = per_adv_sync->sid;
info.interval = per_adv_sync->interval;
info.phy = per_adv_sync->phy;
info.conn = NULL; /* TODO: update for PAST */
/* PAST path: a valid conn_handle means PAST delivered the sync. NULL
* lookup here is a race — the ACL disconnected between PAST event
* enqueue and host processing. Synced cb still fires with conn=NULL.
*/
if (per_adv_sync->conn_handle != BT_CONN_HANDLE_INVALID) {
info.conn = bt_conn_lookup_handle(per_adv_sync->conn_handle, BT_CONN_TYPE_LE);
if (info.conn == NULL) {
LOG_WRN("PaSyncConnGone[%u][%u]", sync_handle, per_adv_sync->conn_handle);
}
}
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
if (listener->synced) {
@@ -353,6 +366,10 @@ int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle)
}
}
if (info.conn) {
bt_conn_unref(info.conn);
}
return 0;
}
@@ -492,3 +509,47 @@ int bt_le_scan_stop(void)
return err;
}
static void past_features_set(void)
{
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER
BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_SEND);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER
BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_RECV);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER */
LOG_DBG("PastFeatSet[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features)));
}
static void past_features_unset(void)
{
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER
BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_SEND);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER
BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_RECV);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER */
LOG_DBG("PastFeatUnset[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features)));
}
_IDF_ONLY
int bt_le_scan_init(void)
{
LOG_DBG("ScanInit");
past_features_set();
return 0;
}
_IDF_ONLY
void bt_le_scan_deinit(void)
{
LOG_DBG("ScanDeinit");
past_features_unset();
}
+6 -1
View File
@@ -118,7 +118,12 @@ void hci_iso(struct net_buf *buf)
iso = bt_conn_lookup_handle(iso(buf)->handle, BT_CONN_TYPE_ISO);
if (iso == NULL) {
LOG_ERR("ConnNotFoundForHdl[%u]", iso(buf)->handle);
/* Expected during BIG/CIG teardown: the bt_conn is unref'd
* synchronously when the host initiates termination, but ISO packets
* already queued for the iso task may still arrive here. Drop them
* silently.
*/
LOG_INF("IsoRxConnGone[%u]", iso(buf)->handle);
return;
}
@@ -78,10 +78,18 @@ struct bt_le_per_adv_sync {
/** Advertiser PHY */
uint8_t phy;
/** ACL conn that delivered PAST; BT_CONN_HANDLE_INVALID for non-PAST sync. */
uint16_t conn_handle;
/** Flags */
ATOMIC_DEFINE(flags, BT_PER_ADV_SYNC_NUM_FLAGS);
};
/* Port-level invalid conn_handle sentinel; matches NimBLE BLE_HS_CONN_HANDLE_NONE.
* Use in adapter-agnostic code that cannot reference NimBLE headers.
*/
#define BT_CONN_HANDLE_INVALID 0xffff
struct bt_dev_le {
/* LE features */
uint8_t features[8];
@@ -97,6 +105,9 @@ struct bt_dev {
extern struct bt_dev bt_dev;
#define BT_LE_FEAT_SET(feat, n) (feat[(n) >> 3] |= BIT((n) & 7))
#define BT_LE_FEAT_UNSET(feat, n) (feat[(n) >> 3] &= ~BIT((n) & 7))
/* Data type to store state related with command to be updated
* when command completes successfully.
*/