mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
feat(ble_audio): Support BLE ISO & BLE Audio deinitialization
This commit is contained in:
@@ -54,6 +54,12 @@ esp_err_t esp_ble_audio_bap_unicast_server_unregister(void)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if BLE_AUDIO_SVC_DEFERRED_ADD
|
||||
if (bt_le_ascs_deinit()) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -772,6 +778,12 @@ esp_err_t esp_ble_audio_bap_scan_delegator_unregister(void)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if BLE_AUDIO_SVC_DEFERRED_ADD
|
||||
if (bt_le_bass_deinit()) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "esp_ble_audio_common_api.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_API, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
esp_err_t esp_ble_audio_data_parse(const uint8_t ltv[], size_t size,
|
||||
bool (*func)(uint8_t type,
|
||||
const uint8_t *data,
|
||||
@@ -127,6 +131,52 @@ unregister_gap:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_audio_common_deinit(const esp_ble_iso_deinit_info_t *info)
|
||||
{
|
||||
bool reset_ext_adv = true;
|
||||
bool reset_pa_sync = true;
|
||||
int err;
|
||||
|
||||
if (info) {
|
||||
if (!info->reset_acl_conn) {
|
||||
LOG_WRN("ConnKeepUnsupported");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
reset_ext_adv = info->reset_ext_adv;
|
||||
reset_pa_sync = info->reset_pa_sync;
|
||||
}
|
||||
|
||||
if (bt_le_host_check_idle()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
err = bt_le_iso_task_deinit();
|
||||
if (err) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
bt_le_audio_deinit();
|
||||
|
||||
err = bt_le_host_deinit();
|
||||
if (err) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (reset_ext_adv) {
|
||||
bt_le_ext_adv_state_reset();
|
||||
}
|
||||
|
||||
if (reset_pa_sync) {
|
||||
bt_le_per_adv_sync_state_reset();
|
||||
}
|
||||
|
||||
bt_le_gatt_app_cb_unregister();
|
||||
bt_le_gap_app_cb_unregister();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -59,6 +59,10 @@ esp_err_t esp_ble_audio_csip_set_member_unregister(esp_ble_audio_csip_set_member
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (bt_le_csis_deinit(svc_inst)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = bt_csip_set_member_unregister_safe(svc_inst);
|
||||
if (err) {
|
||||
return ESP_FAIL;
|
||||
|
||||
@@ -34,6 +34,10 @@ esp_err_t esp_ble_audio_pacs_unregister(void)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (bt_le_pacs_deinit()) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -376,6 +376,16 @@ esp_err_t esp_ble_audio_tbs_unregister_bearer(uint8_t bearer_index)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if BLE_AUDIO_SVC_DEFERRED_ADD
|
||||
if (bearer_index == ESP_BLE_AUDIO_TBS_GTBS_INDEX) {
|
||||
if (bt_le_gtbs_deinit()) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else if (bt_le_tbs_deinit(bearer_index)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
@@ -121,10 +121,30 @@ typedef struct {
|
||||
/**
|
||||
* @brief Post an application-layer GAP event for audio internal usage.
|
||||
*
|
||||
* @note This function is only needed while using NimBLE Host.
|
||||
* @note NimBLE-only: NimBLE has no global GAP callback, so the layers below
|
||||
* see only what the application forwards here. An event left out is
|
||||
* dropped silently. Bluedroid's adapter hooks the stack directly.
|
||||
*
|
||||
* @param type Event type.
|
||||
* @param param Event parameters.
|
||||
* @note Forward every event below that the application's flows can produce.
|
||||
* Forwarding an unused one is harmless; omitting one leaves the
|
||||
* matching state uncreated and fails later and elsewhere:
|
||||
* - BLE_GAP_EVENT_EXT_DISC extended advertising report
|
||||
* - BLE_GAP_EVENT_CONNECT ACL established or failed
|
||||
* - BLE_GAP_EVENT_DISCONNECT ACL closed
|
||||
* - BLE_GAP_EVENT_ENC_CHANGE encryption changed
|
||||
* - BLE_GAP_EVENT_PERIODIC_SYNC PA sync established
|
||||
* - BLE_GAP_EVENT_PERIODIC_SYNC_LOST PA sync lost
|
||||
* - BLE_GAP_EVENT_PERIODIC_REPORT periodic advertising report
|
||||
* - BLE_GAP_EVENT_PERIODIC_TRANSFER PA sync received over PAST
|
||||
* - BLE_GAP_EVENT_PERIODIC_TRANSFER_V2 as above, PAwR
|
||||
*
|
||||
* GATT events go to esp_ble_audio_gatt_app_post_event() instead.
|
||||
*
|
||||
* @note Shares a sink with esp_ble_iso_gap_app_post_event(): forward a given
|
||||
* event through exactly one of them or it is delivered twice.
|
||||
*
|
||||
* @param type Event type, i.e. ble_gap_event::type.
|
||||
* @param param Event parameters, i.e. the struct ble_gap_event pointer.
|
||||
*/
|
||||
void esp_ble_audio_gap_app_post_event(uint16_t type, void *param);
|
||||
|
||||
@@ -132,13 +152,20 @@ void esp_ble_audio_gap_app_post_event(uint16_t type, void *param);
|
||||
/**
|
||||
* @brief Post an application-layer GATT event for audio internal usage.
|
||||
*
|
||||
* @note NimBLE-only. Bluedroid dispatches GATT events directly inside the
|
||||
* adapter (BTA callbacks), so no app-level post is needed. This
|
||||
* declaration is hidden from Bluedroid builds to make misuse a
|
||||
* compile-time error.
|
||||
* @note NimBLE-only: Bluedroid dispatches GATT events inside the adapter, so
|
||||
* no app-level post is needed. Hidden from Bluedroid builds to make
|
||||
* misuse a compile-time error.
|
||||
*
|
||||
* @param type Event type.
|
||||
* @param param Event parameters.
|
||||
* @note Forward all four below here rather than through
|
||||
* esp_ble_audio_gap_app_post_event() - GATT has no ISO counterpart.
|
||||
* Omitting one is silent; ASCS and PACS simply never react.
|
||||
* - BLE_GAP_EVENT_MTU ATT MTU exchanged
|
||||
* - BLE_GAP_EVENT_SUBSCRIBE peer wrote a CCC descriptor
|
||||
* - BLE_GAP_EVENT_NOTIFY_RX notification or indication received
|
||||
* - BLE_GAP_EVENT_NOTIFY_TX notification or indication sent
|
||||
*
|
||||
* @param type Event type, i.e. ble_gap_event::type.
|
||||
* @param param Event parameters, i.e. the struct ble_gap_event pointer.
|
||||
*/
|
||||
void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param);
|
||||
#endif /* !CONFIG_BT_BLUEDROID_ENABLED */
|
||||
@@ -163,6 +190,30 @@ typedef struct {
|
||||
uint8_t dummy; /*!< Dummy field to avoid empty struct */
|
||||
} esp_ble_audio_start_info_t;
|
||||
|
||||
/**
|
||||
* @brief Deinitialize BLE Audio.
|
||||
*
|
||||
* The only precondition is that the application has stopped its streams: a live
|
||||
* stream always has a CIS under it, so one still up makes this return
|
||||
* ESP_ERR_INVALID_STATE with each offending item logged at ERROR level.
|
||||
*
|
||||
* @note Registered profiles need no prior unregister - this releases them
|
||||
* itself, while the host lock and GATT application are still alive.
|
||||
* The per-profile esp_ble_audio_*_unregister() calls are for dropping
|
||||
* one profile while audio stays up.
|
||||
*
|
||||
* @note Also releases the ISO layer, so esp_ble_iso_common_deinit() must not
|
||||
* be called as well. @p info has the same meaning as there.
|
||||
*
|
||||
* @param info Which ISO-layer records to clear, or NULL to clear all.
|
||||
*
|
||||
* @return ESP_OK on success,
|
||||
* ESP_ERR_INVALID_STATE if something is still active,
|
||||
* ESP_ERR_TIMEOUT if the ISO task could not be stopped.
|
||||
* Nothing is released unless ESP_OK is returned.
|
||||
*/
|
||||
esp_err_t esp_ble_audio_common_deinit(const esp_ble_iso_deinit_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Start BLE Audio services.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,8 @@ extern "C" {
|
||||
|
||||
int bt_le_bluedroid_audio_init(void);
|
||||
|
||||
void bt_le_bluedroid_audio_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_media_proxy_pl_init(void);
|
||||
|
||||
int bt_le_bluedroid_vcp_vol_rend_init(void);
|
||||
|
||||
@@ -16,6 +16,8 @@ extern "C" {
|
||||
|
||||
int bt_le_bluedroid_ascs_init(void);
|
||||
|
||||
int bt_le_bluedroid_ascs_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_ascs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -16,6 +16,8 @@ extern "C" {
|
||||
|
||||
int bt_le_bluedroid_bass_init(void);
|
||||
|
||||
int bt_le_bluedroid_bass_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_bass_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bt_le_bluedroid_csis_state_reset(void);
|
||||
|
||||
int bt_le_bluedroid_csis_init(void *csis_svc, uint8_t count);
|
||||
|
||||
int bt_le_bluedroid_csis_deinit(void *csis_svc);
|
||||
|
||||
int bt_le_bluedroid_csis_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bt_le_bluedroid_mcs_state_reset(void);
|
||||
|
||||
int bt_le_bluedroid_gmcs_init(void);
|
||||
|
||||
int bt_le_bluedroid_gmcs_start(void);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bt_le_bluedroid_mics_state_reset(void);
|
||||
|
||||
int bt_le_bluedroid_mics_init(void *micp_inc);
|
||||
|
||||
int bt_le_bluedroid_mics_start(void);
|
||||
|
||||
@@ -16,6 +16,8 @@ extern "C" {
|
||||
|
||||
int bt_le_bluedroid_pacs_init(void);
|
||||
|
||||
int bt_le_bluedroid_pacs_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_pacs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -16,10 +16,14 @@ extern "C" {
|
||||
|
||||
int bt_le_bluedroid_gtbs_init(void);
|
||||
|
||||
int bt_le_bluedroid_gtbs_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_gtbs_start(void);
|
||||
|
||||
int bt_le_bluedroid_tbs_init(void);
|
||||
|
||||
int bt_le_bluedroid_tbs_deinit(uint8_t bearer_index);
|
||||
|
||||
int bt_le_bluedroid_tbs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bt_le_bluedroid_vcs_state_reset(void);
|
||||
|
||||
int bt_le_bluedroid_vcs_init(void *vcp_inc);
|
||||
|
||||
int bt_le_bluedroid_vcs_start(void);
|
||||
|
||||
@@ -162,10 +162,14 @@ enum {
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_init(void);
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_deinit(void);
|
||||
|
||||
int bt_le_bluedroid_set_svc_in_progress(uint8_t value);
|
||||
|
||||
int bt_le_bluedroid_svc_init(struct bt_gatt_service *svc);
|
||||
|
||||
int bt_le_bluedroid_svc_deinit(struct bt_gatt_service *svc);
|
||||
|
||||
int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -71,6 +71,19 @@ int bt_le_bluedroid_audio_init(void)
|
||||
|
||||
bt_le_bluedroid_audio_gatts_init();
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
bt_le_bluedroid_csis_state_reset();
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
bt_le_bluedroid_vcs_state_reset();
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
bt_le_bluedroid_mics_state_reset();
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
#if CONFIG_BT_MCS
|
||||
bt_le_bluedroid_mcs_state_reset();
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
#if CONFIG_BT_PACS
|
||||
err = bt_le_bluedroid_pacs_init();
|
||||
if (err) {
|
||||
@@ -123,6 +136,16 @@ int bt_le_bluedroid_audio_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_audio_deinit(void)
|
||||
{
|
||||
LOG_DBG("[B]AudioDeinit");
|
||||
|
||||
/* The services are removed by the BTA_GATTS_AppDeregister() in the ISO
|
||||
* layer's gatt deinit - GATT_Deregister() stops every service the app
|
||||
* owns - so only this layer's own hook is dropped here. */
|
||||
bt_le_bluedroid_audio_gatts_deinit();
|
||||
}
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
static int bluedroid_gatt_csis_init(struct bt_le_audio_start_info *info,
|
||||
struct bt_gatt_service **inc_csis_svc)
|
||||
|
||||
@@ -38,6 +38,21 @@ int bt_le_bluedroid_ascs_init(void)
|
||||
return bt_le_bluedroid_svc_init(ascs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_ascs_deinit(void)
|
||||
{
|
||||
struct bt_gatt_service *ascs_svc;
|
||||
|
||||
LOG_DBG("[B]AscsDeinit");
|
||||
|
||||
ascs_svc = lib_ascs_svc_get();
|
||||
if (!ascs_svc) {
|
||||
LOG_ERR("[B]AscsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(ascs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_ascs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *ascs_svc;
|
||||
|
||||
@@ -38,6 +38,21 @@ int bt_le_bluedroid_bass_init(void)
|
||||
return bt_le_bluedroid_svc_init(bass_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_bass_deinit(void)
|
||||
{
|
||||
struct bt_gatt_service *bass_svc;
|
||||
|
||||
LOG_DBG("[B]BassDeinit");
|
||||
|
||||
bass_svc = lib_bap_bass_svc_get();
|
||||
if (!bass_svc) {
|
||||
LOG_ERR("[B]BassSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(bass_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_bass_start(void)
|
||||
{
|
||||
struct bt_gatt_service *bass_svc;
|
||||
|
||||
@@ -30,6 +30,11 @@ static BT_AUDIO_EXT_RAM_BSS_ATTR struct csis_inst {
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t csis_svc_count;
|
||||
|
||||
void bt_le_bluedroid_csis_state_reset(void)
|
||||
{
|
||||
csis_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_csis_init(void *svc, uint8_t count)
|
||||
{
|
||||
int err;
|
||||
@@ -58,6 +63,18 @@ int bt_le_bluedroid_csis_init(void *svc, uint8_t count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_csis_deinit(void *csis_svc)
|
||||
{
|
||||
LOG_DBG("[B]CsisDeinit");
|
||||
|
||||
if (csis_svc == NULL) {
|
||||
LOG_ERR("[B]CsisSvcNull");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(csis_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_csis_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -62,12 +62,28 @@ static int bluedroid_gmcs_ots_init(void)
|
||||
|
||||
static int bluedroid_gmcs_ots_start(void)
|
||||
{
|
||||
/* svc_p comes from bluedroid_gmcs_ots_init(), which only runs once the app
|
||||
* calls media_proxy_pl_init(); NULL means MCS was never registered. The
|
||||
* count-guarded loops in vcs.c / mics.c / csis.c skip for the same reason. */
|
||||
if (inc_ots_inst.svc_p == NULL) {
|
||||
LOG_DBG("[B]GmcsOtsNotReg");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(OTS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(inc_ots_inst.svc_p);
|
||||
}
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
|
||||
void bt_le_bluedroid_mcs_state_reset(void)
|
||||
{
|
||||
#if CONFIG_BT_OTS
|
||||
inc_ots_inst.svc_p = NULL;
|
||||
inc_ots_inst.included = false;
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gmcs_init(void)
|
||||
{
|
||||
struct bt_gatt_service *gmcs_svc;
|
||||
@@ -151,6 +167,7 @@ int bt_le_bluedroid_mcs_init(void)
|
||||
* (created during gmcs_init). Reset the flag so it re-resolves per instance. */
|
||||
inc_ots_inst.included = false;
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
|
||||
err = bt_le_bluedroid_svc_init(&list[i]);
|
||||
if (err) {
|
||||
return err;
|
||||
|
||||
@@ -41,6 +41,11 @@ struct inc_svc_inst *mics_not_included_inst(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_mics_state_reset(void)
|
||||
{
|
||||
inc_aics_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_mics_init(void *micp_inc)
|
||||
{
|
||||
struct bt_micp_included *micp_included;
|
||||
|
||||
@@ -38,6 +38,21 @@ int bt_le_bluedroid_pacs_init(void)
|
||||
return bt_le_bluedroid_svc_init(pacs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_pacs_deinit(void)
|
||||
{
|
||||
struct bt_gatt_service *pacs_svc;
|
||||
|
||||
LOG_DBG("[B]PacsDeinit");
|
||||
|
||||
pacs_svc = lib_pacs_svc_get();
|
||||
if (!pacs_svc) {
|
||||
LOG_ERR("[B]PacsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(pacs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_pacs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *pacs_svc;
|
||||
|
||||
@@ -36,6 +36,21 @@ int bt_le_bluedroid_gtbs_init(void)
|
||||
return bt_le_bluedroid_svc_init(gtbs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gtbs_deinit(void)
|
||||
{
|
||||
struct bt_gatt_service *gtbs_svc;
|
||||
|
||||
LOG_DBG("[B]GtbsDeinit");
|
||||
|
||||
gtbs_svc = lib_gtbs_svc_get();
|
||||
if (!gtbs_svc) {
|
||||
LOG_ERR("[B]GtbsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(gtbs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gtbs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *gtbs_svc;
|
||||
@@ -83,6 +98,29 @@ int bt_le_bluedroid_tbs_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_tbs_deinit(uint8_t bearer_index)
|
||||
{
|
||||
#if CONFIG_BT_TBS_BEARER_COUNT > 0
|
||||
struct bt_gatt_service *tbs_list;
|
||||
#endif /* CONFIG_BT_TBS_BEARER_COUNT > 0 */
|
||||
|
||||
LOG_DBG("[B]TbsDeinit[%u]", bearer_index);
|
||||
|
||||
#if CONFIG_BT_TBS_BEARER_COUNT > 0
|
||||
if (bearer_index < CONFIG_BT_TBS_BEARER_COUNT) {
|
||||
tbs_list = lib_tbs_server_list_get();
|
||||
if (!tbs_list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bt_le_bluedroid_svc_deinit(&tbs_list[bearer_index]);
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS_BEARER_COUNT > 0 */
|
||||
|
||||
LOG_ERR("[B]TbsInvBearerIdx[%u]", bearer_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_tbs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *tbs_list;
|
||||
|
||||
@@ -49,6 +49,12 @@ struct inc_svc_inst *vcs_not_included_inst(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_vcs_state_reset(void)
|
||||
{
|
||||
inc_vocs_svc_count = 0;
|
||||
inc_aics_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_vcs_init(void *vcp_inc)
|
||||
{
|
||||
struct bt_vcp_included *vcp_included;
|
||||
|
||||
@@ -33,6 +33,39 @@ static BT_AUDIO_EXT_RAM_BSS_ATTR uint16_t inc_svc_handle;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint16_t svc_handle;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint16_t chrc_handle;
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t aics_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t csis_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t vocs_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t mcs_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t ots_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t tbs_count;
|
||||
|
||||
/* Every service svc_init() created, so the deinit can delete each one:
|
||||
* BTA_GATTS_AppDeregister() clears BTA's srvc_cb[] but leaves gatt_cb.sr_reg[],
|
||||
* which is the table GATTS_StartService() checks on the next init. */
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR struct bt_gatt_service *created_svcs[CONFIG_BT_GATT_MAX_SR_PROFILES];
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t created_svc_count;
|
||||
|
||||
static void svc_created_record(struct bt_gatt_service *svc)
|
||||
{
|
||||
for (uint8_t i = 0; i < created_svc_count; i++) {
|
||||
if (created_svcs[i] == svc) {
|
||||
/* Re-created in place: gtbs_init has no "already added" guard, and
|
||||
* the tbs/mcs loops re-enter for each newly registered instance. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (created_svc_count == ARRAY_SIZE(created_svcs)) {
|
||||
/* Same ceiling as the stack's, so reaching it means the static_assert on
|
||||
* TOTAL_SERVICE_COUNT is out of date rather than that we over-created. */
|
||||
LOG_ERR("[B]SvcRecordFull[%u]", svc_in_progress);
|
||||
return;
|
||||
}
|
||||
|
||||
created_svcs[created_svc_count++] = svc;
|
||||
}
|
||||
|
||||
static bool is_primary_svc(void)
|
||||
{
|
||||
if (svc_in_progress == ASCS_IN_PROGRESS ||
|
||||
@@ -237,9 +270,61 @@ static struct gatts_svc_cb svc_cb = {
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_init(void)
|
||||
{
|
||||
svc_in_progress = 0;
|
||||
inc_svc_handle = 0;
|
||||
svc_handle = 0;
|
||||
chrc_handle = 0;
|
||||
|
||||
created_svc_count = 0;
|
||||
|
||||
aics_count = 0;
|
||||
csis_count = 0;
|
||||
vocs_count = 0;
|
||||
mcs_count = 0;
|
||||
ots_count = 0;
|
||||
tbs_count = 0;
|
||||
|
||||
bt_le_bluedroid_gatts_svc_cb_register(&svc_cb);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_svc_deinit(struct bt_gatt_service *svc)
|
||||
{
|
||||
if (svc == NULL || svc->attrs == NULL) {
|
||||
LOG_ERR("[B]SvcDeinitNoSvc");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (svc->attrs[0].handle == 0) {
|
||||
LOG_DBG("[B]SvcDeinitNotCreated");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DBG("[B]SvcDeinit[0x%04x]", svc->attrs[0].handle);
|
||||
|
||||
BTA_GATTS_DeleteService(svc->attrs[0].handle);
|
||||
svc->attrs[0].handle = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_deinit(void)
|
||||
{
|
||||
/* Reverse creation order, so an included secondary outlives the primary that
|
||||
* includes it. Each delete logs upstream's "Active Service Found" at ERROR;
|
||||
* that is its successful lookup, not a failure. */
|
||||
|
||||
while (created_svc_count > 0) {
|
||||
struct bt_gatt_service *svc = created_svcs[--created_svc_count];
|
||||
|
||||
created_svcs[created_svc_count] = NULL;
|
||||
|
||||
/* Already-unregistered entries fall out as a no-op inside. */
|
||||
(void)bt_le_bluedroid_svc_deinit(svc);
|
||||
}
|
||||
|
||||
bt_le_bluedroid_gatts_svc_cb_register(NULL);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_set_svc_in_progress(uint8_t value)
|
||||
{
|
||||
if (value >= MAX_IN_PROGRESS) {
|
||||
@@ -414,17 +499,6 @@ static struct inc_svc_inst *get_not_included_inst(void)
|
||||
|
||||
static uint8_t get_svc_inst_id(uint16_t svc_uuid)
|
||||
{
|
||||
/* Note:
|
||||
* For LE Audio, some service could have multiple instances.
|
||||
*/
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t aics_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t csis_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t vocs_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t mcs_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t ots_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t tbs_count;
|
||||
|
||||
switch (svc_uuid) {
|
||||
case BT_UUID_AICS_VAL:
|
||||
return aics_count++;
|
||||
@@ -611,6 +685,12 @@ int bt_le_bluedroid_svc_init(struct bt_gatt_service *svc)
|
||||
}
|
||||
}
|
||||
|
||||
/* Created, so the deinit has to delete it. attr_count 0 is a service the
|
||||
* application never registered; svc_init walked nothing. */
|
||||
if (svc->attr_count > 0 && svc->attrs[0].handle != 0) {
|
||||
svc_created_record(svc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -618,11 +698,16 @@ int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc)
|
||||
{
|
||||
BT_LE_ASSERT(svc);
|
||||
|
||||
/* App may not register this svc; skip rather than fail audio_start.
|
||||
* Unused CAP Acceptor capabilities stop at handle 0, GMAS at NULL
|
||||
* attrs - only bt_gmap_register() allocates them. */
|
||||
if (svc->attrs == NULL) {
|
||||
LOG_DBG("[B]SvcNotReg[%u]", svc_in_progress);
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_handle = svc->attrs[0].handle;
|
||||
|
||||
/* App may not register this svc (e.g. CAP Acceptor single mode keeps
|
||||
* unused capability built). Skip rather than fail audio_start.
|
||||
*/
|
||||
if (svc_handle == 0) {
|
||||
LOG_DBG("[B]SvcNotInit[%u]", svc_in_progress);
|
||||
return 0;
|
||||
@@ -632,7 +717,9 @@ int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc)
|
||||
BTA_GATTS_StartService(svc_handle, BTA_GATT_TRANSPORT_LE);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]SvcStartFail");
|
||||
/* Which service and which handle: BTA only says "already started" or
|
||||
* "not created", neither of which names the caller. */
|
||||
LOG_ERR("[B]SvcStartFail[%u][0x%04x]", svc_in_progress, svc_handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ extern "C" {
|
||||
|
||||
int bt_le_nimble_audio_init(void);
|
||||
|
||||
void bt_le_nimble_audio_deinit(void);
|
||||
|
||||
int bt_le_nimble_media_proxy_pl_init(void);
|
||||
|
||||
int bt_le_nimble_vcp_vol_rend_init(void);
|
||||
|
||||
@@ -18,6 +18,8 @@ int bt_le_nimble_ascs_attr_handle_set(void);
|
||||
|
||||
int bt_le_nimble_ascs_init(void);
|
||||
|
||||
int bt_le_nimble_ascs_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,8 @@ int bt_le_nimble_bass_attr_handle_set(void);
|
||||
|
||||
int bt_le_nimble_bass_init(void);
|
||||
|
||||
int bt_le_nimble_bass_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,12 @@ extern "C" {
|
||||
|
||||
int bt_le_nimble_csis_attr_handle_set(void);
|
||||
|
||||
void bt_le_nimble_csis_state_reset(void);
|
||||
|
||||
int bt_le_nimble_csis_init(void *csis_svc, uint8_t count);
|
||||
|
||||
int bt_le_nimble_csis_deinit(void *csis_svc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,8 @@ extern "C" {
|
||||
|
||||
int bt_le_nimble_gmcs_attr_handle_set(void);
|
||||
|
||||
void bt_le_nimble_mcs_state_reset(void);
|
||||
|
||||
int bt_le_nimble_gmcs_init(bool ots_included);
|
||||
|
||||
int bt_le_nimble_mcs_attr_handle_set(void);
|
||||
|
||||
@@ -19,6 +19,8 @@ extern "C" {
|
||||
|
||||
int bt_le_nimble_mics_attr_handle_set(void);
|
||||
|
||||
void bt_le_nimble_mics_state_reset(void);
|
||||
|
||||
int bt_le_nimble_mics_init(void *micp_inc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -21,6 +21,8 @@ int bt_le_nimble_pacs_attr_handle_set(void);
|
||||
|
||||
int bt_le_nimble_pacs_init(void);
|
||||
|
||||
int bt_le_nimble_pacs_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,10 +18,14 @@ int bt_le_nimble_gtbs_attr_handle_set(void);
|
||||
|
||||
int bt_le_nimble_gtbs_init(void);
|
||||
|
||||
int bt_le_nimble_gtbs_deinit(void);
|
||||
|
||||
int bt_le_nimble_tbs_attr_handle_set(void);
|
||||
|
||||
int bt_le_nimble_tbs_init(void);
|
||||
|
||||
int bt_le_nimble_tbs_deinit(uint8_t bearer_index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,8 @@ extern "C" {
|
||||
|
||||
int bt_le_nimble_vcs_attr_handle_set(void);
|
||||
|
||||
void bt_le_nimble_vcs_state_reset(void);
|
||||
|
||||
int bt_le_nimble_vcs_init(void *vcp_inc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "nimble/init.h"
|
||||
#include "common/init.h"
|
||||
#include "common/audio_attr.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
@@ -159,6 +160,9 @@ LOG_MODULE_REGISTER(LEA_NINIT, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
_Static_assert(TOTAL_CCCDS_COUNT <= CONFIG_BT_NIMBLE_MAX_CCCDS, "Too small BT_NIMBLE_MAX_CCCDS");
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR bool nimble_svcs_registered;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR bool nimble_gatts_started;
|
||||
|
||||
int bt_le_nimble_audio_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -169,6 +173,23 @@ int bt_le_nimble_audio_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
bt_le_nimble_csis_state_reset();
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
bt_le_nimble_vcs_state_reset();
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
bt_le_nimble_mics_state_reset();
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
#if CONFIG_BT_MCS
|
||||
bt_le_nimble_mcs_state_reset();
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
if (nimble_svcs_registered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ble_svc_gap_init();
|
||||
|
||||
ble_svc_gatt_init();
|
||||
@@ -222,6 +243,8 @@ int bt_le_nimble_audio_init(void)
|
||||
#endif /* CONFIG_BT_HAS */
|
||||
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
|
||||
|
||||
nimble_svcs_registered = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -442,6 +465,14 @@ int bt_le_nimble_micp_mic_dev_init(void)
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
|
||||
void bt_le_nimble_audio_deinit(void)
|
||||
{
|
||||
LOG_DBG("[N]AudioDeinit");
|
||||
|
||||
/* Nothing to release: the services added here are boot-scoped and the defs
|
||||
* NimBLE holds reference no lib memory, so resources_deinit() is safe. */
|
||||
}
|
||||
|
||||
int bt_le_nimble_audio_start(void *info)
|
||||
{
|
||||
struct bt_gatt_service *inc_csis_svc = NULL;
|
||||
@@ -499,10 +530,17 @@ int bt_le_nimble_audio_start(void *info)
|
||||
}
|
||||
#endif /* CONFIG_BT_GMAP */
|
||||
|
||||
err = ble_gatts_start();
|
||||
if (err) {
|
||||
LOG_ERR("[N]GattsStartFail[%d]", err);
|
||||
return err;
|
||||
/* Once per boot: ble_gatts_start() resets the whole ATT database and only
|
||||
* re-registers defs added since the last start, so calling it again drops
|
||||
* other owners' services. attr_handle_set() still runs every cycle. */
|
||||
if (!nimble_gatts_started) {
|
||||
err = ble_gatts_start();
|
||||
if (err) {
|
||||
LOG_ERR("[N]GattsStartFail[%d]", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
nimble_gatts_started = true;
|
||||
}
|
||||
|
||||
err = nimble_gatt_attr_handle_set();
|
||||
|
||||
@@ -254,3 +254,9 @@ free:
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bt_le_nimble_ascs_deinit(void)
|
||||
{
|
||||
LOG_DBG("[N]AscsDeinit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,3 +218,9 @@ free:
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bt_le_nimble_bass_deinit(void)
|
||||
{
|
||||
LOG_DBG("[N]BassDeinit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,9 @@ static BT_AUDIO_EXT_RAM_BSS_ATTR struct csis_inst {
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t csis_svc_count;
|
||||
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR uint8_t csis_reg_count;
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR bool csis_registered;
|
||||
|
||||
/* Extra one for terminating the CSIS service array */
|
||||
static BT_AUDIO_EXT_RAM_BSS_ATTR struct ble_gatt_svc_def gatt_svc_csis[CSIS_SVC_COUNT + 1];
|
||||
|
||||
@@ -162,7 +165,14 @@ int bt_le_nimble_csis_attr_handle_set(void)
|
||||
struct bt_gatt_service *zsvc = csis_insts[i].svc_p;
|
||||
|
||||
BT_LE_ASSERT(zsvc);
|
||||
BT_LE_ASSERT(csis_insts[i].sirk_handle >= 2);
|
||||
|
||||
/* Zero means no registration round ever covered this instance, so it is
|
||||
* absent from the ATT database and there is no range to anchor. Happens
|
||||
* when CSIS is first registered after the boot's ble_gatts_start(). */
|
||||
if (csis_insts[i].sirk_handle < 2) {
|
||||
LOG_ERR("[N]CsisNoAttrHdl[%u]", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* SIRK is always the first characteristic, so its value handle anchors the range. */
|
||||
start_handle = csis_insts[i].sirk_handle - 2; /* server attr handle & char def handle */
|
||||
@@ -295,6 +305,11 @@ static void csis_svc_init(struct csis_inst *inst,
|
||||
BT_LE_ASSERT(chr_cnt < CSIS_CHR_COUNT);
|
||||
}
|
||||
|
||||
void bt_le_nimble_csis_state_reset(void)
|
||||
{
|
||||
csis_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_csis_init(void *svc, uint8_t count)
|
||||
{
|
||||
bool csis_added = false;
|
||||
@@ -307,11 +322,27 @@ int bt_le_nimble_csis_init(void *svc, uint8_t count)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The attribute table is built by the boot's single ble_gatts_start(), so a
|
||||
* different instance count now needs a table this boot cannot produce. Fail
|
||||
* here, not later on a handle NimBLE never assigned. */
|
||||
if (csis_registered && count != csis_reg_count) {
|
||||
LOG_ERR("[N]CsisCountChanged[%u][%u]", csis_reg_count, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
csis_svc_count = count;
|
||||
|
||||
/* Refreshed every cycle: the lib frees and reallocates its service objects,
|
||||
* while the NimBLE defs below are built once and stay in the database. */
|
||||
for (size_t i = 0; i < csis_svc_count; i++) {
|
||||
csis_insts[i].svc_p = ((struct bt_gatt_service **)svc)[i];
|
||||
}
|
||||
|
||||
if (csis_registered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < csis_svc_count; i++) {
|
||||
csis_svc_init(&csis_insts[i], &gatt_svc_csis[i], csis_insts[i].svc_p);
|
||||
}
|
||||
|
||||
@@ -333,6 +364,9 @@ int bt_le_nimble_csis_init(void *svc, uint8_t count)
|
||||
goto free;
|
||||
}
|
||||
|
||||
csis_reg_count = count;
|
||||
csis_registered = true;
|
||||
|
||||
return 0;
|
||||
|
||||
free:
|
||||
@@ -348,3 +382,11 @@ free:
|
||||
csis_svc_count = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bt_le_nimble_csis_deinit(void *csis_svc)
|
||||
{
|
||||
ARG_UNUSED(csis_svc);
|
||||
|
||||
LOG_DBG("[N]CsisDeinit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -630,6 +630,13 @@ static int inc_ots_svc_init(void)
|
||||
}
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
|
||||
void bt_le_nimble_mcs_state_reset(void)
|
||||
{
|
||||
#if CONFIG_BT_OTS
|
||||
inc_ots_svc_count = 0;
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
}
|
||||
|
||||
int bt_le_nimble_gmcs_init(bool ots_included)
|
||||
{
|
||||
#if CONFIG_BT_OTS
|
||||
|
||||
@@ -346,6 +346,11 @@ static void inc_aics_svc_init(struct inc_aics_inst *inst,
|
||||
INC_AICS_CHR_FLAGS_DESCRIPTION);
|
||||
}
|
||||
|
||||
void bt_le_nimble_mics_state_reset(void)
|
||||
{
|
||||
inc_aics_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_mics_init(void *micp_inc)
|
||||
{
|
||||
struct bt_micp_included *micp_included;
|
||||
|
||||
@@ -275,3 +275,9 @@ int bt_le_nimble_pacs_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_pacs_deinit(void)
|
||||
{
|
||||
LOG_DBG("[N]PacsDeinit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -372,3 +372,15 @@ int bt_le_nimble_tbs_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_gtbs_deinit(void)
|
||||
{
|
||||
LOG_DBG("[N]GtbsDeinit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_tbs_deinit(uint8_t bearer_index)
|
||||
{
|
||||
LOG_DBG("[N]TbsDeinit[%u]", bearer_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -542,6 +542,12 @@ static void inc_aics_svc_init(struct inc_aics_inst *inst,
|
||||
INC_AICS_CHR_FLAGS_DESCRIPTION);
|
||||
}
|
||||
|
||||
void bt_le_nimble_vcs_state_reset(void)
|
||||
{
|
||||
inc_vocs_svc_count = 0;
|
||||
inc_aics_svc_count = 0;
|
||||
}
|
||||
|
||||
int bt_le_nimble_vcs_init(void *vcp_inc)
|
||||
{
|
||||
struct bt_vcp_included *vcp_included;
|
||||
|
||||
@@ -49,14 +49,26 @@ void bt_le_audio_deinit(void);
|
||||
|
||||
int bt_le_ascs_init(void);
|
||||
|
||||
int bt_le_ascs_deinit(void);
|
||||
|
||||
int bt_le_pacs_deinit(void);
|
||||
|
||||
int bt_le_csis_deinit(const void *svc_inst);
|
||||
|
||||
int bt_le_bass_init(void);
|
||||
|
||||
int bt_le_bass_deinit(void);
|
||||
|
||||
int bt_le_tmas_init(void);
|
||||
|
||||
int bt_le_gtbs_init(void);
|
||||
|
||||
int bt_le_gtbs_deinit(void);
|
||||
|
||||
int bt_le_tbs_init(void);
|
||||
|
||||
int bt_le_tbs_deinit(uint8_t bearer_index);
|
||||
|
||||
int bt_le_has_init(void);
|
||||
|
||||
int bt_le_media_proxy_pl_init(void);
|
||||
|
||||
@@ -185,7 +185,7 @@ static const uint16_t ext_structs[] = {
|
||||
sizeof(struct bt_bond_info),
|
||||
};
|
||||
|
||||
#define LEA_VERSION (0x20260820)
|
||||
#define LEA_VERSION (0x20260824)
|
||||
|
||||
struct lib_ext_cfgs {
|
||||
/* BLE */
|
||||
@@ -1085,16 +1085,20 @@ struct lib_ext_funcs {
|
||||
|
||||
/* Scan */
|
||||
int (*_scan_cb_register)(struct bt_le_scan_cb *cb);
|
||||
void (*_scan_cb_unregister)(struct bt_le_scan_cb *cb);
|
||||
int (*_scan_start)(const struct bt_le_scan_param *param, void *cb);
|
||||
int (*_scan_stop)(void);
|
||||
int (*_pa_sync_cb_register)(struct bt_le_per_adv_sync_cb *cb);
|
||||
int (*_pa_sync_cb_unregister)(struct bt_le_per_adv_sync_cb *cb);
|
||||
int (*_pa_sync_get_info)(struct bt_le_per_adv_sync *per_adv_sync,
|
||||
struct bt_le_per_adv_sync_info *info);
|
||||
struct bt_le_per_adv_sync *(*_pa_sync_lookup_addr)(const bt_addr_le_t *adv_addr, uint8_t sid);
|
||||
|
||||
/* Connection */
|
||||
int (*_conn_cb_register)(struct bt_conn_cb *cb);
|
||||
int (*_conn_cb_unregister)(struct bt_conn_cb *cb);
|
||||
int (*_conn_auth_info_cb_register)(struct bt_conn_auth_info_cb *cb);
|
||||
int (*_conn_auth_info_cb_unregister)(struct bt_conn_auth_info_cb *cb);
|
||||
void (*_conn_foreach)(enum bt_conn_type type,
|
||||
void (*func)(struct bt_conn *conn, void *data),
|
||||
void *data);
|
||||
@@ -1295,14 +1299,18 @@ static const struct lib_ext_funcs ext_funcs = {
|
||||
._bt_foreach_bond = (void *)bt_foreach_bond,
|
||||
|
||||
._scan_cb_register = (void *)bt_le_scan_cb_register,
|
||||
._scan_cb_unregister = (void *)bt_le_scan_cb_unregister,
|
||||
._scan_start = (void *)bt_le_scan_start,
|
||||
._scan_stop = (void *)bt_le_scan_stop,
|
||||
._pa_sync_cb_register = (void *)bt_le_per_adv_sync_cb_register,
|
||||
._pa_sync_cb_unregister = (void *)bt_le_per_adv_sync_cb_unregister,
|
||||
._pa_sync_get_info = (void *)bt_le_per_adv_sync_get_info,
|
||||
._pa_sync_lookup_addr = (void *)bt_le_per_adv_sync_lookup_addr,
|
||||
|
||||
._conn_cb_register = (void *)bt_conn_cb_register,
|
||||
._conn_cb_unregister = (void *)bt_conn_cb_unregister,
|
||||
._conn_auth_info_cb_register = (void *)bt_conn_auth_info_cb_register,
|
||||
._conn_auth_info_cb_unregister = (void *)bt_conn_auth_info_cb_unregister,
|
||||
._conn_foreach = (void *)bt_conn_foreach,
|
||||
._conn_get_info = (void *)bt_conn_get_info,
|
||||
._conn_index = (void *)bt_conn_index,
|
||||
@@ -2075,6 +2083,260 @@ static int lib_audio_resources_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Reverse order of lib_audio_resources_init(): a module may reference an earlier
|
||||
* one. Failures log and continue - stopping half way leaves more behind. Keep
|
||||
* every lib_*_init() listed here; a missing counterpart leaks silently. */
|
||||
static void lib_audio_resources_deinit(void)
|
||||
{
|
||||
#if CONFIG_BT_GMAP
|
||||
/* No init counterpart above: bt_gmap_register() allocates GMAS on demand,
|
||||
* so only the deinit side is listed. */
|
||||
if (lib_gmap_server_deinit()) {
|
||||
LOG_ERR("LibGmapSrvDeinitFail");
|
||||
}
|
||||
|
||||
if (lib_gmap_client_deinit()) {
|
||||
LOG_ERR("LibGmapCliDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_GMAP */
|
||||
|
||||
#if CONFIG_BT_HAS_CLIENT
|
||||
if (lib_has_client_deinit()) {
|
||||
LOG_ERR("LibHasCliDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_HAS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_HAS
|
||||
if (lib_has_deinit()) {
|
||||
LOG_ERR("LibHasDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_HAS */
|
||||
|
||||
#if CONFIG_BT_VOCS_CLIENT
|
||||
if (lib_vocs_client_deinit()) {
|
||||
LOG_ERR("LibVocsClientDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_VOCS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT
|
||||
if (lib_vocs_deinit()) {
|
||||
LOG_ERR("LibVocsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_VOCS || CONFIG_BT_VOCS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
if (lib_vcp_vol_rend_deinit()) {
|
||||
LOG_ERR("LibVcpVolRendDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_CTLR
|
||||
if (lib_vcp_vol_ctlr_deinit()) {
|
||||
LOG_ERR("LibVcpVolCtlrDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_CTLR */
|
||||
|
||||
#if CONFIG_BT_TMAP
|
||||
if (lib_tmap_deinit()) {
|
||||
LOG_ERR("LibTmapDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_TMAP */
|
||||
|
||||
#if CONFIG_BT_TBS
|
||||
if (lib_tbs_deinit()) {
|
||||
LOG_ERR("LibTbsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
#if CONFIG_BT_TBS_CLIENT
|
||||
if (lib_tbs_client_deinit()) {
|
||||
LOG_ERR("LibTbsCliDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_PBP
|
||||
if (lib_pbp_deinit()) {
|
||||
LOG_ERR("LibPbpDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_PBP */
|
||||
|
||||
#if CONFIG_BT_MPL
|
||||
if (lib_mpl_deinit()) {
|
||||
LOG_ERR("LibMplDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MPL */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
if (lib_micp_mic_dev_deinit()) {
|
||||
LOG_ERR("LibMicpMicDevDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_CTLR
|
||||
if (lib_micp_mic_ctlr_deinit()) {
|
||||
LOG_ERR("LibMicpMicCtlrDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_CTLR */
|
||||
|
||||
#if CONFIG_BT_MCTL
|
||||
if (lib_media_proxy_deinit()) {
|
||||
LOG_ERR("LibMediaProxyDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MCTL */
|
||||
|
||||
#if CONFIG_BT_MCS
|
||||
if (lib_mcs_deinit()) {
|
||||
LOG_ERR("LibMcsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
#if CONFIG_BT_MCC
|
||||
if (lib_mcc_deinit()) {
|
||||
LOG_ERR("LibMccDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_MCC */
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_COORDINATOR
|
||||
if (lib_csip_set_coordinator_deinit()) {
|
||||
LOG_ERR("LibCsipSetCoordinatorDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
if (lib_csip_set_member_deinit()) {
|
||||
LOG_ERR("LibCsipSetMemberDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
#if CONFIG_BT_BAP_STREAM
|
||||
if (lib_codec_deinit()) {
|
||||
LOG_ERR("LibCodecDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_STREAM */
|
||||
|
||||
#if CONFIG_BT_CCP_CALL_CONTROL_SERVER
|
||||
if (lib_ccp_call_control_server_deinit()) {
|
||||
LOG_ERR("LibCcpCallControlServerDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CCP_CALL_CONTROL_SERVER */
|
||||
|
||||
#if CONFIG_BT_CCP_CALL_CONTROL_CLIENT
|
||||
if (lib_ccp_call_control_client_deinit()) {
|
||||
LOG_ERR("LibCcpCallControlClientDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CCP_CALL_CONTROL_CLIENT */
|
||||
|
||||
if (lib_ccid_deinit()) {
|
||||
LOG_ERR("LibCcidDeinitFail");
|
||||
}
|
||||
|
||||
#if CONFIG_BT_CAP_COMMANDER
|
||||
if (lib_cap_commander_deinit()) {
|
||||
LOG_ERR("LibCapComDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_COMMANDER */
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR
|
||||
if (lib_cap_acceptor_deinit()) {
|
||||
LOG_ERR("LibCapAccDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR */
|
||||
|
||||
#if CONFIG_BT_CAP_INITIATOR
|
||||
if (lib_cap_initiator_deinit()) {
|
||||
LOG_ERR("LibCapIniDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_INITIATOR */
|
||||
|
||||
#if CONFIG_BT_CAP
|
||||
if (lib_cap_stream_deinit()) {
|
||||
LOG_ERR("LibCapStreamDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP */
|
||||
|
||||
#if CONFIG_BT_CAP_INITIATOR_UNICAST || CONFIG_BT_CAP_COMMANDER
|
||||
if (lib_cap_common_deinit()) {
|
||||
LOG_ERR("LibCapCommonDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST || CONFIG_BT_CAP_COMMANDER */
|
||||
|
||||
#if CONFIG_BT_BAP_UNICAST_SERVER
|
||||
if (lib_bap_unicast_server_deinit()) {
|
||||
LOG_ERR("LibBapUniSrvDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_UNICAST_SERVER */
|
||||
|
||||
#if CONFIG_BT_BAP_UNICAST_CLIENT
|
||||
if (lib_bap_unicast_client_deinit()) {
|
||||
LOG_ERR("LibBapUniCliDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
|
||||
|
||||
#if CONFIG_BT_BAP_BROADCAST_ASSISTANT
|
||||
if (lib_bap_broadcast_assistant_deinit()) {
|
||||
LOG_ERR("LibBapBaDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
|
||||
|
||||
#if CONFIG_BT_BAP_SCAN_DELEGATOR
|
||||
if (lib_bap_scan_delegator_deinit()) {
|
||||
LOG_ERR("LibBapSdeDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
#if CONFIG_BT_BAP_BROADCAST_SOURCE
|
||||
if (lib_bap_broadcast_source_deinit()) {
|
||||
LOG_ERR("LibBapBsrcDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
|
||||
|
||||
#if CONFIG_BT_BAP_BROADCAST_SINK
|
||||
if (lib_bap_broadcast_sink_deinit()) {
|
||||
LOG_ERR("LibBapBsnkDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_BROADCAST_SINK */
|
||||
|
||||
#if CONFIG_BT_PACS
|
||||
if (lib_pacs_deinit()) {
|
||||
LOG_ERR("LibPacsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_PACS */
|
||||
|
||||
#if CONFIG_BT_ASCS
|
||||
if (lib_ascs_deinit()) {
|
||||
LOG_ERR("LibAscsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_ASCS */
|
||||
|
||||
#if CONFIG_BT_BAP_STREAM
|
||||
if (lib_bap_stream_deinit()) {
|
||||
LOG_ERR("LibBapStreamDeinitFail");
|
||||
}
|
||||
|
||||
if (lib_bap_iso_deinit()) {
|
||||
LOG_ERR("LibBapIsoDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_STREAM */
|
||||
|
||||
#if CONFIG_BT_BAP_BASE
|
||||
if (lib_bap_base_deinit()) {
|
||||
LOG_ERR("LibBapBaseDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_BASE */
|
||||
|
||||
#if CONFIG_BT_AICS_CLIENT
|
||||
if (lib_aics_client_deinit()) {
|
||||
LOG_ERR("LibAicsClientDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_AICS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT
|
||||
if (lib_aics_deinit()) {
|
||||
LOG_ERR("LibAicsDeinitFail");
|
||||
}
|
||||
#endif /* CONFIG_BT_AICS || CONFIG_BT_AICS_CLIENT */
|
||||
}
|
||||
|
||||
int bt_le_audio_init(void)
|
||||
{
|
||||
int err;
|
||||
@@ -2112,13 +2374,13 @@ int bt_le_audio_init(void)
|
||||
|
||||
err = lib_audio_resources_init();
|
||||
if (err) {
|
||||
return err;
|
||||
goto deinit_lib;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
err = bt_le_l2cap_ots_init();
|
||||
if (err) {
|
||||
return err;
|
||||
goto deinit_lib;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2128,20 +2390,33 @@ int bt_le_audio_init(void)
|
||||
err = bt_le_nimble_audio_init();
|
||||
#endif
|
||||
if (err) {
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
bt_le_l2cap_ots_deinit();
|
||||
#endif
|
||||
return err;
|
||||
goto deinit_ots;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
deinit_ots:
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
bt_le_l2cap_ots_deinit();
|
||||
#endif
|
||||
deinit_lib:
|
||||
lib_audio_resources_deinit();
|
||||
return err;
|
||||
}
|
||||
|
||||
void bt_le_audio_deinit(void)
|
||||
{
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_bluedroid_audio_deinit();
|
||||
#else
|
||||
bt_le_nimble_audio_deinit();
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
bt_le_l2cap_ots_deinit();
|
||||
#endif
|
||||
|
||||
lib_audio_resources_deinit();
|
||||
}
|
||||
|
||||
#if BLE_AUDIO_SVC_DEFERRED_ADD
|
||||
@@ -2156,6 +2431,17 @@ int bt_le_ascs_init(void)
|
||||
return bt_le_nimble_ascs_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_le_ascs_deinit(void)
|
||||
{
|
||||
LOG_DBG("AscsDeinit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_ascs_deinit();
|
||||
#else
|
||||
return bt_le_nimble_ascs_deinit();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_ASCS */
|
||||
|
||||
#if CONFIG_BT_BAP_SCAN_DELEGATOR
|
||||
@@ -2169,6 +2455,17 @@ int bt_le_bass_init(void)
|
||||
return bt_le_nimble_bass_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_le_bass_deinit(void)
|
||||
{
|
||||
LOG_DBG("BassDeinit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_bass_deinit();
|
||||
#else
|
||||
return bt_le_nimble_bass_deinit();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
#if CONFIG_BT_TMAP
|
||||
@@ -2196,6 +2493,17 @@ int bt_le_gtbs_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_le_gtbs_deinit(void)
|
||||
{
|
||||
LOG_DBG("GtbsDeinit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gtbs_deinit();
|
||||
#else
|
||||
return bt_le_nimble_gtbs_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_le_tbs_init(void)
|
||||
{
|
||||
LOG_DBG("TbsInit");
|
||||
@@ -2206,6 +2514,17 @@ int bt_le_tbs_init(void)
|
||||
return bt_le_nimble_tbs_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_le_tbs_deinit(uint8_t bearer_index)
|
||||
{
|
||||
LOG_DBG("TbsDeinit[%u]", bearer_index);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_tbs_deinit(bearer_index);
|
||||
#else
|
||||
return bt_le_nimble_tbs_deinit(bearer_index);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
#if CONFIG_BT_HAS
|
||||
@@ -2261,6 +2580,40 @@ int bt_le_micp_mic_dev_init(void)
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
|
||||
|
||||
#if CONFIG_BT_PACS
|
||||
int bt_le_pacs_deinit(void)
|
||||
{
|
||||
LOG_DBG("PacsDeinit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_pacs_deinit();
|
||||
#else
|
||||
return bt_le_nimble_pacs_deinit();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_PACS */
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
int bt_le_csis_deinit(const void *svc_inst)
|
||||
{
|
||||
struct bt_gatt_service *csis_svc;
|
||||
|
||||
LOG_DBG("CsisDeinit");
|
||||
|
||||
csis_svc = lib_csip_set_member_svc_get(svc_inst);
|
||||
if (!csis_svc) {
|
||||
LOG_ERR("CsisSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_csis_deinit(csis_svc);
|
||||
#else
|
||||
return bt_le_nimble_csis_deinit(csis_svc);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
int bt_le_audio_start(void *info)
|
||||
{
|
||||
LOG_DBG("AudioStart");
|
||||
|
||||
@@ -44,10 +44,12 @@ static BT_AUDIO_EXT_RAM_BSS_ATTR sys_slist_t l2cap_servers;
|
||||
extern int bt_gatt_ots_conn_cb_register(void);
|
||||
extern void bt_gatt_ots_conn_cb_unregister(void);
|
||||
extern int bt_gatt_ots_instances_prepare(void);
|
||||
extern void bt_ots_instances_rewind(void);
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
#if CONFIG_BT_OTS_CLIENT
|
||||
extern int bt_gatt_ots_client_conn_cb_register(void);
|
||||
extern void bt_gatt_ots_client_conn_cb_unregister(void);
|
||||
extern void bt_ots_client_unregister_all(void);
|
||||
#endif /* CONFIG_BT_OTS_CLIENT */
|
||||
extern int bt_gatt_ots_l2cap_init(void);
|
||||
|
||||
@@ -361,17 +363,31 @@ static void l2cap_sent(uint16_t conn_handle, uint16_t psm)
|
||||
}
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
void bt_le_l2cap_event_free(void *data)
|
||||
{
|
||||
struct bt_le_l2cap_event *qev = data;
|
||||
|
||||
if (qev == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only RECEIVED carries a buffer of its own; the rest are header-only. */
|
||||
if (qev->type == BT_LE_L2CAP_EVENT_RECEIVED) {
|
||||
free(qev->received.data);
|
||||
}
|
||||
|
||||
free(qev);
|
||||
}
|
||||
|
||||
static int l2cap_post_event(struct bt_le_l2cap_event *qev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_L2CAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("L2capPostFail[%d][%u]", err, qev->type);
|
||||
if (qev->type == BT_LE_L2CAP_EVENT_RECEIVED) {
|
||||
free(qev->received.data);
|
||||
}
|
||||
free(qev);
|
||||
ISO_POST_FAIL_LOG(err, "L2capPostFail[%d][%u]", err, qev->type);
|
||||
bt_le_l2cap_event_free(qev);
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -811,14 +827,20 @@ void bt_le_l2cap_ots_deinit(void)
|
||||
{
|
||||
LOG_DBG("L2capOtsDeinit");
|
||||
|
||||
/* TODO(deinit): unassign OTS obj managers / clear instance->obj_manager. */
|
||||
|
||||
/* Symmetric with the registers in _init: conn_cbs is never reset elsewhere. */
|
||||
#if CONFIG_BT_OTS
|
||||
bt_gatt_ots_conn_cb_unregister();
|
||||
|
||||
/* Give the instances handed out by bt_ots_free_instance_get() back to the
|
||||
* pool; the profiles that took them are released right after this. */
|
||||
bt_ots_instances_rewind();
|
||||
#endif /* CONFIG_BT_OTS */
|
||||
#if CONFIG_BT_OTS_CLIENT
|
||||
bt_gatt_ots_client_conn_cb_unregister();
|
||||
|
||||
/* Before lib_audio_resources_deinit() frees the bt_ots_client instances
|
||||
* the table points at - this runs first in bt_le_audio_deinit(). */
|
||||
bt_ots_client_unregister_all();
|
||||
#endif /* CONFIG_BT_OTS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
|
||||
@@ -106,6 +106,8 @@ int bt_le_l2cap_post_sent(uint16_t conn_handle, uint16_t psm);
|
||||
|
||||
void bt_le_l2cap_handle_event(void *data, size_t data_len);
|
||||
|
||||
void bt_le_l2cap_event_free(void *data);
|
||||
|
||||
int bt_le_l2cap_ots_init(void);
|
||||
|
||||
void bt_le_l2cap_ots_deinit(void);
|
||||
|
||||
@@ -563,6 +563,9 @@ int bt_ots_init(struct bt_ots *ots,
|
||||
|
||||
/* Check OACP supported features against Kconfig. */
|
||||
if (ots_init->features.oacp & (~((uint32_t) OACP_FEAT))) {
|
||||
/* cb is what bt_ots_instances_rewind() reads to decide there is an init
|
||||
* to reverse, so every bail after the assignment above has to undo it. */
|
||||
ots->cb = NULL;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -575,6 +578,7 @@ int bt_ots_init(struct bt_ots *ots,
|
||||
|
||||
/* Check OLCP supported features against Kconfig. */
|
||||
if (ots_init->features.olcp & (~((uint32_t) OLCP_FEAT))) {
|
||||
ots->cb = NULL;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ots->features.olcp = ots_init->features.olcp;
|
||||
@@ -583,6 +587,7 @@ int bt_ots_init(struct bt_ots *ots,
|
||||
/* Register L2CAP context. */
|
||||
err = bt_gatt_ots_l2cap_register(&ots->l2cap);
|
||||
if (err) {
|
||||
ots->cb = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -594,6 +599,7 @@ int bt_ots_init(struct bt_ots *ots,
|
||||
LOG_ERR("OtsL2capUnregFail[%d]", unreg_err);
|
||||
}
|
||||
|
||||
ots->cb = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -768,6 +774,38 @@ struct bt_ots *bt_ots_free_instance_get(void)
|
||||
return &BT_GATT_OTS_INSTANCE_LIST_START[instance_cnt++];
|
||||
}
|
||||
|
||||
/* Both pools only count up, so without this a second init finds them exhausted
|
||||
* (McsNoFreeOtsInst / OtsObjMgrInstUnavail). Safe here: the profile that took an
|
||||
* instance has dropped its reference by now. */
|
||||
void bt_ots_instances_rewind(void)
|
||||
{
|
||||
for (struct bt_ots *instance = BT_GATT_OTS_INSTANCE_LIST_START;
|
||||
instance != BT_GATT_OTS_INSTANCE_LIST_END; instance++) {
|
||||
/* cb is the marker for "bt_ots_init() ran here": it is set on entry and
|
||||
* cleared again on every failure path, so it is exactly the set of
|
||||
* instances with something to reverse. Reverse order of that function. */
|
||||
if (instance->cb != NULL) {
|
||||
k_work_deinit_delayable(&instance->olcp_ind.work);
|
||||
k_work_deinit_delayable(&instance->oacp_ind.work);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
||||
bt_ots_dir_list_deinit(&instance->dir_list);
|
||||
}
|
||||
|
||||
(void)bt_gatt_service_unregister(instance->service);
|
||||
(void)bt_gatt_ots_l2cap_unregister(&instance->l2cap);
|
||||
instance->cb = NULL;
|
||||
}
|
||||
|
||||
if (instance->obj_manager != NULL) {
|
||||
bt_gatt_ots_obj_manager_release(instance->obj_manager);
|
||||
instance->obj_manager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
instance_cnt = 0;
|
||||
}
|
||||
|
||||
int bt_gatt_ots_instances_prepare(void)
|
||||
{
|
||||
uint32_t index;
|
||||
|
||||
@@ -637,6 +637,15 @@ int bt_ots_client_unregister(uint8_t index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt_ots_client_unregister_all(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(otc_insts); i++) {
|
||||
if (otc_insts[i].otc_inst != NULL) {
|
||||
(void)bt_ots_client_unregister(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
int bt_ots_client_read_feature(struct bt_ots_client *otc_inst,
|
||||
struct bt_conn *conn)
|
||||
|
||||
@@ -320,6 +320,16 @@ void bt_ots_dir_list_init(struct bt_ots_dir_list **dir_list, void *obj_manager)
|
||||
dir_list_update_size(*dir_list, obj_manager);
|
||||
}
|
||||
|
||||
void bt_ots_dir_list_deinit(struct bt_ots_dir_list **dir_list)
|
||||
{
|
||||
if (*dir_list == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(*dir_list, 0, sizeof(**dir_list));
|
||||
*dir_list = NULL;
|
||||
}
|
||||
|
||||
ssize_t bt_ots_dir_list_content_get(struct bt_ots_dir_list *dir_list, void *obj_manager,
|
||||
void **data, size_t len, off_t offset)
|
||||
{
|
||||
|
||||
@@ -161,6 +161,7 @@ void bt_ots_dir_list_selected(struct bt_ots_dir_list *dir_list, void *obj_manage
|
||||
struct bt_gatt_ots_object *cur_obj);
|
||||
void bt_ots_dir_list_content_changed(struct bt_ots_dir_list *dir_list, void *obj_manager);
|
||||
void bt_ots_dir_list_init(struct bt_ots_dir_list **dir_list, void *obj_manager);
|
||||
void bt_ots_dir_list_deinit(struct bt_ots_dir_list **dir_list);
|
||||
ssize_t bt_ots_dir_list_content_get(struct bt_ots_dir_list *dir_list, void *obj_manager,
|
||||
void **data, size_t len, off_t offset);
|
||||
bool bt_ots_dir_list_is_idle(const struct bt_ots_dir_list *dir_list);
|
||||
|
||||
@@ -256,3 +256,19 @@ void *bt_gatt_ots_obj_manager_assign(void)
|
||||
|
||||
return cur_manager;
|
||||
}
|
||||
|
||||
void bt_gatt_ots_obj_manager_release(void *obj_manager)
|
||||
{
|
||||
struct bt_gatt_ots_obj_manager *manager = obj_manager;
|
||||
|
||||
if (manager == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < CONFIG_BT_OTS_MAX_OBJ_CNT; i++) {
|
||||
manager->pool[i].is_allocated = false;
|
||||
}
|
||||
|
||||
sys_dlist_init(&manager->list);
|
||||
manager->is_assigned = false;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ bool bt_gatt_ots_obj_manager_obj_contains(void *obj_manager, struct bt_gatt_ots_
|
||||
|
||||
void *bt_gatt_ots_obj_manager_assign(void);
|
||||
|
||||
void bt_gatt_ots_obj_manager_release(void *obj_manager);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -32,86 +32,128 @@ struct bt_gatt_service;
|
||||
extern struct bt_aics *lib_aics_insts_get(void);
|
||||
extern void *lib_aics_svc_get(struct bt_aics *aics);
|
||||
extern int lib_aics_init(void);
|
||||
extern int lib_aics_deinit(void);
|
||||
extern int lib_aics_client_init(void);
|
||||
extern int lib_aics_client_deinit(void);
|
||||
|
||||
extern int lib_bap_base_init(void);
|
||||
extern int lib_bap_base_deinit(void);
|
||||
extern int lib_bap_iso_init(void);
|
||||
extern int lib_bap_iso_deinit(void);
|
||||
extern int lib_bap_stream_init(void);
|
||||
extern int lib_bap_stream_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_ascs_svc_get(void);
|
||||
extern int lib_ascs_init(void);
|
||||
extern int lib_ascs_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_bap_bass_svc_get(void);
|
||||
extern int lib_bap_broadcast_assistant_init(void);
|
||||
extern int lib_bap_broadcast_assistant_deinit(void);
|
||||
extern int lib_bap_broadcast_sink_init(void);
|
||||
extern int lib_bap_broadcast_sink_deinit(void);
|
||||
extern int lib_bap_broadcast_source_init(void);
|
||||
extern int lib_bap_broadcast_source_deinit(void);
|
||||
extern int lib_bap_scan_delegator_init(void);
|
||||
extern int lib_bap_scan_delegator_deinit(void);
|
||||
extern int lib_bap_unicast_client_init(void);
|
||||
extern int lib_bap_unicast_client_deinit(void);
|
||||
extern int lib_bap_unicast_server_init(void);
|
||||
extern int lib_bap_unicast_server_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_pacs_svc_get(void);
|
||||
extern int lib_pacs_init(void);
|
||||
extern int lib_pacs_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_cas_svc_get(void);
|
||||
|
||||
extern int lib_cap_common_init(void);
|
||||
extern int lib_cap_common_deinit(void);
|
||||
extern int lib_cap_stream_init(void);
|
||||
extern int lib_cap_stream_deinit(void);
|
||||
extern int lib_cap_initiator_init(void);
|
||||
extern int lib_cap_initiator_deinit(void);
|
||||
extern int lib_cap_acceptor_init(void);
|
||||
extern int lib_cap_acceptor_deinit(void);
|
||||
extern int lib_cap_commander_init(void);
|
||||
extern int lib_cap_commander_deinit(void);
|
||||
|
||||
extern int lib_ccid_init(void);
|
||||
extern int lib_ccid_deinit(void);
|
||||
|
||||
extern int lib_ccp_call_control_client_init(void);
|
||||
extern int lib_ccp_call_control_client_deinit(void);
|
||||
extern int lib_ccp_call_control_server_init(void);
|
||||
extern int lib_ccp_call_control_server_deinit(void);
|
||||
|
||||
extern int lib_codec_init(void);
|
||||
extern int lib_codec_deinit(void);
|
||||
|
||||
extern int lib_csip_set_coordinator_init(void);
|
||||
extern int lib_csip_set_coordinator_deinit(void);
|
||||
extern void *lib_csip_set_member_svc_get(const void *svc_inst);
|
||||
extern int lib_csip_set_member_init(void);
|
||||
extern int lib_csip_set_member_deinit(void);
|
||||
|
||||
extern int lib_gmap_client_init(void);
|
||||
extern int lib_gmap_client_deinit(void);
|
||||
extern struct bt_gatt_service *lib_gmas_svc_get(void);
|
||||
extern int lib_gmap_server_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_has_svc_get(void);
|
||||
extern int lib_has_init(void);
|
||||
extern int lib_has_deinit(void);
|
||||
extern int lib_has_client_init(void);
|
||||
extern int lib_has_client_deinit(void);
|
||||
|
||||
extern int lib_mcc_init(void);
|
||||
extern int lib_mcc_deinit(void);
|
||||
extern struct bt_gatt_service *lib_gmcs_svc_get(void);
|
||||
extern struct bt_gatt_service *lib_mcs_server_list_get(void);
|
||||
extern int lib_mcs_init(void);
|
||||
extern int lib_mcs_deinit(void);
|
||||
|
||||
extern int lib_media_proxy_init(void);
|
||||
extern int lib_media_proxy_deinit(void);
|
||||
|
||||
extern int lib_micp_mic_ctlr_init(void);
|
||||
extern int lib_micp_mic_ctlr_deinit(void);
|
||||
extern struct bt_gatt_service *lib_mics_svc_get(void);
|
||||
extern int lib_micp_mic_dev_init(void);
|
||||
extern int lib_micp_mic_dev_deinit(void);
|
||||
|
||||
extern int lib_mpl_init(void);
|
||||
extern int lib_mpl_deinit(void);
|
||||
|
||||
extern int lib_pbp_init(void);
|
||||
extern int lib_pbp_deinit(void);
|
||||
|
||||
extern int lib_tbs_client_init(void);
|
||||
extern int lib_tbs_client_deinit(void);
|
||||
extern struct bt_gatt_service *lib_gtbs_svc_get(void);
|
||||
extern struct bt_gatt_service *lib_tbs_server_list_get(void);
|
||||
extern int lib_tbs_init(void);
|
||||
extern int lib_tbs_deinit(void);
|
||||
|
||||
extern struct bt_gatt_service *lib_tmas_svc_get(void);
|
||||
extern int lib_tmap_init(void);
|
||||
extern int lib_tmap_deinit(void);
|
||||
|
||||
extern int lib_vcp_vol_ctlr_init(void);
|
||||
extern int lib_vcp_vol_ctlr_deinit(void);
|
||||
extern struct bt_gatt_service *lib_vcs_svc_get(void);
|
||||
extern int lib_vcp_vol_rend_init(void);
|
||||
extern int lib_vcp_vol_rend_deinit(void);
|
||||
|
||||
struct bt_vocs;
|
||||
struct bt_vocs_server;
|
||||
|
||||
extern int lib_vocs_client_init(void);
|
||||
extern int lib_vocs_client_deinit(void);
|
||||
extern struct bt_vocs_server *lib_vocs_insts_get(void);
|
||||
extern void *lib_vocs_svc_get(struct bt_vocs *vocs);
|
||||
extern int lib_vocs_init(void);
|
||||
extern int lib_vocs_deinit(void);
|
||||
|
||||
struct bt_conn;
|
||||
struct bt_gatt_attr;
|
||||
|
||||
Submodule components/bt/esp_ble_audio/lib/lib updated: 4cfb5e656a...3565467bac
@@ -6,8 +6,14 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "esp_ble_iso_common_api.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_API, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
esp_err_t esp_ble_iso_data_parse(const uint8_t ltv[], size_t size,
|
||||
bool (*func)(uint8_t type,
|
||||
const uint8_t *data,
|
||||
@@ -128,6 +134,7 @@ esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL) {
|
||||
LOG_WRN("AclUnknown[%u]", conn_handle);
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -266,6 +273,7 @@ esp_err_t esp_ble_iso_big_create(uint8_t adv_handle,
|
||||
|
||||
adv = bt_le_ext_adv_find(adv_handle);
|
||||
if (adv == NULL) {
|
||||
LOG_WRN("ExtAdvUnknown[%u]", adv_handle);
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -294,6 +302,7 @@ esp_err_t esp_ble_iso_big_sync(uint16_t sync_handle,
|
||||
|
||||
per_adv_sync = bt_le_per_adv_sync_find(sync_handle);
|
||||
if (per_adv_sync == NULL) {
|
||||
LOG_WRN("PaSyncUnknown[%u]", sync_handle);
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto unlock;
|
||||
}
|
||||
@@ -434,6 +443,44 @@ unregister_gap:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_iso_common_deinit(const esp_ble_iso_deinit_info_t *info)
|
||||
{
|
||||
bool reset_ext_adv = true;
|
||||
bool reset_pa_sync = true;
|
||||
int err;
|
||||
|
||||
if (info) {
|
||||
if (!info->reset_acl_conn) {
|
||||
LOG_WRN("ConnKeepUnsupported");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
reset_ext_adv = info->reset_ext_adv;
|
||||
reset_pa_sync = info->reset_pa_sync;
|
||||
}
|
||||
|
||||
if (bt_le_host_check_idle()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
err = bt_le_host_deinit();
|
||||
if (err) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (reset_ext_adv) {
|
||||
bt_le_ext_adv_state_reset();
|
||||
}
|
||||
|
||||
if (reset_pa_sync) {
|
||||
bt_le_per_adv_sync_state_reset();
|
||||
}
|
||||
|
||||
bt_le_gap_app_cb_unregister();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
uint8_t esp_ble_iso_bluedroid_get_gattc_if(void)
|
||||
{
|
||||
|
||||
@@ -367,6 +367,10 @@ esp_err_t esp_ble_iso_cig_terminate(esp_ble_iso_cig_t *cig);
|
||||
* @param conn_handle Connection handle.
|
||||
* @param count Number of channels to connect.
|
||||
*
|
||||
* @note ISO only knows links whose connection event it saw, so one
|
||||
* established before esp_ble_iso_common_init() returns
|
||||
* ESP_ERR_NOT_FOUND until it is handed back.
|
||||
*
|
||||
* @return ESP_OK on success, or an error code on failure.
|
||||
*/
|
||||
esp_err_t esp_ble_iso_chan_connect(esp_ble_iso_connect_param_t *param,
|
||||
@@ -578,13 +582,38 @@ typedef struct {
|
||||
/**
|
||||
* @brief Post an application-layer GAP event for ISO internal usage.
|
||||
*
|
||||
* @note This function is only needed while using NimBLE Host.
|
||||
* @note NimBLE-only: NimBLE has no global GAP callback, so ISO sees only what
|
||||
* the application forwards here. An event left out is dropped silently.
|
||||
* Bluedroid's ISO layer hooks the stack directly.
|
||||
*
|
||||
* @param type Event type.
|
||||
* @param param Event parameters.
|
||||
* @note Forward every event below that the application's flows can produce.
|
||||
* Forwarding one ISO does not use is harmless; omitting one leaves the
|
||||
* matching ISO state uncreated and fails later and elsewhere:
|
||||
* - BLE_GAP_EVENT_EXT_DISC extended advertising report
|
||||
* - BLE_GAP_EVENT_CONNECT ACL established or failed
|
||||
* - BLE_GAP_EVENT_DISCONNECT ACL closed
|
||||
* - BLE_GAP_EVENT_ENC_CHANGE encryption changed
|
||||
* - BLE_GAP_EVENT_PERIODIC_SYNC PA sync established
|
||||
* - BLE_GAP_EVENT_PERIODIC_SYNC_LOST PA sync lost
|
||||
* - BLE_GAP_EVENT_PERIODIC_REPORT periodic advertising report
|
||||
* - BLE_GAP_EVENT_PERIODIC_TRANSFER PA sync received over PAST
|
||||
* - BLE_GAP_EVENT_PERIODIC_TRANSFER_V2 as above, PAwR
|
||||
*
|
||||
* BIGInfo needs no forwarding: ISO takes it from the controller itself
|
||||
* and delivers it as ESP_BLE_ISO_GAP_EVENT_BIGINFO_RECV.
|
||||
*
|
||||
* @param type Event type, i.e. ble_gap_event::type.
|
||||
* @param param Event parameters, i.e. the struct ble_gap_event pointer.
|
||||
*/
|
||||
void esp_ble_iso_gap_app_post_event(uint16_t type, void *param);
|
||||
|
||||
/** Which of ISO's records of application-owned objects deinit clears. */
|
||||
typedef struct {
|
||||
bool reset_ext_adv; /*!< Clear the advertising sets added for BIG */
|
||||
bool reset_pa_sync; /*!< Clear the periodic advertising syncs */
|
||||
bool reset_acl_conn; /*!< Clear the ACL links. Must be true - see below */
|
||||
} esp_ble_iso_deinit_info_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize ISO common functionality.
|
||||
*
|
||||
@@ -594,6 +623,34 @@ void esp_ble_iso_gap_app_post_event(uint16_t type, void *param);
|
||||
*/
|
||||
esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize ISO common functionality.
|
||||
*
|
||||
* The application must first disconnect all CIS/BIS and terminate every CIG/BIG.
|
||||
* If any is still up this returns ESP_ERR_INVALID_STATE and releases nothing,
|
||||
* logging each offending item at ERROR level.
|
||||
*
|
||||
* ACL links, advertising sets and periodic advertising syncs belong to the
|
||||
* application: they neither block deinit nor get torn down, only ISO's record of
|
||||
* them goes. @p info chooses which records to drop - a dropped one is logged at
|
||||
* WARNING level and must be handed back after the next init. NULL drops all three.
|
||||
*
|
||||
* reset_acl_conn must be true for now: on Bluedroid the GATT teardown drops ISO's
|
||||
* reference, so a link ISO alone held is disconnected while a shared one stays up,
|
||||
* and ISO cannot yet tell the two apart.
|
||||
*
|
||||
* @param info Which records to clear, or NULL to clear all.
|
||||
*
|
||||
* @note Must not be called from an ISO callback (they run on the ISO task,
|
||||
* which this stops).
|
||||
*
|
||||
* @return ESP_OK on success,
|
||||
* ESP_ERR_INVALID_STATE if something ISO owns is still active,
|
||||
* ESP_ERR_TIMEOUT if the ISO task could not be stopped.
|
||||
* Nothing is released unless ESP_OK is returned.
|
||||
*/
|
||||
esp_err_t esp_ble_iso_common_deinit(const esp_ble_iso_deinit_info_t *info);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Get the engine's internal GATTC interface handle (Bluedroid only).
|
||||
|
||||
@@ -212,7 +212,7 @@ void bt_le_bluedroid_gap_post_event(uint16_t event, void *param)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GapPostEvtFail[%d][%u]", err, qev->type);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GapPostEvtFail[%d][%u]", err, qev->type);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -409,12 +409,8 @@ static void bt_le_bluedroid_gap_post_event_bta(tBTA_DM_BLE_5_GAP_EVENT event,
|
||||
|
||||
err = bt_le_iso_task_post(q_type, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
/* Floodable reports drop by design when the queue is full; only a
|
||||
* failure on the reliable (normal-queue) path is a real error. */
|
||||
if (q_type == ISO_QUEUE_ITEM_TYPE_GAP_EVENT) {
|
||||
LOG_ERR("[B]GapPostEvtBtaFail[%d][%u]", err, qev->type);
|
||||
} else {
|
||||
LOG_DBG("[B]GapRptDrop[%u]", qev->type);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GapPostEvtBtaFail[%d][%u]", err, qev->type);
|
||||
}
|
||||
goto free;
|
||||
}
|
||||
@@ -422,26 +418,7 @@ static void bt_le_bluedroid_gap_post_event_bta(tBTA_DM_BLE_5_GAP_EVENT event,
|
||||
return;
|
||||
|
||||
free:
|
||||
/* Mirror nimble/gap.c cleanup: free nested data buffers carried by
|
||||
* specific event types before freeing the qev container itself. */
|
||||
switch (qev->type) {
|
||||
case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV:
|
||||
if (qev->ext_scan_recv.data) {
|
||||
free(qev->ext_scan_recv.data);
|
||||
qev->ext_scan_recv.data = NULL;
|
||||
}
|
||||
break;
|
||||
case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV:
|
||||
if (qev->pa_sync_recv.data) {
|
||||
free(qev->pa_sync_recv.data);
|
||||
qev->pa_sync_recv.data = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(qev);
|
||||
bt_le_gap_event_free(qev);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_scan_start(const struct bt_le_scan_param *param)
|
||||
|
||||
@@ -476,7 +476,7 @@ static void gattc_connect_event_handler(tBTA_GATTC_CONNECT *connect)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcConnPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcConnPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -496,7 +496,7 @@ static void gattc_disconnect_event_handler(tBTA_GATTC_DISCONNECT *disconnect)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcDiscPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcDiscPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -516,7 +516,7 @@ static void gattc_open_event_handler(tBTA_GATTC_OPEN *open)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcOpenPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcOpenPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -537,7 +537,7 @@ static void gattc_mtu_event_handler(tBTA_GATTC_CFG_MTU *cfg_mtu)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcMtuPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcMtuPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -557,7 +557,7 @@ static void gattc_disc_cmpl_event_handler(tBTA_GATTC_DIS_CMPL *disc_cmpl)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcDiscCmplPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcDiscCmplPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -589,11 +589,8 @@ static void gattc_read_chrc_event_handler(tBTA_GATTC_READ *read)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcReadChrcPostFail[%d]", err);
|
||||
if (qev->gattc_read_chrc.value) {
|
||||
free(qev->gattc_read_chrc.value);
|
||||
}
|
||||
free(qev);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcReadChrcPostFail[%d]", err);
|
||||
bt_le_gatt_event_free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,7 +611,7 @@ static void gattc_write_chrc_event_handler(tBTA_GATTC_WRITE *write)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcWriteChrcPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcWriteChrcPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -641,7 +638,7 @@ static void gatts_notify_tx_event_handler(tBTA_GATTS_REQ *req)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsNotifyTxPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsNotifyTxPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -671,7 +668,7 @@ static void gattc_notify_rx_event_handler(tBTA_GATTC_NOTIFY *notify)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattcNotifyRxPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattcNotifyRxPostFail[%d]", err);
|
||||
if (qev->gattc_notify_rx.value) {
|
||||
free(qev->gattc_notify_rx.value);
|
||||
}
|
||||
@@ -697,7 +694,7 @@ static void gatts_connect_event_handler(tBTA_GATTS_CONN *connect)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsConnPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsConnPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -717,7 +714,7 @@ static void gatts_disconnect_event_handler(tBTA_GATTS_CONN *disconnect)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsDiscPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsDiscPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -738,7 +735,7 @@ static void gatts_mtu_event_handler(tBTA_GATTS_REQ *req)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsMtuPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsMtuPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -763,7 +760,7 @@ static void gatts_read_req_handler(tBTA_GATTS_REQ *req)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsReadPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsReadPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -798,11 +795,8 @@ static void gatts_write_req_handler(tBTA_GATTS_REQ *req)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsWritePostFail[%d]", err);
|
||||
if (qev->gatts_write.value) {
|
||||
free(qev->gatts_write.value);
|
||||
}
|
||||
free(qev);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsWritePostFail[%d]", err);
|
||||
bt_le_gatt_event_free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,13 +816,20 @@ static void gatts_exec_write_req_handler(tBTA_GATTS_REQ *req)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GattsExecPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]GattsExecPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
{
|
||||
/* BTA_GATTS_AppDeregister is async, so its events land after deinit returns.
|
||||
* Drop on the flag, not gatts_if - a re-register can hand back the same if. */
|
||||
if (gatt_shutting_down) {
|
||||
LOG_INF("[B]GattsDropEvt[%u]", event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case BTA_GATTS_REG_EVT:
|
||||
LOG_DBG("[B]GattsRegEvt[%u][%u]",
|
||||
@@ -838,10 +839,6 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->reg_oper.uuid.uu.uuid128[0],
|
||||
p_data->reg_oper.uuid.uu.uuid128[1]);
|
||||
|
||||
if (gatt_shutting_down) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_data->reg_oper.status == BTA_GATT_OK &&
|
||||
memcmp(&p_data->reg_oper.uuid, &gatts_app_uuid, sizeof(tBT_UUID)) == 0) {
|
||||
gatts_if = p_data->reg_oper.server_if;
|
||||
@@ -869,7 +866,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->conn.conn_params.timeout);
|
||||
|
||||
if (p_data->conn.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsConnUnknownIf[%u]", p_data->conn.server_if);
|
||||
LOG_ERR("[B]GattsConnUnknownIf[%u][%u]", p_data->conn.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -885,7 +882,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->conn.remote_bda[4], p_data->conn.remote_bda[5]);
|
||||
|
||||
if (p_data->conn.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsDisconnUnknownIf[%u]", p_data->conn.server_if);
|
||||
LOG_ERR("[B]GattsDisconnUnknownIf[%u][%u]", p_data->conn.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -913,8 +910,8 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->req_data.p_data ? p_data->req_data.p_data->mtu : 0);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id) != gatts_if) {
|
||||
LOG_ERR("[B]GattsMtuUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id));
|
||||
LOG_ERR("[B]GattsMtuUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id), gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -955,7 +952,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->create.uuid.uu.uuid128[1]);
|
||||
|
||||
if (p_data->create.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsCreateUnknownIf[%u]", p_data->create.server_if);
|
||||
LOG_ERR("[B]GattsCreateUnknownIf[%u][%u]", p_data->create.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -972,7 +969,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->add_result.attr_id, p_data->add_result.service_id);
|
||||
|
||||
if (p_data->add_result.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsAddInclSvcUnknownIf[%u]", p_data->add_result.server_if);
|
||||
LOG_ERR("[B]GattsAddInclSvcUnknownIf[%u][%u]", p_data->add_result.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -990,7 +987,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->add_result.char_uuid.len, p_data->add_result.char_uuid.uu.uuid16);
|
||||
|
||||
if (p_data->add_result.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsAddCharUnknownIf[%u]", p_data->add_result.server_if);
|
||||
LOG_ERR("[B]GattsAddCharUnknownIf[%u][%u]", p_data->add_result.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1008,7 +1005,7 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->add_result.char_uuid.len, p_data->add_result.char_uuid.uu.uuid16);
|
||||
|
||||
if (p_data->add_result.server_if != gatts_if) {
|
||||
LOG_ERR("[B]GattsAddDescrUnknownIf[%u]", p_data->add_result.server_if);
|
||||
LOG_ERR("[B]GattsAddDescrUnknownIf[%u][%u]", p_data->add_result.server_if, gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1034,8 +1031,8 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
p_data->req_data.p_data->read_req.need_rsp);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id) != gatts_if) {
|
||||
LOG_ERR("[B]GattsReadUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id));
|
||||
LOG_ERR("[B]GattsReadUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id), gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1058,8 +1055,8 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
}
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id) != gatts_if) {
|
||||
LOG_ERR("[B]GattsWriteUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id));
|
||||
LOG_ERR("[B]GattsWriteUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id), gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1078,8 +1075,8 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
}
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id) != gatts_if) {
|
||||
LOG_ERR("[B]GattsExecUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id));
|
||||
LOG_ERR("[B]GattsExecUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->req_data.conn_id), gatts_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1117,6 +1114,12 @@ static void gatts_app_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
|
||||
static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
{
|
||||
/* See gatts_app_cb. */
|
||||
if (gatt_shutting_down) {
|
||||
LOG_INF("[B]GattcDropEvt[%u]", event);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case BTA_GATTC_REG_EVT:
|
||||
LOG_DBG("[B]GattcRegEvt[%u][%u]",
|
||||
@@ -1126,10 +1129,6 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->reg_oper.app_uuid.uu.uuid128[0],
|
||||
p_data->reg_oper.app_uuid.uu.uuid128[1]);
|
||||
|
||||
if (gatt_shutting_down) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_data->reg_oper.status == BTA_GATT_OK &&
|
||||
memcmp(&p_data->reg_oper.app_uuid, &gattc_app_uuid, sizeof(tBT_UUID)) == 0) {
|
||||
gattc_if = p_data->reg_oper.client_if;
|
||||
@@ -1156,7 +1155,7 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->connect.conn_params.latency, p_data->connect.conn_params.timeout);
|
||||
|
||||
if (p_data->connect.client_if != gattc_if) {
|
||||
LOG_ERR("[B]GattcConnUnknownIf[%u]", p_data->connect.client_if);
|
||||
LOG_ERR("[B]GattcConnUnknownIf[%u][%u]", p_data->connect.client_if, gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1172,7 +1171,7 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->disconnect.remote_bda[4], p_data->disconnect.remote_bda[5]);
|
||||
|
||||
if (p_data->disconnect.client_if != gattc_if) {
|
||||
LOG_ERR("[B]GattcDisconnUnknownIf[%u]", p_data->disconnect.client_if);
|
||||
LOG_ERR("[B]GattcDisconnUnknownIf[%u][%u]", p_data->disconnect.client_if, gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1189,7 +1188,7 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->open.remote_bda[4], p_data->open.remote_bda[5]);
|
||||
|
||||
if (p_data->open.client_if != gattc_if) {
|
||||
LOG_ERR("[B]GattcOpenUnknownIf[%u]", p_data->open.client_if);
|
||||
LOG_ERR("[B]GattcOpenUnknownIf[%u][%u]", p_data->open.client_if, gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1213,8 +1212,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->cfg_mtu.status, p_data->cfg_mtu.conn_id, p_data->cfg_mtu.mtu);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->cfg_mtu.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcMtuUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->cfg_mtu.conn_id));
|
||||
LOG_ERR("[B]GattcMtuUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->cfg_mtu.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1235,8 +1234,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->dis_cmpl.status, p_data->dis_cmpl.conn_id);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->dis_cmpl.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcDiscSvcCmplUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->dis_cmpl.conn_id));
|
||||
LOG_ERR("[B]GattcDiscSvcCmplUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->dis_cmpl.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1254,8 +1253,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->srvc_res.service_uuid.inst_id);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->srvc_res.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcSearchResUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->srvc_res.conn_id));
|
||||
LOG_ERR("[B]GattcSearchResUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->srvc_res.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1267,8 +1266,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
BTA_GATTC_SERVICE_INFO_FROM_REMOTE_DEVICE) ? "Remote" : "NVS");
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->search_cmpl.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcSearchCmplUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->search_cmpl.conn_id));
|
||||
LOG_ERR("[B]GattcSearchCmplUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->search_cmpl.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1278,8 +1277,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->read.status, p_data->read.conn_id, p_data->read.handle);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->read.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcReadCharUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->read.conn_id));
|
||||
LOG_ERR("[B]GattcReadCharUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->read.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1307,8 +1306,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->write.handle, p_data->write.offset);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->write.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcWriteCharUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->write.conn_id));
|
||||
LOG_ERR("[B]GattcWriteCharUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->write.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1340,8 +1339,8 @@ static void gattc_app_cb(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
|
||||
p_data->notify.bda[4], p_data->notify.bda[5]);
|
||||
|
||||
if (BTC_GATT_GET_GATT_IF(p_data->notify.conn_id) != gattc_if) {
|
||||
LOG_ERR("[B]GattcNotifUnknownIf[%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->notify.conn_id));
|
||||
LOG_ERR("[B]GattcNotifUnknownIf[%u][%u]",
|
||||
BTC_GATT_GET_GATT_IF(p_data->notify.conn_id), gattc_if);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1405,9 +1404,9 @@ static void post_acl_connect_app_event(struct gatt_conn *gatt_conn)
|
||||
qev->acl_connect.status = gatt_conn->status;
|
||||
|
||||
/* Populate identity unconditionally: connect_event_handler fills these
|
||||
* fields before OPEN_EVT arrives, so failure events still carry valid
|
||||
* conn_handle / role / dst to the application — matches NimBLE's
|
||||
* BLE_GAP_EVENT_CONNECT, which always exposes the full descriptor. */
|
||||
* fields before OPEN_EVT arrives, so a failure that got that far still
|
||||
* carries valid conn_handle / role / dst to the application. One that
|
||||
* did not is reported by post_acl_connect_fail_app_event() instead. */
|
||||
qev->acl_connect.conn_handle = gatt_conn->conn_handle;
|
||||
qev->acl_connect.role = gatt_conn->role;
|
||||
qev->acl_connect.dst.type = gatt_conn->peer.type;
|
||||
@@ -1415,7 +1414,29 @@ static void post_acl_connect_app_event(struct gatt_conn *gatt_conn)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]AclConnPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]AclConnPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
/* A connect that never reached the link layer gets no CONNECT_EVT, so nothing
|
||||
* would tell the application its request died. Identity stays zero, matching
|
||||
* NimBLE, which fills the descriptor only on status 0. */
|
||||
static void post_acl_connect_fail_app_event(uint8_t status)
|
||||
{
|
||||
struct bt_le_gap_app_param *qev;
|
||||
int err;
|
||||
|
||||
qev = bt_le_ext_calloc(1, sizeof(*qev));
|
||||
BT_LE_ASSERT(qev);
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_ACL_CONNECT;
|
||||
|
||||
qev->acl_connect.status = status;
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
ISO_POST_FAIL_LOG(err, "[B]AclConnFailPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -1435,7 +1456,7 @@ static void post_acl_disconnect_app_event(uint16_t conn_handle, uint8_t reason)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]AclDiscPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "[B]AclDiscPostFail[%d]", err);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
@@ -1542,7 +1563,16 @@ static void handle_gattc_open_event(struct bt_le_gattc_open_event *event)
|
||||
|
||||
gatt_conn = find_gatt_conn_by_conn_id_or_index(event->conn_id);
|
||||
if (gatt_conn == NULL) {
|
||||
LOG_ERR("[B]GattcOpenUnknownDev");
|
||||
/* A non-zero status here is the application's own connect request failing
|
||||
* before any link existed; a success without a slot is a real
|
||||
* inconsistency and stays an error. */
|
||||
if (event->status) {
|
||||
LOG_WRN("[B]GattcOpenFailed[%u][0x%04x]", event->status, event->conn_id);
|
||||
post_acl_connect_fail_app_event(event->status);
|
||||
} else {
|
||||
LOG_ERR("[B]GattcOpenUnknownDev[0x%04x]", event->conn_id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1928,7 +1958,7 @@ static void handle_gatts_disconnect_event(struct bt_le_gatts_disconnect_event *e
|
||||
|
||||
gatt_conn = find_gatt_conn_with_conn_id(event->conn_id);
|
||||
if (gatt_conn == NULL) {
|
||||
LOG_WRN("[B]GattsDisconnUnknownDev");
|
||||
LOG_DBG("[B]GattsDisconnUnknownDev");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3500,7 +3530,8 @@ int bt_le_bluedroid_gatt_init(void)
|
||||
|
||||
void bt_le_bluedroid_gatt_deinit(void)
|
||||
{
|
||||
/* Block late REG_EVT gives before tearing down the sems. */
|
||||
/* Must precede the deregisters: it is what makes the event callbacks drop
|
||||
* everything BTA still delivers for this registration. */
|
||||
gatt_shutting_down = true;
|
||||
|
||||
if (gattc_if != 0) {
|
||||
|
||||
@@ -111,6 +111,7 @@ static void direct_hci_complete_cb(BT_HDR *response, void *context)
|
||||
/* deinit may have set the shutdown flag and be about to delete the
|
||||
* sem. Skip the give to avoid asserting on a NULL handle. */
|
||||
if (direct_hci_shutting_down) {
|
||||
LOG_INF("[B]DirectHciDropCmpl[0x%04x]", opcode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@ static int hci_cmd_create_cis(struct net_buf *buf, struct net_buf **rsp)
|
||||
BT_LE_ASSERT(cis_params);
|
||||
|
||||
for (size_t i = 0; i < cis_count; i++) {
|
||||
cis_params[i].cis_hdl = sys_get_le16(buf->data + 4 + i * sizeof(struct ble_hci_cis_hdls));
|
||||
cis_params[i].cis_hdl = sys_get_le16(buf->data + 4 + i * sizeof(struct ble_hci_cis_hdls));
|
||||
cis_params[i].acl_hdl = sys_get_le16(buf->data + 6 + i * sizeof(struct ble_hci_cis_hdls));
|
||||
}
|
||||
|
||||
@@ -1089,7 +1089,9 @@ static void iso_evt_handler(tBTM_BLE_ISO_EVENT event, tBTM_BLE_ISO_CB_PARAMS *pa
|
||||
|
||||
err = bt_le_iso_task_post(q_type, qdata, qdata_len);
|
||||
if (err) {
|
||||
LOG_ERR("[B]IsoPostEvtFail[%d][%02x]", err, event);
|
||||
if (q_type == ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT) {
|
||||
ISO_POST_FAIL_LOG(err, "[B]IsoPostEvtFail[%d][%02x]", err, event);
|
||||
}
|
||||
free(qdata);
|
||||
}
|
||||
}
|
||||
@@ -1330,8 +1332,12 @@ int bt_le_bluedroid_iso_init(void)
|
||||
void bt_le_bluedroid_iso_deinit(void)
|
||||
{
|
||||
#if CONFIG_BT_ISO_UNICAST
|
||||
/* Mirror bt_le_iso_init() which enables bit 32 only on unicast build. */
|
||||
iso_disable_cis();
|
||||
/* Core 6.0 Vol 4 Part E 7.8.115: LE Set Host Feature is Command Disallowed
|
||||
* while any connection exists, and the ACL outlives ISO deinit. Skip - a
|
||||
* stale host-support bit is harmless and the next init sets it again. */
|
||||
if (bt_le_acl_conn_count() == 0) {
|
||||
iso_disable_cis();
|
||||
}
|
||||
#endif /* CONFIG_BT_ISO_UNICAST */
|
||||
|
||||
#if CONFIG_BT_ISO_RX
|
||||
|
||||
@@ -262,12 +262,8 @@ void bt_le_nimble_gap_post_event(void *param)
|
||||
|
||||
err = bt_le_iso_task_post(q_type, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
/* Floodable reports drop by design when the queue is full; only a
|
||||
* failure on the reliable (normal-queue) path is a real error. */
|
||||
if (q_type == ISO_QUEUE_ITEM_TYPE_GAP_EVENT) {
|
||||
LOG_ERR("[N]GapPostEvtFail[%d][%u]", err, qev->type);
|
||||
} else {
|
||||
LOG_DBG("[N]GapRptDrop[%u]", qev->type);
|
||||
ISO_POST_FAIL_LOG(err, "[N]GapPostEvtFail[%d][%u]", err, qev->type);
|
||||
}
|
||||
goto free;
|
||||
}
|
||||
@@ -275,24 +271,7 @@ void bt_le_nimble_gap_post_event(void *param)
|
||||
return;
|
||||
|
||||
free:
|
||||
switch (qev->type) {
|
||||
case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV:
|
||||
if (qev->ext_scan_recv.data) {
|
||||
free(qev->ext_scan_recv.data);
|
||||
qev->ext_scan_recv.data = NULL;
|
||||
}
|
||||
break;
|
||||
case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV:
|
||||
if (qev->pa_sync_recv.data) {
|
||||
free(qev->pa_sync_recv.data);
|
||||
qev->pa_sync_recv.data = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(qev);
|
||||
bt_le_gap_event_free(qev);
|
||||
}
|
||||
|
||||
int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb)
|
||||
|
||||
@@ -102,15 +102,8 @@ void bt_le_nimble_gatt_post_event(void *param)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[N]GattPostEvtFail[%d][%u]", err, qev->type);
|
||||
|
||||
if (qev->type == BT_LE_GATTC_NOTIFY_RX_EVENT &&
|
||||
qev->gattc_notify_rx.value) {
|
||||
free(qev->gattc_notify_rx.value);
|
||||
qev->gattc_notify_rx.value = NULL;
|
||||
}
|
||||
|
||||
free(qev);
|
||||
ISO_POST_FAIL_LOG(err, "[N]GattPostEvtFail[%d][%u]", err, qev->type);
|
||||
bt_le_gatt_event_free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +133,7 @@ int bt_le_nimble_gatt_post_disc_event(uint16_t conn_handle, ble_uuid16_t *uuid,
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[N]GattPostDiscEvtFail[%d][%u]", err, type);
|
||||
ISO_POST_FAIL_LOG(err, "[N]GattPostDiscEvtFail[%d][%u]", err, type);
|
||||
free(qev);
|
||||
return err;
|
||||
}
|
||||
@@ -165,7 +158,7 @@ int bt_le_nimble_gatt_post_disc_cmpl_event(uint16_t conn_handle, uint8_t status)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[N]GattPostDiscCmplEvtFail[%d][%u][%02x]", err, conn_handle, status);
|
||||
ISO_POST_FAIL_LOG(err, "[N]GattPostDiscCmplEvtFail[%d][%u][%02x]", err, conn_handle, status);
|
||||
free(qev);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -808,7 +808,9 @@ static void iso_evt_rx(uint8_t event, const void *data,
|
||||
|
||||
err = bt_le_iso_task_post(q_type, qdata, qdata_len);
|
||||
if (err) {
|
||||
LOG_ERR("[N]IsoPostEvtFail[%d][%02x]", err, event);
|
||||
if (q_type == ISO_QUEUE_ITEM_TYPE_ISO_HCI_EVENT) {
|
||||
ISO_POST_FAIL_LOG(err, "[N]IsoPostEvtFail[%d][%02x]", err, event);
|
||||
}
|
||||
free(qdata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,17 @@ struct bt_le_ext_adv *bt_le_ext_adv_find(uint8_t adv_handle)
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
void bt_le_ext_adv_state_reset(void)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(ext_adv_pool); i++) {
|
||||
if (atomic_test_bit(ext_adv_pool[i].flags, BT_PER_ADV_PARAMS_SET)) {
|
||||
LOG_WRN("DeinitDropExtAdv[%u]", ext_adv_pool[i].handle);
|
||||
}
|
||||
}
|
||||
|
||||
memset(ext_adv_pool, 0, sizeof(ext_adv_pool));
|
||||
}
|
||||
|
||||
int bt_le_ext_adv_new_safe(uint8_t adv_handle, uint8_t addr_type,
|
||||
const uint8_t *addr, uint8_t sid)
|
||||
{
|
||||
|
||||
@@ -527,6 +527,32 @@ static void handle_bond_delete_event_safe(struct bt_le_gap_app_param *param)
|
||||
bt_le_gap_app_cb_evt(&event);
|
||||
}
|
||||
|
||||
void bt_le_gap_event_free(void *data)
|
||||
{
|
||||
struct bt_le_gap_app_param *qev = data;
|
||||
|
||||
if (qev == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (qev->type) {
|
||||
case BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV:
|
||||
if (qev->ext_scan_recv.data) {
|
||||
free(qev->ext_scan_recv.data);
|
||||
}
|
||||
break;
|
||||
case BT_LE_GAP_APP_PARAM_PA_SYNC_RECV:
|
||||
if (qev->pa_sync_recv.data) {
|
||||
free(qev->pa_sync_recv.data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(qev);
|
||||
}
|
||||
|
||||
void bt_le_gap_handle_event(uint8_t *data, size_t data_len)
|
||||
{
|
||||
struct bt_le_gap_app_param *param;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
@@ -46,6 +47,31 @@ void bt_conn_get_acl_conns(struct bt_conn **conns, uint8_t *count)
|
||||
*count = ARRAY_SIZE(acl_conns);
|
||||
}
|
||||
|
||||
size_t bt_le_acl_conn_count(void)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(acl_conns); i++) {
|
||||
if (acl_conns[i].state != BT_CONN_DISCONNECTED) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void bt_le_conn_reset(void)
|
||||
{
|
||||
LOG_DBG("ConnReset");
|
||||
|
||||
memset(acl_conns, 0, sizeof(acl_conns));
|
||||
memset(conn_ltk, 0, sizeof(conn_ltk));
|
||||
memset(iso_conns, 0, sizeof(struct bt_conn) * CONFIG_BT_ISO_MAX_CHAN);
|
||||
|
||||
sys_slist_init(&conn_cbs);
|
||||
sys_slist_init(&auth_info_cbs);
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id,
|
||||
const bt_addr_le_t *peer)
|
||||
@@ -382,6 +408,27 @@ int bt_le_acl_conn_new(uint16_t conn_handle,
|
||||
return (conn ? 0 : -ENOMEM);
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
int bt_le_acl_conn_new_safe(uint16_t conn_handle, uint8_t role, uint8_t addr_type,
|
||||
const uint8_t *addr, uint8_t sec_level)
|
||||
{
|
||||
bt_addr_le_t dst;
|
||||
int err;
|
||||
|
||||
if (addr == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dst.type = addr_type;
|
||||
bt_addr_copy(&dst.a, (const bt_addr_t *)addr);
|
||||
|
||||
bt_le_host_lock();
|
||||
err = bt_le_acl_conn_new(conn_handle, role, &dst, sec_level);
|
||||
bt_le_host_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Point conn->le.keys at this ACL connection's LTK slot, filled with the bonded
|
||||
* LTK the adapter captured. Used as key K by the lib's CSIS SIRK encryption. */
|
||||
_IDF_ONLY
|
||||
|
||||
@@ -1641,3 +1641,34 @@ void bt_le_gatt_handle_event(uint8_t *data, size_t data_len)
|
||||
bt_le_nimble_gatt_handle_event(data, data_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bt_le_gatt_event_free(void *data)
|
||||
{
|
||||
struct bt_le_gatt_event_param *qev = data;
|
||||
|
||||
if (qev == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (qev->type) {
|
||||
case BT_LE_GATTC_NOTIFY_RX_EVENT:
|
||||
if (qev->gattc_notify_rx.value) {
|
||||
free(qev->gattc_notify_rx.value);
|
||||
}
|
||||
break;
|
||||
case BT_LE_GATTC_READ_CHRC_EVENT:
|
||||
if (qev->gattc_read_chrc.value) {
|
||||
free(qev->gattc_read_chrc.value);
|
||||
}
|
||||
break;
|
||||
case BT_LE_GATTS_WRITE_EVENT:
|
||||
if (qev->gatts_write.value) {
|
||||
free(qev->gatts_write.value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(qev);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
|
||||
#include <../host/conn_internal.h>
|
||||
|
||||
#include "common/host.h"
|
||||
#include "common/conn.h"
|
||||
#include "common/app/gap.h"
|
||||
#include "common/app/gatt.h"
|
||||
|
||||
@@ -28,6 +33,8 @@ LOG_MODULE_REGISTER(ISO_HOST, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
static BT_ISO_CTRL_BSS_ATTR struct k_mutex host_mutex;
|
||||
|
||||
extern struct bt_conn iso_conns[CONFIG_BT_ISO_MAX_CHAN];
|
||||
|
||||
#if HOST_LOCK_DEBUG
|
||||
void bt_le_host_lock_debug(const char *func, int line)
|
||||
#else /* HOST_LOCK_DEBUG */
|
||||
@@ -69,6 +76,32 @@ void bt_le_host_unlock(void)
|
||||
k_mutex_unlock(&host_mutex);
|
||||
}
|
||||
|
||||
int bt_le_host_check_idle(void)
|
||||
{
|
||||
struct bt_iso_chan *chan;
|
||||
size_t busy = 0;
|
||||
|
||||
/* Only what ISO created; the application's adv sets, sync and ACL are
|
||||
* dropped by bt_le_host_deinit() rather than blocked on. Counts every
|
||||
* offender so one attempt tells the caller the whole list. */
|
||||
|
||||
bt_le_host_lock();
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(iso_conns); i++) {
|
||||
chan = iso_conns[i].iso.chan;
|
||||
if (chan && chan->state != BT_ISO_STATE_DISCONNECTED) {
|
||||
LOG_ERR("DeinitBusyIsoChan[%u][state=%u]", i, chan->state);
|
||||
busy++;
|
||||
}
|
||||
}
|
||||
|
||||
busy += bt_le_iso_report_busy();
|
||||
|
||||
bt_le_host_unlock();
|
||||
|
||||
return busy ? -EBUSY : 0;
|
||||
}
|
||||
|
||||
int bt_le_host_init(void)
|
||||
{
|
||||
int err;
|
||||
@@ -77,6 +110,10 @@ int bt_le_host_init(void)
|
||||
|
||||
k_mutex_create(&host_mutex);
|
||||
|
||||
bt_le_conn_reset();
|
||||
|
||||
bt_le_iso_state_reset();
|
||||
|
||||
err = bt_le_scan_init();
|
||||
if (err) {
|
||||
goto delete_mutex;
|
||||
@@ -125,13 +162,23 @@ delete_mutex:
|
||||
return err;
|
||||
}
|
||||
|
||||
void bt_le_host_deinit(void)
|
||||
int bt_le_host_deinit(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_DBG("HostDeinit");
|
||||
|
||||
bt_le_iso_task_deinit();
|
||||
/* Everything below frees state the task dispatches into, so bail out while
|
||||
* it is still alive rather than free underneath it. */
|
||||
err = bt_le_iso_task_deinit();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_le_iso_deinit();
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* No gap_deinit: BTM_BleGapRegisterCallback refuses NULL, so the callback
|
||||
* stays. Harmless - task_post rejects once the task is gone. */
|
||||
bt_le_bluedroid_gatt_deinit();
|
||||
#else
|
||||
bt_le_nimble_gattc_db_deinit();
|
||||
@@ -139,5 +186,9 @@ void bt_le_host_deinit(void)
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
bt_le_scan_deinit();
|
||||
|
||||
/* Last: iso_task has exited and the callbacks above are gone, so nothing
|
||||
* can take the mutex any more. */
|
||||
k_mutex_delete(&host_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ int bt_le_ext_adv_new_safe(uint8_t adv_handle, uint8_t addr_type,
|
||||
|
||||
int bt_le_ext_adv_delete_safe(uint8_t adv_handle);
|
||||
|
||||
void bt_le_ext_adv_state_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -303,6 +303,8 @@ void bt_le_gap_app_biginfo_event(uint8_t *param);
|
||||
|
||||
void bt_le_gap_handle_event(uint8_t *data, size_t data_len);
|
||||
|
||||
void bt_le_gap_event_free(void *data);
|
||||
|
||||
void bt_le_gap_app_post_event(uint16_t type, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -30,6 +30,10 @@ extern "C" {
|
||||
|
||||
void bt_conn_get_acl_conns(struct bt_conn **conns, uint8_t *count);
|
||||
|
||||
size_t bt_le_acl_conn_count(void);
|
||||
|
||||
void bt_le_conn_reset(void);
|
||||
|
||||
struct bt_conn *bt_le_acl_conn_find(uint16_t conn_handle);
|
||||
|
||||
int bt_le_acl_conn_new(uint16_t conn_handle,
|
||||
@@ -37,6 +41,9 @@ int bt_le_acl_conn_new(uint16_t conn_handle,
|
||||
bt_addr_le_t *dst,
|
||||
uint8_t sec_level);
|
||||
|
||||
int bt_le_acl_conn_new_safe(uint16_t conn_handle, uint8_t role, uint8_t addr_type,
|
||||
const uint8_t *addr, uint8_t sec_level);
|
||||
|
||||
int bt_le_acl_conn_delete(uint16_t conn_handle);
|
||||
|
||||
void bt_conn_le_set_ltk(struct bt_conn *conn, const uint8_t *ltk);
|
||||
|
||||
@@ -297,6 +297,8 @@ void bt_le_acl_conn_bond_deleted_gatt_listener(uint8_t id, const bt_addr_le_t *p
|
||||
|
||||
void bt_le_gatt_handle_event(uint8_t *data, size_t data_len);
|
||||
|
||||
void bt_le_gatt_event_free(void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,9 @@ void bt_le_host_unlock(void);
|
||||
|
||||
int bt_le_host_init(void);
|
||||
|
||||
void bt_le_host_deinit(void);
|
||||
int bt_le_host_check_idle(void);
|
||||
|
||||
int bt_le_host_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -75,6 +75,10 @@ int bt_le_iso_rx(const uint8_t *data, uint16_t len, void *arg);
|
||||
|
||||
int bt_le_iso_disconnect(uint16_t conn_handle, uint8_t reason);
|
||||
|
||||
void bt_le_iso_state_reset(void);
|
||||
|
||||
size_t bt_le_iso_report_busy(void);
|
||||
|
||||
int bt_le_iso_init(void);
|
||||
|
||||
void bt_le_iso_deinit(void);
|
||||
|
||||
@@ -48,6 +48,15 @@ int bt_le_per_adv_sync_new(uint16_t sync_handle,
|
||||
uint16_t conn_handle,
|
||||
struct bt_le_per_adv_sync **out_sync);
|
||||
|
||||
int bt_le_per_adv_sync_new_safe(uint16_t sync_handle,
|
||||
uint8_t sid,
|
||||
uint8_t phy,
|
||||
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);
|
||||
|
||||
int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle);
|
||||
@@ -62,6 +71,8 @@ int bt_le_scan_init(void);
|
||||
|
||||
void bt_le_scan_deinit(void);
|
||||
|
||||
void bt_le_per_adv_sync_state_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -116,10 +116,15 @@ struct iso_queue_item {
|
||||
#define ISO_CRITICAL_QUEUE_LEN 32
|
||||
#define ISO_NORMAL_QUEUE_LEN 64
|
||||
#define ISO_FLOODABLE_QUEUE_LEN 32
|
||||
/* The set must be able to hold one token per item across all three queues. */
|
||||
/* Not a tier. One-deep and written only by deinit, so the stop signal can never
|
||||
* hit a full queue - which is what lets the task block on the set indefinitely
|
||||
* instead of polling for iso_task_stopping. */
|
||||
#define ISO_CTRL_QUEUE_LEN 1
|
||||
/* The set must be able to hold one token per item across all queues. */
|
||||
#define ISO_QUEUE_SET_LEN (ISO_CRITICAL_QUEUE_LEN + \
|
||||
ISO_NORMAL_QUEUE_LEN + \
|
||||
ISO_FLOODABLE_QUEUE_LEN)
|
||||
ISO_FLOODABLE_QUEUE_LEN + \
|
||||
ISO_CTRL_QUEUE_LEN)
|
||||
#define ISO_QUEUE_ITEM_SIZE sizeof(struct iso_queue_item)
|
||||
|
||||
#if CONFIG_BT_ISO_DISPATCH_MONITOR
|
||||
@@ -132,9 +137,21 @@ void bt_le_iso_dispatch_stats_dump(void);
|
||||
int bt_le_iso_task_post(enum iso_queue_item_type type,
|
||||
void *data, size_t data_len);
|
||||
|
||||
/* -ESHUTDOWN is expected for as long as an ACL, scan or PA sync outlives the
|
||||
* deinit that stopped it; anything else is a real drop. A macro so each file
|
||||
* logs under its own LOG_MODULE_REGISTER. */
|
||||
#define ISO_POST_FAIL_LOG(_err, ...) \
|
||||
do { \
|
||||
if ((_err) == -ESHUTDOWN) { \
|
||||
LOG_DBG(__VA_ARGS__); \
|
||||
} else { \
|
||||
LOG_ERR(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int bt_le_iso_task_init(void);
|
||||
|
||||
void bt_le_iso_task_deinit(void);
|
||||
int bt_le_iso_task_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -170,6 +170,24 @@ int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
int bt_le_per_adv_sync_cb_unregister(struct bt_le_per_adv_sync_cb *cb)
|
||||
{
|
||||
LOG_DBG("PaSyncCbUnreg");
|
||||
|
||||
if (cb == NULL) {
|
||||
LOG_ERR("PaSyncCbNull");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sys_slist_find_and_remove(&pa_sync_cbs, &cb->node)) {
|
||||
LOG_ERR("PaSyncCbNotReg[%p]", cb);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
int bt_le_per_adv_sync_get_info(struct bt_le_per_adv_sync *per_adv_sync,
|
||||
struct bt_le_per_adv_sync_info *info)
|
||||
@@ -322,6 +340,23 @@ int bt_le_per_adv_sync_new(uint16_t sync_handle,
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
int bt_le_per_adv_sync_new_safe(uint16_t sync_handle,
|
||||
uint8_t sid,
|
||||
uint8_t phy,
|
||||
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 err;
|
||||
bt_le_host_lock();
|
||||
err = bt_le_per_adv_sync_new(sync_handle, sid, phy, interval, addr_type,
|
||||
addr, conn_handle, out_sync);
|
||||
bt_le_host_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_le_per_adv_sync_delete(uint16_t sync_handle)
|
||||
{
|
||||
struct bt_le_per_adv_sync *per_adv_sync = NULL;
|
||||
@@ -551,6 +586,17 @@ static void past_features_unset(void)
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
void bt_le_per_adv_sync_state_reset(void)
|
||||
{
|
||||
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)) {
|
||||
LOG_WRN("DeinitDropPaSync[%u][%04x]", i, per_adv_sync_pool[i].handle);
|
||||
}
|
||||
}
|
||||
|
||||
memset(per_adv_sync_pool, 0, sizeof(per_adv_sync_pool));
|
||||
}
|
||||
|
||||
int bt_le_scan_init(void)
|
||||
{
|
||||
LOG_DBG("ScanInit");
|
||||
|
||||
@@ -20,11 +20,25 @@
|
||||
|
||||
#include "common/host.h"
|
||||
#include "common/iso.h"
|
||||
#include "common/gatt.h"
|
||||
#include "common/app/gap.h"
|
||||
#include "common/app/gatt.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_TASK, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
/* Nothing to poll for - iso_ctrl_queue wakes the task for deinit. The dispatch
|
||||
* monitor is the exception: its periodic dump is driven from this loop, so it
|
||||
* needs a wakeup even while no event arrives. */
|
||||
#if CONFIG_BT_ISO_DISPATCH_MONITOR
|
||||
#define ISO_TASK_WAIT (ISO_STATS_DUMP_PERIOD_US / 1000 / portTICK_PERIOD_MS)
|
||||
#else /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
#define ISO_TASK_WAIT portMAX_DELAY
|
||||
#endif /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
|
||||
/* Generous: expiry means a dispatch handler is wedged, which is a bug
|
||||
* elsewhere. Deinit reports it upward rather than freeing under a live task. */
|
||||
#define ISO_TASK_STOP_TIMEOUT (2000 / portTICK_PERIOD_MS)
|
||||
|
||||
/* Three priority tiers share one task via a queue set. The task drains
|
||||
* critical before normal before floodable, so a flood of GAP reports cannot
|
||||
* delay the latency-critical ISO data path. See common/task.h for the mapping.
|
||||
@@ -32,10 +46,17 @@ LOG_MODULE_REGISTER(ISO_TASK, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
static BT_ISO_CTRL_BSS_ATTR QueueHandle_t iso_critical_queue;
|
||||
static BT_ISO_CTRL_BSS_ATTR QueueHandle_t iso_normal_queue;
|
||||
static BT_ISO_CTRL_BSS_ATTR QueueHandle_t iso_floodable_queue;
|
||||
/* Not a tier: deinit-only wakeup, see ISO_CTRL_QUEUE_LEN. */
|
||||
static BT_ISO_CTRL_BSS_ATTR QueueHandle_t iso_ctrl_queue;
|
||||
static BT_ISO_CTRL_BSS_ATTR QueueSetHandle_t iso_queue_set;
|
||||
|
||||
static BT_ISO_CTRL_BSS_ATTR TaskHandle_t iso_task_handle;
|
||||
|
||||
/* Gate + handshake for deinit. iso_task_stopping also rejects new posts, so a
|
||||
* producer cannot strand a payload on a queue nobody will drain. */
|
||||
static BT_ISO_CTRL_BSS_ATTR volatile bool iso_task_stopping;
|
||||
static BT_ISO_CTRL_BSS_ATTR SemaphoreHandle_t iso_task_stopped;
|
||||
|
||||
extern void bt_le_timer_handle_event(void *arg, size_t gen);
|
||||
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
@@ -43,6 +64,7 @@ extern void bt_le_timer_handle_event(void *arg, size_t gen);
|
||||
* OTS, so the shim lives there. Declared instead of included to keep esp_ble_iso
|
||||
* free of audio headers; both live in the bt component, so the link resolves. */
|
||||
extern void bt_le_l2cap_handle_event(void *data, size_t data_len);
|
||||
extern void bt_le_l2cap_event_free(void *data);
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_ISO_DISPATCH_MONITOR
|
||||
@@ -90,6 +112,52 @@ void bt_le_iso_dispatch_stats_dump(void)
|
||||
}
|
||||
#endif /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
|
||||
static void iso_item_release(const struct iso_queue_item *item)
|
||||
{
|
||||
switch (item->type) {
|
||||
case ISO_QUEUE_ITEM_TYPE_TIMER_EVENT:
|
||||
/* data is the k_work, data_len its generation counter - not a block. */
|
||||
break;
|
||||
case ISO_QUEUE_ITEM_TYPE_GATT_EVENT:
|
||||
bt_le_gatt_event_free(item->data);
|
||||
break;
|
||||
case ISO_QUEUE_ITEM_TYPE_GAP_EVENT:
|
||||
case ISO_QUEUE_ITEM_TYPE_EXT_ADV_REPORT:
|
||||
case ISO_QUEUE_ITEM_TYPE_PER_ADV_REPORT:
|
||||
bt_le_gap_event_free(item->data);
|
||||
break;
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
case ISO_QUEUE_ITEM_TYPE_L2CAP_EVENT:
|
||||
bt_le_l2cap_event_free(item->data);
|
||||
break;
|
||||
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
|
||||
default:
|
||||
if (item->data) {
|
||||
free(item->data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Runs on iso_task after the loop exits, so no producer can be mid-dispatch and
|
||||
* the queues are provably empty when iso_queues_destroy() deletes them. */
|
||||
static void iso_queues_drain(void)
|
||||
{
|
||||
struct iso_queue_item item = {0};
|
||||
|
||||
while (xQueueReceive(iso_critical_queue, &item, 0) == pdTRUE) {
|
||||
iso_item_release(&item);
|
||||
}
|
||||
|
||||
while (xQueueReceive(iso_normal_queue, &item, 0) == pdTRUE) {
|
||||
iso_item_release(&item);
|
||||
}
|
||||
|
||||
while (xQueueReceive(iso_floodable_queue, &item, 0) == pdTRUE) {
|
||||
iso_item_release(&item);
|
||||
}
|
||||
}
|
||||
|
||||
static void iso_dispatch_item(const struct iso_queue_item *item)
|
||||
{
|
||||
#if CONFIG_BT_ISO_DISPATCH_MONITOR
|
||||
@@ -127,9 +195,7 @@ static void iso_dispatch_item(const struct iso_queue_item *item)
|
||||
bt_le_iso_handle_rx_data(item->data, item->data_len);
|
||||
break;
|
||||
default:
|
||||
if (item->data) {
|
||||
free(item->data);
|
||||
}
|
||||
iso_item_release(item);
|
||||
BT_LE_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
@@ -147,13 +213,11 @@ static void iso_task(void *p)
|
||||
#endif /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
struct iso_queue_item item = {0};
|
||||
|
||||
while (1) {
|
||||
/* Block until any tier has data. The returned member handle is ignored:
|
||||
* we always service by strict priority below (critical > normal >
|
||||
* floodable), processing one item per wakeup and re-checking critical
|
||||
* first on the next loop. A pdFALSE receive is tolerated as a benign
|
||||
* side effect of servicing queues outside xQueueSelectFromSet. */
|
||||
(void)xQueueSelectFromSet(iso_queue_set, portMAX_DELAY);
|
||||
while (!iso_task_stopping) {
|
||||
/* The returned handle is ignored: service by strict priority instead
|
||||
* (critical > normal > floodable), one item per wakeup. A pdFALSE
|
||||
* receive is benign - that is what a deinit wakeup looks like. */
|
||||
(void)xQueueSelectFromSet(iso_queue_set, ISO_TASK_WAIT);
|
||||
|
||||
if (xQueueReceive(iso_critical_queue, &item, 0) == pdTRUE) {
|
||||
iso_dispatch_item(&item);
|
||||
@@ -170,6 +234,14 @@ static void iso_task(void *p)
|
||||
}
|
||||
#endif /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
}
|
||||
|
||||
/* Draining here rather than in the deinit caller keeps payload ownership on
|
||||
* a single task: no producer is mid-post and no consumer is mid-dispatch. */
|
||||
iso_queues_drain();
|
||||
|
||||
xSemaphoreGive(iso_task_stopped);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
int bt_le_iso_task_post(enum iso_queue_item_type type,
|
||||
@@ -180,6 +252,13 @@ int bt_le_iso_task_post(enum iso_queue_item_type type,
|
||||
TickType_t wait;
|
||||
int ret;
|
||||
|
||||
/* No consumer before init or after deinit began, so accepting would strand
|
||||
* the payload (callers free on failure). Distinct from the -1 below: this
|
||||
* one persists, a full queue is transient. */
|
||||
if (iso_task_handle == NULL || iso_task_stopping) {
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
item.type = type;
|
||||
item.data = data;
|
||||
item.data_len = data_len;
|
||||
@@ -249,6 +328,7 @@ static void iso_queues_destroy(void)
|
||||
iso_queue_destroy_one(&iso_critical_queue);
|
||||
iso_queue_destroy_one(&iso_normal_queue);
|
||||
iso_queue_destroy_one(&iso_floodable_queue);
|
||||
iso_queue_destroy_one(&iso_ctrl_queue);
|
||||
|
||||
if (iso_queue_set) {
|
||||
vQueueDelete(iso_queue_set);
|
||||
@@ -262,19 +342,31 @@ int bt_le_iso_task_init(void)
|
||||
|
||||
LOG_DBG("IsoTaskInit");
|
||||
|
||||
/* Reset here, not at definition, so a deinit/re-init cycle starts clean. */
|
||||
iso_task_stopping = false;
|
||||
|
||||
iso_task_stopped = xSemaphoreCreateBinary();
|
||||
if (iso_task_stopped == NULL) {
|
||||
LOG_ERR("IsoTaskSemCreateFail");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iso_critical_queue = xQueueCreate(ISO_CRITICAL_QUEUE_LEN, ISO_QUEUE_ITEM_SIZE);
|
||||
iso_normal_queue = xQueueCreate(ISO_NORMAL_QUEUE_LEN, ISO_QUEUE_ITEM_SIZE);
|
||||
iso_floodable_queue = xQueueCreate(ISO_FLOODABLE_QUEUE_LEN, ISO_QUEUE_ITEM_SIZE);
|
||||
iso_ctrl_queue = xQueueCreate(ISO_CTRL_QUEUE_LEN, ISO_QUEUE_ITEM_SIZE);
|
||||
iso_queue_set = xQueueCreateSet(ISO_QUEUE_SET_LEN);
|
||||
if (iso_critical_queue == NULL || iso_normal_queue == NULL ||
|
||||
iso_floodable_queue == NULL || iso_queue_set == NULL) {
|
||||
iso_floodable_queue == NULL || iso_ctrl_queue == NULL ||
|
||||
iso_queue_set == NULL) {
|
||||
LOG_ERR("IsoQCreateFail");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (xQueueAddToSet(iso_critical_queue, iso_queue_set) != pdPASS ||
|
||||
xQueueAddToSet(iso_normal_queue, iso_queue_set) != pdPASS ||
|
||||
xQueueAddToSet(iso_floodable_queue, iso_queue_set) != pdPASS) {
|
||||
xQueueAddToSet(iso_floodable_queue, iso_queue_set) != pdPASS ||
|
||||
xQueueAddToSet(iso_ctrl_queue, iso_queue_set) != pdPASS) {
|
||||
LOG_ERR("IsoQSetAddFail");
|
||||
goto fail;
|
||||
}
|
||||
@@ -295,22 +387,60 @@ int bt_le_iso_task_init(void)
|
||||
|
||||
fail:
|
||||
iso_queues_destroy();
|
||||
vSemaphoreDelete(iso_task_stopped);
|
||||
iso_task_stopped = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
void bt_le_iso_task_deinit(void)
|
||||
int bt_le_iso_task_deinit(void)
|
||||
{
|
||||
struct iso_queue_item item = {0};
|
||||
|
||||
LOG_DBG("IsoTaskDeinit");
|
||||
|
||||
if (iso_task_handle) {
|
||||
vTaskDelete(iso_task_handle);
|
||||
iso_task_handle = NULL;
|
||||
if (iso_task_handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This blocks on the task's own exit, so calling it from iso_task would
|
||||
* wait for itself forever. */
|
||||
if (xTaskGetCurrentTaskHandle() == iso_task_handle) {
|
||||
LOG_ERR("IsoTaskDeinitFromSelf");
|
||||
return -EDEADLK;
|
||||
}
|
||||
|
||||
/* Stops new posts as well, so the queues can only shrink from here. */
|
||||
iso_task_stopping = true;
|
||||
|
||||
/* Setting the flag cannot wake a task blocked on the set. Posted after it so
|
||||
* whichever select consumes this token re-checks the flag as true; deinit is
|
||||
* the sole producer of a one-deep queue, so the send cannot fail. */
|
||||
(void)xQueueSend(iso_ctrl_queue, &item, 0);
|
||||
|
||||
if (xSemaphoreTake(iso_task_stopped, ISO_TASK_STOP_TIMEOUT) != pdTRUE) {
|
||||
/* A dispatch handler is wedged. Deleting the queues now would pull them
|
||||
* out from under a live task, so leave everything in place and let the
|
||||
* caller abort the teardown instead. */
|
||||
LOG_ERR("IsoTaskStopTimeout");
|
||||
iso_task_stopping = false;
|
||||
/* Take the wakeup back: nothing reads this queue, so leaving it there
|
||||
* would make the next attempt's send fail and never wake the task. */
|
||||
(void)xQueueReceive(iso_ctrl_queue, &item, 0);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
iso_task_handle = NULL;
|
||||
|
||||
#if CONFIG_BT_ISO_DISPATCH_MONITOR
|
||||
/* Task is gone: no concurrent writer, safe to read the stats. */
|
||||
bt_le_iso_dispatch_stats_dump();
|
||||
#endif /* CONFIG_BT_ISO_DISPATCH_MONITOR */
|
||||
|
||||
/* Drained by the task before it exited, so these are empty. */
|
||||
iso_queues_destroy();
|
||||
|
||||
vSemaphoreDelete(iso_task_stopped);
|
||||
iso_task_stopped = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2445,6 +2445,23 @@ int bt_iso_big_register_cb(struct bt_iso_big_cb *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_iso_big_unregister_cb(struct bt_iso_big_cb *cb)
|
||||
{
|
||||
CHECKIF(cb == NULL) {
|
||||
LOG_ERR("BigCbNull");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sys_slist_find_and_remove(&iso_big_cbs, &cb->_node)) {
|
||||
LOG_ERR("BigCbNotReg[%p]", cb);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_ISO_BROADCASTER)
|
||||
static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
|
||||
struct bt_iso_big_create_param *param)
|
||||
@@ -3553,3 +3570,54 @@ void bt_iso_reset_safe(void)
|
||||
bt_iso_reset();
|
||||
bt_le_host_unlock();
|
||||
}
|
||||
|
||||
void bt_le_iso_state_reset(void)
|
||||
{
|
||||
/* Clear the CIG/BIG pools, the registered server and the BIG callback list.
|
||||
* Not bt_iso_reset(), which is the HCI-reset path and tears down live
|
||||
* channels. Call from init, before anything registers. */
|
||||
|
||||
LOG_DBG("IsoStateReset");
|
||||
|
||||
#if CONFIG_BT_ISO_CENTRAL
|
||||
memset(cigs, 0, sizeof(cigs));
|
||||
#endif /* CONFIG_BT_ISO_CENTRAL */
|
||||
|
||||
#if CONFIG_BT_ISO_PERIPHERAL
|
||||
iso_server = NULL;
|
||||
#endif /* CONFIG_BT_ISO_PERIPHERAL */
|
||||
|
||||
#if CONFIG_BT_ISO_BROADCAST
|
||||
memset(bigs, 0, sizeof(bigs));
|
||||
sys_slist_init(&iso_big_cbs);
|
||||
#endif /* CONFIG_BT_ISO_BROADCAST */
|
||||
}
|
||||
|
||||
size_t bt_le_iso_report_busy(void)
|
||||
{
|
||||
size_t busy = 0;
|
||||
|
||||
/* Number of CIG/BIG slots still allocated; each is logged at ERROR. */
|
||||
|
||||
#if CONFIG_BT_ISO_CENTRAL
|
||||
/* A CIS disconnect only moves the CIG to INACTIVE; nothing but
|
||||
* bt_iso_cig_terminate() frees the slot and the controller's CIG. */
|
||||
for (size_t i = 0; i < ARRAY_SIZE(cigs); i++) {
|
||||
if (cigs[i].state != BT_ISO_CIG_STATE_IDLE) {
|
||||
LOG_ERR("DeinitBusyCig[%u][state=%u]", i, cigs[i].state);
|
||||
busy++;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_ISO_CENTRAL */
|
||||
|
||||
#if CONFIG_BT_ISO_BROADCAST
|
||||
for (size_t i = 0; i < ARRAY_SIZE(bigs); i++) {
|
||||
if (atomic_test_bit(bigs[i].flags, BT_BIG_INITIALIZED)) {
|
||||
LOG_ERR("DeinitBusyBig[%u]", i);
|
||||
busy++;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_ISO_BROADCAST */
|
||||
|
||||
return busy;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ void bt_le_assert(const char *tag, size_t info,
|
||||
/* Use instead of assert(): CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE sets
|
||||
* -DNDEBUG, which turns every assert() into a no-op and lets execution fall
|
||||
* through onto the very pointer it was guarding. This one always checks. */
|
||||
#define BT_LE_ASSERT(_cond) \
|
||||
do { \
|
||||
if (!(_cond)) { \
|
||||
bt_le_assert(#_cond, 0, __FILE__, __LINE__, __func__); \
|
||||
} \
|
||||
#define BT_LE_ASSERT(_cond) \
|
||||
do { \
|
||||
if (!(_cond)) { \
|
||||
bt_le_assert(#_cond, 0, __FILE_NAME__, __LINE__, __func__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -34,7 +34,7 @@ static void iso_timer_cb(void *arg)
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_TIMER_EVENT, work, work->gen);
|
||||
if (err) {
|
||||
LOG_ERR("TimerCbPostFail[%d]", err);
|
||||
ISO_POST_FAIL_LOG(err, "TimerCbPostFail[%d]", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -422,6 +422,19 @@ struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_addr(const bt_addr_le_t *ad
|
||||
*/
|
||||
int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb);
|
||||
|
||||
/**
|
||||
* @brief Unregister periodic advertising sync callbacks.
|
||||
*
|
||||
* Counterpart of @ref bt_le_per_adv_sync_cb_register(). The list is boot-scoped,
|
||||
* so a module that stops listening must remove itself or keep being invoked.
|
||||
*
|
||||
* @param cb Callback struct previously registered.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -ENOENT if @p cb was not registered.
|
||||
*/
|
||||
int bt_le_per_adv_sync_cb_unregister(struct bt_le_per_adv_sync_cb *cb);
|
||||
|
||||
/** LE scan parameters */
|
||||
struct bt_le_scan_param {
|
||||
/** Scan type. @ref BT_LE_SCAN_TYPE_ACTIVE or @ref BT_LE_SCAN_TYPE_PASSIVE. */
|
||||
|
||||
Reference in New Issue
Block a user