mirror of
https://github.com/espressif/esp-idf.git
synced 2026-06-04 20:26:38 +03:00
feat(ble_audio): Support running ISO & LE Audio with Bluedroid Host
This commit is contained in:
@@ -29,13 +29,24 @@ endif()
|
||||
list(APPEND ble_audio_include_dirs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/api/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include"
|
||||
)
|
||||
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
set(audio_adapter "host/adapter/nimble")
|
||||
elseif(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
set(audio_adapter "host/adapter/bluedroid")
|
||||
endif()
|
||||
|
||||
list(APPEND ble_audio_include_dirs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/include"
|
||||
)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/server.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/init.c"
|
||||
)
|
||||
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/server.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/init.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/init.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/api/esp_ble_audio_aics_api.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/api/esp_ble_audio_bap_api.c"
|
||||
@@ -57,69 +68,71 @@ list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/api/esp_ble_audio_vocs_api.c"
|
||||
)
|
||||
|
||||
# Profile glue files live under the host adapter; same set of profile sources
|
||||
# for either host, dispatched via ${audio_adapter}.
|
||||
if(CONFIG_BT_ASCS)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/ascs.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/ascs.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_PACS)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/pacs.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/pacs.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_BAP_SCAN_DELEGATOR)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/bass.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/bass.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_CAP_ACCEPTOR)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/cas.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/cas.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_CSIP_SET_MEMBER)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/csis.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/csis.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_TBS)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/tbs.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/tbs.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_TMAP)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/tmas.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/tmas.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_VCP_VOL_REND)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/vcs.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/vcs.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_MICP_MIC_DEV)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/mics.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/mics.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_MCS)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/mcs.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/mcs.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_HAS)
|
||||
list(APPEND ble_audio_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/profiles/has.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/${audio_adapter}/profiles/has.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ if BT_MCC
|
||||
it.
|
||||
|
||||
config BT_MCC_OTS
|
||||
bool "Media Control Client support for Object Transfer Service (depends on OTS Client)"
|
||||
depends on BT_OTS_CLIENT
|
||||
bool "Media Control Client support for Object Transfer Service"
|
||||
select BT_OTS_CLIENT
|
||||
help
|
||||
Use this option to configure support in the Media Control Client for
|
||||
an included Object Transfer Service in the Media Control Service.
|
||||
|
||||
@@ -71,9 +71,10 @@ if BT_MPL
|
||||
|
||||
config BT_MPL_OBJECTS
|
||||
bool "Support for media player objects"
|
||||
depends on BT_OTS
|
||||
select BT_OTS
|
||||
# TODO: Temporarily depends also on BT_MCS, to avoid issues with the
|
||||
# bt_mcs_get_ots() call
|
||||
# bt_mcs_get_ots() call. BT_MCS stays as `depends on` because it has
|
||||
# non-leaf prerequisites (BT_MCTL_LOCAL_PLAYER_REMOTE_CONTROL ...).
|
||||
depends on BT_MCS
|
||||
# OTS shall be instantiated as a Secondary Service and shall be
|
||||
# included in MCS or GMCS.
|
||||
|
||||
@@ -70,10 +70,12 @@ void esp_ble_audio_gap_app_post_event(uint8_t type, void *param)
|
||||
bt_le_gap_app_post_event(type, param);
|
||||
}
|
||||
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param)
|
||||
{
|
||||
bt_le_gatt_app_post_event(type, param);
|
||||
}
|
||||
#endif /* !CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
esp_err_t esp_ble_audio_common_init(esp_ble_audio_init_info_t *info)
|
||||
{
|
||||
@@ -156,3 +158,10 @@ esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info)
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
uint8_t esp_ble_audio_bluedroid_get_gattc_if(void)
|
||||
{
|
||||
return bt_le_bluedroid_gattc_get_if();
|
||||
}
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
@@ -128,15 +128,20 @@ typedef struct {
|
||||
*/
|
||||
void esp_ble_audio_gap_app_post_event(uint8_t type, void *param);
|
||||
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Post an application-layer GATT event for audio internal usage.
|
||||
*
|
||||
* @note This function is only needed while using NimBLE Host.
|
||||
* @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.
|
||||
*
|
||||
* @param type Event type.
|
||||
* @param param Event parameters.
|
||||
*/
|
||||
void esp_ble_audio_gatt_app_post_event(uint8_t type, void *param);
|
||||
#endif /* !CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
/**
|
||||
* @brief Initialize BLE Audio common functionality.
|
||||
@@ -167,6 +172,21 @@ typedef struct {
|
||||
*/
|
||||
esp_err_t esp_ble_audio_common_start(esp_ble_audio_start_info_t *info);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Get the engine's internal GATTC interface handle (Bluedroid only).
|
||||
*
|
||||
* Pass this to esp_ble_gattc_aux_open() / esp_ble_gattc_open() so the
|
||||
* resulting ACL events route back to the engine, avoiding the need for the
|
||||
* application to register a second BTA GATTC app for connection initiation.
|
||||
*
|
||||
* @return Engine's gattc_if (ABI-compatible with esp_gatt_if_t), or
|
||||
* ESP_GATT_IF_NONE (0xFF) if GATTC registration has not completed —
|
||||
* callers must bail rather than pass it to aux_open.
|
||||
*/
|
||||
uint8_t esp_ble_audio_bluedroid_get_gattc_if(void);
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_INIT_H_
|
||||
#define HOST_BLUEDROID_INIT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
#include "bluedroid/profiles/ascs.h"
|
||||
#include "bluedroid/profiles/bass.h"
|
||||
#include "bluedroid/profiles/cas.h"
|
||||
#include "bluedroid/profiles/csis.h"
|
||||
#include "bluedroid/profiles/mcs.h"
|
||||
#include "bluedroid/profiles/mics.h"
|
||||
#include "bluedroid/profiles/pacs.h"
|
||||
#include "bluedroid/profiles/tbs.h"
|
||||
#include "bluedroid/profiles/tmas.h"
|
||||
#include "bluedroid/profiles/vcs.h"
|
||||
#include "bluedroid/profiles/has.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_audio_init(void);
|
||||
|
||||
int bt_le_bluedroid_media_proxy_pl_init(void);
|
||||
|
||||
int bt_le_bluedroid_vcp_vol_rend_init(void);
|
||||
|
||||
int bt_le_bluedroid_micp_mic_dev_init(void);
|
||||
|
||||
int bt_le_bluedroid_audio_start(void *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_INIT_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_ASCS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_ASCS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_ascs_init(void);
|
||||
|
||||
int bt_le_bluedroid_ascs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_ASCS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_BASS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_BASS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_bass_init(void);
|
||||
|
||||
int bt_le_bluedroid_bass_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_BASS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_CAS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_CAS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_cas_init(void *csis_svc_p);
|
||||
|
||||
int bt_le_bluedroid_cas_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_CAS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_CSIS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_CSIS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_csis_init(void *csis_svc, uint8_t count);
|
||||
|
||||
int bt_le_bluedroid_csis_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_CSIS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_HAS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_HAS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_has_init(void);
|
||||
|
||||
int bt_le_bluedroid_has_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_HAS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_MCS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_MCS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_gmcs_init(void);
|
||||
|
||||
int bt_le_bluedroid_gmcs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_MCS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_MICS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_MICS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_mics_init(void *micp_inc);
|
||||
|
||||
int bt_le_bluedroid_mics_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_MICS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_PACS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_PACS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_pacs_init(void);
|
||||
|
||||
int bt_le_bluedroid_pacs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_PACS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_TBS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_TBS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_gtbs_init(void);
|
||||
|
||||
int bt_le_bluedroid_gtbs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_TBS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_TMAS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_TMAS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_tmas_init(void);
|
||||
|
||||
int bt_le_bluedroid_tmas_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_TMAS_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_PROFILE_VCS_H_
|
||||
#define HOST_BLUEDROID_PROFILE_VCS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int bt_le_bluedroid_vcs_init(void *vcp_inc);
|
||||
|
||||
int bt_le_bluedroid_vcs_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_PROFILE_VCS_H_ */
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_SERVER_H_
|
||||
#define HOST_BLUEDROID_SERVER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline char *audio_svc_uuid_to_str(uint16_t uuid)
|
||||
{
|
||||
switch (uuid) {
|
||||
case BT_UUID_AICS_VAL: return "AICS";
|
||||
case BT_UUID_CAS_VAL: return "CAS";
|
||||
case BT_UUID_VCS_VAL: return "VCS";
|
||||
case BT_UUID_VOCS_VAL: return "VOCS";
|
||||
case BT_UUID_CSIS_VAL: return "CSIS";
|
||||
case BT_UUID_MCS_VAL: return "MCS";
|
||||
case BT_UUID_GMCS_VAL: return "GMCS";
|
||||
case BT_UUID_TBS_VAL: return "TBS";
|
||||
case BT_UUID_GTBS_VAL: return "GTBS";
|
||||
case BT_UUID_MICS_VAL: return "MICS";
|
||||
case BT_UUID_ASCS_VAL: return "ASCS";
|
||||
case BT_UUID_BASS_VAL: return "BASS";
|
||||
case BT_UUID_PACS_VAL: return "PACS";
|
||||
case BT_UUID_BASIC_AUDIO_VAL: return "BASIC_AUDIO";
|
||||
case BT_UUID_HAS_VAL: return "HAS";
|
||||
case BT_UUID_TMAS_VAL: return "TMAS";
|
||||
case BT_UUID_PBA_VAL: return "PBA";
|
||||
case BT_UUID_GMAS_VAL: return "GMAS";
|
||||
case BT_UUID_OTS_VAL: return "OTS";
|
||||
default: return "UnknownSvc";
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *audio_chrc_uuid_to_str(uint16_t uuid)
|
||||
{
|
||||
switch (uuid) {
|
||||
case BT_UUID_OTS_FEATURE_VAL: return "OTS_FEATURE";
|
||||
case BT_UUID_OTS_NAME_VAL: return "OTS_NAME";
|
||||
case BT_UUID_OTS_TYPE_VAL: return "OTS_TYPE";
|
||||
case BT_UUID_OTS_SIZE_VAL: return "OTS_SIZE";
|
||||
case BT_UUID_OTS_FIRST_CREATED_VAL: return "OTS_FIRST_CREATED";
|
||||
case BT_UUID_OTS_LAST_MODIFIED_VAL: return "OTS_LAST_MODIFIED";
|
||||
case BT_UUID_OTS_ID_VAL: return "OTS_ID";
|
||||
case BT_UUID_OTS_PROPERTIES_VAL: return "OTS_PROPERTIES";
|
||||
case BT_UUID_OTS_ACTION_CP_VAL: return "OTS_ACTION_CP";
|
||||
case BT_UUID_OTS_LIST_CP_VAL: return "OTS_LIST_CP";
|
||||
case BT_UUID_OTS_LIST_FILTER_VAL: return "OTS_LIST_FILTER";
|
||||
case BT_UUID_OTS_CHANGED_VAL: return "OTS_CHANGED";
|
||||
case BT_UUID_GATT_TMAPR_VAL: return "TMAP_ROLE";
|
||||
case BT_UUID_AICS_STATE_VAL: return "AICS_STATE";
|
||||
case BT_UUID_AICS_GAIN_SETTINGS_VAL: return "AICS_GAIN_SETTINGS";
|
||||
case BT_UUID_AICS_INPUT_TYPE_VAL: return "AICS_INPUT_TYPE";
|
||||
case BT_UUID_AICS_INPUT_STATUS_VAL: return "AICS_INPUT_STATUS";
|
||||
case BT_UUID_AICS_CONTROL_VAL: return "AICS_CONTROL";
|
||||
case BT_UUID_AICS_DESCRIPTION_VAL: return "AICS_DESCRIPTION";
|
||||
case BT_UUID_VCS_STATE_VAL: return "VCS_STATE";
|
||||
case BT_UUID_VCS_CONTROL_VAL: return "VCS_CONTROL";
|
||||
case BT_UUID_VCS_FLAGS_VAL: return "VCS_FLAGS";
|
||||
case BT_UUID_VOCS_STATE_VAL: return "VOCS_STATE";
|
||||
case BT_UUID_VOCS_LOCATION_VAL: return "VOCS_LOCATION";
|
||||
case BT_UUID_VOCS_CONTROL_VAL: return "VOCS_CONTROL";
|
||||
case BT_UUID_VOCS_DESCRIPTION_VAL: return "VOCS_DESCRIPTION";
|
||||
case BT_UUID_CSIS_SIRK_VAL: return "CSIS_SIRK";
|
||||
case BT_UUID_CSIS_SET_SIZE_VAL: return "CSIS_SET_SIZE";
|
||||
case BT_UUID_CSIS_SET_LOCK_VAL: return "CSIS_SET_LOCK";
|
||||
case BT_UUID_CSIS_RANK_VAL: return "CSIS_RANK";
|
||||
case BT_UUID_MCS_PLAYER_NAME_VAL: return "MCS_PLAYER_NAME";
|
||||
case BT_UUID_MCS_ICON_OBJ_ID_VAL: return "MCS_ICON_OBJ_ID";
|
||||
case BT_UUID_MCS_ICON_URL_VAL: return "MCS_ICON_URL";
|
||||
case BT_UUID_MCS_TRACK_CHANGED_VAL: return "MCS_TRACK_CHANGED";
|
||||
case BT_UUID_MCS_TRACK_TITLE_VAL: return "MCS_TRACK_TITLE";
|
||||
case BT_UUID_MCS_TRACK_DURATION_VAL: return "MCS_TRACK_DURATION";
|
||||
case BT_UUID_MCS_TRACK_POSITION_VAL: return "MCS_TRACK_POSITION";
|
||||
case BT_UUID_MCS_PLAYBACK_SPEED_VAL: return "MCS_PLAYBACK_SPEED";
|
||||
case BT_UUID_MCS_SEEKING_SPEED_VAL: return "MCS_SEEKING_SPEED";
|
||||
case BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL: return "MCS_TRACK_SEGMENTS_OBJ_ID";
|
||||
case BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL: return "MCS_CURRENT_TRACK_OBJ_ID";
|
||||
case BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL: return "MCS_NEXT_TRACK_OBJ_ID";
|
||||
case BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL: return "MCS_PARENT_GROUP_OBJ_ID";
|
||||
case BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL: return "MCS_CURRENT_GROUP_OBJ_ID";
|
||||
case BT_UUID_MCS_PLAYING_ORDER_VAL: return "MCS_PLAYING_ORDER";
|
||||
case BT_UUID_MCS_PLAYING_ORDERS_VAL: return "MCS_PLAYING_ORDERS";
|
||||
case BT_UUID_MCS_MEDIA_STATE_VAL: return "MCS_MEDIA_STATE";
|
||||
case BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL: return "MCS_MEDIA_CONTROL_POINT";
|
||||
case BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL: return "MCS_MEDIA_CONTROL_OPCODES";
|
||||
case BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL: return "MCS_SEARCH_RESULTS_OBJ_ID";
|
||||
case BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL: return "MCS_SEARCH_CONTROL_POINT";
|
||||
case BT_UUID_TBS_PROVIDER_NAME_VAL: return "TBS_PROVIDER_NAME";
|
||||
case BT_UUID_TBS_UCI_VAL: return "TBS_UCI";
|
||||
case BT_UUID_TBS_TECHNOLOGY_VAL: return "TBS_TECHNOLOGY";
|
||||
case BT_UUID_TBS_URI_LIST_VAL: return "TBS_URI_LIST";
|
||||
case BT_UUID_TBS_SIGNAL_STRENGTH_VAL: return "TBS_SIGNAL_STRENGTH";
|
||||
case BT_UUID_TBS_SIGNAL_INTERVAL_VAL: return "TBS_SIGNAL_INTERVAL";
|
||||
case BT_UUID_TBS_LIST_CURRENT_CALLS_VAL: return "TBS_LIST_CURRENT_CALLS";
|
||||
case BT_UUID_CCID_VAL: return "CCID";
|
||||
case BT_UUID_TBS_STATUS_FLAGS_VAL: return "TBS_STATUS_FLAGS";
|
||||
case BT_UUID_TBS_INCOMING_URI_VAL: return "TBS_INCOMING_URI";
|
||||
case BT_UUID_TBS_CALL_STATE_VAL: return "TBS_CALL_STATE";
|
||||
case BT_UUID_TBS_CALL_CONTROL_POINT_VAL: return "TBS_CALL_CONTROL_POINT";
|
||||
case BT_UUID_TBS_OPTIONAL_OPCODES_VAL: return "TBS_OPTIONAL_OPCODES";
|
||||
case BT_UUID_TBS_TERMINATE_REASON_VAL: return "TBS_TERMINATE_REASON";
|
||||
case BT_UUID_TBS_INCOMING_CALL_VAL: return "TBS_INCOMING_CALL";
|
||||
case BT_UUID_TBS_FRIENDLY_NAME_VAL: return "TBS_FRIENDLY_NAME";
|
||||
case BT_UUID_MICS_MUTE_VAL: return "MICS_MUTE";
|
||||
case BT_UUID_ASCS_ASE_SNK_VAL: return "ASCS_ASE_SNK";
|
||||
case BT_UUID_ASCS_ASE_SRC_VAL: return "ASCS_ASE_SRC";
|
||||
case BT_UUID_ASCS_ASE_CP_VAL: return "ASCS_ASE_CP";
|
||||
case BT_UUID_BASS_CONTROL_POINT_VAL: return "BASS_CP";
|
||||
case BT_UUID_BASS_RECV_STATE_VAL: return "BASS_RECV_STATE";
|
||||
case BT_UUID_PACS_SNK_VAL: return "PACS_SNK";
|
||||
case BT_UUID_PACS_SNK_LOC_VAL: return "PACS_SNK_LOC";
|
||||
case BT_UUID_PACS_SRC_VAL: return "PACS_SRC";
|
||||
case BT_UUID_PACS_SRC_LOC_VAL: return "PACS_SRC_LOC";
|
||||
case BT_UUID_PACS_AVAILABLE_CONTEXT_VAL: return "PACS_AVAILABLE_CONTEXT";
|
||||
case BT_UUID_PACS_SUPPORTED_CONTEXT_VAL: return "PACS_SUPPORTED_CONTEXT";
|
||||
case BT_UUID_HAS_HEARING_AID_FEATURES_VAL: return "HAS_HEARING_AID_FEATURES";
|
||||
case BT_UUID_HAS_PRESET_CONTROL_POINT_VAL: return "HAS_PRESET_CONTROL_POINT";
|
||||
case BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL: return "HAS_ACTIVE_PRESET_INDEX";
|
||||
case BT_UUID_GMAP_ROLE_VAL: return "GMAP_ROLE";
|
||||
case BT_UUID_GMAP_UGG_FEAT_VAL: return "GMAP_UGG_FEAT";
|
||||
case BT_UUID_GMAP_UGT_FEAT_VAL: return "GMAP_UGT_FEAT";
|
||||
case BT_UUID_GMAP_BGS_FEAT_VAL: return "GMAP_BGS_FEAT";
|
||||
case BT_UUID_GMAP_BGR_FEAT_VAL: return "GMAP_BGR_FEAT";
|
||||
default: return "UnknownChrc";
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
AICS_IN_PROGRESS,
|
||||
ASCS_IN_PROGRESS,
|
||||
BASS_IN_PROGRESS,
|
||||
CAS_IN_PROGRESS,
|
||||
CSIS_IN_PROGRESS,
|
||||
HAS_IN_PROGRESS,
|
||||
GMCS_IN_PROGRESS,
|
||||
MCS_IN_PROGRESS,
|
||||
MICS_IN_PROGRESS,
|
||||
PACS_IN_PROGRESS,
|
||||
GTBS_IN_PROGRESS,
|
||||
TBS_IN_PROGRESS,
|
||||
TMAS_IN_PROGRESS,
|
||||
VCS_IN_PROGRESS,
|
||||
VOCS_IN_PROGRESS,
|
||||
|
||||
MAX_IN_PROGRESS,
|
||||
};
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_init(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_start(struct bt_gatt_service *svc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_SERVER_H_ */
|
||||
342
components/bt/esp_ble_audio/host/adapter/bluedroid/init.c
Normal file
342
components/bt/esp_ble_audio/host/adapter/bluedroid/init.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bta/bta_gatt_common.h"
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/audio/micp.h>
|
||||
#include <zephyr/bluetooth/audio/vcp.h>
|
||||
|
||||
#include "bluedroid/init.h"
|
||||
#include "common/init.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_BINIT, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
|
||||
#else /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
#define CSIS_SVC_COUNT 0
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
/* 3 is reserved for other GATT services */
|
||||
#define TOTAL_SERVICE_COUNT (3 + \
|
||||
(IS_ENABLED(CONFIG_BT_ASCS) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_PACS) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_TMAP) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_MCS) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_CSIP_SET_MEMBER) ? CSIS_SVC_COUNT : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_VCP_VOL_REND) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_MICP_MIC_DEV) ? 1 : 0) + \
|
||||
CONFIG_BT_VOCS_MAX_INSTANCE_COUNT + \
|
||||
CONFIG_BT_AICS_MAX_INSTANCE_COUNT + \
|
||||
(IS_ENABLED(CONFIG_BT_TBS) ? 1 : 0) + \
|
||||
(IS_ENABLED(CONFIG_BT_HAS) ? 1 : 0))
|
||||
|
||||
_Static_assert(TOTAL_SERVICE_COUNT <= CONFIG_BT_GATT_MAX_SR_PROFILES, "Too small BT_GATT_MAX_SR_PROFILES");
|
||||
|
||||
int bt_le_bluedroid_audio_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
BTA_GATT_SetLocalMTU(BLE_AUDIO_ATT_MTU_MIN);
|
||||
|
||||
bt_le_bluedroid_audio_gatts_init();
|
||||
|
||||
#if CONFIG_BT_PACS
|
||||
err = bt_le_bluedroid_pacs_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_PACS */
|
||||
|
||||
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
|
||||
#if CONFIG_BT_ASCS
|
||||
err = bt_le_bluedroid_ascs_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_ASCS */
|
||||
|
||||
#if CONFIG_BT_BAP_SCAN_DELEGATOR
|
||||
err = bt_le_bluedroid_bass_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
#if CONFIG_BT_TMAP
|
||||
err = bt_le_bluedroid_tmas_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_TMAP */
|
||||
|
||||
#if CONFIG_BT_TBS
|
||||
err = bt_le_bluedroid_gtbs_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
#if CONFIG_BT_HAS
|
||||
err = bt_le_bluedroid_has_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_HAS */
|
||||
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
struct bt_gatt_service *csis_svc[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT];
|
||||
uint8_t count;
|
||||
int err;
|
||||
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*inc_csis_svc = NULL;
|
||||
count = 0;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(info->csis_insts); i++) {
|
||||
if (info->csis_insts[i].svc_inst == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
csis_svc[count] = lib_csip_set_member_svc_get(info->csis_insts[i].svc_inst);
|
||||
if (!csis_svc[count]) {
|
||||
LOG_ERR("[B]CsisSvcGetFail[%u]", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (info->csis_insts[i].included_by_cas) {
|
||||
if (*inc_csis_svc == NULL) {
|
||||
*inc_csis_svc = csis_svc[count];
|
||||
} else {
|
||||
/* CAS may include at most one CSIS — caller misconfigured. */
|
||||
LOG_ERR("[B]CsisMultiIncByCas");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
err = bt_le_bluedroid_csis_init(csis_svc, count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
#if CONFIG_BT_MCS
|
||||
int bt_le_bluedroid_media_proxy_pl_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
#if CONFIG_BT_MPL_OBJECTS
|
||||
|
||||
#endif /* CONFIG_BT_MPL_OBJECTS */
|
||||
|
||||
err = bt_le_bluedroid_gmcs_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
int bt_le_bluedroid_vcp_vol_rend_init(void)
|
||||
{
|
||||
struct bt_vcp_included vcp_included;
|
||||
int err;
|
||||
|
||||
memset(&vcp_included, 0, sizeof(vcp_included));
|
||||
|
||||
err = bt_vcp_vol_rend_included_get_safe(&vcp_included);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_bluedroid_vcs_init(&vcp_included);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
int bt_le_bluedroid_micp_mic_dev_init(void)
|
||||
{
|
||||
struct bt_micp_included micp_included;
|
||||
int err;
|
||||
|
||||
memset(&micp_included, 0, sizeof(micp_included));
|
||||
|
||||
err = bt_micp_mic_dev_included_get_safe(&micp_included);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_le_bluedroid_mics_init(&micp_included);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
|
||||
int bt_le_bluedroid_audio_start(void *info)
|
||||
{
|
||||
struct bt_gatt_service *inc_csis_svc = NULL;
|
||||
int err = 0;
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
/* Note:
|
||||
* Should add CSIS before CAS in case one CSIS instance
|
||||
* is included by CAS.
|
||||
*/
|
||||
err = bluedroid_gatt_csis_init(info, &inc_csis_svc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR
|
||||
err = bt_le_bluedroid_cas_init(inc_csis_svc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#else /* CONFIG_BT_CAP_ACCEPTOR */
|
||||
ARG_UNUSED(inc_csis_svc);
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR */
|
||||
|
||||
#if (BLE_AUDIO_SVC_DEFERRED_ADD == 0)
|
||||
#if CONFIG_BT_MCS
|
||||
err = bt_le_bluedroid_media_proxy_pl_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
err = bt_le_bluedroid_vcp_vol_rend_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
err = bt_le_bluedroid_micp_mic_dev_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
#endif /* (BLE_AUDIO_SVC_DEFERRED_ADD == 0) */
|
||||
|
||||
#if CONFIG_BT_ASCS
|
||||
err = bt_le_bluedroid_ascs_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_ASCS */
|
||||
|
||||
#if CONFIG_BT_PACS
|
||||
err = bt_le_bluedroid_pacs_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_PACS */
|
||||
|
||||
#if CONFIG_BT_BAP_SCAN_DELEGATOR
|
||||
err = bt_le_bluedroid_bass_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
#if CONFIG_BT_TMAP
|
||||
err = bt_le_bluedroid_tmas_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_TMAP */
|
||||
|
||||
#if CONFIG_BT_CSIP_SET_MEMBER
|
||||
err = bt_le_bluedroid_csis_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_CSIP_SET_MEMBER */
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR
|
||||
err = bt_le_bluedroid_cas_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
err = bt_le_bluedroid_vcs_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
err = bt_le_bluedroid_mics_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
|
||||
#if CONFIG_BT_MCS
|
||||
err = bt_le_bluedroid_gmcs_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
#if CONFIG_BT_TBS
|
||||
err = bt_le_bluedroid_gtbs_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
#if CONFIG_BT_HAS
|
||||
err = bt_le_bluedroid_has_start();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_BT_HAS */
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_ASCS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_ascs_init(void)
|
||||
{
|
||||
struct bt_gatt_service *ascs_svc;
|
||||
|
||||
LOG_DBG("[B]AscsInit");
|
||||
|
||||
ascs_svc = lib_ascs_svc_get();
|
||||
if (!ascs_svc) {
|
||||
LOG_ERR("[B]AscsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(ASCS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(ascs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_ascs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *ascs_svc;
|
||||
|
||||
LOG_DBG("[B]AscsStart");
|
||||
|
||||
ascs_svc = lib_ascs_svc_get();
|
||||
if (!ascs_svc) {
|
||||
LOG_ERR("[B]AscsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(ASCS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(ascs_svc);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_BASS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_bass_init(void)
|
||||
{
|
||||
struct bt_gatt_service *bass_svc;
|
||||
|
||||
LOG_DBG("[B]BassInit");
|
||||
|
||||
bass_svc = lib_bap_bass_svc_get();
|
||||
if (!bass_svc) {
|
||||
LOG_ERR("[B]BassSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(BASS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(bass_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_bass_start(void)
|
||||
{
|
||||
struct bt_gatt_service *bass_svc;
|
||||
|
||||
LOG_DBG("[B]BassStart");
|
||||
|
||||
bass_svc = lib_bap_bass_svc_get();
|
||||
if (!bass_svc) {
|
||||
LOG_ERR("[B]BassSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(BASS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(bass_svc);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_CAS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
|
||||
static struct inc_svc_inst inc_csis_inst;
|
||||
|
||||
struct inc_svc_inst *cas_not_included_inst(void)
|
||||
{
|
||||
if (inc_csis_inst.included == false) {
|
||||
return &inc_csis_inst;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
|
||||
int bt_le_bluedroid_cas_init(void *csis_svc_p)
|
||||
{
|
||||
struct bt_gatt_service *cas_svc;
|
||||
int err = 0;
|
||||
|
||||
LOG_DBG("[B]CasInit");
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
|
||||
/* csis_svc_p is non-NULL in practice (SET_MEMBER depends on CSIP_SET_MEMBER,
|
||||
* which populates it), but guard for parity with the nimble adapter. With
|
||||
* no CSIS, mark included=true so cas_not_included_inst() skips it and
|
||||
* svc_init never feeds a NULL svc_p into BTA_GATTS_AddIncludeService. */
|
||||
if (csis_svc_p) {
|
||||
/* The instance of CSIS is included by CAS */
|
||||
inc_csis_inst.svc_p = csis_svc_p;
|
||||
/* Reset included before svc_init; see mics.c for rationale. */
|
||||
inc_csis_inst.included = false;
|
||||
} else {
|
||||
inc_csis_inst.included = true;
|
||||
}
|
||||
#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
ARG_UNUSED(csis_svc_p);
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
|
||||
cas_svc = lib_cas_svc_get();
|
||||
if (!cas_svc) {
|
||||
LOG_ERR("[B]CasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(CAS_IN_PROGRESS);
|
||||
|
||||
err = bt_le_bluedroid_svc_init(cas_svc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
|
||||
if (cas_not_included_inst()) {
|
||||
LOG_ERR("[B]CasCsisNotInc");
|
||||
return -EIO;
|
||||
}
|
||||
#else /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
/* Insert CAS to the GATT db list */
|
||||
err = bt_gatt_service_register_safe(cas_svc);
|
||||
if (err) {
|
||||
LOG_ERR("[B]CasSvcRegFail[%d]", err);
|
||||
}
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_cas_start(void)
|
||||
{
|
||||
struct bt_gatt_service *cas_svc;
|
||||
|
||||
LOG_DBG("[B]CasStart");
|
||||
|
||||
cas_svc = lib_cas_svc_get();
|
||||
if (!cas_svc) {
|
||||
LOG_ERR("[B]CasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(CAS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(cas_svc);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_CSIS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#define CSIS_SVC_COUNT CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT
|
||||
|
||||
static struct csis_inst {
|
||||
struct bt_gatt_service *svc_p;
|
||||
} csis_insts[CSIS_SVC_COUNT];
|
||||
|
||||
static uint8_t csis_svc_count;
|
||||
|
||||
int bt_le_bluedroid_csis_init(void *svc, uint8_t count)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]CsisInit");
|
||||
|
||||
if (count > CSIS_SVC_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(CSIS_IN_PROGRESS);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
csis_insts[i].svc_p = ((struct bt_gatt_service **)svc)[i];
|
||||
|
||||
err = bt_le_bluedroid_svc_init(csis_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit the count only after the loop succeeds, so a mid-loop failure
|
||||
* doesn't leave csis_start() iterating uninitialized entries. */
|
||||
csis_svc_count = count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_csis_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]CsisStart");
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(CSIS_IN_PROGRESS);
|
||||
|
||||
for (size_t i = 0; i < csis_svc_count; i++) {
|
||||
err = bt_le_bluedroid_svc_start(csis_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_HAS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_has_init(void)
|
||||
{
|
||||
struct bt_gatt_service *has_svc;
|
||||
|
||||
LOG_DBG("[B]HasInit");
|
||||
|
||||
has_svc = lib_has_svc_get();
|
||||
if (!has_svc) {
|
||||
LOG_ERR("[B]HasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(HAS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(has_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_has_start(void)
|
||||
{
|
||||
struct bt_gatt_service *has_svc;
|
||||
|
||||
LOG_DBG("[B]HasStart");
|
||||
|
||||
has_svc = lib_has_svc_get();
|
||||
if (!has_svc) {
|
||||
LOG_ERR("[B]HasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(HAS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(has_svc);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_MCS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_gmcs_init(void)
|
||||
{
|
||||
struct bt_gatt_service *gmcs_svc;
|
||||
|
||||
gmcs_svc = lib_mcs_svc_get();
|
||||
if (!gmcs_svc) {
|
||||
LOG_ERR("[B]GmcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(GMCS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(gmcs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gmcs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *gmcs_svc;
|
||||
|
||||
gmcs_svc = lib_mcs_svc_get();
|
||||
if (!gmcs_svc) {
|
||||
LOG_ERR("[B]GmcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(GMCS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(gmcs_svc);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/audio/micp.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_MICS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#define AICS_INST_COUNT CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT
|
||||
|
||||
static uint8_t inc_aics_svc_count;
|
||||
|
||||
static struct inc_svc_inst inc_aics_insts[AICS_INST_COUNT];
|
||||
|
||||
struct inc_svc_inst *mics_not_included_inst(void)
|
||||
{
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
if (inc_aics_insts[i].included == false) {
|
||||
return &inc_aics_insts[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_mics_init(void *micp_inc)
|
||||
{
|
||||
struct bt_micp_included *micp_included;
|
||||
struct bt_gatt_service *mics_svc;
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]MicsInit");
|
||||
|
||||
mics_svc = lib_mics_svc_get();
|
||||
if (!mics_svc) {
|
||||
LOG_ERR("[B]MicsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset before the NULL check so a re-init with micp_included == NULL
|
||||
* doesn't iterate over stale entries from a previous non-NULL call. */
|
||||
inc_aics_svc_count = 0;
|
||||
|
||||
micp_included = micp_inc;
|
||||
|
||||
if (micp_included) {
|
||||
if (micp_included->aics_cnt > AICS_INST_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
|
||||
|
||||
/* MICS may include zero or more instances of AICS */
|
||||
for (size_t i = 0; i < micp_included->aics_cnt; i++) {
|
||||
inc_aics_insts[i].svc_p = lib_aics_svc_get(micp_included->aics[i]);
|
||||
if (!inc_aics_insts[i].svc_p) {
|
||||
LOG_ERR("[B]AicsSvcGetFail[%u]", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset included before svc_init: server.c sets it to true when
|
||||
* the include attribute is processed. Without this reset, a
|
||||
* re-init where the include attribute is missing would leave
|
||||
* the stale true from a previous init and mics_not_included_inst()
|
||||
* would falsely report all instances as included. */
|
||||
inc_aics_insts[i].included = false;
|
||||
|
||||
err = bt_le_bluedroid_svc_init(inc_aics_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit the count only after every instance initialized — a mid-loop
|
||||
* failure above leaves it at 0 (reset on entry) so mics_start() never
|
||||
* iterates partially-initialized entries. */
|
||||
inc_aics_svc_count = micp_included->aics_cnt;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(MICS_IN_PROGRESS);
|
||||
|
||||
err = bt_le_bluedroid_svc_init(mics_svc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (mics_not_included_inst()) {
|
||||
LOG_ERR("[B]MicsAicsNotAllInc");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_mics_start(void)
|
||||
{
|
||||
struct bt_gatt_service *mics_svc;
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]MicsStart");
|
||||
|
||||
mics_svc = lib_mics_svc_get();
|
||||
if (!mics_svc) {
|
||||
LOG_ERR("[B]MicsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
|
||||
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
err = bt_le_bluedroid_svc_start(inc_aics_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(MICS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(mics_svc);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_PACS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_pacs_init(void)
|
||||
{
|
||||
struct bt_gatt_service *pacs_svc;
|
||||
|
||||
LOG_DBG("[B]PacsInit");
|
||||
|
||||
pacs_svc = lib_pacs_svc_get();
|
||||
if (!pacs_svc) {
|
||||
LOG_ERR("[B]PacsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(PACS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(pacs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_pacs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *pacs_svc;
|
||||
|
||||
LOG_DBG("[B]PacsStart");
|
||||
|
||||
pacs_svc = lib_pacs_svc_get();
|
||||
if (!pacs_svc) {
|
||||
LOG_ERR("[B]PacsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(PACS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(pacs_svc);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_TBS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_gtbs_init(void)
|
||||
{
|
||||
struct bt_gatt_service *gtbs_svc;
|
||||
|
||||
gtbs_svc = lib_gtbs_svc_get();
|
||||
if (!gtbs_svc) {
|
||||
LOG_ERR("[B]GtbsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(GTBS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(gtbs_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gtbs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *gtbs_svc;
|
||||
|
||||
gtbs_svc = lib_gtbs_svc_get();
|
||||
if (!gtbs_svc) {
|
||||
LOG_ERR("[B]GtbsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(GTBS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(gtbs_svc);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_TMAS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
int bt_le_bluedroid_tmas_init(void)
|
||||
{
|
||||
struct bt_gatt_service *tmas_svc;
|
||||
|
||||
LOG_DBG("[B]TmasInit");
|
||||
|
||||
tmas_svc = lib_tmas_svc_get();
|
||||
if (!tmas_svc) {
|
||||
LOG_ERR("[B]TmasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(TMAS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_init(tmas_svc);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_tmas_start(void)
|
||||
{
|
||||
struct bt_gatt_service *tmas_svc;
|
||||
|
||||
LOG_DBG("[B]TmasStart");
|
||||
|
||||
tmas_svc = lib_tmas_svc_get();
|
||||
if (!tmas_svc) {
|
||||
LOG_ERR("[B]TmasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(TMAS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(tmas_svc);
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/audio/vcp.h>
|
||||
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_VCS, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#define VOCS_INST_COUNT CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT
|
||||
#define AICS_INST_COUNT CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT
|
||||
|
||||
static uint8_t inc_vocs_svc_count;
|
||||
static uint8_t inc_aics_svc_count;
|
||||
|
||||
static struct inc_svc_inst inc_vocs_insts[VOCS_INST_COUNT];
|
||||
static struct inc_svc_inst inc_aics_insts[AICS_INST_COUNT];
|
||||
|
||||
struct inc_svc_inst *vcs_not_included_inst(void)
|
||||
{
|
||||
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
|
||||
if (inc_vocs_insts[i].included == false) {
|
||||
return &inc_vocs_insts[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
if (inc_aics_insts[i].included == false) {
|
||||
return &inc_aics_insts[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_vcs_init(void *vcp_inc)
|
||||
{
|
||||
struct bt_vcp_included *vcp_included;
|
||||
struct bt_gatt_service *vcs_svc;
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]VcsInit");
|
||||
|
||||
vcs_svc = lib_vcs_svc_get();
|
||||
if (!vcs_svc) {
|
||||
LOG_ERR("[B]VcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset before the NULL check so a re-init with vcp_included == NULL
|
||||
* doesn't iterate over stale entries from a previous non-NULL call. */
|
||||
inc_vocs_svc_count = 0;
|
||||
inc_aics_svc_count = 0;
|
||||
|
||||
vcp_included = vcp_inc;
|
||||
|
||||
if (vcp_included) {
|
||||
if (vcp_included->vocs_cnt > VOCS_INST_COUNT ||
|
||||
vcp_included->aics_cnt > AICS_INST_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
inc_vocs_svc_count = vcp_included->vocs_cnt;
|
||||
inc_aics_svc_count = vcp_included->aics_cnt;
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(VOCS_IN_PROGRESS);
|
||||
|
||||
/* VCS may include zero or more instances of VOCS */
|
||||
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
|
||||
inc_vocs_insts[i].svc_p = lib_vocs_svc_get(vcp_included->vocs[i]);
|
||||
if (!inc_vocs_insts[i].svc_p) {
|
||||
LOG_ERR("[B]VocsSvcGetFail[%u]", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset included before svc_init; see mics.c for rationale. */
|
||||
inc_vocs_insts[i].included = false;
|
||||
|
||||
err = bt_le_bluedroid_svc_init(inc_vocs_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
|
||||
|
||||
/* VCS may include zero or more instances of AICS */
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
inc_aics_insts[i].svc_p = lib_aics_svc_get(vcp_included->aics[i]);
|
||||
if (!inc_aics_insts[i].svc_p) {
|
||||
LOG_ERR("[B]AicsSvcGetFail[%u]", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset included before svc_init; see mics.c for rationale. */
|
||||
inc_aics_insts[i].included = false;
|
||||
|
||||
err = bt_le_bluedroid_svc_init(inc_aics_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(VCS_IN_PROGRESS);
|
||||
|
||||
err = bt_le_bluedroid_svc_init(vcs_svc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (vcs_not_included_inst()) {
|
||||
LOG_ERR("[B]VcsVocsAicsNotAllInc");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_vcs_start(void)
|
||||
{
|
||||
struct bt_gatt_service *vcs_svc;
|
||||
int err;
|
||||
|
||||
LOG_DBG("[B]VcsStart");
|
||||
|
||||
vcs_svc = lib_vcs_svc_get();
|
||||
if (!vcs_svc) {
|
||||
LOG_ERR("[B]VcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(VOCS_IN_PROGRESS);
|
||||
|
||||
for (size_t i = 0; i < inc_vocs_svc_count; i++) {
|
||||
err = bt_le_bluedroid_svc_start(inc_vocs_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(AICS_IN_PROGRESS);
|
||||
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
err = bt_le_bluedroid_svc_start(inc_aics_insts[i].svc_p);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
bt_le_bluedroid_set_svc_in_progress(VCS_IN_PROGRESS);
|
||||
|
||||
return bt_le_bluedroid_svc_start(vcs_svc);
|
||||
}
|
||||
596
components/bt/esp_ble_audio/host/adapter/bluedroid/server.c
Normal file
596
components/bt/esp_ble_audio/host/adapter/bluedroid/server.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/audio/micp.h>
|
||||
#include <zephyr/bluetooth/audio/vcp.h>
|
||||
|
||||
#include <../host/conn_internal.h>
|
||||
|
||||
#include "bta/bta_gatt_api.h"
|
||||
|
||||
#include "bluedroid/gatt.h"
|
||||
#include "bluedroid/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
LOG_MODULE_REGISTER(LEA_GSRV, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
static uint8_t svc_in_progress;
|
||||
|
||||
static uint16_t inc_svc_handle;
|
||||
static uint16_t svc_handle;
|
||||
static uint16_t chrc_handle;
|
||||
|
||||
static bool is_primary_svc(void)
|
||||
{
|
||||
if (svc_in_progress == ASCS_IN_PROGRESS ||
|
||||
svc_in_progress == BASS_IN_PROGRESS ||
|
||||
svc_in_progress == CAS_IN_PROGRESS ||
|
||||
svc_in_progress == CSIS_IN_PROGRESS ||
|
||||
svc_in_progress == HAS_IN_PROGRESS ||
|
||||
svc_in_progress == GMCS_IN_PROGRESS ||
|
||||
svc_in_progress == MCS_IN_PROGRESS ||
|
||||
svc_in_progress == MICS_IN_PROGRESS ||
|
||||
svc_in_progress == PACS_IN_PROGRESS ||
|
||||
svc_in_progress == GTBS_IN_PROGRESS ||
|
||||
svc_in_progress == TBS_IN_PROGRESS ||
|
||||
svc_in_progress == TMAS_IN_PROGRESS ||
|
||||
svc_in_progress == VCS_IN_PROGRESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_secondary_svc(void)
|
||||
{
|
||||
if (svc_in_progress == AICS_IN_PROGRESS ||
|
||||
svc_in_progress == VOCS_IN_PROGRESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool any_included_svc(void)
|
||||
{
|
||||
if (svc_in_progress == CAS_IN_PROGRESS ||
|
||||
svc_in_progress == MICS_IN_PROGRESS ||
|
||||
svc_in_progress == VCS_IN_PROGRESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_svc_uuid_valid(uint16_t uuid)
|
||||
{
|
||||
switch (svc_in_progress) {
|
||||
case AICS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_AICS_VAL);
|
||||
|
||||
case ASCS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_ASCS_VAL);
|
||||
|
||||
case BASS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_BASS_VAL);
|
||||
|
||||
case CAS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_CAS_VAL);
|
||||
|
||||
case CSIS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_CSIS_VAL);
|
||||
|
||||
case HAS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_HAS_VAL);
|
||||
|
||||
case GMCS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_GMCS_VAL);
|
||||
|
||||
case MCS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_MCS_VAL);
|
||||
|
||||
case MICS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_MICS_VAL);
|
||||
|
||||
case PACS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_PACS_VAL);
|
||||
|
||||
case GTBS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_GTBS_VAL);
|
||||
|
||||
case TBS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_TBS_VAL);
|
||||
|
||||
case TMAS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_TMAS_VAL);
|
||||
|
||||
case VCS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_VCS_VAL);
|
||||
|
||||
case VOCS_IN_PROGRESS:
|
||||
return (uuid == BT_UUID_VOCS_VAL);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void svc_create_cb(uint16_t service_id, uint16_t svc_instance,
|
||||
bool is_primary, uint8_t status, void *uuid)
|
||||
{
|
||||
int result = status;
|
||||
|
||||
if ((is_primary_svc() && is_primary == false) ||
|
||||
(is_secondary_svc() && is_primary == true) ||
|
||||
((tBT_UUID *)uuid)->len != 2 ||
|
||||
is_svc_uuid_valid(((tBT_UUID *)uuid)->uu.uuid16) == false) {
|
||||
/* uuid16 is only meaningful when len == 2; for 32/128-bit UUIDs the
|
||||
* union access would log the first 2 bytes of a wider value. */
|
||||
if (((tBT_UUID *)uuid)->len == 2) {
|
||||
LOG_ERR("[B]SvcCreateMismatch[%u][%u][2][0x%04x]",
|
||||
svc_in_progress, is_primary,
|
||||
((tBT_UUID *)uuid)->uu.uuid16);
|
||||
} else {
|
||||
LOG_ERR("[B]SvcCreateMismatch[%u][%u][%u][nonU16]",
|
||||
svc_in_progress, is_primary,
|
||||
((tBT_UUID *)uuid)->len);
|
||||
}
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
svc_handle = service_id;
|
||||
|
||||
end:
|
||||
bt_le_bluedroid_gatts_sem_give(result);
|
||||
}
|
||||
|
||||
static void inc_svc_add_cb(uint16_t service_id, uint16_t attr_id, uint8_t status)
|
||||
{
|
||||
int result = status;
|
||||
|
||||
if (service_id != svc_handle) {
|
||||
LOG_ERR("[B]IncSvcAddMismatch[%u][%u][%u]",
|
||||
svc_in_progress, service_id, svc_handle);
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
inc_svc_handle = attr_id;
|
||||
|
||||
end:
|
||||
bt_le_bluedroid_gatts_sem_give(result);
|
||||
}
|
||||
|
||||
static void chrc_add_cb(uint16_t service_id, uint16_t attr_id,
|
||||
uint8_t status, void *uuid)
|
||||
{
|
||||
int result = status;
|
||||
|
||||
if (service_id != svc_handle || ((tBT_UUID *)uuid)->len != 2) {
|
||||
/* uuid16 is only meaningful when len == 2; for 32/128-bit UUIDs the
|
||||
* union access would log the first 2 bytes of a wider value. */
|
||||
if (((tBT_UUID *)uuid)->len == 2) {
|
||||
LOG_ERR("[B]ChrcAddMismatch[%u][%u][%u][2][0x%04x]",
|
||||
svc_in_progress, service_id, svc_handle,
|
||||
((tBT_UUID *)uuid)->uu.uuid16);
|
||||
} else {
|
||||
LOG_ERR("[B]ChrcAddMismatch[%u][%u][%u][%u][nonU16]",
|
||||
svc_in_progress, service_id, svc_handle,
|
||||
((tBT_UUID *)uuid)->len);
|
||||
}
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
chrc_handle = attr_id;
|
||||
|
||||
end:
|
||||
bt_le_bluedroid_gatts_sem_give(result);
|
||||
}
|
||||
|
||||
static void svc_start_cb(uint16_t service_id, uint8_t status)
|
||||
{
|
||||
int result = status;
|
||||
|
||||
if (service_id != svc_handle) {
|
||||
LOG_ERR("[B]SvcStartMismatch[%u][%u]", service_id, svc_handle);
|
||||
result = -1;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_gatts_sem_give(result);
|
||||
}
|
||||
|
||||
static struct gatts_svc_cb svc_cb = {
|
||||
.svc_create_cb = svc_create_cb,
|
||||
.inc_svc_add_cb = inc_svc_add_cb,
|
||||
.chrc_add_cb = chrc_add_cb,
|
||||
.svc_start_cb = svc_start_cb,
|
||||
};
|
||||
|
||||
void bt_le_bluedroid_audio_gatts_init(void)
|
||||
{
|
||||
bt_le_bluedroid_gatts_svc_cb_register(&svc_cb);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_set_svc_in_progress(uint8_t value)
|
||||
{
|
||||
if (value >= MAX_IN_PROGRESS) {
|
||||
LOG_ERR("[B]SvcInProgressInv[%u]", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
svc_in_progress = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_svc_attr_uuid_valid(uint16_t attr_uuid)
|
||||
{
|
||||
switch (svc_in_progress) {
|
||||
case AICS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_AICS_STATE_VAL ||
|
||||
attr_uuid == BT_UUID_AICS_GAIN_SETTINGS_VAL ||
|
||||
attr_uuid == BT_UUID_AICS_INPUT_TYPE_VAL ||
|
||||
attr_uuid == BT_UUID_AICS_INPUT_STATUS_VAL ||
|
||||
attr_uuid == BT_UUID_AICS_CONTROL_VAL ||
|
||||
attr_uuid == BT_UUID_AICS_DESCRIPTION_VAL);
|
||||
|
||||
case ASCS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_ASCS_ASE_SNK_VAL ||
|
||||
attr_uuid == BT_UUID_ASCS_ASE_SRC_VAL ||
|
||||
attr_uuid == BT_UUID_ASCS_ASE_CP_VAL);
|
||||
|
||||
case BASS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_BASS_CONTROL_POINT_VAL ||
|
||||
attr_uuid == BT_UUID_BASS_RECV_STATE_VAL);
|
||||
|
||||
case CAS_IN_PROGRESS:
|
||||
/* No characteristic in CAS */
|
||||
return false;
|
||||
|
||||
case CSIS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_CSIS_SIRK_VAL ||
|
||||
attr_uuid == BT_UUID_CSIS_SET_SIZE_VAL ||
|
||||
attr_uuid == BT_UUID_CSIS_SET_LOCK_VAL ||
|
||||
attr_uuid == BT_UUID_CSIS_RANK_VAL);
|
||||
|
||||
case HAS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_HAS_HEARING_AID_FEATURES_VAL ||
|
||||
attr_uuid == BT_UUID_HAS_PRESET_CONTROL_POINT_VAL ||
|
||||
attr_uuid == BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL);
|
||||
|
||||
case GMCS_IN_PROGRESS:
|
||||
case MCS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_MCS_PLAYER_NAME_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_ICON_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_ICON_URL_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_TRACK_CHANGED_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_TRACK_TITLE_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_TRACK_DURATION_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_TRACK_POSITION_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_PLAYBACK_SPEED_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_SEEKING_SPEED_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_PLAYING_ORDER_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_PLAYING_ORDERS_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_MEDIA_STATE_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL ||
|
||||
attr_uuid == BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL ||
|
||||
attr_uuid == BT_UUID_CCID_VAL);
|
||||
|
||||
case MICS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_MICS_MUTE_VAL);
|
||||
|
||||
case PACS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_PACS_SNK_VAL ||
|
||||
attr_uuid == BT_UUID_PACS_SNK_LOC_VAL ||
|
||||
attr_uuid == BT_UUID_PACS_SRC_VAL ||
|
||||
attr_uuid == BT_UUID_PACS_SRC_LOC_VAL ||
|
||||
attr_uuid == BT_UUID_PACS_AVAILABLE_CONTEXT_VAL ||
|
||||
attr_uuid == BT_UUID_PACS_SUPPORTED_CONTEXT_VAL);
|
||||
|
||||
case GTBS_IN_PROGRESS:
|
||||
case TBS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_TBS_PROVIDER_NAME_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_UCI_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_TECHNOLOGY_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_URI_LIST_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_SIGNAL_STRENGTH_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_SIGNAL_INTERVAL_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_LIST_CURRENT_CALLS_VAL ||
|
||||
attr_uuid == BT_UUID_CCID_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_STATUS_FLAGS_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_INCOMING_URI_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_CALL_STATE_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_CALL_CONTROL_POINT_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_OPTIONAL_OPCODES_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_TERMINATE_REASON_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_INCOMING_CALL_VAL ||
|
||||
attr_uuid == BT_UUID_TBS_FRIENDLY_NAME_VAL);
|
||||
|
||||
case TMAS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_GATT_TMAPR_VAL);
|
||||
|
||||
case VCS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_VCS_STATE_VAL ||
|
||||
attr_uuid == BT_UUID_VCS_CONTROL_VAL ||
|
||||
attr_uuid == BT_UUID_VCS_FLAGS_VAL);
|
||||
|
||||
case VOCS_IN_PROGRESS:
|
||||
return (attr_uuid == BT_UUID_VOCS_STATE_VAL ||
|
||||
attr_uuid == BT_UUID_VOCS_LOCATION_VAL ||
|
||||
attr_uuid == BT_UUID_VOCS_CONTROL_VAL ||
|
||||
attr_uuid == BT_UUID_VOCS_DESCRIPTION_VAL);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct inc_svc_inst *get_not_included_inst(void)
|
||||
{
|
||||
switch (svc_in_progress) {
|
||||
#if CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER
|
||||
case CAS_IN_PROGRESS:
|
||||
extern struct inc_svc_inst *cas_not_included_inst(void);
|
||||
return cas_not_included_inst();
|
||||
#endif /* CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER */
|
||||
|
||||
#if CONFIG_BT_MICP_MIC_DEV
|
||||
case MICS_IN_PROGRESS:
|
||||
extern struct inc_svc_inst *mics_not_included_inst(void);
|
||||
return mics_not_included_inst();
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
|
||||
#if CONFIG_BT_VCP_VOL_REND
|
||||
case VCS_IN_PROGRESS:
|
||||
extern struct inc_svc_inst *vcs_not_included_inst(void);
|
||||
return vcs_not_included_inst();
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_svc_inst_id(uint16_t svc_uuid)
|
||||
{
|
||||
/* Note:
|
||||
* For LE Audio, some service could have multiple instances.
|
||||
*/
|
||||
|
||||
static uint8_t aics_count;
|
||||
static uint8_t csis_count;
|
||||
static uint8_t vocs_count;
|
||||
static uint8_t mcs_count;
|
||||
static uint8_t ots_count;
|
||||
static uint8_t tbs_count;
|
||||
|
||||
switch (svc_uuid) {
|
||||
case BT_UUID_AICS_VAL:
|
||||
return aics_count++;
|
||||
|
||||
case BT_UUID_CSIS_VAL:
|
||||
return csis_count++;
|
||||
|
||||
case BT_UUID_VOCS_VAL:
|
||||
return vocs_count++;
|
||||
|
||||
case BT_UUID_MCS_VAL:
|
||||
return mcs_count++;
|
||||
|
||||
case BT_UUID_OTS_VAL:
|
||||
return ots_count++;
|
||||
|
||||
case BT_UUID_TBS_VAL:
|
||||
return tbs_count++;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_svc_init(struct bt_gatt_service *svc)
|
||||
{
|
||||
struct bt_gatt_attr *curr_attr;
|
||||
struct bt_gatt_attr *next_attr;
|
||||
struct inc_svc_inst *inc_inst;
|
||||
struct bt_gatt_chrc *chrc;
|
||||
tBTA_GATT_PERM perm;
|
||||
uint16_t attr_uuid;
|
||||
uint8_t inst_id;
|
||||
tBT_UUID uuid;
|
||||
|
||||
assert(svc);
|
||||
|
||||
for (size_t i = 0; i < svc->attr_count; i++) {
|
||||
curr_attr = &svc->attrs[i];
|
||||
|
||||
attr_uuid = BT_UUID_16(curr_attr->uuid)->val;
|
||||
|
||||
switch (attr_uuid) {
|
||||
case BT_UUID_GATT_PRIMARY_VAL:
|
||||
if (is_primary_svc() == false) {
|
||||
LOG_ERR("[B]NotCreatingPrimary");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(curr_attr->user_data);
|
||||
|
||||
bt_le_bluedroid_gatt_uuid_convert(curr_attr->user_data, &uuid);
|
||||
inst_id = get_svc_inst_id(uuid.uu.uuid16);
|
||||
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_CreateService(bt_le_bluedroid_gatts_get_if(), &uuid, inst_id, svc->attr_count, true);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]PrimaryCreateFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curr_attr->handle = svc_handle;
|
||||
|
||||
LOG_INF("[B]PrimarySvc[%s][0x%04x][%u][0x%04x][%d]",
|
||||
audio_svc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
|
||||
inst_id, curr_attr->perm, svc_handle);
|
||||
break;
|
||||
|
||||
case BT_UUID_GATT_SECONDARY_VAL:
|
||||
if (is_secondary_svc() == false) {
|
||||
LOG_ERR("[B]NotCreatingSecondary");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(curr_attr->user_data);
|
||||
|
||||
bt_le_bluedroid_gatt_uuid_convert(curr_attr->user_data, &uuid);
|
||||
inst_id = get_svc_inst_id(uuid.uu.uuid16);
|
||||
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_CreateService(bt_le_bluedroid_gatts_get_if(), &uuid, inst_id, svc->attr_count, false);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]SecondaryCreateFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curr_attr->handle = svc_handle;
|
||||
|
||||
LOG_INF("[B]SecondarySvc[%s][0x%04x][%u][0x%04x][%d]",
|
||||
audio_svc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
|
||||
inst_id, curr_attr->perm, svc_handle);
|
||||
break;
|
||||
|
||||
case BT_UUID_GATT_INCLUDE_VAL:
|
||||
if (any_included_svc() == false) {
|
||||
LOG_ERR("[B]NoSvcToInc[%u]", svc_in_progress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
inc_inst = get_not_included_inst();
|
||||
|
||||
if (inc_inst == NULL) {
|
||||
LOG_ERR("[B]IncSvcNotFound[%u]", svc_in_progress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_AddIncludeService(svc_handle, inc_inst->svc_p->attrs[0].handle);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]IncSvcAddFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curr_attr->handle = inc_svc_handle;
|
||||
inc_inst->included = true; /* Mark the svc as included */
|
||||
|
||||
LOG_INF("[B]IncSvc[%s][0x%04x][0x%04x][%d]",
|
||||
audio_svc_uuid_to_str(BT_UUID_16(inc_inst->svc_p->attrs[0].user_data)->val),
|
||||
BT_UUID_16(inc_inst->svc_p->attrs[0].user_data)->val,
|
||||
curr_attr->perm, inc_svc_handle);
|
||||
break;
|
||||
|
||||
case BT_UUID_GATT_CHRC_VAL:
|
||||
/* Chrc declaration must be followed by its value attribute.
|
||||
* Standard BT_GATT_CHARACTERISTIC pairs them, but guard against
|
||||
* a malformed table where it is the last entry. */
|
||||
if (i + 1 >= svc->attr_count) {
|
||||
LOG_ERR("[B]ChrcDeclLastAttr[%u]", svc_in_progress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
next_attr = &svc->attrs[i + 1];
|
||||
perm = bt_le_bluedroid_gatt_perm_convert(next_attr->perm);
|
||||
|
||||
assert(curr_attr->user_data);
|
||||
|
||||
chrc = curr_attr->user_data;
|
||||
bt_le_bluedroid_gatt_uuid_convert(chrc->uuid, &uuid);
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_AddCharacteristic(svc_handle, &uuid, perm, chrc->properties, NULL, NULL);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]ChrcAddFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Characteristic declaration handle and Characteristic value handle */
|
||||
curr_attr->handle = chrc_handle - 1;
|
||||
next_attr->handle = chrc_handle;
|
||||
|
||||
LOG_INF("[B]Chrc[%s][0x%04x][%u][%u][0x%04x][0x%02x]",
|
||||
audio_chrc_uuid_to_str(uuid.uu.uuid16), uuid.uu.uuid16,
|
||||
chrc_handle - 1, chrc_handle, next_attr->perm, chrc->properties);
|
||||
break;
|
||||
|
||||
case BT_UUID_GATT_CCC_VAL:
|
||||
perm = bt_le_bluedroid_gatt_perm_convert(curr_attr->perm);
|
||||
bt_le_bluedroid_gatt_uuid_convert(curr_attr->uuid, &uuid);
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_AddCharDescriptor(svc_handle, perm, &uuid, NULL, NULL);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]ChrcCccdAddFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curr_attr->handle = chrc_handle;
|
||||
|
||||
LOG_INF("[B]ChrcCccd[%u][0x%04x]", chrc_handle, curr_attr->perm);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_svc_attr_uuid_valid(attr_uuid) == false) {
|
||||
LOG_ERR("[B]InvSvcAttrUuid[0x%04x][%u]", attr_uuid, svc_in_progress);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_svc_start(struct bt_gatt_service *svc)
|
||||
{
|
||||
assert(svc);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bt_le_bluedroid_gatts_sem_reset();
|
||||
BTA_GATTS_StartService(svc_handle, BTA_GATT_TRANSPORT_LE);
|
||||
|
||||
if (bt_le_bluedroid_gatts_sem_take()) {
|
||||
LOG_ERR("[B]SvcStartFail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -313,13 +313,18 @@ static int nimble_gatt_csis_init(struct bt_le_audio_start_info *info,
|
||||
}
|
||||
|
||||
csis_svc[count] = lib_csip_set_member_svc_get(info->csis_insts[i].svc_inst);
|
||||
assert(csis_svc[count]);
|
||||
if (!csis_svc[count]) {
|
||||
LOG_ERR("[N]CsisSvcGetFail[%u]", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (info->csis_insts[i].included_by_cas) {
|
||||
if (*inc_csis_svc == NULL) {
|
||||
*inc_csis_svc = csis_svc[count];
|
||||
} else {
|
||||
assert(0);
|
||||
/* CAS may include at most one CSIS — caller misconfigured. */
|
||||
LOG_ERR("[N]CsisMultiIncByCas");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -122,7 +122,10 @@ int bt_le_nimble_ascs_attr_handle_set(void)
|
||||
}
|
||||
|
||||
ascs_svc = lib_ascs_svc_get();
|
||||
assert(ascs_svc);
|
||||
if (!ascs_svc) {
|
||||
LOG_ERR("[N]AscsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
assert(ase_control_point_handle >= 2);
|
||||
start_handle = ase_control_point_handle - 2; /* server attr handle & char def handle */
|
||||
@@ -164,7 +167,10 @@ static int ascs_svc_check(void)
|
||||
*/
|
||||
|
||||
ascs_svc = lib_ascs_svc_get();
|
||||
assert(ascs_svc);
|
||||
if (!ascs_svc) {
|
||||
LOG_ERR("[N]AscsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]AscsSvcCheck");
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -98,7 +98,10 @@ int bt_le_nimble_bass_attr_handle_set(void)
|
||||
}
|
||||
|
||||
bass_svc = lib_bap_bass_svc_get();
|
||||
assert(bass_svc);
|
||||
if (!bass_svc) {
|
||||
LOG_ERR("[N]BassSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
assert(bass_control_point_handle >= 2);
|
||||
start_handle = bass_control_point_handle - 2; /* server attr handle & char def handle */
|
||||
@@ -134,7 +137,10 @@ static int bass_svc_check(void)
|
||||
*/
|
||||
|
||||
bass_svc = lib_bap_bass_svc_get();
|
||||
assert(bass_svc);
|
||||
if (!bass_svc) {
|
||||
LOG_ERR("[N]BassSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]BassSvcCheck");
|
||||
|
||||
|
||||
@@ -60,7 +60,10 @@ int bt_le_nimble_cas_attr_handle_set(void)
|
||||
}
|
||||
|
||||
cas_svc = lib_cas_svc_get();
|
||||
assert(cas_svc);
|
||||
if (!cas_svc) {
|
||||
LOG_ERR("[N]CasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]CasAttrHdlSet[%u][%u]", handle, cas_svc->attr_count);
|
||||
|
||||
@@ -113,7 +116,10 @@ int bt_le_nimble_cas_init(void *csis_svc_p)
|
||||
struct bt_gatt_service *cas_svc;
|
||||
|
||||
cas_svc = lib_cas_svc_get();
|
||||
assert(cas_svc);
|
||||
if (!cas_svc) {
|
||||
LOG_ERR("[N]CasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Insert CAS to the GATT db list */
|
||||
rc = bt_gatt_service_register_safe(cas_svc);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -120,7 +120,10 @@ int bt_le_nimble_has_attr_handle_set(void)
|
||||
}
|
||||
|
||||
has_svc = lib_has_svc_get();
|
||||
assert(has_svc);
|
||||
if (!has_svc) {
|
||||
LOG_ERR("[N]HasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
assert(has_svc->attr_count > 0);
|
||||
|
||||
end_handle = start_handle + has_svc->attr_count - 1;
|
||||
@@ -136,7 +139,7 @@ int bt_le_nimble_has_attr_handle_set(void)
|
||||
attr = has_svc->attrs + has_svc->attr_count - 1;
|
||||
|
||||
if (attr->handle != end_handle) {
|
||||
LOG_ERR("[N]HasMismatchAttrHdl (%u %u %u %u)",
|
||||
LOG_ERR("[N]HasMismatchAttrHdl[%u][%u][%u][%u]",
|
||||
start_handle, end_handle, attr->handle, has_svc->attr_count);
|
||||
return -1;
|
||||
}
|
||||
@@ -155,7 +158,10 @@ static int has_svc_check(void)
|
||||
*/
|
||||
|
||||
has_svc = lib_has_svc_get();
|
||||
assert(has_svc);
|
||||
if (!has_svc) {
|
||||
LOG_ERR("[N]HasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]HasSvcCheck");
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -403,7 +403,10 @@ int bt_le_nimble_gmcs_attr_handle_set(void)
|
||||
}
|
||||
|
||||
gmcs_svc = lib_mcs_svc_get();
|
||||
assert(gmcs_svc);
|
||||
if (!gmcs_svc) {
|
||||
LOG_ERR("[N]GmcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
end_handle = start_handle + gmcs_svc->attr_count - 1;
|
||||
|
||||
@@ -446,7 +449,10 @@ static int gmcs_svc_check(void)
|
||||
*/
|
||||
|
||||
gmcs_svc = lib_mcs_svc_get();
|
||||
assert(gmcs_svc);
|
||||
if (!gmcs_svc) {
|
||||
LOG_ERR("[N]GmcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]GmcsSvcCheck");
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -159,7 +159,10 @@ static int mics_svc_check(void)
|
||||
bool chr_found;
|
||||
|
||||
mics_svc = lib_mics_svc_get();
|
||||
assert(mics_svc);
|
||||
if (!mics_svc) {
|
||||
LOG_ERR("[N]MicsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]MicsSvcCheck");
|
||||
|
||||
@@ -244,7 +247,10 @@ int bt_le_nimble_mics_attr_handle_set(void)
|
||||
}
|
||||
|
||||
mics_svc = lib_mics_svc_get();
|
||||
assert(mics_svc);
|
||||
if (!mics_svc) {
|
||||
LOG_ERR("[N]MicsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
end_handle = start_handle + mics_svc->attr_count - 1;
|
||||
|
||||
@@ -379,6 +385,11 @@ int bt_le_nimble_mics_init(void *micp_inc)
|
||||
inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]);
|
||||
|
||||
inc_aics_insts[i].svc_p = lib_aics_svc_get(micp_included->aics[i]);
|
||||
if (!inc_aics_insts[i].svc_p) {
|
||||
LOG_ERR("[N]AicsSvcGetFail[%u]", i);
|
||||
rc = -ENODEV;
|
||||
goto free;
|
||||
}
|
||||
|
||||
mics_inc_svcs[i] = &gatt_svc_inc_aics[i];
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -166,7 +166,10 @@ int bt_le_nimble_pacs_attr_handle_set(void)
|
||||
uint16_t end_handle = 0;
|
||||
|
||||
pacs_svc = lib_pacs_svc_get();
|
||||
assert(pacs_svc);
|
||||
if (!pacs_svc) {
|
||||
LOG_ERR("[N]PacsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_PAC_SNK
|
||||
assert(pacs_snk_handle >= 2);
|
||||
@@ -214,7 +217,10 @@ static int pacs_svc_check(void)
|
||||
*/
|
||||
|
||||
pacs_svc = lib_pacs_svc_get();
|
||||
assert(pacs_svc);
|
||||
if (!pacs_svc) {
|
||||
LOG_ERR("[N]PacsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]PacsSvcCheck");
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -178,7 +178,10 @@ int bt_le_nimble_gtbs_attr_handle_set(void)
|
||||
}
|
||||
|
||||
gtbs_svc = lib_gtbs_svc_get();
|
||||
assert(gtbs_svc);
|
||||
if (!gtbs_svc) {
|
||||
LOG_ERR("[N]GtbsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]GtbsAttrHdlSet[%u][%u]", handle, gtbs_svc->attr_count);
|
||||
|
||||
@@ -200,7 +203,10 @@ static int gtbs_svc_check(void)
|
||||
*/
|
||||
|
||||
gtbs_svc = lib_gtbs_svc_get();
|
||||
assert(gtbs_svc);
|
||||
if (!gtbs_svc) {
|
||||
LOG_ERR("[N]GtbsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]GtbsSvcCheck");
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -71,7 +71,10 @@ int bt_le_nimble_tmas_attr_handle_set(void)
|
||||
}
|
||||
|
||||
tmas_svc = lib_tmas_svc_get();
|
||||
assert(tmas_svc);
|
||||
if (!tmas_svc) {
|
||||
LOG_ERR("[N]TmasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]TmasAttrHdlSet[%u][%u]", handle, tmas_svc->attr_count);
|
||||
|
||||
@@ -93,7 +96,10 @@ static int tmas_svc_check(void)
|
||||
*/
|
||||
|
||||
tmas_svc = lib_tmas_svc_get();
|
||||
assert(tmas_svc);
|
||||
if (!tmas_svc) {
|
||||
LOG_ERR("[N]TmasSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]TmasSvcCheck");
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "host/ble_gatt.h"
|
||||
#include "host/ble_hs_mbuf.h"
|
||||
|
||||
#include "nimble/profiles/server.h"
|
||||
#include "nimble/server.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
@@ -261,7 +261,10 @@ static int vcs_svc_check(void)
|
||||
*/
|
||||
|
||||
vcs_svc = lib_vcs_svc_get();
|
||||
assert(vcs_svc);
|
||||
if (!vcs_svc) {
|
||||
LOG_ERR("[N]VcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]VCSSvcCheck");
|
||||
|
||||
@@ -380,7 +383,10 @@ int bt_le_nimble_vcs_attr_handle_set(void)
|
||||
}
|
||||
|
||||
vcs_svc = lib_vcs_svc_get();
|
||||
assert(vcs_svc);
|
||||
if (!vcs_svc) {
|
||||
LOG_ERR("[N]VcsSvcGetFail");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
end_handle = start_handle + vcs_svc->attr_count - 1;
|
||||
|
||||
@@ -576,6 +582,11 @@ int bt_le_nimble_vcs_init(void *vcp_inc)
|
||||
inc_vocs_svc_init(&inc_vocs_insts[i], &gatt_svc_inc_vocs[i]);
|
||||
|
||||
inc_vocs_insts[i].svc_p = lib_vocs_svc_get(vcp_included->vocs[i]);
|
||||
if (!inc_vocs_insts[i].svc_p) {
|
||||
LOG_ERR("[N]VocsSvcGetFail[%u]", i);
|
||||
rc = -ENODEV;
|
||||
goto free;
|
||||
}
|
||||
|
||||
vcs_inc_svcs[i] = &gatt_svc_inc_vocs[i];
|
||||
}
|
||||
@@ -608,6 +619,11 @@ int bt_le_nimble_vcs_init(void *vcp_inc)
|
||||
inc_aics_svc_init(&inc_aics_insts[i], &gatt_svc_inc_aics[i]);
|
||||
|
||||
inc_aics_insts[i].svc_p = lib_aics_svc_get(vcp_included->aics[i]);
|
||||
if (!inc_aics_insts[i].svc_p) {
|
||||
LOG_ERR("[N]AicsSvcGetFail[%u]", i);
|
||||
rc = -ENODEV;
|
||||
goto free;
|
||||
}
|
||||
|
||||
vcs_inc_svcs[inc_vocs_svc_count + i] = &gatt_svc_inc_aics[i];
|
||||
}
|
||||
@@ -670,13 +686,17 @@ free:
|
||||
}
|
||||
|
||||
if (inc_aics_svc_count) {
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
free((void *)gatt_svc_inc_aics[i].characteristics);
|
||||
gatt_svc_inc_aics[i].characteristics = NULL;
|
||||
}
|
||||
/* A VOCS-phase failure reaches here with the count already set
|
||||
* but gatt_svc_inc_aics not yet allocated (still NULL). */
|
||||
if (gatt_svc_inc_aics) {
|
||||
for (size_t i = 0; i < inc_aics_svc_count; i++) {
|
||||
free((void *)gatt_svc_inc_aics[i].characteristics);
|
||||
gatt_svc_inc_aics[i].characteristics = NULL;
|
||||
}
|
||||
|
||||
free(gatt_svc_inc_aics);
|
||||
gatt_svc_inc_aics = NULL;
|
||||
free(gatt_svc_inc_aics);
|
||||
gatt_svc_inc_aics = NULL;
|
||||
}
|
||||
|
||||
inc_aics_svc_count = 0;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,11 @@
|
||||
#include <../host/conn_internal.h>
|
||||
#include <../host/hci_core.h>
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/init.h"
|
||||
#else
|
||||
#include "nimble/init.h"
|
||||
#endif
|
||||
|
||||
#include "../../../lib/include/audio.h"
|
||||
|
||||
@@ -2091,7 +2095,11 @@ int bt_le_audio_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_audio_init();
|
||||
#else
|
||||
return bt_le_nimble_audio_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BLE_AUDIO_SVC_DEFERRED_ADD
|
||||
@@ -2100,7 +2108,11 @@ int bt_le_ascs_init(void)
|
||||
{
|
||||
LOG_DBG("AscsInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_ascs_init();
|
||||
#else
|
||||
return bt_le_nimble_ascs_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_ASCS */
|
||||
|
||||
@@ -2109,7 +2121,11 @@ int bt_le_bass_init(void)
|
||||
{
|
||||
LOG_DBG("BassInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_bass_init();
|
||||
#else
|
||||
return bt_le_nimble_bass_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
|
||||
|
||||
@@ -2118,7 +2134,11 @@ int bt_le_tmas_init(void)
|
||||
{
|
||||
LOG_DBG("TmasInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_tmas_init();
|
||||
#else
|
||||
return bt_le_nimble_tmas_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_TMAP */
|
||||
|
||||
@@ -2127,7 +2147,11 @@ int bt_le_gtbs_init(void)
|
||||
{
|
||||
LOG_DBG("GtbsInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gtbs_init();
|
||||
#else
|
||||
return bt_le_nimble_gtbs_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_TBS */
|
||||
|
||||
@@ -2136,7 +2160,11 @@ int bt_le_has_init(void)
|
||||
{
|
||||
LOG_DBG("HasInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_has_init();
|
||||
#else
|
||||
return bt_le_nimble_has_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_HAS */
|
||||
|
||||
@@ -2145,7 +2173,11 @@ int bt_le_media_proxy_pl_init(void)
|
||||
{
|
||||
LOG_DBG("MprxPlInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_media_proxy_pl_init();
|
||||
#else
|
||||
return bt_le_nimble_media_proxy_pl_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_MCS */
|
||||
|
||||
@@ -2154,7 +2186,11 @@ int bt_le_vcp_vol_rend_init(void)
|
||||
{
|
||||
LOG_DBG("VcpVolRendInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_vcp_vol_rend_init();
|
||||
#else
|
||||
return bt_le_nimble_vcp_vol_rend_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_VCP_VOL_REND */
|
||||
|
||||
@@ -2163,7 +2199,11 @@ int bt_le_micp_mic_dev_init(void)
|
||||
{
|
||||
LOG_DBG("MicpMicDevInit");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_micp_mic_dev_init();
|
||||
#else
|
||||
return bt_le_nimble_micp_mic_dev_init();
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_BT_MICP_MIC_DEV */
|
||||
#endif /* BLE_AUDIO_SVC_DEFERRED_ADD */
|
||||
@@ -2172,7 +2212,11 @@ int bt_le_audio_start(void *info)
|
||||
{
|
||||
LOG_DBG("AudioStart");
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_audio_start(info);
|
||||
#else
|
||||
return bt_le_nimble_audio_start(info);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ble_audio_lib_compressed_out(uint8_t log_level, uint32_t log_index, size_t arg_cnt, ...)
|
||||
|
||||
@@ -15,12 +15,24 @@ if(CONFIG_BT_CONTROLLER_ONLY OR NOT CONFIG_BT_ISO)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND ble_iso_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.db.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.nrp.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gap.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/iso.c"
|
||||
)
|
||||
elseif(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND ble_iso_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/bluedroid/hci.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/bluedroid/iso.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/bluedroid/gap.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/bluedroid/gatt/gatt.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND ble_iso_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.db.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gatt/gatt.nrp.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/gap.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/iso.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/adv.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/conn.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/gatt.c"
|
||||
@@ -45,23 +57,37 @@ list(APPEND ble_iso_srcs
|
||||
)
|
||||
|
||||
# L2CAP host shim wiring is currently only consumed by the OTS service
|
||||
# (which lives in esp_ble_audio). Keep the same gate so build output
|
||||
# matches the pre-split behavior; the .c files belong to the host shim.
|
||||
# (which lives in esp_ble_audio). common/l2cap.c has both host branches
|
||||
# (Bluedroid returns -ENOTSUP), so compile it under either host whenever
|
||||
# OTS is enabled; the NimBLE-only adapter glue stays NimBLE-gated.
|
||||
if(CONFIG_BT_OTS OR CONFIG_BT_OTS_CLIENT)
|
||||
list(APPEND ble_iso_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/l2cap.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/l2cap.c"
|
||||
)
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND ble_iso_srcs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/l2cap.c"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND ble_iso_include_dirs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/api/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/common/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/include"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/subsys/bluetooth"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/subsys/bluetooth/host"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include"
|
||||
)
|
||||
|
||||
if(CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND ble_iso_include_dirs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/nimble/include"
|
||||
)
|
||||
elseif(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND ble_iso_include_dirs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host/adapter/bluedroid/include"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(ble_iso_srcs "${ble_iso_srcs}" PARENT_SCOPE)
|
||||
set(ble_iso_include_dirs "${ble_iso_include_dirs}" PARENT_SCOPE)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
config BT_ISO
|
||||
bool
|
||||
select BT_NIMBLE_ISO if BT_NIMBLE_ENABLED
|
||||
select BT_BLE_FEAT_ISO_EN if BT_BLUEDROID_ENABLED
|
||||
|
||||
config BT_ISO_TX
|
||||
bool
|
||||
@@ -44,7 +45,6 @@ config BT_ISO_BROADCASTER
|
||||
bool "Bluetooth Isochronous Broadcaster Support"
|
||||
select BT_ISO_BROADCAST
|
||||
select BT_ISO_TX
|
||||
select BT_BROADCASTER
|
||||
help
|
||||
This option enables support for the Bluetooth Isochronous Broadcaster.
|
||||
|
||||
@@ -68,6 +68,7 @@ if BT_ISO
|
||||
|
||||
config BT_ISO_TEST_PARAMS
|
||||
bool "ISO test parameters support"
|
||||
default y if BT_BLUEDROID_ENABLED
|
||||
default BT_NIMBLE_ISO_TEST if BT_NIMBLE_ENABLED
|
||||
help
|
||||
Enabling advanced ISO parameters will allow the use of the ISO test
|
||||
@@ -79,7 +80,10 @@ if BT_ISO
|
||||
|
||||
config BT_ISO_MAX_CIG
|
||||
int "Maximum number of Connected Isochronous Groups (CIGs) to support"
|
||||
range 1 BT_NIMBLE_ISO_CIG
|
||||
range 1 1 if BT_BLUEDROID_ENABLED
|
||||
range 1 BT_NIMBLE_ISO_CIG if BT_NIMBLE_ENABLED
|
||||
default 1 if BT_BLUEDROID_ENABLED
|
||||
default BT_NIMBLE_ISO_CIG if BT_NIMBLE_ENABLED
|
||||
help
|
||||
Maximum number of CIGs that are supported by the host. A CIG can be
|
||||
used for either transmitting or receiving.
|
||||
@@ -90,7 +94,10 @@ if BT_ISO
|
||||
|
||||
config BT_ISO_MAX_BIG
|
||||
int "Maximum number of Broadcast Isochronous Groups (BIGs) to support"
|
||||
range 1 BT_NIMBLE_ISO_BIG
|
||||
range 1 1 if BT_BLUEDROID_ENABLED
|
||||
range 1 BT_NIMBLE_ISO_BIG if BT_NIMBLE_ENABLED
|
||||
default 1 if BT_BLUEDROID_ENABLED
|
||||
default BT_NIMBLE_ISO_BIG if BT_NIMBLE_ENABLED
|
||||
help
|
||||
Maximum number of BIGs that are supported by the host. A BIG can be
|
||||
used for either transmitting or receiving, but not at the same time.
|
||||
|
||||
@@ -430,3 +430,10 @@ unregister_gap:
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
uint8_t esp_ble_iso_bluedroid_get_gattc_if(void)
|
||||
{
|
||||
return bt_le_bluedroid_gattc_get_if();
|
||||
}
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
@@ -591,6 +591,21 @@ void esp_ble_iso_gap_app_post_event(uint8_t type, void *param);
|
||||
*/
|
||||
esp_err_t esp_ble_iso_common_init(esp_ble_iso_init_info_t *info);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Get the engine's internal GATTC interface handle (Bluedroid only).
|
||||
*
|
||||
* Pass this to esp_ble_gattc_aux_open() / esp_ble_gattc_open() so the
|
||||
* resulting ACL events route back to the engine, avoiding the need for the
|
||||
* application to register a second BTA GATTC app for connection initiation.
|
||||
*
|
||||
* @return Engine's gattc_if (ABI-compatible with esp_gatt_if_t), or
|
||||
* ESP_GATT_IF_NONE (0xFF) if GATTC registration has not completed —
|
||||
* callers must bail rather than pass it to aux_open.
|
||||
*/
|
||||
uint8_t esp_ble_iso_bluedroid_get_gattc_if(void);
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
506
components/bt/esp_ble_iso/host/adapter/bluedroid/gap.c
Normal file
506
components/bt/esp_ble_iso/host/adapter/bluedroid/gap.c
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/bluetooth/buf.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
|
||||
#include <../host/hci_core.h>
|
||||
#include <../host/iso_internal.h>
|
||||
|
||||
#include "bta/bta_api.h"
|
||||
#include "stack/btm_ble_api.h"
|
||||
#include "stack/hcidefs.h"
|
||||
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gattc_api.h"
|
||||
#include "esp_gatts_api.h"
|
||||
|
||||
#include "bluedroid/btm_error.h"
|
||||
#include "bluedroid/hci.h"
|
||||
|
||||
#include "common/host.h"
|
||||
#include "common/app/gap.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_BGAP, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
extern void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event,
|
||||
tBTA_DM_BLE_5_GAP_CB_PARAMS *params);
|
||||
|
||||
#if (BLE_50_EXTEND_SYNC_EN == TRUE)
|
||||
/* Active PA sync handle tracker. Used to synthesize a PA_SYNC_LOST event
|
||||
* to the iso task when the application calls
|
||||
* esp_ble_gap_periodic_adv_sync_terminate(): Bluedroid's
|
||||
* BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT only carries a
|
||||
* status byte and lacks sync_handle, so we recover it from here. This
|
||||
* mirrors NimBLE host behavior, where ble_gap_periodic_adv_sync_terminate
|
||||
* internally enqueues a sync_lost event.
|
||||
*
|
||||
* The tracker is populated by both PA_SYNC_ESTAB (direct scan-and-sync)
|
||||
* and PA_SYNC_TRANS_RECV (PAST-delivered sync) on success, and cleared
|
||||
* by real PA_SYNC_LOST or by the synthesized terminate path below.
|
||||
*
|
||||
* Single-slot — assumes one active PA sync (and at most one in-flight
|
||||
* terminate) at a time. The audio examples never hold multiple PA syncs
|
||||
* concurrently. Multi-sync acceptors / Broadcast Assistants will need an
|
||||
* N-slot tracker plus per-terminate intent capture.
|
||||
*
|
||||
* TODO(bluedroid): drop this once
|
||||
* BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT also surfaces
|
||||
* sync_handle (BTM_BlePeriodicAdvSyncTerm in btm_ble_5_gap.c knows the
|
||||
* handle, it just isn't propagated into cb_params). Ideally Bluedroid
|
||||
* would directly synthesize a SYNC_LOST event on successful terminate,
|
||||
* matching the NimBLE host contract; then both this tracker and the
|
||||
* synthesis below become dead code. */
|
||||
#define ISO_PA_SYNC_HANDLE_NONE 0xFFFF
|
||||
static uint16_t active_pa_sync_handle = ISO_PA_SYNC_HANDLE_NONE;
|
||||
#endif /* BLE_50_EXTEND_SYNC_EN == TRUE */
|
||||
|
||||
/* Fast-path BTA → iso-queue post.
|
||||
*
|
||||
* BTU calls gap_app_cb directly; this function bypasses the BTC dispatch
|
||||
* hop for the audio-critical events so they reach the iso task in the same
|
||||
* order BTU received them. BIGINFO_ADV_REPORT already posts directly from
|
||||
* iso_evt_handler; routing PA_SYNC_ESTAB / PA_SYNC_LOST / EXT_ADV_REPORT /
|
||||
* PAST_RECV the same way keeps both event streams ordered. */
|
||||
static void bt_le_bluedroid_gap_post_event_bta(tBTA_DM_BLE_5_GAP_EVENT event,
|
||||
tBTA_DM_BLE_5_GAP_CB_PARAMS *params);
|
||||
|
||||
static void gap_app_cb(tBTA_DM_BLE_5_GAP_EVENT event, tBTA_DM_BLE_5_GAP_CB_PARAMS *params)
|
||||
{
|
||||
/* Audio-critical data events: post directly to iso task here to keep
|
||||
* ordering with BIGINFO_ADV_REPORT (which iso_evt_handler also posts
|
||||
* directly). The BTC dispatch below still runs for non-audio recipients
|
||||
* of esp_ble_gap_register_callback. */
|
||||
switch (event) {
|
||||
#if (BLE_50_EXTEND_SCAN_EN == TRUE)
|
||||
case BTM_BLE_5_GAP_EXT_ADV_REPORT_EVT:
|
||||
#endif
|
||||
#if (BLE_50_EXTEND_SYNC_EN == TRUE)
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_ESTAB_EVT:
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_LOST_EVT:
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT:
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_REPORT_EVT:
|
||||
#endif
|
||||
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
|
||||
case BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_RECV_EVT:
|
||||
#endif
|
||||
bt_le_bluedroid_gap_post_event_bta(event, params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Forward to BTC so esp_ble_gap_register_callback() recipients see it. */
|
||||
btc_ble_5_gap_callback(event, params);
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_gap_post_event(uint16_t event, void *param)
|
||||
{
|
||||
const esp_ble_gap_cb_param_t *p = param;
|
||||
struct bt_le_gap_app_param *qev = NULL;
|
||||
int err;
|
||||
|
||||
qev = calloc(1, sizeof(*qev));
|
||||
assert(qev);
|
||||
|
||||
/* Only AUTH_CMPL reaches here from the application's
|
||||
* esp_ble_gap_register_callback path. EXT_ADV_REPORT / PA_SYNC_ESTAB /
|
||||
* PA_SYNC_LOST / PAST_RECV are posted directly by gap_app_cb on the BTM
|
||||
* BLE 5 channel; SMP events have no such channel so AUTH_CMPL is the
|
||||
* only one the application must forward. */
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_AUTH_CMPL_EVT: {
|
||||
const esp_ble_auth_cmpl_t *a = &p->ble_security.auth_cmpl;
|
||||
struct gatt_conn *gatt_conn;
|
||||
uint8_t sec_level;
|
||||
|
||||
gatt_conn = bt_le_bluedroid_find_gatt_conn_with_addr(a->addr_type, a->bd_addr, false);
|
||||
if (gatt_conn == NULL) {
|
||||
LOG_ERR("[B]UnknownDevForEnc");
|
||||
free(qev);
|
||||
return;
|
||||
}
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_SECURITY_CHANGE;
|
||||
|
||||
qev->security_change.status = (a->success ? 0x00 : 0xFF);
|
||||
|
||||
/* Populate connection identity unconditionally so failure events
|
||||
* carry valid conn_handle / role / dst to the application. */
|
||||
qev->security_change.conn_handle = gatt_conn->conn_handle;
|
||||
qev->security_change.role = gatt_conn->role;
|
||||
qev->security_change.dst.type = gatt_conn->peer.type;
|
||||
memcpy(qev->security_change.dst.val, gatt_conn->peer.val, BT_ADDR_SIZE);
|
||||
|
||||
if (qev->security_change.status == 0) {
|
||||
/* Derive level from auth_mode bits (mirrors NimBLE's sec_state
|
||||
* mapping). esp_ble_auth_cmpl_t exposes neither encrypted/
|
||||
* authenticated flags nor a key_size, so MITM presence is the
|
||||
* only authenticated-vs-Just-Works signal we have. */
|
||||
if (!(a->auth_mode & ESP_LE_AUTH_REQ_MITM)) {
|
||||
sec_level = BT_SECURITY_L2;
|
||||
} else if (!(a->auth_mode & ESP_LE_AUTH_REQ_SC_ONLY)) {
|
||||
sec_level = BT_SECURITY_L3;
|
||||
} else {
|
||||
sec_level = BT_SECURITY_L4;
|
||||
}
|
||||
|
||||
qev->security_change.sec_level = sec_level;
|
||||
qev->security_change.bonded = (a->auth_mode & ESP_LE_AUTH_BOND) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_WRN("[B]GapPostEvtUnexp[%u]", event);
|
||||
free(qev);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
free(qev);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_le_bluedroid_gap_post_event_bta(tBTA_DM_BLE_5_GAP_EVENT event,
|
||||
tBTA_DM_BLE_5_GAP_CB_PARAMS *params)
|
||||
{
|
||||
struct bt_le_gap_app_param *qev = NULL;
|
||||
int err;
|
||||
|
||||
qev = calloc(1, sizeof(*qev));
|
||||
assert(qev);
|
||||
|
||||
switch (event) {
|
||||
#if (BLE_50_EXTEND_SCAN_EN == TRUE)
|
||||
case BTM_BLE_5_GAP_EXT_ADV_REPORT_EVT: {
|
||||
const tBTM_BLE_EXT_ADV_REPORT *r = ¶ms->ext_adv_report;
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_EXT_SCAN_RECV;
|
||||
|
||||
qev->ext_scan_recv.event_type = (r->data_status << 5) | r->event_type;
|
||||
qev->ext_scan_recv.addr.type = r->addr_type;
|
||||
memcpy(qev->ext_scan_recv.addr.val, r->addr, BT_ADDR_SIZE);
|
||||
/* BTM declares rssi/tx_power as UINT8; the bytes are spec-defined as
|
||||
* signed (RSSI typically negative). Cast preserves the bit pattern. */
|
||||
qev->ext_scan_recv.rssi = (int8_t)r->rssi;
|
||||
qev->ext_scan_recv.tx_power = (int8_t)r->tx_power;
|
||||
qev->ext_scan_recv.sid = r->sid;
|
||||
qev->ext_scan_recv.pri_phy = r->primary_phy;
|
||||
qev->ext_scan_recv.sec_phy = r->secondry_phy;
|
||||
qev->ext_scan_recv.per_adv_itvl = r->per_adv_interval;
|
||||
qev->ext_scan_recv.data_len = r->adv_data_len;
|
||||
|
||||
if (qev->ext_scan_recv.data_len) {
|
||||
qev->ext_scan_recv.data = calloc(1, qev->ext_scan_recv.data_len);
|
||||
assert(qev->ext_scan_recv.data);
|
||||
memcpy(qev->ext_scan_recv.data, r->adv_data, qev->ext_scan_recv.data_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BLE_50_EXTEND_SCAN_EN == TRUE */
|
||||
|
||||
#if (BLE_50_EXTEND_SYNC_EN == TRUE)
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_ESTAB_EVT: {
|
||||
const tBTM_BLE_PERIOD_ADV_SYNC_ESTAB *e = ¶ms->sync_estab;
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC;
|
||||
|
||||
qev->pa_sync.status = e->status;
|
||||
qev->pa_sync.sync_handle = e->sync_handle;
|
||||
qev->pa_sync.addr.type = e->adv_addr_type;
|
||||
memcpy(qev->pa_sync.addr.val, e->adv_addr, BT_ADDR_SIZE);
|
||||
qev->pa_sync.sid = e->sid;
|
||||
qev->pa_sync.adv_phy = e->adv_phy;
|
||||
qev->pa_sync.per_adv_itvl = e->period_adv_interval;
|
||||
qev->pa_sync.adv_ca = e->adv_clk_accuracy;
|
||||
|
||||
if (e->status == 0) {
|
||||
if (active_pa_sync_handle != ISO_PA_SYNC_HANDLE_NONE) {
|
||||
/* Concurrent PA sync: single-slot tracker overwrites the
|
||||
* existing handle, so a later terminate on the first sync
|
||||
* would synthesize SYNC_LOST against the wrong one.
|
||||
* See ISO_PA_SYNC_HANDLE_NONE doc for the multi-sync TODO. */
|
||||
LOG_WRN("[B]PaSyncEstabOverwrite[%04x->%04x]",
|
||||
active_pa_sync_handle, e->sync_handle);
|
||||
} else {
|
||||
LOG_INF("[B]PaSyncEstab[%04x]", e->sync_handle);
|
||||
}
|
||||
active_pa_sync_handle = e->sync_handle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_LOST_EVT:
|
||||
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_LOST;
|
||||
|
||||
/* Public API exposes only sync_handle; reason isn't surfaced. */
|
||||
qev->pa_sync_lost.sync_handle = params->sync_lost.sync_handle;
|
||||
qev->pa_sync_lost.reason = 0;
|
||||
|
||||
if (active_pa_sync_handle == qev->pa_sync_lost.sync_handle) {
|
||||
LOG_INF("[B]PaSyncLost[%04x]", qev->pa_sync_lost.sync_handle);
|
||||
active_pa_sync_handle = ISO_PA_SYNC_HANDLE_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT:
|
||||
/* Host-commanded terminate: synthesize PA_SYNC_LOST so the iso
|
||||
* task sees a unified sync-end event regardless of whether the
|
||||
* sync was lost on-air or torn down via
|
||||
* esp_ble_gap_periodic_adv_sync_terminate(). The complete event
|
||||
* only carries status; recover sync_handle from the tracker.
|
||||
* See ISO_PA_SYNC_HANDLE_NONE definition for limitations and
|
||||
* the Bluedroid TODO. */
|
||||
if (params->per_adv_sync_term.status != BTM_SUCCESS ||
|
||||
active_pa_sync_handle == ISO_PA_SYNC_HANDLE_NONE) {
|
||||
LOG_WRN("[B]PaSyncTermNoSynth[%02x][%04x]",
|
||||
params->per_adv_sync_term.status, active_pa_sync_handle);
|
||||
free(qev);
|
||||
return;
|
||||
}
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_LOST;
|
||||
qev->pa_sync_lost.sync_handle = active_pa_sync_handle;
|
||||
qev->pa_sync_lost.reason = 0;
|
||||
|
||||
LOG_INF("[B]PaSyncTermSynth[%04x]", active_pa_sync_handle);
|
||||
active_pa_sync_handle = ISO_PA_SYNC_HANDLE_NONE;
|
||||
break;
|
||||
|
||||
case BTM_BLE_5_GAP_PERIODIC_ADV_REPORT_EVT: {
|
||||
const tBTM_PERIOD_ADV_REPORT *r = ¶ms->period_adv_report;
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_RECV;
|
||||
|
||||
qev->pa_sync_recv.sync_handle = r->sync_handle;
|
||||
qev->pa_sync_recv.tx_power = r->tx_power;
|
||||
qev->pa_sync_recv.rssi = r->rssi;
|
||||
qev->pa_sync_recv.data_status = r->data_status;
|
||||
qev->pa_sync_recv.data_len = r->data_length;
|
||||
|
||||
if (qev->pa_sync_recv.data_len) {
|
||||
qev->pa_sync_recv.data = calloc(1, qev->pa_sync_recv.data_len);
|
||||
assert(qev->pa_sync_recv.data);
|
||||
memcpy(qev->pa_sync_recv.data, r->data, qev->pa_sync_recv.data_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BLE_50_EXTEND_SYNC_EN == TRUE */
|
||||
|
||||
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
|
||||
case BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_RECV_EVT: {
|
||||
const tBTM_BLE_PERIOD_ADV_SYNC_TRANS_RECV *r = ¶ms->past_recv;
|
||||
struct gatt_conn *gatt_conn;
|
||||
|
||||
/* Look up the PAST-delivering ACL handle by peer BDA — past_recv
|
||||
* doesn't carry addr type. */
|
||||
gatt_conn = bt_le_bluedroid_find_gatt_conn_with_addr(0, r->addr, true);
|
||||
if (gatt_conn == NULL) {
|
||||
LOG_ERR("[B]UnknownPastSrc");
|
||||
free(qev);
|
||||
return;
|
||||
}
|
||||
|
||||
qev->type = BT_LE_GAP_APP_PARAM_PA_SYNC_PAST;
|
||||
|
||||
qev->pa_sync_past.status = r->status;
|
||||
qev->pa_sync_past.sync_handle = r->sync_handle;
|
||||
qev->pa_sync_past.addr.type = r->adv_addr_type;
|
||||
memcpy(qev->pa_sync_past.addr.val, r->adv_addr, BT_ADDR_SIZE);
|
||||
qev->pa_sync_past.sid = r->adv_sid;
|
||||
qev->pa_sync_past.adv_phy = r->adv_phy;
|
||||
qev->pa_sync_past.per_adv_itvl = r->adv_interval;
|
||||
qev->pa_sync_past.adv_ca = r->adv_clk_accuracy;
|
||||
qev->pa_sync_past.conn_handle = gatt_conn->conn_handle;
|
||||
|
||||
#if (BLE_50_EXTEND_SYNC_EN == TRUE)
|
||||
/* PAST-established syncs need tracker too: a later app-initiated
|
||||
* terminate hits TERMINATE_COMPLETE_EVT regardless of how the sync
|
||||
* was originally created. Gated by BLE_50_EXTEND_SYNC_EN since
|
||||
* that's where the tracker decl + LOST/TERMINATE consumers live. */
|
||||
if (r->status == 0) {
|
||||
if (active_pa_sync_handle != ISO_PA_SYNC_HANDLE_NONE) {
|
||||
LOG_WRN("[B]PaSyncTransOverwrite[%04x->%04x]",
|
||||
active_pa_sync_handle, r->sync_handle);
|
||||
} else {
|
||||
LOG_INF("[B]PaSyncTrans[%04x]", r->sync_handle);
|
||||
}
|
||||
active_pa_sync_handle = r->sync_handle;
|
||||
}
|
||||
#endif /* BLE_50_EXTEND_SYNC_EN == TRUE */
|
||||
break;
|
||||
}
|
||||
#endif /* BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE */
|
||||
|
||||
default:
|
||||
free(qev);
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
if (err) {
|
||||
LOG_ERR("[B]GapPostEvtBtaFail[%d][%u]", err, qev->type);
|
||||
goto free;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_scan_start(const struct bt_le_scan_param *param)
|
||||
{
|
||||
tBTM_STATUS status;
|
||||
|
||||
LOG_DBG("[B]ScanStart[%u][%u][%u]", param->type, param->interval, param->window);
|
||||
|
||||
#if USE_DIRECT_HCI
|
||||
{
|
||||
/* HCI LE Set Extended Scan Parameters (uncoded only):
|
||||
* own_addr_type(1) | scan_filter_policy(1) | scanning_phys(1)
|
||||
* | per-phy { scan_type(1) | scan_interval(2) | scan_window(2) } */
|
||||
uint8_t cmd_params[8];
|
||||
|
||||
cmd_params[0] = BLE_ADDR_PUBLIC;
|
||||
cmd_params[1] = 0; /* filter_policy: accept all */
|
||||
cmd_params[2] = 0x01; /* scanning_phys: LE 1M only */
|
||||
cmd_params[3] = param->type;
|
||||
sys_put_le16(param->interval, cmd_params + 4);
|
||||
sys_put_le16(param->window, cmd_params + 6);
|
||||
|
||||
status = bt_le_bluedroid_hci_send_sync(HCI_BLE_SET_EXT_SCAN_PARAMS,
|
||||
cmd_params, sizeof(cmd_params),
|
||||
NULL, 0);
|
||||
}
|
||||
#else /* USE_DIRECT_HCI */
|
||||
{
|
||||
tBTM_BLE_EXT_SCAN_PARAMS scan_params = {0};
|
||||
|
||||
scan_params.own_addr_type = BLE_ADDR_PUBLIC;
|
||||
scan_params.filter_policy = 0;
|
||||
scan_params.scan_duplicate = 0;
|
||||
scan_params.cfg_mask = BTM_BLE_GAP_EXT_SCAN_UNCODE_MASK;
|
||||
scan_params.uncoded_cfg.scan_type = param->type;
|
||||
scan_params.uncoded_cfg.scan_interval = param->interval;
|
||||
scan_params.uncoded_cfg.scan_window = param->window;
|
||||
|
||||
bt_le_host_lock();
|
||||
status = BTM_BleSetExtendedScanParams(&scan_params);
|
||||
bt_le_host_unlock();
|
||||
}
|
||||
#endif /* USE_DIRECT_HCI */
|
||||
|
||||
if (status != BTM_SUCCESS) {
|
||||
LOG_ERR("[B]SetScanParamsFail[%02x]", status);
|
||||
return bluedroid_err_to_errno(status);
|
||||
}
|
||||
|
||||
#if USE_DIRECT_HCI
|
||||
{
|
||||
/* HCI LE Set Extended Scan Enable:
|
||||
* enable(1) | filter_duplicates(1) | duration(2) | period(2)
|
||||
* duration=period=0 → continuous scan. */
|
||||
uint8_t cmd_params[6] = { 1, 0, 0, 0, 0, 0 };
|
||||
|
||||
status = bt_le_bluedroid_hci_send_sync(HCI_BLE_SET_EXT_SCAN_ENABLE,
|
||||
cmd_params, sizeof(cmd_params),
|
||||
NULL, 0);
|
||||
}
|
||||
#else /* USE_DIRECT_HCI */
|
||||
bt_le_host_lock();
|
||||
status = BTM_BleExtendedScan(true, 0, 0);
|
||||
bt_le_host_unlock();
|
||||
#endif /* USE_DIRECT_HCI */
|
||||
|
||||
if (status != BTM_SUCCESS) {
|
||||
LOG_ERR("[B]ScanStartFail[%02x]", status);
|
||||
}
|
||||
|
||||
return bluedroid_err_to_errno(status);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_scan_stop(void)
|
||||
{
|
||||
tBTM_STATUS status;
|
||||
|
||||
LOG_DBG("[B]ScanStop");
|
||||
|
||||
#if USE_DIRECT_HCI
|
||||
{
|
||||
/* HCI LE Set Extended Scan Enable with enable=0; other fields
|
||||
* are ignored by the controller per spec but must be present. */
|
||||
uint8_t cmd_params[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
status = bt_le_bluedroid_hci_send_sync(HCI_BLE_SET_EXT_SCAN_ENABLE,
|
||||
cmd_params, sizeof(cmd_params),
|
||||
NULL, 0);
|
||||
}
|
||||
#else /* USE_DIRECT_HCI */
|
||||
bt_le_host_lock();
|
||||
status = BTM_BleExtendedScan(false, 0, 0);
|
||||
bt_le_host_unlock();
|
||||
#endif /* USE_DIRECT_HCI */
|
||||
|
||||
if (status != BTM_SUCCESS) {
|
||||
LOG_ERR("[B]ScanStopFail[%02x]", status);
|
||||
}
|
||||
|
||||
return bluedroid_err_to_errno(status);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_iso_disconnect(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
tBTM_STATUS status;
|
||||
|
||||
LOG_DBG("[B]IsoDisconn[0x%03x][%02x]", conn_handle, reason);
|
||||
|
||||
/* No direct_hci variant: HCI Disconnect returns Command_Status;
|
||||
* outcome arrives via BTM_BLE_ISO_CIS_DISCONNECTED_EVT. */
|
||||
status = BTM_BleDisconCis(conn_handle, reason);
|
||||
|
||||
if (status != BTM_SUCCESS) {
|
||||
LOG_ERR("[B]IsoDisconnFail[0x%03x][%02x]", conn_handle, status);
|
||||
}
|
||||
|
||||
return bluedroid_err_to_errno(status);
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_gap_init(void)
|
||||
{
|
||||
BTM_BleGapRegisterCallback(gap_app_cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
3092
components/bt/esp_ble_iso/host/adapter/bluedroid/gatt/gatt.c
Normal file
3092
components/bt/esp_ble_iso/host/adapter/bluedroid/gatt/gatt.c
Normal file
File diff suppressed because it is too large
Load Diff
198
components/bt/esp_ble_iso/host/adapter/bluedroid/hci.c
Normal file
198
components/bt/esp_ble_iso/host/adapter/bluedroid/hci.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "bluedroid/hci.h"
|
||||
|
||||
#if USE_DIRECT_HCI
|
||||
|
||||
/* hci/hci_layer.h pulls in osi/osi.h which defines a 2-arg CONCAT(a, b)
|
||||
* macro that conflicts with the variadic CONCAT(...) from Zephyr's
|
||||
* <zephyr/sys/util.h>. hci.c does not use CONCAT itself, so drop the
|
||||
* Zephyr definition before pulling in osi's. */
|
||||
#undef CONCAT
|
||||
#include "hci/hci_layer.h"
|
||||
|
||||
#include "stack/hcimsgs.h"
|
||||
#include "stack/btm_ble_api.h"
|
||||
#include "bluedroid/btm_error.h"
|
||||
|
||||
#include "common/host.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_BHCI, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
/* Adapter-private sync cmd path. Decouples sync HCI cmds from BTU's global
|
||||
* ble_sync_info entirely: each cmd carries its own command_complete_cb (this
|
||||
* file's direct_hci_complete_cb) and the caller waits on direct_hci_sem,
|
||||
* not ble_sync_info.sync_sem. Two-task race on sync_info->opcode disappears.
|
||||
*
|
||||
* Caller sets direct_hci_rsp.opcode before transmit; cb verifies the
|
||||
* response opcode matches before giving the sem (guards against unexpected
|
||||
* stray Command_Complete dispatches).
|
||||
*
|
||||
* direct_hci_complete_cb runs on the hci_layer task — keep it tiny and
|
||||
* non-blocking, no host_lock, no further dispatch.
|
||||
*
|
||||
* Concurrent safety: send_sync is serialized by callers via bt_le_host_lock,
|
||||
* so the static rsp_buf pointer / opcode latch are single-slot. */
|
||||
static struct k_sem direct_hci_sem;
|
||||
|
||||
/* Set by deinit before deleting the sem. Late-arriving cb's must check
|
||||
* this before touching the sem. Residual race exists (cb past the check
|
||||
* but pre-give vs. deinit completing the delete) — accepted in practice
|
||||
* because the BTU/HCI layer offers no way to cancel an in-flight cmd. */
|
||||
static volatile bool direct_hci_shutting_down;
|
||||
|
||||
static struct {
|
||||
uint16_t opcode; /* expected — set by caller, verified by cb */
|
||||
uint8_t status; /* HCI status from Command_Complete */
|
||||
} direct_hci_rsp;
|
||||
|
||||
/* Internal sink for the cmd-specific return payload (bytes after the status
|
||||
* byte). The cb copies HERE, never into the caller's stack buffer — a
|
||||
* timed-out caller may already have freed its stack frame by the time a late
|
||||
* cb runs on the hci_layer task. The caller copies this out only after a
|
||||
* successful take. Static storage: a late cb always has a valid target, so no
|
||||
* teardown race. Sized for the largest payload any direct-HCI caller reads
|
||||
* back (SET_CIG: 2 + 2*cis_count, ISO_READ_TX_SYNC: 11). */
|
||||
#define DIRECT_HCI_RSP_MAX MAX(2 + 2 * CONFIG_BT_ISO_MAX_CHAN, 11)
|
||||
static uint8_t direct_hci_rsp_data[DIRECT_HCI_RSP_MAX];
|
||||
static uint8_t direct_hci_rsp_data_len;
|
||||
|
||||
static void direct_hci_complete_cb(BT_HDR *response, void *context)
|
||||
{
|
||||
/* Command_Complete event layout after BT_HDR data/offset:
|
||||
* [0] event code (0x0E) [1] param len [2] num_cmd_packets
|
||||
* [3..4] opcode (LE) [5] status [6..] cmd-specific params
|
||||
*/
|
||||
uint8_t *stream = response->data + response->offset + 3;
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
uint8_t event_param_len;
|
||||
|
||||
ARG_UNUSED(context);
|
||||
|
||||
event_param_len = response->data[response->offset + 1];
|
||||
|
||||
STREAM_TO_UINT16(opcode, stream);
|
||||
STREAM_TO_UINT8(status, stream);
|
||||
|
||||
if (opcode != direct_hci_rsp.opcode) {
|
||||
LOG_ERR("[B]DirectHciOpcodeMismatch[exp=0x%04x][got=0x%04x]",
|
||||
direct_hci_rsp.opcode, opcode);
|
||||
/* Drop — don't give sem, caller times out. */
|
||||
osi_free(response);
|
||||
return;
|
||||
}
|
||||
|
||||
direct_hci_rsp.status = status;
|
||||
|
||||
/* Copy cmd-specific return params (everything after the status byte)
|
||||
* into the caller's buffer. event_param_len counts:
|
||||
* num_cmd_packets(1) + opcode(2) + status(1) + cmd-specific(N)
|
||||
* so the payload available to caller is event_param_len - 4. */
|
||||
if (event_param_len > 4) {
|
||||
direct_hci_rsp_data_len = MIN(event_param_len - 4, sizeof(direct_hci_rsp_data));
|
||||
memcpy(direct_hci_rsp_data, stream, direct_hci_rsp_data_len);
|
||||
}
|
||||
|
||||
osi_free(response);
|
||||
|
||||
/* 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
k_sem_give(&direct_hci_sem);
|
||||
}
|
||||
|
||||
tBTM_STATUS bt_le_bluedroid_hci_send_sync(uint16_t opcode,
|
||||
const uint8_t *cmd_params,
|
||||
uint8_t cmd_params_len,
|
||||
uint8_t *rsp_buf,
|
||||
uint8_t rsp_buf_len)
|
||||
{
|
||||
BT_HDR *p;
|
||||
UINT8 *pp;
|
||||
hci_cmd_metadata_t *metadata;
|
||||
|
||||
p = HCI_GET_CMD_BUF(cmd_params_len);
|
||||
if (p == NULL) {
|
||||
return BTM_NO_RESOURCES;
|
||||
}
|
||||
|
||||
pp = p->data;
|
||||
UINT16_TO_STREAM(pp, opcode);
|
||||
UINT8_TO_STREAM(pp, cmd_params_len);
|
||||
if (cmd_params_len > 0 && cmd_params != NULL) {
|
||||
memcpy(pp, cmd_params, cmd_params_len);
|
||||
}
|
||||
|
||||
metadata = HCI_GET_CMD_METAMSG(p);
|
||||
metadata->command_complete_cb = direct_hci_complete_cb;
|
||||
metadata->command_status_cb = NULL;
|
||||
metadata->opcode = opcode;
|
||||
metadata->context = NULL;
|
||||
|
||||
/* Set expected opcode and rsp sink BEFORE transmit — cb may run
|
||||
* before transmit returns if response is already queued. */
|
||||
direct_hci_rsp.opcode = opcode;
|
||||
direct_hci_rsp.status = 0;
|
||||
direct_hci_rsp_data_len = 0;
|
||||
|
||||
/* Drop any stale give from a previous timed-out cmd whose cb arrived
|
||||
* late. Must run AFTER opcode update (so any cb arriving after this
|
||||
* drain hits the mismatch path and doesn't give) and BEFORE transmit
|
||||
* (so this cmd's own cb-give isn't accidentally consumed here). */
|
||||
k_sem_reset(&direct_hci_sem);
|
||||
|
||||
hci_layer_get_interface()->transmit_command(p, direct_hci_complete_cb,
|
||||
NULL, NULL);
|
||||
|
||||
if (k_sem_take(&direct_hci_sem, K_SEM_SHORT) != 0) {
|
||||
LOG_ERR("[B]DirectHciTimeout[0x%04x]", opcode);
|
||||
return BTM_ERR_PROCESSING;
|
||||
}
|
||||
|
||||
/* The cb gives the sem only after its memcpy, so the payload is complete;
|
||||
* copy it into the caller's (now-confirmed-live) sink. */
|
||||
if (rsp_buf != NULL && rsp_buf_len > 0 && direct_hci_rsp_data_len > 0) {
|
||||
memcpy(rsp_buf, direct_hci_rsp_data, MIN(direct_hci_rsp_data_len, rsp_buf_len));
|
||||
}
|
||||
|
||||
if (direct_hci_rsp.status != HCI_SUCCESS) {
|
||||
LOG_ERR("[B]DirectHciStatus[0x%04x][%02x]",
|
||||
opcode, direct_hci_rsp.status);
|
||||
return BTM_HCI_ERROR | direct_hci_rsp.status;
|
||||
}
|
||||
|
||||
return BTM_SUCCESS;
|
||||
}
|
||||
|
||||
int bt_le_bluedroid_hci_init(void)
|
||||
{
|
||||
direct_hci_shutting_down = false;
|
||||
k_sem_create(&direct_hci_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bt_le_bluedroid_hci_deinit(void)
|
||||
{
|
||||
/* Flip the gate first so any cb past this point skips the give.
|
||||
* Drain any give that was already posted before the flag flip so
|
||||
* the sem is clean before deletion. */
|
||||
direct_hci_shutting_down = true;
|
||||
k_sem_reset(&direct_hci_sem);
|
||||
k_sem_delete(&direct_hci_sem);
|
||||
}
|
||||
|
||||
#endif /* USE_DIRECT_HCI */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "stack/btm_api.h"
|
||||
|
||||
/**
|
||||
* Translate a Bluedroid BTM status (tBTM_STATUS, see stack/btm_api.h) into
|
||||
* a standard negative POSIX errno.
|
||||
*
|
||||
* Counterpart to nimble_err_to_errno() — both adapters return errno values
|
||||
* to common/ and lib code so the audio layer can branch on -EAGAIN /
|
||||
* -EBUSY / -ENOMEM etc. without knowing which host it ran on.
|
||||
*
|
||||
* Unknown codes map to -EIO so caller logic doesn't accidentally match a
|
||||
* known errno.
|
||||
*/
|
||||
static inline int bluedroid_err_to_errno(tBTM_STATUS status)
|
||||
{
|
||||
switch (status) {
|
||||
case BTM_SUCCESS: return 0;
|
||||
case BTM_CMD_STARTED: return 0;
|
||||
case BTM_CMD_STORED: return 0;
|
||||
case BTM_SUCCESS_NO_SECURITY: return 0;
|
||||
case BTM_BUSY: return -EBUSY;
|
||||
case BTM_NO_RESOURCES: return -ENOMEM;
|
||||
case BTM_MODE_UNSUPPORTED: return -ENOTSUP;
|
||||
case BTM_ILLEGAL_VALUE: return -EINVAL;
|
||||
case BTM_WRONG_MODE: return -EPERM;
|
||||
case BTM_UNKNOWN_ADDR: return -ENOENT;
|
||||
case BTM_DEVICE_TIMEOUT: return -ETIMEDOUT;
|
||||
case BTM_BAD_VALUE_RET: return -EBADMSG;
|
||||
case BTM_ERR_PROCESSING: return -EIO;
|
||||
case BTM_NOT_AUTHORIZED: return -EACCES;
|
||||
case BTM_DEV_RESET: return -ECONNRESET;
|
||||
case BTM_ILLEGAL_ACTION: return -EPERM;
|
||||
case BTM_FAILED_ON_SECURITY: return -EPERM;
|
||||
case BTM_REPEATED_ATTEMPTS: return -EAGAIN;
|
||||
default: return -EIO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_APP_GAP_H_
|
||||
#define HOST_BLUEDROID_APP_GAP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bt_le_bluedroid_gap_post_event(uint16_t event, void *param);
|
||||
|
||||
int bt_le_bluedroid_scan_start(const struct bt_le_scan_param *param);
|
||||
|
||||
int bt_le_bluedroid_scan_stop(void);
|
||||
|
||||
int bt_le_bluedroid_iso_disconnect(uint16_t conn_handle, uint8_t reason);
|
||||
|
||||
int bt_le_bluedroid_gap_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_APP_GAP_H_ */
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_GATT_H_
|
||||
#define HOST_BLUEDROID_GATT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/slist.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct gatt_conn {
|
||||
uint8_t used : 1;
|
||||
uint8_t conn_create : 1;
|
||||
uint8_t gattc_open : 1;
|
||||
uint8_t cfg_mtu : 1;
|
||||
uint8_t mtu_posted : 1;
|
||||
|
||||
uint8_t status;
|
||||
uint8_t gatt_if;
|
||||
uint16_t conn_handle;
|
||||
uint8_t role;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t val[6];
|
||||
} peer;
|
||||
|
||||
uint16_t mtu;
|
||||
|
||||
/* FIFO of in-flight GATTC read/write ops; mirrors BTA p_cmd_list ordering.
|
||||
* BTA EVTs deliver attr_handle/status only — we need this to recover the
|
||||
* caller's params on each cmpl. See struct gattc_list_node in gatt.c. */
|
||||
sys_slist_t gattc_list;
|
||||
|
||||
/* FIFO of pending GATTS indications. GATT spec restricts per-conn to a
|
||||
* single outstanding indication; this queue absorbs that limit so callers
|
||||
* never see -EBUSY. See struct gatts_list_node in gatt.c. Mirrors
|
||||
* NimBLE adapter NRP indicate behavior. */
|
||||
sys_slist_t gatts_list;
|
||||
|
||||
/* FIFO of in-flight GATTS notify markers. BTA fires CONF_EVT for notify
|
||||
* too (immediately after send) — tBTA_GATTS_REQ carries no notify/indicate
|
||||
* flag so the handler pops this list first to disambiguate from the
|
||||
* indication acks tracked in gatts_list. See struct gatts_notify_node. */
|
||||
sys_slist_t gatts_notify_list;
|
||||
};
|
||||
|
||||
uint8_t bt_le_bluedroid_gattc_get_if(void);
|
||||
|
||||
uint8_t bt_le_bluedroid_gatts_get_if(void);
|
||||
|
||||
void bt_le_bluedroid_gatts_sem_reset(void);
|
||||
|
||||
int bt_le_bluedroid_gatts_sem_take(void);
|
||||
|
||||
void bt_le_bluedroid_gatts_sem_give(int result);
|
||||
|
||||
struct gatt_conn *bt_le_bluedroid_find_gatt_conn_with_addr(uint8_t addr_type,
|
||||
const uint8_t addr[6],
|
||||
bool ignore_type);
|
||||
|
||||
struct gatt_conn *bt_le_bluedroid_find_gatt_conn_with_handle(uint16_t conn_handle);
|
||||
|
||||
struct gatt_conn *bt_le_bluedroid_find_free_gatt_conn(void);
|
||||
|
||||
void bt_le_bluedroid_gatt_handle_event(uint8_t *data, size_t data_len);
|
||||
|
||||
void bt_le_bluedroid_gatt_uuid_convert(const struct bt_uuid *uuid_in, void *uuid_out);
|
||||
|
||||
uint16_t bt_le_bluedroid_gatt_perm_convert(uint16_t perm_in);
|
||||
|
||||
uint16_t bt_le_bluedroid_gatt_get_mtu(struct bt_conn *conn);
|
||||
|
||||
ssize_t bt_le_bluedroid_gatts_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t buf_len, uint16_t offset,
|
||||
const void *value, uint16_t value_len);
|
||||
|
||||
int bt_le_bluedroid_gatts_notify(struct bt_conn *conn, struct bt_gatt_notify_params *params);
|
||||
|
||||
int bt_le_bluedroid_gatts_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params);
|
||||
|
||||
int bt_le_bluedroid_gattc_disc_start(uint16_t conn_handle);
|
||||
|
||||
int bt_le_bluedroid_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params);
|
||||
|
||||
int bt_le_bluedroid_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params *params);
|
||||
|
||||
int bt_le_bluedroid_gattc_write(struct bt_conn *conn, struct bt_gatt_write_params *params);
|
||||
|
||||
int bt_le_bluedroid_gattc_write_without_rsp(struct bt_conn *conn, uint16_t handle,
|
||||
const void *data, uint16_t length);
|
||||
|
||||
int bt_le_bluedroid_gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params *params);
|
||||
|
||||
int bt_le_bluedroid_gatt_init(void);
|
||||
|
||||
void bt_le_bluedroid_gatt_deinit(void);
|
||||
|
||||
struct inc_svc_inst {
|
||||
struct bt_gatt_service *svc_p;
|
||||
bool included;
|
||||
};
|
||||
|
||||
struct gatts_svc_cb {
|
||||
void (*svc_create_cb)(uint16_t service_id, uint16_t svc_instance,
|
||||
bool is_primary, uint8_t status, void *uuid);
|
||||
|
||||
void (*inc_svc_add_cb)(uint16_t service_id, uint16_t attr_id, uint8_t status);
|
||||
|
||||
void (*chrc_add_cb)(uint16_t service_id, uint16_t attr_id,
|
||||
uint8_t status, void *uuid);
|
||||
|
||||
void (*svc_start_cb)(uint16_t service_id, uint8_t status);
|
||||
};
|
||||
|
||||
void bt_le_bluedroid_gatts_svc_cb_register(struct gatts_svc_cb *cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_GATT_H_ */
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_APP_HCI_H_
|
||||
#define HOST_BLUEDROID_APP_HCI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "stack/btm_ble_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* When set to 1, sync HCI commands issued by the iso adapter bypass BTM
|
||||
* and the global ble_sync_info to avoid the sync_info opcode race with
|
||||
* concurrent BTC/BTA sync cmds. Experimental. Toggle is shared with
|
||||
* iso.c and gap.c via this header so the BTM fallback paths in both
|
||||
* files stay in sync. */
|
||||
#define USE_DIRECT_HCI 1
|
||||
|
||||
int bt_le_bluedroid_hci_init(void);
|
||||
|
||||
void bt_le_bluedroid_hci_deinit(void);
|
||||
|
||||
/* Send a sync HCI command, bypassing BTM and ble_sync_info. `cmd_params`
|
||||
* is the cmd parameter payload (without opcode/length preamble).
|
||||
*
|
||||
* Returns BTM_SUCCESS, BTM_HCI_ERROR | hci_status on controller failure,
|
||||
* or BTM_ERR_PROCESSING on host-side timeout.
|
||||
*
|
||||
* If `rsp_buf` is non-NULL, up to `rsp_buf_len` bytes of the
|
||||
* cmd-specific return params (the bytes after the status byte in the
|
||||
* HCI Command_Complete event) are copied in. If the actual payload is
|
||||
* shorter, the tail of rsp_buf is left untouched; if longer, the excess
|
||||
* is silently dropped. Callers parse opcode-specific structure.
|
||||
*
|
||||
* Serialization: NOT thread-safe — internally uses single-slot static
|
||||
* state (sem, opcode latch, rsp buffer pointer). Callers must serialize
|
||||
* externally; in practice all current callers (iso.c hci_cmd_* and
|
||||
* gap.c scan_start/stop) run on the iso task, so single-task affinity
|
||||
* provides serialization without explicit locking. */
|
||||
tBTM_STATUS bt_le_bluedroid_hci_send_sync(uint16_t opcode,
|
||||
const uint8_t *cmd_params,
|
||||
uint8_t cmd_params_len,
|
||||
uint8_t *rsp_buf,
|
||||
uint8_t rsp_buf_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_APP_HCI_H_ */
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef HOST_BLUEDROID_ISO_H_
|
||||
#define HOST_BLUEDROID_ISO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct net_buf;
|
||||
|
||||
int bt_le_bluedroid_hci_iso_cmd_send_sync(uint16_t opcode,
|
||||
struct net_buf *buf,
|
||||
struct net_buf **rsp);
|
||||
|
||||
int bt_le_bluedroid_iso_init(void);
|
||||
|
||||
void bt_le_bluedroid_iso_deinit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HOST_BLUEDROID_ISO_H_ */
|
||||
1276
components/bt/esp_ble_iso/host/adapter/bluedroid/iso.c
Normal file
1276
components/bt/esp_ble_iso/host/adapter/bluedroid/iso.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -217,9 +217,9 @@ void bt_le_nimble_gap_post_event(void *param)
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("[N]GapPostEvtUnexp[%u]", ev->type);
|
||||
free(qev);
|
||||
assert(0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GAP_EVENT, qev, sizeof(*qev));
|
||||
@@ -253,22 +253,39 @@ free:
|
||||
|
||||
int bt_le_nimble_scan_start(const struct bt_le_scan_param *param, ble_gap_event_fn *cb)
|
||||
{
|
||||
struct ble_gap_disc_params scan_param = {0};
|
||||
struct ble_gap_ext_disc_params uncoded = {0};
|
||||
int rc;
|
||||
|
||||
scan_param.itvl = param->interval;
|
||||
scan_param.window = param->window;
|
||||
scan_param.filter_policy = 0;
|
||||
scan_param.limited = 0;
|
||||
scan_param.passive = !param->type;
|
||||
scan_param.filter_duplicates = 0;
|
||||
LOG_DBG("[N]ScanStart[%u][%u][%u]", param->type, param->interval, param->window);
|
||||
|
||||
return nimble_err_to_errno(ble_gap_disc(BLE_OWN_ADDR_PUBLIC, BLE_HS_FOREVER,
|
||||
&scan_param, cb, NULL));
|
||||
uncoded.itvl = param->interval;
|
||||
uncoded.window = param->window;
|
||||
uncoded.passive = !param->type;
|
||||
|
||||
/* LE Audio sources broadcast via extended advertising; legacy
|
||||
* ble_gap_disc would miss them. Uncoded-only mirrors the Bluedroid
|
||||
* side which sets BTM_BLE_GAP_EXT_SCAN_UNCODE_MASK. */
|
||||
rc = ble_gap_ext_disc(BLE_OWN_ADDR_PUBLIC, 0, 0, 0, 0, 0,
|
||||
&uncoded, NULL, cb, NULL);
|
||||
if (rc) {
|
||||
LOG_ERR("[N]ScanStartFail[%d]", rc);
|
||||
}
|
||||
|
||||
return nimble_err_to_errno(rc);
|
||||
}
|
||||
|
||||
int bt_le_nimble_scan_stop(void)
|
||||
{
|
||||
return nimble_err_to_errno(ble_gap_disc_cancel());
|
||||
int rc;
|
||||
|
||||
LOG_DBG("[N]ScanStop");
|
||||
|
||||
rc = ble_gap_disc_cancel();
|
||||
if (rc) {
|
||||
LOG_ERR("[N]ScanStopFail[%d]", rc);
|
||||
}
|
||||
|
||||
return nimble_err_to_errno(rc);
|
||||
}
|
||||
|
||||
int bt_le_nimble_iso_disconnect(uint16_t conn_handle, uint8_t reason)
|
||||
|
||||
@@ -95,9 +95,9 @@ void bt_le_nimble_gatt_post_event(void *param)
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("[N]GattPostEvtUnexp[%u]", ev->type);
|
||||
free(qev);
|
||||
assert(0);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
err = bt_le_iso_task_post(ISO_QUEUE_ITEM_TYPE_GATT_EVENT, qev, sizeof(*qev));
|
||||
@@ -209,7 +209,7 @@ static void handle_gattc_notify_rx_event_safe(struct bt_le_gattc_notify_rx_event
|
||||
|
||||
conn = bt_le_acl_conn_find(event->conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]NotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNtfRxNotConn[%u][%u]", event->conn_handle, BT_CONN_STATE_GET(conn));
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -222,6 +222,12 @@ static void handle_gattc_notify_rx_event_safe(struct bt_le_gattc_notify_rx_event
|
||||
if (params->ccc_handle != BT_GATT_AUTO_DISCOVER_CCC_HANDLE &&
|
||||
params->value_handle == event->attr_handle) {
|
||||
if (params->notify) {
|
||||
/* Return value intentionally ignored. Zephyr unsubscribes on
|
||||
* BT_GATT_ITER_STOP, but lib clients return STOP on a single
|
||||
* malformed/short notify (e.g. unicast_client_cp_notify);
|
||||
* tearing down a core subscription like the ASCS control point
|
||||
* over one bad PDU would drop every later notification. Tolerate
|
||||
* the bad PDU and keep the subscription. */
|
||||
params->notify(conn, params, event->value, event->len);
|
||||
}
|
||||
}
|
||||
@@ -446,6 +452,16 @@ int bt_le_nimble_gattc_discover(struct bt_conn *conn, struct bt_gatt_discover_pa
|
||||
LOG_DBG("[N]GattcDisc[%u]", conn->handle);
|
||||
|
||||
if (params->uuid) {
|
||||
/* Downstream gattc_db_disc_*_by_uuid takes ble_uuid16_t — reject
|
||||
* non-16-bit caller UUIDs explicitly. BT_UUID_16 would otherwise
|
||||
* reinterpret a 32/128-bit struct and feed garbage to the lookup.
|
||||
* LE Audio profiles only use SIG-assigned 16-bit UUIDs, so this
|
||||
* gate stays a compile-time-style guard in practice. */
|
||||
if (params->uuid->type != BT_UUID_TYPE_16) {
|
||||
LOG_ERR("[N]DiscNon16BitUuid[%u]", params->uuid->type);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
uuid.u.type = BLE_UUID_TYPE_16;
|
||||
uuid.value = BT_UUID_16(params->uuid)->val;
|
||||
}
|
||||
|
||||
@@ -529,9 +529,11 @@ static void gattc_db_disc(struct gattc_db *adb, uint8_t status)
|
||||
* to the upper layer.
|
||||
*/
|
||||
if (status == DISC_FAIL) {
|
||||
uint16_t conn_handle = adb->conn_handle;
|
||||
|
||||
gattc_db_del(adb);
|
||||
|
||||
bt_le_nimble_gatt_post_disc_cmpl_event(adb->conn_handle, 0x01);
|
||||
bt_le_nimble_gatt_post_disc_cmpl_event(conn_handle, 0x01);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -553,9 +555,11 @@ static void gattc_db_disc(struct gattc_db *adb, uint8_t status)
|
||||
* we will delete the gatt client database and post the
|
||||
* discovery completion event.
|
||||
*/
|
||||
uint16_t conn_handle = adb->conn_handle;
|
||||
|
||||
gattc_db_del(adb);
|
||||
|
||||
bt_le_nimble_gatt_post_disc_cmpl_event(adb->conn_handle, 0x01);
|
||||
bt_le_nimble_gatt_post_disc_cmpl_event(conn_handle, 0x01);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -590,8 +594,8 @@ static int gattc_db_disc_all_svcs_cb_safe(uint16_t conn_handle,
|
||||
case 0:
|
||||
assert(svc);
|
||||
|
||||
LOG_DBG("[N]GattcDbDiscAllSvcs[%s][%u][%u]",
|
||||
audio_svc_uuid_to_str(svc->uuid.u16.value),
|
||||
LOG_DBG("[N]GattcDbDiscAllSvcs[0x%04x][%u][%u]",
|
||||
svc->uuid.u16.value,
|
||||
svc->start_handle, svc->end_handle);
|
||||
|
||||
gattc_db_svc_insert(adb, svc);
|
||||
@@ -637,7 +641,7 @@ static int gattc_db_find_inc_svcs_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbFindIncSvcsCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -646,8 +650,8 @@ static int gattc_db_find_inc_svcs_cb_safe(uint16_t conn_handle,
|
||||
case 0:
|
||||
assert(svc);
|
||||
|
||||
LOG_DBG("[N]GattcDbFindIncSvcs[%s][%u][%u]",
|
||||
audio_svc_uuid_to_str(svc->uuid.u16.value),
|
||||
LOG_DBG("[N]GattcDbFindIncSvcs[0x%04x][%u][%u]",
|
||||
svc->uuid.u16.value,
|
||||
svc->start_handle, svc->end_handle);
|
||||
|
||||
gattc_db_inc_svc_insert(asvc, svc);
|
||||
@@ -725,7 +729,7 @@ static int gattc_db_disc_all_inc_chrs_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbDiscAllIncChrsCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -783,7 +787,7 @@ static int gattc_db_disc_all_chrs_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbDiscAllChrsCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -843,7 +847,7 @@ static int gattc_db_disc_all_inc_dscs_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbDiscAllIncDscsCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -906,7 +910,7 @@ static int gattc_db_disc_all_dscs_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbDiscAllDscsCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -967,7 +971,7 @@ static int gattc_db_enable_notify_cb_safe(uint16_t conn_handle,
|
||||
|
||||
adb = gattc_db_find(conn_handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDbEnableNotifyCbNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
@@ -987,10 +991,17 @@ static int gattc_db_enable_notify_cb_safe(uint16_t conn_handle,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Mark the CCCD write as completed */
|
||||
achrc->cccd_write = 1;
|
||||
|
||||
gattc_db_disc(adb, DISC_SUCCESS);
|
||||
if (rc) {
|
||||
/* Terminal failure (ENOTCONN/ETIMEOUT) — bail via DISC_FAIL so the
|
||||
* next CCCD write isn't queued; it would otherwise sit on NimBLE's
|
||||
* pending list and only resolve after the 30s ATT timeout, by which
|
||||
* time the adb has been removed. */
|
||||
gattc_db_disc(adb, DISC_FAIL);
|
||||
} else {
|
||||
/* Mark the CCCD write as completed */
|
||||
achrc->cccd_write = 1;
|
||||
gattc_db_disc(adb, DISC_SUCCESS);
|
||||
}
|
||||
|
||||
end:
|
||||
bt_le_host_unlock();
|
||||
@@ -1014,7 +1025,7 @@ static int handle_gattc_disc_svc_by_uuid(struct bt_conn *conn, ble_uuid16_t *uui
|
||||
|
||||
adb = gattc_db_find(conn->handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDiscSvcByUuidNotFound");
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -1068,7 +1079,7 @@ static int handle_gattc_find_inc_svcs(struct bt_conn *conn,
|
||||
|
||||
adb = gattc_db_find(conn->handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcFindIncSvcsNotFound");
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -1087,6 +1098,9 @@ static int handle_gattc_find_inc_svcs(struct bt_conn *conn,
|
||||
inc_svc.start_handle = ainc_svc->svc.start_handle;
|
||||
inc_svc.end_handle = ainc_svc->svc.end_handle;
|
||||
|
||||
/* Include declaration's own attribute type — same rationale
|
||||
* as the Bluedroid side: caller may dereference attr->uuid. */
|
||||
attr.uuid = BT_UUID_GATT_INCLUDE;
|
||||
attr.user_data = &inc_svc;
|
||||
/* TODO:
|
||||
* When CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY is enabled, use ainc_svc->attr_handle here.
|
||||
@@ -1158,7 +1172,7 @@ static int handle_gattc_disc_chrs(struct bt_conn *conn, ble_uuid16_t *uuid,
|
||||
|
||||
adb = gattc_db_find(conn->handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDiscChrsNotFound");
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -1234,7 +1248,7 @@ void handle_gattc_db_disc_event_safe(struct bt_le_gattc_discover_event *event)
|
||||
|
||||
conn = bt_le_acl_conn_find(event->conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcDbNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcDbDiscNotConn[%u][%u]", event->conn_handle, BT_CONN_STATE_GET(conn));
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -1341,7 +1355,7 @@ static int handle_gattc_disc_all_dscs(struct bt_conn *conn,
|
||||
|
||||
adb = gattc_db_find(conn->handle);
|
||||
if (adb == NULL) {
|
||||
LOG_ERR("[N]GattcDbNotFound");
|
||||
LOG_WRN("[N]GattcDiscAllDscsNotFound");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ static int gattc_nrp_read_by_uuid_cb_safe(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNrpRdByUuidNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
rc = -ENOTCONN;
|
||||
goto end;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ static int gattc_nrp_read_long_cb_safe(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNrpRdLongNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
rc = -ENOTCONN;
|
||||
goto end;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNrpRdSingleNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
rc = -ENOTCONN;
|
||||
goto end;
|
||||
}
|
||||
@@ -404,7 +404,7 @@ static int gattc_nrp_write_cb_safe(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNrpWrNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
rc = -ENOTCONN;
|
||||
goto end;
|
||||
}
|
||||
@@ -480,7 +480,7 @@ static int gattc_nrp_subscribe_cb_safe(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattcNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattcNrpSubNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
rc = -ENOTCONN;
|
||||
goto end;
|
||||
}
|
||||
@@ -560,7 +560,7 @@ void bt_le_nimble_gatts_nrp_indicate_cb(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("[N]GattsNrpNotConn[%d]", __LINE__);
|
||||
LOG_INF("[N]GattsNrpIndNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -902,17 +902,22 @@ int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *param
|
||||
case GATTS_NRP_INDICATE:
|
||||
assert(nrp_head->indicate.params);
|
||||
|
||||
/* params is the deep copy taken at insert time; cb sees the copy's
|
||||
* address, not the caller's original (which may have been reused).
|
||||
* On match: err propagates the mapped NimBLE status (0 on EDONE,
|
||||
* else err). On handle mismatch the cb event doesn't correspond
|
||||
* to this queue head — we cannot report this head's real outcome,
|
||||
* so fire with BT_ATT_ERR_UNLIKELY to signal failure rather than
|
||||
* silently passing the wrong op's status (could be 0/success and
|
||||
* mislead the lib state machine). */
|
||||
if (nrp_head->indicate.params->attr->handle !=
|
||||
((struct bt_gatt_indicate_params *)params)->attr->handle) {
|
||||
LOG_ERR("[N]GattNrpMismatchIndHdl[%u][%u]",
|
||||
((struct bt_gatt_indicate_params *)params)->attr->handle,
|
||||
nrp_head->indicate.params->attr->handle);
|
||||
assert(0); /* Should not happen */
|
||||
err = BT_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* params is the deep copy taken at insert time; cb sees the copy's
|
||||
* address, not the caller's original (which may have been reused).
|
||||
* err propagates the mapped NimBLE status (0 on EDONE, else err). */
|
||||
nrp_head->indicate.params->func(conn, nrp_head->indicate.params, err);
|
||||
|
||||
free(nrp_head->indicate.data_copy);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct net_buf;
|
||||
|
||||
int bt_le_nimble_iso_cmd_send_sync(uint16_t opcode,
|
||||
struct net_buf *buf,
|
||||
struct net_buf **rsp);
|
||||
|
||||
@@ -842,15 +842,20 @@ int bt_le_nimble_iso_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* nimble's setters reject NULL and refuse re-registration (EALREADY), and
|
||||
* expose no unregister path — so deinit cannot clear these. On a host
|
||||
* re-enable the callback is still our own iso_evt_rx / bt_le_iso_rx, so
|
||||
* treat EALREADY as success instead of failing the whole init. (evt setter
|
||||
* returns -BLE_HS_EALREADY, pkt setter returns BLE_HS_EALREADY.) */
|
||||
err = ble_hs_iso_evt_rx_cb_set(iso_evt_rx);
|
||||
if (err) {
|
||||
if (err && err != -BLE_HS_EALREADY) {
|
||||
LOG_ERR("[N]IsoEvtRxCbSetFail[%d]", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_ISO_RX
|
||||
err = ble_hs_iso_pkt_rx_cb_set(bt_le_iso_rx);
|
||||
if (err) {
|
||||
if (err && err != BLE_HS_EALREADY) {
|
||||
LOG_ERR("[N]IsoPktRxCbSetFail[%d]", err);
|
||||
return err;
|
||||
}
|
||||
@@ -869,14 +874,11 @@ int bt_le_nimble_iso_init(void)
|
||||
|
||||
void bt_le_nimble_iso_deinit(void)
|
||||
{
|
||||
LOG_DBG("IsoDeinit");
|
||||
|
||||
ble_hs_iso_evt_rx_cb_set(NULL);
|
||||
|
||||
#if CONFIG_BT_ISO_RX
|
||||
ble_hs_iso_pkt_rx_cb_set(NULL);
|
||||
#endif /* CONFIG_BT_ISO_RX */
|
||||
LOG_DBG("[N]IsoDeinit");
|
||||
|
||||
/* nimble exposes no way to unregister iso_evt_rx / bt_le_iso_rx (the
|
||||
* setters reject NULL); they harmlessly persist until the next init,
|
||||
* which tolerates the resulting EALREADY. */
|
||||
#if CONFIG_BT_ISO_UNICAST
|
||||
iso_disable_cis();
|
||||
#endif /* CONFIG_BT_ISO_UNICAST */
|
||||
|
||||
@@ -87,7 +87,11 @@ static int ots_l2cap_event_cb(struct ble_l2cap_event *event, void *arg)
|
||||
ots_chan = event->connect.chan;
|
||||
|
||||
if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) {
|
||||
assert(0);
|
||||
LOG_ERR("[N]CocGetChanInfoFail");
|
||||
/* Roll back the latch so the next COC_CONNECTED isn't refused
|
||||
* by the if (ots_chan) guard above. */
|
||||
ots_chan = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_DBG("[N]CocConnect[%u][%04x][%04x][%04x][%u][%u][%u][%u]",
|
||||
@@ -320,7 +324,7 @@ int bt_le_nimble_l2cap_init(void)
|
||||
|
||||
void bt_le_nimble_l2cap_deinit(void)
|
||||
{
|
||||
LOG_DBG("NimbleL2capDeinit");
|
||||
LOG_DBG("[N]L2capDeinit");
|
||||
|
||||
/* TODO: free the ots_mbuf_pool and ots_mbuf_mempool */
|
||||
|
||||
|
||||
@@ -517,8 +517,11 @@ void bt_le_gap_handle_event(uint8_t *data, size_t data_len)
|
||||
|
||||
void bt_le_gap_app_post_event(uint8_t type, void *param)
|
||||
{
|
||||
/* Currently type is not used */
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* For Bluedroid, post the typed event to the ISO task instead. */
|
||||
bt_le_bluedroid_gap_post_event(type, param);
|
||||
#else
|
||||
ARG_UNUSED(type);
|
||||
|
||||
bt_le_nimble_gap_post_event(param);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ void bt_le_gatts_app_subscribe_event(struct bt_le_gatts_subscribe_event *param)
|
||||
bt_le_gatt_app_cb_evt(&event);
|
||||
}
|
||||
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
void bt_le_gatt_app_post_event(uint8_t type, void *param)
|
||||
{
|
||||
/* Currently type is not used */
|
||||
@@ -113,3 +114,24 @@ void bt_le_gatt_app_post_event(uint8_t type, void *param)
|
||||
|
||||
bt_le_nimble_gatt_post_event(param);
|
||||
}
|
||||
#endif /* !CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* Bluedroid-only: GATTC open completion carries the BTA gattc_if, which has
|
||||
* no NimBLE analogue. MTU and disc-cmpl events reuse the host-agnostic
|
||||
* helpers above (bt_le_gatt_app_mtu_change_event / bt_le_gattc_app_disc_cmpl_event). */
|
||||
void bt_le_gattc_app_open_event(struct bt_le_gattc_open_event *param, uint8_t gattc_if)
|
||||
{
|
||||
struct bt_le_gatt_app_event event = {
|
||||
.type = BT_LE_GATT_APP_EVENT_GATTC_OPEN,
|
||||
};
|
||||
|
||||
LOG_DBG("GattcOpenAppEvt[%u][%02x][%u]", param->conn_handle, param->status, gattc_if);
|
||||
|
||||
event.gattc_open.status = param->status;
|
||||
event.gattc_open.conn_handle = param->conn_handle;
|
||||
event.gattc_open.gattc_if = gattc_if;
|
||||
|
||||
bt_le_gatt_app_cb_evt(&event);
|
||||
}
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
@@ -382,11 +382,12 @@ int bt_le_acl_conn_delete(uint16_t conn_handle)
|
||||
{
|
||||
struct bt_conn *conn;
|
||||
|
||||
LOG_DBG("AclConnDel[%u]", conn_handle);
|
||||
LOG_INF("AclConnDel[%u]", conn_handle);
|
||||
|
||||
/* disconnected_listener already flipped state to DISCONNECTED. */
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
if (conn == NULL || conn->state != BT_CONN_DISCONNECTED) {
|
||||
LOG_ERR("AclConnDelNotDisc[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -406,7 +407,7 @@ int bt_le_acl_conn_update(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnUpdNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -543,7 +544,7 @@ int bt_le_acl_conn_connected_listener(uint16_t conn_handle)
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnConnectedListenerNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -566,10 +567,15 @@ int bt_le_acl_conn_disconnected_listener(uint16_t conn_handle, uint8_t reason)
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnDisconnectedListenerNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* Flip before dispatch — lib disconnect cbs guard late notifies on
|
||||
* bt_conn_get_info().state. Otherwise BTA queues the send and the conn
|
||||
* is gone by the time BTU drains it ("Unknown connection ID"). */
|
||||
conn->state = BT_CONN_DISCONNECTED;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, listener, _node) {
|
||||
if (listener->disconnected) {
|
||||
listener->disconnected(conn, reason);
|
||||
@@ -593,7 +599,7 @@ int bt_le_acl_conn_security_changed_listener(uint16_t conn_handle, bt_security_t
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnSecChgListenerNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -621,7 +627,7 @@ int bt_le_acl_conn_identity_resolved_listener(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnIdResolvedListenerNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -644,7 +650,7 @@ int bt_le_acl_conn_pairing_completed_listener(uint16_t conn_handle, bool bonded)
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("AclConnPairingCompletedListenerNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,11 @@ uint16_t bt_gatt_get_mtu(struct bt_conn *conn)
|
||||
|
||||
assert(conn);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
mtu = bt_le_bluedroid_gatt_get_mtu(conn);
|
||||
#else
|
||||
mtu = bt_le_nimble_gatt_get_mtu(conn);
|
||||
#endif
|
||||
|
||||
LOG_DBG("GattGetMtu[%u]", mtu);
|
||||
|
||||
@@ -141,13 +145,12 @@ uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr)
|
||||
{
|
||||
uint16_t handle = 0;
|
||||
|
||||
LOG_DBG("GattAttrGetHdl");
|
||||
|
||||
if (attr && attr->handle) {
|
||||
handle = attr->handle;
|
||||
}
|
||||
|
||||
LOG_DBG("Hdl[%u]", handle);
|
||||
LOG_DBG("GattAttrGetHdl[%u]", handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -162,32 +165,29 @@ uint16_t bt_gatt_attr_value_handle(const struct bt_gatt_attr *attr)
|
||||
* Currently this function is only used by TMAP.
|
||||
*/
|
||||
|
||||
LOG_DBG("GattAttrValHdl");
|
||||
|
||||
if (attr) {
|
||||
LOG_DBG("GattAttrUuid[%s]", attr->uuid ? bt_uuid_str(attr->uuid) : "Null");
|
||||
|
||||
if (attr->uuid == NULL) {
|
||||
handle = (attr->handle + 1);
|
||||
} else {
|
||||
LOG_DBG("Uuid[%s]", bt_uuid_str(attr->uuid));
|
||||
|
||||
if (bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC) == 0) {
|
||||
struct bt_gatt_chrc *chrc = attr->user_data;
|
||||
|
||||
assert(chrc);
|
||||
handle = chrc->value_handle;
|
||||
|
||||
LOG_DBG("ValHdl[%u]", handle);
|
||||
|
||||
if (handle == 0) {
|
||||
/* Fall back to Zephyr value handle policy */
|
||||
handle = bt_gatt_attr_get_handle(attr) + 1;
|
||||
LOG_INF("ValHdlNew[%u]", handle);
|
||||
LOG_INF("GattAttrValHdlNew[%u]", handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DBG("Hdl[%u]", handle);
|
||||
LOG_DBG("GattAttrValHdl[%u]", handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -401,8 +401,13 @@ ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gatts_attr_read(conn, attr, buf, buf_len,
|
||||
offset, value, value_len);
|
||||
#else
|
||||
return bt_le_nimble_gatts_attr_read(conn, attr, buf, buf_len,
|
||||
offset, value, value_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
@@ -415,11 +420,15 @@ int bt_gatt_notify_cb(struct bt_conn *conn, struct bt_gatt_notify_params *params
|
||||
LOG_DBG("GattNtfCb[%u]", params->len);
|
||||
|
||||
if (conn && conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattNtfNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
err = bt_le_bluedroid_gatts_notify(conn, params);
|
||||
#else
|
||||
err = bt_le_nimble_gatts_notify(conn, params);
|
||||
#endif
|
||||
|
||||
/* gatts_notify is synchronous (mbuf-copy + dispatch on return); fire the
|
||||
* caller's completion cb here so state machines like PACS_FLAG_NOTIFY_RDY
|
||||
@@ -440,7 +449,7 @@ int bt_gatt_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *param
|
||||
LOG_DBG("GattInd[%s]", bt_uuid_str(params->attr->uuid));
|
||||
|
||||
if (conn && conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattIndNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -454,7 +463,11 @@ int bt_gatt_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *param
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gatts_indicate(conn, params);
|
||||
#else
|
||||
return bt_le_nimble_gatts_indicate(conn, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_IDF
|
||||
@@ -774,7 +787,8 @@ bool bt_gatt_is_subscribed(struct bt_conn *conn,
|
||||
LOG_DBG("GattIsSub[%04x][%s]", ccc_type, bt_uuid_str(attr->uuid));
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
/* Query — disconnected conn is "not subscribed", not an error. */
|
||||
LOG_INF("GattIsSubNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -952,7 +966,7 @@ int bt_gatts_sub_changed(uint16_t conn_handle,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattsSubChgNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -975,7 +989,11 @@ int bt_gattc_disc_start_safe(uint16_t conn_handle)
|
||||
int err;
|
||||
LOG_DBG("GattcDiscStart[%u]", conn_handle);
|
||||
bt_le_host_lock();
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
err = bt_le_bluedroid_gattc_disc_start(conn_handle);
|
||||
#else
|
||||
err = bt_le_nimble_gattc_disc_start(conn_handle);
|
||||
#endif
|
||||
bt_le_host_unlock();
|
||||
return err;
|
||||
}
|
||||
@@ -991,7 +1009,7 @@ int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *param
|
||||
LOG_DBG("GattDisc[%u][%u]", params->start_handle, params->end_handle);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattDiscNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -1000,7 +1018,11 @@ int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *param
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gattc_discover(conn, params);
|
||||
#else
|
||||
return bt_le_nimble_gattc_discover(conn, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct gattc_sub *gattc_sub_find(struct bt_conn *conn)
|
||||
@@ -1141,7 +1163,11 @@ static int gattc_write_ccc(struct bt_conn *conn, struct bt_gatt_subscribe_params
|
||||
{
|
||||
LOG_DBG("GattcWrCcc[%u][%04x]", params->ccc_handle, params->value);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gattc_write_ccc(conn, params);
|
||||
#else
|
||||
return bt_le_nimble_gattc_write_ccc(conn, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
@@ -1167,7 +1193,7 @@ int bt_gatt_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *par
|
||||
* can resubscribe.
|
||||
*/
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattSubNotConn[%u][%u]", conn->handle, conn->state);
|
||||
params->value_handle = 0; /* unlinked: clear retry guard */
|
||||
return -ENOTCONN;
|
||||
}
|
||||
@@ -1251,7 +1277,7 @@ int bt_gatt_unsubscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *p
|
||||
params->value, params->value_handle, params->ccc_handle, params->end_handle);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattUnsubNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -1327,7 +1353,7 @@ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
|
||||
LOG_DBG("GattRd[%u]", params->handle_count);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattRdNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -1345,7 +1371,11 @@ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gattc_read(conn, params);
|
||||
#else
|
||||
return bt_le_nimble_gattc_read(conn, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_IDF
|
||||
@@ -1360,7 +1390,7 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
||||
LOG_DBG("GattWr[%u][%u][%u]", params->handle, params->length, params->offset);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattWrNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -1369,7 +1399,11 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gattc_write(conn, params);
|
||||
#else
|
||||
return bt_le_nimble_gattc_write(conn, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
@@ -1388,7 +1422,7 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle,
|
||||
LOG_DBG("GattWrCmd[%u][%u][%u]", handle, length, sign);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_ERR("GattWrCmdNotConn[%u][%u]", conn->handle, conn->state);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
@@ -1397,7 +1431,11 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle,
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_gattc_write_without_rsp(conn, handle, data, length);
|
||||
#else
|
||||
return bt_le_nimble_gattc_write_without_rsp(conn, handle, data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIB_ONLY
|
||||
@@ -1407,6 +1445,7 @@ void bt_le_acl_conn_disconnected_gatt_listener(uint16_t conn_handle)
|
||||
|
||||
LOG_DBG("AclConnDisconnectedGattListener[%u]", conn_handle);
|
||||
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_nimble_gatt_nrp_clear(conn_handle);
|
||||
|
||||
/* Drop the cached GATT client database so the next connection runs a
|
||||
@@ -1420,10 +1459,12 @@ void bt_le_acl_conn_disconnected_gatt_listener(uint16_t conn_handle)
|
||||
* and Service Changed handling end-to-end.
|
||||
*/
|
||||
bt_le_nimble_gattc_db_remove(conn_handle);
|
||||
#endif
|
||||
|
||||
/* The cached DB is dropped above, so the app will rediscover and call
|
||||
* bt_gatt_subscribe() again on reconnect with the BAP library's reused
|
||||
* `bt_gatt_subscribe_params` pointers. Drop those nodes from the
|
||||
/* On NimBLE the cached DB was dropped above; on Bluedroid no client-side
|
||||
* DB cache cleanup is performed here. Either way the app will rediscover
|
||||
* and call bt_gatt_subscribe() again on reconnect with the BAP library's
|
||||
* reused `bt_gatt_subscribe_params` pointers. Drop those nodes from the
|
||||
* tracking list (and zero their value) so the duplicate check in
|
||||
* bt_gatt_subscribe() doesn't short-circuit with -EALREADY, which
|
||||
* would otherwise skip the CCCD write and starve notifications.
|
||||
@@ -1438,5 +1479,9 @@ void bt_le_gatt_handle_event(uint8_t *data, size_t data_len)
|
||||
{
|
||||
assert(data && data_len);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_bluedroid_gatt_handle_event(data, data_len);
|
||||
#else
|
||||
bt_le_nimble_gatt_handle_event(data, data_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -70,5 +70,9 @@ int bt_hci_cmd_send_sync(uint16_t opcode,
|
||||
{
|
||||
LOG_DBG("HciCmdSendSync[%04x]", opcode);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_hci_iso_cmd_send_sync(opcode, buf, rsp);
|
||||
#else
|
||||
return bt_le_nimble_iso_cmd_send_sync(opcode, buf, rsp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
#include "common/app/gap.h"
|
||||
#include "common/app/gatt.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/gap.h"
|
||||
#include "bluedroid/gatt.h"
|
||||
#endif
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_HOST, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
static struct k_mutex host_mutex;
|
||||
|
||||
#define TIMEOUT_MS (5000 / portTICK_PERIOD_MS) /* 5s */
|
||||
|
||||
#if HOST_LOCK_DEBUG
|
||||
void bt_le_host_lock_debug(const char *func, int line)
|
||||
#else /* HOST_LOCK_DEBUG */
|
||||
@@ -31,9 +34,9 @@ void bt_le_host_lock(void)
|
||||
{
|
||||
/* LOG_DBG("%s: %d", func, line); */
|
||||
|
||||
int err = k_mutex_lock(&host_mutex, TIMEOUT_MS);
|
||||
int err = k_mutex_lock(&host_mutex, K_MUTEX_SHORT);
|
||||
if (err) {
|
||||
/* 5s wait failed: the host stack is wedged. k_mutex_lock has
|
||||
/* K_MUTEX_SHORT wait failed: the host stack is wedged. k_mutex_lock has
|
||||
* already logged self/holder task names. Use libc abort() rather
|
||||
* than assert(0) — assert is a no-op under NDEBUG, which would
|
||||
* let the caller enter the critical section without the mutex
|
||||
@@ -84,11 +87,23 @@ int bt_le_host_init(void)
|
||||
}
|
||||
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
|
||||
|
||||
err = bt_le_iso_init();
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
err = bt_le_bluedroid_gap_init();
|
||||
if (err) {
|
||||
goto deinit_l2cap;
|
||||
}
|
||||
|
||||
err = bt_le_bluedroid_gatt_init();
|
||||
if (err) {
|
||||
goto deinit_bluedroid_gatt;
|
||||
}
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
err = bt_le_iso_init();
|
||||
if (err) {
|
||||
goto deinit_bluedroid_gatt;
|
||||
}
|
||||
|
||||
err = bt_le_iso_task_init();
|
||||
if (err) {
|
||||
goto deinit_iso;
|
||||
@@ -98,7 +113,11 @@ int bt_le_host_init(void)
|
||||
|
||||
deinit_iso:
|
||||
bt_le_iso_deinit();
|
||||
deinit_bluedroid_gatt:
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_bluedroid_gatt_deinit();
|
||||
deinit_l2cap:
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
bt_le_l2cap_deinit();
|
||||
deinit_scan: /* only reachable when OTS path is compiled in */
|
||||
@@ -116,6 +135,9 @@ void bt_le_host_deinit(void)
|
||||
|
||||
bt_le_iso_task_deinit();
|
||||
bt_le_iso_deinit();
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_bluedroid_gatt_deinit();
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
#if CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT
|
||||
bt_le_l2cap_deinit();
|
||||
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
|
||||
|
||||
@@ -11,7 +11,11 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/gap.h"
|
||||
#else
|
||||
#include "nimble/gap.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -11,7 +11,11 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* ref bluedroid/app/gatt.h was an empty header; nothing to include here. */
|
||||
#else
|
||||
#include "nimble/gatt.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -37,6 +41,14 @@ struct bt_le_gatt_app_event_gatts_subscribe {
|
||||
uint8_t reason;
|
||||
};
|
||||
|
||||
/* Bluedroid-only: surfaces the GATTC open completion (carries the gattc_if
|
||||
* the BTA dispatcher used, which NimBLE has no analogue of). */
|
||||
struct bt_le_gatt_app_event_gattc_open {
|
||||
uint8_t status;
|
||||
uint16_t conn_handle;
|
||||
uint8_t gattc_if;
|
||||
};
|
||||
|
||||
struct bt_le_gatt_app_event {
|
||||
uint8_t type;
|
||||
|
||||
@@ -44,6 +56,7 @@ struct bt_le_gatt_app_event {
|
||||
struct bt_le_gatt_app_event_gatt_mtu_change gatt_mtu_change;
|
||||
struct bt_le_gatt_app_event_gattc_disc_cmpl gattc_disc_cmpl;
|
||||
struct bt_le_gatt_app_event_gatts_subscribe gatts_subscribe;
|
||||
struct bt_le_gatt_app_event_gattc_open gattc_open;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -51,6 +64,7 @@ enum bt_le_gatt_app_event_type {
|
||||
BT_LE_GATT_APP_EVENT_GATT_MTU_CHANGE,
|
||||
BT_LE_GATT_APP_EVENT_GATTC_DISC_CMPL,
|
||||
BT_LE_GATT_APP_EVENT_GATTS_SUBSCRIBE,
|
||||
BT_LE_GATT_APP_EVENT_GATTC_OPEN,
|
||||
|
||||
BT_LE_GATT_APP_EVENT_MAX,
|
||||
};
|
||||
@@ -67,7 +81,18 @@ void bt_le_gattc_app_disc_cmpl_event(struct bt_le_gattc_disc_cmpl_event *param);
|
||||
|
||||
void bt_le_gatts_app_subscribe_event(struct bt_le_gatts_subscribe_event *param);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
void bt_le_gattc_app_open_event(struct bt_le_gattc_open_event *param, uint8_t gattc_if);
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* NimBLE-only: callers post the raw ble_gap_event so the adapter can
|
||||
* translate it into the host-agnostic bt_le_gatt_app_event. Bluedroid has
|
||||
* no analogous app-level event stream (BTA dispatches directly to BTC),
|
||||
* so this is hidden from the API surface to make misuse a compile error.
|
||||
*/
|
||||
void bt_le_gatt_app_post_event(uint8_t type, void *param);
|
||||
#endif /* !CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -13,13 +13,21 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* TODO */
|
||||
#else
|
||||
#include "nimble/gap.h"
|
||||
#include "nimble/iso.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 0xff is out of bt_conn_state_t range — distinguishes NULL conn from any
|
||||
* real state in logs. */
|
||||
#define BT_CONN_STATE_GET(_c) ((_c) ? (_c)->state : 0xff)
|
||||
|
||||
void bt_conn_get_acl_conns(struct bt_conn **conns, uint8_t *count);
|
||||
|
||||
struct bt_conn *bt_le_acl_conn_find(uint16_t conn_handle);
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
#include <zephyr/autoconf.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/gatt.h"
|
||||
#else
|
||||
#include "nimble/gatt.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -73,16 +77,115 @@ struct bt_le_gatts_notify_tx_event {
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
/* Bluedroid-side adapter events. NimBLE produces ACL connect/disconnect via
|
||||
* the GAP event path (BT_LE_GAP_APP_PARAM_ACL_*), but Bluedroid's BTA
|
||||
* surfaces these through GATTS/GATTC callbacks. The bluedroid adapter posts
|
||||
* these typed events into the iso task and translates them into ACL/MTU/
|
||||
* discovery events for the LE Audio profile dispatcher. */
|
||||
|
||||
struct bt_le_addr_simple {
|
||||
uint8_t type;
|
||||
uint8_t val[6];
|
||||
};
|
||||
|
||||
struct bt_le_gattc_connect_event {
|
||||
uint16_t conn_handle;
|
||||
uint8_t role;
|
||||
struct bt_le_addr_simple peer;
|
||||
};
|
||||
|
||||
struct bt_le_gattc_disconnect_event {
|
||||
uint16_t conn_handle;
|
||||
uint8_t reason;
|
||||
};
|
||||
|
||||
struct bt_le_gattc_open_event {
|
||||
uint8_t status;
|
||||
uint16_t conn_handle;
|
||||
};
|
||||
|
||||
struct bt_le_gattc_mtu_event {
|
||||
uint8_t status;
|
||||
uint16_t conn_handle;
|
||||
uint16_t mtu;
|
||||
};
|
||||
|
||||
struct bt_le_gattc_read_chrc_event {
|
||||
uint8_t status;
|
||||
uint16_t conn_handle;
|
||||
uint16_t attr_handle;
|
||||
uint16_t len;
|
||||
uint8_t *value;
|
||||
};
|
||||
|
||||
struct bt_le_gattc_write_chrc_event {
|
||||
uint8_t status;
|
||||
uint16_t conn_handle;
|
||||
uint16_t attr_handle;
|
||||
uint16_t offset;
|
||||
};
|
||||
|
||||
struct bt_le_gatts_connect_event {
|
||||
uint16_t conn_handle;
|
||||
uint8_t role;
|
||||
struct bt_le_addr_simple peer;
|
||||
};
|
||||
|
||||
struct bt_le_gatts_disconnect_event {
|
||||
uint16_t conn_handle;
|
||||
uint8_t reason;
|
||||
};
|
||||
|
||||
struct bt_le_gatts_mtu_event {
|
||||
uint16_t conn_handle;
|
||||
uint16_t mtu;
|
||||
};
|
||||
|
||||
struct bt_le_gatts_read_event {
|
||||
uint16_t conn_handle;
|
||||
uint32_t trans_id;
|
||||
uint8_t peer[6];
|
||||
uint16_t attr_handle;
|
||||
uint16_t offset;
|
||||
bool is_long;
|
||||
bool need_rsp;
|
||||
};
|
||||
|
||||
struct bt_le_gatts_write_event {
|
||||
uint16_t conn_handle;
|
||||
uint32_t trans_id;
|
||||
uint8_t peer[6];
|
||||
uint16_t attr_handle;
|
||||
uint16_t offset;
|
||||
bool is_prep;
|
||||
bool need_rsp;
|
||||
uint16_t len;
|
||||
uint8_t *value;
|
||||
};
|
||||
|
||||
struct bt_le_gatt_event_param {
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
struct bt_le_gatt_mtu_change_event gatt_mtu_change;
|
||||
struct bt_le_gattc_discover_event gattc_discover;
|
||||
struct bt_le_gattc_disc_cmpl_event gattc_disc_cmpl;
|
||||
struct bt_le_gatts_subscribe_event gatts_subscribe;
|
||||
struct bt_le_gattc_notify_rx_event gattc_notify_rx;
|
||||
struct bt_le_gatts_notify_tx_event gatts_notify_tx;
|
||||
struct bt_le_gatt_mtu_change_event gatt_mtu_change;
|
||||
struct bt_le_gattc_discover_event gattc_discover;
|
||||
struct bt_le_gattc_disc_cmpl_event gattc_disc_cmpl;
|
||||
struct bt_le_gatts_subscribe_event gatts_subscribe;
|
||||
struct bt_le_gattc_notify_rx_event gattc_notify_rx;
|
||||
struct bt_le_gatts_notify_tx_event gatts_notify_tx;
|
||||
|
||||
/* Bluedroid-only paths (see comment above). */
|
||||
struct bt_le_gattc_connect_event gattc_connect;
|
||||
struct bt_le_gattc_disconnect_event gattc_disconnect;
|
||||
struct bt_le_gattc_open_event gattc_open;
|
||||
struct bt_le_gattc_mtu_event gattc_mtu;
|
||||
struct bt_le_gattc_read_chrc_event gattc_read_chrc;
|
||||
struct bt_le_gattc_write_chrc_event gattc_write_chrc;
|
||||
struct bt_le_gatts_connect_event gatts_connect;
|
||||
struct bt_le_gatts_disconnect_event gatts_disconnect;
|
||||
struct bt_le_gatts_mtu_event gatts_mtu;
|
||||
struct bt_le_gatts_read_event gatts_read;
|
||||
struct bt_le_gatts_write_event gatts_write;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -94,231 +197,22 @@ enum {
|
||||
BT_LE_GATTC_NOTIFY_RX_EVENT,
|
||||
BT_LE_GATTS_NOTIFY_TX_EVENT,
|
||||
|
||||
/* Bluedroid-only paths (see comment above). */
|
||||
BT_LE_GATTC_CONNECT_EVENT,
|
||||
BT_LE_GATTC_DISCONNECT_EVENT,
|
||||
BT_LE_GATTC_OPEN_EVENT,
|
||||
BT_LE_GATTC_MTU_EVENT,
|
||||
BT_LE_GATTC_READ_CHRC_EVENT,
|
||||
BT_LE_GATTC_WRITE_CHRC_EVENT,
|
||||
BT_LE_GATTS_CONNECT_EVENT,
|
||||
BT_LE_GATTS_DISCONNECT_EVENT,
|
||||
BT_LE_GATTS_MTU_EVENT,
|
||||
BT_LE_GATTS_READ_EVENT,
|
||||
BT_LE_GATTS_WRITE_EVENT,
|
||||
|
||||
BT_LE_GATT_EVENT_MAX,
|
||||
};
|
||||
|
||||
static inline char *audio_svc_uuid_to_str(uint16_t uuid)
|
||||
{
|
||||
switch (uuid) {
|
||||
case BT_UUID_GAP_VAL:
|
||||
return "GAP";
|
||||
case BT_UUID_GATT_VAL:
|
||||
return "GATT";
|
||||
case BT_UUID_AICS_VAL:
|
||||
return "AICS";
|
||||
case BT_UUID_CAS_VAL:
|
||||
return "CAS";
|
||||
case BT_UUID_VCS_VAL:
|
||||
return "VCS";
|
||||
case BT_UUID_VOCS_VAL:
|
||||
return "VOCS";
|
||||
case BT_UUID_CSIS_VAL:
|
||||
return "CSIS";
|
||||
case BT_UUID_MCS_VAL:
|
||||
return "MCS";
|
||||
case BT_UUID_GMCS_VAL:
|
||||
return "GMCS";
|
||||
case BT_UUID_TBS_VAL:
|
||||
return "TBS";
|
||||
case BT_UUID_GTBS_VAL:
|
||||
return "GTBS";
|
||||
case BT_UUID_MICS_VAL:
|
||||
return "MICS";
|
||||
case BT_UUID_ASCS_VAL:
|
||||
return "ASCS";
|
||||
case BT_UUID_BASS_VAL:
|
||||
return "BASS";
|
||||
case BT_UUID_PACS_VAL:
|
||||
return "PACS";
|
||||
case BT_UUID_BASIC_AUDIO_VAL:
|
||||
return "BASIC_AUDIO";
|
||||
case BT_UUID_HAS_VAL:
|
||||
return "HAS";
|
||||
case BT_UUID_TMAS_VAL:
|
||||
return "TMAS";
|
||||
case BT_UUID_PBA_VAL:
|
||||
return "PBA";
|
||||
case BT_UUID_GMAS_VAL:
|
||||
return "GMAS";
|
||||
case BT_UUID_OTS_VAL:
|
||||
return "OTS";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *audio_chrc_uuid_to_str(uint16_t uuid)
|
||||
{
|
||||
switch (uuid) {
|
||||
case BT_UUID_OTS_FEATURE_VAL:
|
||||
return "OTS_FEATURE";
|
||||
case BT_UUID_OTS_NAME_VAL:
|
||||
return "OTS_NAME";
|
||||
case BT_UUID_OTS_TYPE_VAL:
|
||||
return "OTS_TYPE";
|
||||
case BT_UUID_OTS_SIZE_VAL:
|
||||
return "OTS_SIZE";
|
||||
case BT_UUID_OTS_FIRST_CREATED_VAL:
|
||||
return "OTS_FIRST_CREATED";
|
||||
case BT_UUID_OTS_LAST_MODIFIED_VAL:
|
||||
return "OTS_LAST_MODIFIED";
|
||||
case BT_UUID_OTS_ID_VAL:
|
||||
return "OTS_ID";
|
||||
case BT_UUID_OTS_PROPERTIES_VAL:
|
||||
return "OTS_PROPERTIES";
|
||||
case BT_UUID_OTS_ACTION_CP_VAL:
|
||||
return "OTS_ACTION_CP";
|
||||
case BT_UUID_OTS_LIST_CP_VAL:
|
||||
return "OTS_LIST_CP";
|
||||
case BT_UUID_OTS_LIST_FILTER_VAL:
|
||||
return "OTS_LIST_FILTER";
|
||||
case BT_UUID_OTS_CHANGED_VAL:
|
||||
return "OTS_CHANGED";
|
||||
case BT_UUID_GATT_TMAPR_VAL:
|
||||
return "TMAP_ROLE";
|
||||
case BT_UUID_AICS_STATE_VAL:
|
||||
return "AICS_STATE";
|
||||
case BT_UUID_AICS_GAIN_SETTINGS_VAL:
|
||||
return "AICS_GAIN_SETTINGS";
|
||||
case BT_UUID_AICS_INPUT_TYPE_VAL:
|
||||
return "AICS_INPUT_TYPE";
|
||||
case BT_UUID_AICS_INPUT_STATUS_VAL:
|
||||
return "AICS_INPUT_STATUS";
|
||||
case BT_UUID_AICS_CONTROL_VAL:
|
||||
return "AICS_CONTROL";
|
||||
case BT_UUID_AICS_DESCRIPTION_VAL:
|
||||
return "AICS_DESCRIPTION";
|
||||
case BT_UUID_VCS_STATE_VAL:
|
||||
return "VCS_STATE";
|
||||
case BT_UUID_VCS_CONTROL_VAL:
|
||||
return "VCS_CONTROL";
|
||||
case BT_UUID_VCS_FLAGS_VAL:
|
||||
return "VCS_FLAGS";
|
||||
case BT_UUID_VOCS_STATE_VAL:
|
||||
return "VOCS_STATE";
|
||||
case BT_UUID_VOCS_LOCATION_VAL:
|
||||
return "VOCS_LOCATION";
|
||||
case BT_UUID_VOCS_CONTROL_VAL:
|
||||
return "VOCS_CONTROL";
|
||||
case BT_UUID_VOCS_DESCRIPTION_VAL:
|
||||
return "VOCS_DESCRIPTION";
|
||||
case BT_UUID_CSIS_SIRK_VAL:
|
||||
return "CSIS_SIRK";
|
||||
case BT_UUID_CSIS_SET_SIZE_VAL:
|
||||
return "CSIS_SET_SIZE";
|
||||
case BT_UUID_CSIS_SET_LOCK_VAL:
|
||||
return "CSIS_SET_LOCK";
|
||||
case BT_UUID_CSIS_RANK_VAL:
|
||||
return "CSIS_RANK";
|
||||
case BT_UUID_MCS_PLAYER_NAME_VAL:
|
||||
return "MCS_PLAYER_NAME";
|
||||
case BT_UUID_MCS_ICON_OBJ_ID_VAL:
|
||||
return "MCS_ICON_OBJ_ID";
|
||||
case BT_UUID_MCS_ICON_URL_VAL:
|
||||
return "MCS_ICON_URL";
|
||||
case BT_UUID_MCS_TRACK_CHANGED_VAL:
|
||||
return "MCS_TRACK_CHANGED";
|
||||
case BT_UUID_MCS_TRACK_TITLE_VAL:
|
||||
return "MCS_TRACK_TITLE";
|
||||
case BT_UUID_MCS_TRACK_DURATION_VAL:
|
||||
return "MCS_TRACK_DURATION";
|
||||
case BT_UUID_MCS_TRACK_POSITION_VAL:
|
||||
return "MCS_TRACK_POSITION";
|
||||
case BT_UUID_MCS_PLAYBACK_SPEED_VAL:
|
||||
return "MCS_PLAYBACK_SPEED";
|
||||
case BT_UUID_MCS_SEEKING_SPEED_VAL:
|
||||
return "MCS_SEEKING_SPEED";
|
||||
case BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID_VAL:
|
||||
return "MCS_TRACK_SEGMENTS_OBJ_ID";
|
||||
case BT_UUID_MCS_CURRENT_TRACK_OBJ_ID_VAL:
|
||||
return "MCS_CURRENT_TRACK_OBJ_ID";
|
||||
case BT_UUID_MCS_NEXT_TRACK_OBJ_ID_VAL:
|
||||
return "MCS_NEXT_TRACK_OBJ_ID";
|
||||
case BT_UUID_MCS_PARENT_GROUP_OBJ_ID_VAL:
|
||||
return "MCS_PARENT_GROUP_OBJ_ID";
|
||||
case BT_UUID_MCS_CURRENT_GROUP_OBJ_ID_VAL:
|
||||
return "MCS_CURRENT_GROUP_OBJ_ID";
|
||||
case BT_UUID_MCS_PLAYING_ORDER_VAL:
|
||||
return "MCS_PLAYING_ORDER";
|
||||
case BT_UUID_MCS_PLAYING_ORDERS_VAL:
|
||||
return "MCS_PLAYING_ORDERS";
|
||||
case BT_UUID_MCS_MEDIA_STATE_VAL:
|
||||
return "MCS_MEDIA_STATE";
|
||||
case BT_UUID_MCS_MEDIA_CONTROL_POINT_VAL:
|
||||
return "MCS_MEDIA_CONTROL_POINT";
|
||||
case BT_UUID_MCS_MEDIA_CONTROL_OPCODES_VAL:
|
||||
return "MCS_MEDIA_CONTROL_OPCODES";
|
||||
case BT_UUID_MCS_SEARCH_RESULTS_OBJ_ID_VAL:
|
||||
return "MCS_SEARCH_RESULTS_OBJ_ID";
|
||||
case BT_UUID_MCS_SEARCH_CONTROL_POINT_VAL:
|
||||
return "MCS_SEARCH_CONTROL_POINT";
|
||||
case BT_UUID_TBS_PROVIDER_NAME_VAL:
|
||||
return "TBS_PROVIDER_NAME";
|
||||
case BT_UUID_TBS_UCI_VAL:
|
||||
return "TBS_UCI";
|
||||
case BT_UUID_TBS_TECHNOLOGY_VAL:
|
||||
return "TBS_TECHNOLOGY";
|
||||
case BT_UUID_TBS_URI_LIST_VAL:
|
||||
return "TBS_URI_LIST";
|
||||
case BT_UUID_TBS_SIGNAL_STRENGTH_VAL:
|
||||
return "TBS_SIGNAL_STRENGTH";
|
||||
case BT_UUID_TBS_SIGNAL_INTERVAL_VAL:
|
||||
return "TBS_SIGNAL_INTERVAL";
|
||||
case BT_UUID_TBS_LIST_CURRENT_CALLS_VAL:
|
||||
return "TBS_LIST_CURRENT_CALLS";
|
||||
case BT_UUID_CCID_VAL:
|
||||
return "CCID";
|
||||
case BT_UUID_TBS_STATUS_FLAGS_VAL:
|
||||
return "TBS_STATUS_FLAGS";
|
||||
case BT_UUID_TBS_INCOMING_URI_VAL:
|
||||
return "TBS_INCOMING_URI";
|
||||
case BT_UUID_TBS_CALL_STATE_VAL:
|
||||
return "TBS_CALL_STATE";
|
||||
case BT_UUID_TBS_CALL_CONTROL_POINT_VAL:
|
||||
return "TBS_CALL_CONTROL_POINT";
|
||||
case BT_UUID_TBS_OPTIONAL_OPCODES_VAL:
|
||||
return "TBS_OPTIONAL_OPCODES";
|
||||
case BT_UUID_TBS_TERMINATE_REASON_VAL:
|
||||
return "TBS_TERMINATE_REASON";
|
||||
case BT_UUID_TBS_INCOMING_CALL_VAL:
|
||||
return "TBS_INCOMING_CALL";
|
||||
case BT_UUID_TBS_FRIENDLY_NAME_VAL:
|
||||
return "TBS_FRIENDLY_NAME";
|
||||
case BT_UUID_MICS_MUTE_VAL:
|
||||
return "MICS_MUTE";
|
||||
case BT_UUID_ASCS_ASE_SNK_VAL:
|
||||
return "ASCS_ASE_SNK";
|
||||
case BT_UUID_ASCS_ASE_SRC_VAL:
|
||||
return "ASCS_ASE_SRC";
|
||||
case BT_UUID_ASCS_ASE_CP_VAL:
|
||||
return "ASCS_ASE_CP";
|
||||
case BT_UUID_BASS_CONTROL_POINT_VAL:
|
||||
return "BASS_CP";
|
||||
case BT_UUID_BASS_RECV_STATE_VAL:
|
||||
return "BASS_RECV_STATE";
|
||||
case BT_UUID_PACS_SNK_VAL:
|
||||
return "PACS_SNK";
|
||||
case BT_UUID_PACS_SNK_LOC_VAL:
|
||||
return "PACS_SNK_LOC";
|
||||
case BT_UUID_PACS_SRC_VAL:
|
||||
return "PACS_SRC";
|
||||
case BT_UUID_PACS_SRC_LOC_VAL:
|
||||
return "PACS_SRC_LOC";
|
||||
case BT_UUID_PACS_AVAILABLE_CONTEXT_VAL:
|
||||
return "PACS_AVAILABLE_CONTEXT";
|
||||
case BT_UUID_PACS_SUPPORTED_CONTEXT_VAL:
|
||||
return "PACS_SUPPORTED_CONTEXT";
|
||||
case BT_UUID_HAS_HEARING_AID_FEATURES_VAL:
|
||||
return "HAS_HEARING_AID_FEATURES";
|
||||
case BT_UUID_HAS_PRESET_CONTROL_POINT_VAL:
|
||||
return "HAS_PRESET_CONTROL_POINT";
|
||||
case BT_UUID_HAS_ACTIVE_PRESET_INDEX_VAL:
|
||||
return "HAS_ACTIVE_PRESET_INDEX";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct gattc_sub {
|
||||
uint8_t id;
|
||||
bt_addr_le_t peer;
|
||||
|
||||
@@ -13,12 +13,18 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/iso.h"
|
||||
#else
|
||||
#include "nimble/iso.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct net_buf;
|
||||
|
||||
struct bt_le_iso_cb {
|
||||
void (*cis_dis)(struct net_buf *buf);
|
||||
void (*cis_est)(struct net_buf *buf);
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* TODO */
|
||||
#else
|
||||
#include "nimble/l2cap.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "bluedroid/gap.h"
|
||||
#else
|
||||
#include "nimble/gap.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -20,18 +20,32 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#if CONFIG_BT_BLUEDROID_PINNED_TO_CORE
|
||||
#define ISO_TASK_CORE CONFIG_BT_BLUEDROID_PINNED_TO_CORE
|
||||
#else /* CONFIG_BT_BLUEDROID_PINNED_TO_CORE */
|
||||
#define ISO_TASK_CORE (0)
|
||||
#endif /* CONFIG_BT_BLUEDROID_PINNED_TO_CORE */
|
||||
#else /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
#if CONFIG_BT_NIMBLE_PINNED_TO_CORE
|
||||
#define ISO_TASK_CORE CONFIG_BT_NIMBLE_PINNED_TO_CORE
|
||||
#else /* CONFIG_BT_NIMBLE_PINNED_TO_CORE */
|
||||
#define ISO_TASK_CORE (0)
|
||||
#endif /* CONFIG_BT_NIMBLE_PINNED_TO_CORE */
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#define ISO_TASK_STACK_SIZE 4096
|
||||
#define ISO_TASK_NAME "iso_task"
|
||||
/* Ref:
|
||||
* - Bluedroid BTC task: configMAX_PRIORITIES - 6
|
||||
* - Bluedroid BTU task: configMAX_PRIORITIES - 5
|
||||
* - NimBLE Host task: configMAX_PRIORITIES - 4
|
||||
*/
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#define ISO_TASK_PRIO (configMAX_PRIORITIES - 5)
|
||||
#else
|
||||
#define ISO_TASK_PRIO (configMAX_PRIORITIES - 4)
|
||||
#endif
|
||||
|
||||
enum iso_queue_item_type {
|
||||
ISO_QUEUE_ITEM_TYPE_TIMER_EVENT,
|
||||
|
||||
@@ -25,11 +25,19 @@
|
||||
|
||||
LOG_MODULE_REGISTER(ISO_SHIM, CONFIG_BT_ISO_LOG_LEVEL);
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#ifdef CONFIG_BT_BLE_ISO_STD_FLOW_CTRL
|
||||
#define ISO_STD_FLOW_CTRL true
|
||||
#else /* CONFIG_BT_BLE_ISO_STD_FLOW_CTRL */
|
||||
#define ISO_STD_FLOW_CTRL false
|
||||
#endif /* CONFIG_BT_BLE_ISO_STD_FLOW_CTRL */
|
||||
#else /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
#ifdef CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL
|
||||
#define ISO_STD_FLOW_CTRL true
|
||||
#else /* CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL */
|
||||
#define ISO_STD_FLOW_CTRL false
|
||||
#endif /* CONFIG_BT_NIMBLE_ISO_STD_FLOW_CTRL */
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#define ISO_PKT_FIRST_FRAG (0b00)
|
||||
#define ISO_PKT_CONT_FRAG (0b01)
|
||||
@@ -757,7 +765,11 @@ void bt_le_iso_handle_rx_data(uint8_t *data, size_t data_len)
|
||||
|
||||
int bt_le_iso_disconnect(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return bt_le_bluedroid_iso_disconnect(conn_handle, reason);
|
||||
#else
|
||||
return bt_le_nimble_iso_disconnect(conn_handle, reason);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void iso_features_set(void)
|
||||
@@ -819,7 +831,11 @@ int bt_le_iso_init(void)
|
||||
r_ble_ll_isoal_tx_comp_cb_set(iso_tx_comp_cb);
|
||||
#endif /* CONFIG_BT_ISO_TX */
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
err = bt_le_bluedroid_iso_init();
|
||||
#else
|
||||
err = bt_le_nimble_iso_init();
|
||||
#endif
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -839,5 +855,9 @@ void bt_le_iso_deinit(void)
|
||||
r_ble_ll_isoal_tx_comp_cb_set(NULL);
|
||||
#endif /* CONFIG_BT_ISO_TX */
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
bt_le_bluedroid_iso_deinit();
|
||||
#else
|
||||
bt_le_nimble_iso_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ int bt_le_l2cap_accept(uint16_t conn_handle, uint16_t psm,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_INF("L2capAcceptNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
|
||||
*result = L2CAP_LE_ERR_INVALID_PARAMS;
|
||||
return -ENOTCONN;
|
||||
@@ -219,7 +219,7 @@ void bt_le_l2cap_connected(uint16_t conn_handle, uint16_t psm,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_INF("L2capConnectedNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ void bt_le_l2cap_disconnected(uint16_t conn_handle, uint16_t psm)
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_INF("L2capDisconnectedNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ void bt_le_l2cap_received(uint16_t conn_handle, uint16_t psm,
|
||||
|
||||
conn = bt_le_acl_conn_find(conn_handle);
|
||||
if (conn == NULL || conn->state != BT_CONN_CONNECTED) {
|
||||
LOG_ERR("NotConn[%d]", __LINE__);
|
||||
LOG_INF("L2capReceivedNotConn[%u][%u]", conn_handle, BT_CONN_STATE_GET(conn));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -315,7 +315,9 @@ void bt_le_l2cap_received(uint16_t conn_handle, uint16_t psm,
|
||||
_IDF_ONLY
|
||||
int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint16_t psm)
|
||||
{
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
int err;
|
||||
#endif
|
||||
|
||||
LOG_DBG("L2capChanConnect[%04x]", psm);
|
||||
|
||||
@@ -334,6 +336,12 @@ int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* L2CAP COC is not yet implemented in the Bluedroid adapter (no
|
||||
* bt_le_bluedroid_l2cap_chan_connect exists). Return early so callers
|
||||
* like bt_gatt_ots_l2cap_connect see a clean -ENOTSUP. */
|
||||
return -ENOTSUP;
|
||||
#else
|
||||
err = bt_le_nimble_l2cap_chan_connect(conn->handle);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -342,12 +350,15 @@ int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan, uint
|
||||
l2cap_chan_add(conn, chan, psm);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
#if !CONFIG_BT_BLUEDROID_ENABLED
|
||||
int err;
|
||||
#endif
|
||||
|
||||
LOG_DBG("L2capChanDisconnect");
|
||||
|
||||
@@ -361,6 +372,9 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return -ENOTSUP;
|
||||
#else
|
||||
err = bt_le_nimble_l2cap_chan_disconnect(chan);
|
||||
if (err) {
|
||||
/* If the disconnect failed, remove the channel from the connection.
|
||||
@@ -371,6 +385,7 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan)
|
||||
}
|
||||
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
@@ -393,7 +408,11 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
return -ENOTSUP;
|
||||
#else
|
||||
return bt_le_nimble_l2cap_chan_send(chan, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
_IDF_ONLY
|
||||
@@ -490,10 +509,18 @@ int bt_le_l2cap_init(void)
|
||||
}
|
||||
#endif /* CONFIG_BT_OTS || CONFIG_BT_OTS_CLIENT */
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
/* No adapter-level L2CAP init exists (COC not implemented). Don't fail
|
||||
* host init here — the host-agnostic OTS registrations above are still
|
||||
* valid; any actual COC connect attempt later returns -ENOTSUP in
|
||||
* bt_l2cap_chan_connect, so OTS features fail gracefully at use time
|
||||
* instead of preventing the whole host from coming up. */
|
||||
#else
|
||||
err = bt_le_nimble_l2cap_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -484,7 +484,12 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, void *cb)
|
||||
int err = 0;
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) == false) {
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
ARG_UNUSED(cb);
|
||||
err = bt_le_bluedroid_scan_start(param);
|
||||
#else
|
||||
err = bt_le_nimble_scan_start(param, cb);
|
||||
#endif
|
||||
if (err == 0) {
|
||||
atomic_set_bit(bt_dev.flags, BT_DEV_SCANNING);
|
||||
}
|
||||
@@ -501,7 +506,11 @@ int bt_le_scan_stop(void)
|
||||
int err = 0;
|
||||
|
||||
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
err = bt_le_bluedroid_scan_stop();
|
||||
#else
|
||||
err = bt_le_nimble_scan_stop();
|
||||
#endif
|
||||
if (err == 0) {
|
||||
atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,49 @@
|
||||
#define CONFIG_LITTLE_ENDIAN 1
|
||||
#define CONFIG_BT_CONN_TX_USER_DATA_SIZE 8
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
|
||||
#define CONFIG_BT_ISO_EXT_ADV CONFIG_BT_BLE_50_EXTEND_ADV_EN
|
||||
#define CONFIG_BT_ISO_PER_ADV CONFIG_BT_BLE_50_PERIODIC_ADV_EN
|
||||
|
||||
/* Bluedroid host does not expose ext-adv/periodic-sync slot counts;
|
||||
* keep using the controller-side limits as the source of truth. */
|
||||
#if CONFIG_BT_ISO_EXT_ADV
|
||||
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET CONFIG_BT_LE_MAX_EXT_ADV_INSTANCES
|
||||
#else /* CONFIG_BT_ISO_EXT_ADV */
|
||||
#define CONFIG_BT_EXT_ADV_MAX_ADV_SET 0
|
||||
#endif /* CONFIG_BT_ISO_EXT_ADV */
|
||||
|
||||
#if CONFIG_BT_ISO_PER_ADV
|
||||
#define CONFIG_BT_PER_ADV_SYNC_MAX CONFIG_BT_LE_MAX_PERIODIC_SYNCS
|
||||
#else /* CONFIG_BT_ISO_PER_ADV */
|
||||
#define CONFIG_BT_PER_ADV_SYNC_MAX 0
|
||||
#endif /* CONFIG_BT_ISO_PER_ADV */
|
||||
|
||||
#if CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER
|
||||
#else /* CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER */
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER 0
|
||||
#define CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER 0
|
||||
#endif /* CONFIG_BT_BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER */
|
||||
|
||||
#define CONFIG_BT_MAX_CONN CONFIG_BT_ACL_CONNECTIONS
|
||||
#define CONFIG_BT_SMP CONFIG_BT_BLE_SMP_ENABLE
|
||||
#define CONFIG_BT_MAX_PAIRED CONFIG_BT_SMP_MAX_BONDS
|
||||
|
||||
#if CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_CIS_MAX_COUNT + CONFIG_BT_BLE_ISO_BIS_MAX_COUNT, "Too large ISO channels");
|
||||
#elif CONFIG_BT_ISO_UNICAST && !CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_CIS_MAX_COUNT, "Too large ISO channels");
|
||||
#elif !CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_BLE_ISO_BIS_MAX_COUNT, "Too large ISO channels");
|
||||
#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels");
|
||||
#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
|
||||
#else /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
#define CONFIG_BT_MAX_CONN CONFIG_BT_NIMBLE_MAX_CONNECTIONS
|
||||
#define CONFIG_BT_SMP CONFIG_BT_NIMBLE_SECURITY_ENABLE
|
||||
#define CONFIG_BT_MAX_PAIRED CONFIG_BT_NIMBLE_MAX_BONDS
|
||||
@@ -46,3 +89,5 @@ _Static_assert(CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_NIMBLE_ISO_BIS, "Too large IS
|
||||
#else /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
_Static_assert(CONFIG_BT_ISO_MAX_CHAN == 0, "Too large ISO channels");
|
||||
#endif /* CONFIG_BT_ISO_UNICAST && CONFIG_BT_ISO_BROADCAST */
|
||||
|
||||
#endif /* CONFIG_BT_BLUEDROID_ENABLED */
|
||||
|
||||
@@ -28,6 +28,7 @@ extern "C" {
|
||||
/* Mutex */
|
||||
|
||||
#define K_MUTEX_FOREVER portMAX_DELAY
|
||||
#define K_MUTEX_SHORT (5000 / portTICK_PERIOD_MS)
|
||||
|
||||
struct k_mutex {
|
||||
SemaphoreHandle_t handle;
|
||||
@@ -99,6 +100,94 @@ static inline int k_mutex_unlock(struct k_mutex *mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Semaphore */
|
||||
|
||||
#define K_SEM_FOREVER portMAX_DELAY
|
||||
#define K_SEM_SHORT (5000 / portTICK_PERIOD_MS)
|
||||
|
||||
struct k_sem {
|
||||
SemaphoreHandle_t handle;
|
||||
int result;
|
||||
};
|
||||
|
||||
static inline void k_sem_create(struct k_sem *sem)
|
||||
{
|
||||
assert(sem);
|
||||
assert(sem->handle == NULL);
|
||||
|
||||
sem->handle = xSemaphoreCreateBinary();
|
||||
assert(sem->handle);
|
||||
sem->result = 0;
|
||||
}
|
||||
|
||||
static inline void k_sem_delete(struct k_sem *sem)
|
||||
{
|
||||
assert(sem);
|
||||
assert(sem->handle);
|
||||
|
||||
vSemaphoreDelete(sem->handle);
|
||||
sem->handle = NULL;
|
||||
}
|
||||
|
||||
/* Inline log helper with a fixed tag, mirroring K_MUTEX_LOG_ERR. The sem
|
||||
* helpers are inlined across many TUs, not all of which call
|
||||
* LOG_MODULE_REGISTER, so we cannot reference the per-TU __iso_log_tag.
|
||||
* Hardcode the "ISO_SEM" tag and keep the same level gating. */
|
||||
#if CONFIG_BT_ISO_NO_LOG || (CONFIG_BT_ISO_LOG_LEVEL < BT_ISO_LOG_ERROR)
|
||||
#define K_SEM_LOG_ERR(fmt, args...)
|
||||
#else
|
||||
#define K_SEM_LOG_ERR(fmt, args...) BT_ISO_LOGE("ISO_SEM", fmt, ## args)
|
||||
#endif
|
||||
|
||||
static inline int k_sem_take(struct k_sem *sem, uint32_t timeout)
|
||||
{
|
||||
assert(sem);
|
||||
assert(sem->handle);
|
||||
|
||||
/* Do NOT touch sem->result here. The producer may have already written
|
||||
* it and called k_sem_give before this take ran (BTU/HCI cb on a
|
||||
* higher-priority task). Clearing now would race-overwrite the
|
||||
* producer's value. Caller must k_sem_reset() before initiating the
|
||||
* async op that will produce the result. */
|
||||
|
||||
if (xSemaphoreTake(sem->handle, timeout) == pdTRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !CONFIG_BT_ISO_NO_LOG && (CONFIG_BT_ISO_LOG_LEVEL >= BT_ISO_LOG_ERROR)
|
||||
K_SEM_LOG_ERR("TakeFail[self=%s]", pcTaskGetName(NULL));
|
||||
#else
|
||||
K_SEM_LOG_ERR("TakeFail");
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static inline int k_sem_give(struct k_sem *sem)
|
||||
{
|
||||
assert(sem);
|
||||
assert(sem->handle);
|
||||
|
||||
if (xSemaphoreGive(sem->handle) != pdTRUE) {
|
||||
K_SEM_LOG_ERR("GiveFail");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Discard any pending give. Used by callers that reuse the same sem across
|
||||
* cmd/response cycles where a previous cycle timed out — without this, a
|
||||
* late give from the timed-out cycle would unblock the next take and the
|
||||
* caller would see uninitialized response data. */
|
||||
static inline void k_sem_reset(struct k_sem *sem)
|
||||
{
|
||||
assert(sem);
|
||||
assert(sem->handle);
|
||||
|
||||
xQueueReset(sem->handle);
|
||||
sem->result = 0;
|
||||
}
|
||||
|
||||
/* Timer */
|
||||
|
||||
typedef uint32_t k_timeout_t;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
This example acts as a **BAP Broadcast Sink**. It scans for extended advertisements that carry the Broadcast Audio Announcement Service UUID and whose complete-name AD matches the hard-coded `"BAP Broadcast Source"` string; on a hit, it creates a periodic-advertising sync, builds a BAP broadcast sink for that PA handle and broadcast ID, decodes the BASE / BIGInfo from the PA channel, and then synchronizes to the BIG to receive BIS streams.
|
||||
|
||||
The build runs on top of the NimBLE host stack and the ESP BLE Audio component set. Sink-side APIs used: `esp_ble_audio_common_init` / `_start`, `esp_ble_audio_pacs_register` + `esp_ble_audio_pacs_cap_register` (sink PAC and sink location enabled), `esp_ble_audio_bap_scan_delegator_register` (so a Broadcast Assistant can drive PA-sync, broadcast-code, and BIS-sync requests via BASS), `esp_ble_audio_bap_broadcast_sink_register_cb`, `esp_ble_audio_bap_broadcast_sink_create` / `_sync` / `_stop` / `_delete`, and `esp_ble_audio_bap_base_get_subgroup_count` / `_get_bis_indexes`. PAC capabilities are LC3 with sample rates 16 kHz + 24 kHz, frame duration 10 ms, 1 channel, 40–60 octets/frame, 1 frame/SDU. The fallback broadcast code is `"1234"`; if a Broadcast Assistant has supplied one through BASS it is used instead.
|
||||
The build runs on top of the selected BLE host stack (Bluedroid by default; NimBLE via the `sdkconfig.defaults.nimble` overlay) and the ESP BLE Audio component set. Sink-side APIs used: `esp_ble_audio_common_init` / `_start`, `esp_ble_audio_pacs_register` + `esp_ble_audio_pacs_cap_register` (sink PAC and sink location enabled), `esp_ble_audio_bap_scan_delegator_register` (so a Broadcast Assistant can drive PA-sync, broadcast-code, and BIS-sync requests via BASS), `esp_ble_audio_bap_broadcast_sink_register_cb`, `esp_ble_audio_bap_broadcast_sink_create` / `_sync` / `_stop` / `_delete`, and `esp_ble_audio_bap_base_get_subgroup_count` / `_get_bis_indexes`. PAC capabilities are LC3 with sample rates 16 kHz + 24 kHz, frame duration 10 ms, 1 channel, 40–60 octets/frame, 1 frame/SDU. The fallback broadcast code is `"1234"`; if a Broadcast Assistant has supplied one through BASS it is used instead.
|
||||
|
||||
After PA sync is established, `ble_gap_disc_cancel()` stops the extended scanner — BASE/BIGInfo arrive over the PA channel — and `pa_sync_lost()` re-arms the scanner.
|
||||
After PA sync is established, `scan_stop()` halts the extended scanner — BASE/BIGInfo arrive over the PA channel — and `pa_sync_lost()` calls `scan_start()` to re-arm. The host-specific GAP/PA-sync plumbing lives in `main/bluedroid/scan.c` and `main/nimble/scan.c`; `main.c` only sees the host-agnostic interface in `scan.h`.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -34,11 +34,24 @@ The example inherits a Just-Works pairing model (LE Secure Connections, no MITM,
|
||||
|
||||
## Build & Flash
|
||||
|
||||
The base `sdkconfig.defaults` defaults to the **Bluedroid** host; idf.py automatically merges the per-target overlay (`sdkconfig.defaults.$IDF_TARGET`). To build with **NimBLE** host instead, layer `sdkconfig.defaults.nimble` on top via `-DSDKCONFIG_DEFAULTS`.
|
||||
|
||||
### Bluedroid host (default)
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4 # or esp32s31
|
||||
idf.py set-target esp32h4
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
### NimBLE host
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4
|
||||
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32h4;sdkconfig.defaults.nimble" -p PORT flash monitor
|
||||
```
|
||||
|
||||
For `esp32s31`, replace the chip overlay accordingly.
|
||||
|
||||
(Exit serial monitor with `Ctrl-]`.)
|
||||
|
||||
## Example Flow
|
||||
@@ -46,8 +59,8 @@ idf.py -p PORT flash monitor
|
||||
1. `app_main` initializes NVS, calls `bluetooth_init()`, and calls `esp_ble_audio_common_init(&info)` with `info.gap_cb = iso_gap_app_cb`.
|
||||
2. PACS is registered (`snk_pac` + `snk_loc`), each stream's `ops` field is wired to `stream_ops`, and the LC3 sink capability is registered via `esp_ble_audio_pacs_cap_register(ESP_BLE_AUDIO_DIR_SINK, ...)`.
|
||||
3. The scan delegator (`scan_delegator_cbs`: `recv_state_updated`, `pa_sync_req`, `pa_sync_term_req`, `broadcast_code`, `bis_sync_req`) and broadcast-sink callbacks (`base_recv`, `syncable`) are registered, then `esp_ble_audio_common_start(NULL)` runs.
|
||||
4. `ext_scan_start()` runs passive extended discovery (`itvl=window=160`). For each `ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV`, `data_cb` matches the complete/short/broadcast name AD type against `"BAP Broadcast Source"` and records the Broadcast ID from the Broadcast Audio Service Data.
|
||||
5. On match (and only when not already PA-syncing and no scan-delegator state is pinned), `pa_sync_create()` calls `ble_gap_periodic_adv_sync_create` with `skip=0`, `sync_timeout=10s`.
|
||||
4. `scan_init()` performs host-specific GAP setup (Bluedroid: registers the GAP callback for `*_COMPLETE_EVT` semaphore signalling + posts `EXT_ADV_REPORT` / `PERIODIC_ADV_SYNC_ESTAB` / `PERIODIC_ADV_REPORT` / `PERIODIC_ADV_SYNC_LOST` to the audio engine; NimBLE: no-op — the scan-instance callback is passed at `ble_gap_disc` / `ble_gap_periodic_adv_sync_create` time). `scan_start()` then runs passive extended discovery (`itvl=window=160`). For each `ESP_BLE_AUDIO_GAP_EVENT_EXT_SCAN_RECV`, `data_cb` matches the complete/short/broadcast name AD type against `"BAP Broadcast Source"` and records the Broadcast ID from the Broadcast Audio Service Data.
|
||||
5. On match (and only when not already PA-syncing and no scan-delegator state is pinned), `pa_sync_create(addr_type, addr, sid)` invokes the host-specific PA-sync create routine (`ble_gap_periodic_adv_sync_create` / `esp_ble_gap_periodic_adv_create_sync`) with `skip=0`, `sync_timeout=10s`.
|
||||
6. `ESP_BLE_AUDIO_GAP_EVENT_PA_SYNC` clears `pa_syncing`, cancels discovery, stores `sync_handle`, and calls `esp_ble_audio_bap_broadcast_sink_create()`.
|
||||
7. `base_recv_cb` extracts the subgroup count and BIS index bitfield (masked by `bis_index_mask`); when no Broadcast Assistant is connected, `requested_bis_sync` defaults to `ESP_BLE_AUDIO_BAP_BIS_SYNC_NO_PREF`.
|
||||
8. `syncable_cb` AND-masks the BASE bitfield with the requested mask, copies `TARGET_BROADCAST_CODE` if the BIG is encrypted (unless BASS already supplied one), and calls `esp_ble_audio_bap_broadcast_sink_sync()` with the chosen mask and `streams_p`.
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
set(srcs "main.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND srcs "bluedroid/scan.c")
|
||||
else()
|
||||
list(APPEND srcs "nimble/scan.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES bt nvs_flash)
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
static SemaphoreHandle_t scan_sem;
|
||||
|
||||
/* Controller status latched by gap_event_handler for EXAMPLE_WAIT_API_CHECK. */
|
||||
static esp_bt_status_t scan_op_status;
|
||||
|
||||
#define WAIT_API(_call) EXAMPLE_WAIT_API_CHECK(_call, scan_sem, portMAX_DELAY, scan_op_status)
|
||||
|
||||
static esp_ble_ext_scan_params_t ext_scan_params = {
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE,
|
||||
.cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK,
|
||||
.uncoded_cfg = {
|
||||
.scan_type = BLE_SCAN_TYPE_PASSIVE,
|
||||
.scan_interval = SCAN_INTERVAL,
|
||||
.scan_window = SCAN_WINDOW,
|
||||
},
|
||||
};
|
||||
|
||||
static void gap_event_handler(esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT:
|
||||
scan_op_status = param->set_ext_scan_params.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT:
|
||||
scan_op_status = param->ext_scan_start.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT:
|
||||
scan_op_status = param->ext_scan_stop.status;
|
||||
xSemaphoreGive(scan_sem);
|
||||
break;
|
||||
|
||||
/* PA sync / ext adv events: forwarded by adapter's BTA path, not here. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
scan_sem = xSemaphoreCreateBinary();
|
||||
if (scan_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create scan semaphore");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to register GAP callback, err %d", err);
|
||||
vSemaphoreDelete(scan_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_scan_start(void)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_set_ext_scan_params(&ext_scan_params));
|
||||
WAIT_API(esp_ble_gap_start_ext_scan(0, 0));
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for broadcast source...");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int ext_scan_stop(void)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_stop_ext_scan());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int pa_sync_create(uint8_t addr_type, const uint8_t addr[6], uint8_t sid)
|
||||
{
|
||||
esp_ble_gap_periodic_adv_sync_params_t params = {
|
||||
.filter_policy = 0,
|
||||
.sid = sid,
|
||||
.addr_type = addr_type,
|
||||
.skip = PA_SYNC_SKIP,
|
||||
.sync_timeout = PA_SYNC_TIMEOUT,
|
||||
};
|
||||
|
||||
memcpy(params.addr, addr, sizeof(params.addr));
|
||||
|
||||
/* Fire-and-forget: sync establishment (PERIODIC_ADV_SYNC_ESTAB_EVT) is
|
||||
* air-dependent and surfaces asynchronously. */
|
||||
return esp_ble_gap_periodic_adv_create_sync(¶ms);
|
||||
}
|
||||
|
||||
int pa_sync_terminate(uint16_t sync_handle)
|
||||
{
|
||||
return esp_ble_gap_periodic_adv_sync_terminate(sync_handle);
|
||||
}
|
||||
@@ -13,10 +13,6 @@
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "esp_ble_audio_lc3_defs.h"
|
||||
#include "esp_ble_audio_bap_api.h"
|
||||
@@ -25,18 +21,13 @@
|
||||
#include "ble_audio_example_init.h"
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSNK"
|
||||
#include "scan.h"
|
||||
|
||||
#define TARGET_DEVICE_NAME "BAP Broadcast Source"
|
||||
#define TARGET_DEVICE_NAME_LEN (sizeof(TARGET_DEVICE_NAME) - 1)
|
||||
|
||||
#define TARGET_BROADCAST_CODE "1234"
|
||||
|
||||
#define SCAN_INTERVAL 160 /* 100ms */
|
||||
#define SCAN_WINDOW 160 /* 100ms */
|
||||
|
||||
#define PA_SYNC_SKIP 0
|
||||
#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */
|
||||
#define PA_SYNC_HANDLE_INIT UINT16_MAX
|
||||
|
||||
#define CONN_HANDLE_INIT UINT16_MAX
|
||||
@@ -90,61 +81,6 @@ static esp_ble_audio_pacs_cap_t cap = {
|
||||
.codec_cap = &codec_cap,
|
||||
};
|
||||
|
||||
static void ext_scan_start(void)
|
||||
{
|
||||
struct ble_gap_disc_params params = {0};
|
||||
uint8_t own_addr_type;
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
params.passive = 1;
|
||||
params.itvl = SCAN_INTERVAL;
|
||||
params.window = SCAN_WINDOW;
|
||||
|
||||
err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start scanning, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for broadcast source...");
|
||||
}
|
||||
|
||||
static int pa_sync_create(const bt_addr_le_t *addr, uint8_t adv_sid)
|
||||
{
|
||||
struct ble_gap_periodic_sync_params params = {0};
|
||||
ble_addr_t sync_addr = {0};
|
||||
|
||||
sync_addr.type = addr->type;
|
||||
memcpy(sync_addr.val, addr->a.val, sizeof(sync_addr.val));
|
||||
params.skip = PA_SYNC_SKIP;
|
||||
params.sync_timeout = PA_SYNC_TIMEOUT;
|
||||
|
||||
return ble_gap_periodic_adv_sync_create(&sync_addr, adv_sid, ¶ms,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
}
|
||||
|
||||
static int pa_sync_terminate(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ble_gap_periodic_adv_sync_terminate(sync_handle);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to terminate PA sync, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "PA sync terminated");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void recv_state_updated_cb(esp_ble_conn_t *conn,
|
||||
const esp_ble_audio_bap_scan_delegator_recv_state_t *recv_state)
|
||||
{
|
||||
@@ -199,13 +135,27 @@ static int pa_sync_term_req_cb(esp_ble_conn_t *conn,
|
||||
|
||||
req_recv_state = recv_state;
|
||||
|
||||
err = pa_sync_terminate();
|
||||
/* Nothing to terminate if PAST/PA-sync never landed (e.g., PAST setup failed
|
||||
* earlier). Issuing the HCI terminate with the sentinel handle gets 0x12
|
||||
* (Invalid HCI Command Parameters) back from the controller. Mirrors
|
||||
* cap_acceptor_broadcast.c. */
|
||||
if (sync_handle == PA_SYNC_HANDLE_INIT) {
|
||||
ESP_LOGI(TAG, "PA sync never established, skip terminate");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = pa_sync_terminate(sync_handle);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to terminate PA sync, err %d", err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sync_handle = PA_SYNC_HANDLE_INIT;
|
||||
ESP_LOGI(TAG, "PA sync terminated");
|
||||
|
||||
/* Let the synthesized PA_SYNC_LOST event drive cleanup via pa_sync_lost
|
||||
* (it gates on the original sync_handle). Resetting sync_handle here would
|
||||
* make that gate miss and leak broadcast_sink. Mirrors
|
||||
* cap_acceptor_broadcast.c. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -481,7 +431,6 @@ static bool data_cb(uint8_t type, const uint8_t *data,
|
||||
static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event)
|
||||
{
|
||||
struct scan_recv_data sr = {0};
|
||||
bt_addr_le_t addr;
|
||||
int err;
|
||||
|
||||
/* Periodic advertising interval. 0 if no periodic advertising. */
|
||||
@@ -500,10 +449,9 @@ static void ext_scan_recv(esp_ble_audio_gap_app_event_t *event)
|
||||
if (pa_syncing == false && req_recv_state == NULL) {
|
||||
broadcaster_broadcast_id = sr.broadcast_id;
|
||||
|
||||
addr.type = event->ext_scan_recv.addr.type;
|
||||
memcpy(addr.a.val, event->ext_scan_recv.addr.val, sizeof(addr.a.val));
|
||||
|
||||
err = pa_sync_create(&addr, event->ext_scan_recv.sid);
|
||||
err = pa_sync_create(event->ext_scan_recv.addr.type,
|
||||
event->ext_scan_recv.addr.val,
|
||||
event->ext_scan_recv.sid);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to create PA sync, err %d", err);
|
||||
return;
|
||||
@@ -533,7 +481,7 @@ static void pa_sync(esp_ble_audio_gap_app_event_t *event)
|
||||
* via the PA sync channel, so the extended scanner is no longer
|
||||
* needed. Stop it now — pa_sync_lost() will restart it on loss.
|
||||
*/
|
||||
rc = ble_gap_disc_cancel();
|
||||
rc = ext_scan_stop();
|
||||
if (rc) {
|
||||
ESP_LOGW(TAG, "Failed to stop scanning, err %d", rc);
|
||||
}
|
||||
@@ -618,6 +566,12 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
err = app_host_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to init host, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_ble_audio_common_init(&info);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio, err %d", err);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/ble_hs.h"
|
||||
|
||||
#include "esp_ble_audio_common_api.h"
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
/* Forward only the GAP events the application consumes. */
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_EXT_DISC:
|
||||
case BLE_GAP_EVENT_PERIODIC_SYNC:
|
||||
case BLE_GAP_EVENT_PERIODIC_REPORT:
|
||||
case BLE_GAP_EVENT_PERIODIC_SYNC_LOST:
|
||||
esp_ble_audio_gap_app_post_event(event->type, event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_scan_start(void)
|
||||
{
|
||||
struct ble_gap_disc_params params = {0};
|
||||
uint8_t own_addr_type;
|
||||
int err;
|
||||
|
||||
err = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to determine own addr type, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
params.passive = 1;
|
||||
params.itvl = SCAN_INTERVAL;
|
||||
params.window = SCAN_WINDOW;
|
||||
|
||||
err = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, ¶ms,
|
||||
gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start scanning, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Scanning for broadcast source...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_scan_stop(void)
|
||||
{
|
||||
return ble_gap_disc_cancel();
|
||||
}
|
||||
|
||||
int pa_sync_create(uint8_t addr_type, const uint8_t addr[6], uint8_t sid)
|
||||
{
|
||||
struct ble_gap_periodic_sync_params params = {0};
|
||||
ble_addr_t sync_addr = {0};
|
||||
|
||||
sync_addr.type = addr_type;
|
||||
memcpy(sync_addr.val, addr, sizeof(sync_addr.val));
|
||||
params.skip = PA_SYNC_SKIP;
|
||||
params.sync_timeout = PA_SYNC_TIMEOUT;
|
||||
|
||||
return ble_gap_periodic_adv_sync_create(&sync_addr, sid, ¶ms,
|
||||
gap_event_cb, NULL);
|
||||
}
|
||||
|
||||
int pa_sync_terminate(uint16_t sync_handle)
|
||||
{
|
||||
return ble_gap_periodic_adv_sync_terminate(sync_handle);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSNK"
|
||||
|
||||
#define SCAN_INTERVAL 160 /* 100ms */
|
||||
#define SCAN_WINDOW 160 /* 100ms */
|
||||
|
||||
#define PA_SYNC_SKIP 0
|
||||
#define PA_SYNC_TIMEOUT 1000 /* 1000 * 10ms = 10s */
|
||||
|
||||
int app_host_init(void);
|
||||
|
||||
int ext_scan_start(void);
|
||||
int ext_scan_stop(void);
|
||||
|
||||
int pa_sync_create(uint8_t addr_type, const uint8_t addr[6], uint8_t sid);
|
||||
int pa_sync_terminate(uint16_t sync_handle);
|
||||
@@ -3,14 +3,14 @@
|
||||
#
|
||||
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
CONFIG_BT_CLASSIC_ENABLED=n
|
||||
CONFIG_BT_CONTROLLER_ENABLED=y
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=1
|
||||
CONFIG_BT_BLE_FEAT_ISO_EN=y
|
||||
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
@@ -24,6 +24,8 @@ CONFIG_BT_PAC_SRC_NOTIFIABLE=y
|
||||
CONFIG_BT_PAC_SRC_LOC_WRITEABLE=y
|
||||
CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE=y
|
||||
CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE=y
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=30
|
||||
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE=60
|
||||
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# NimBLE host overlay for this example.
|
||||
# Use with:
|
||||
# idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.$IDF_TARGET;sdkconfig.defaults.nimble" build
|
||||
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_NVS_PERSIST=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=20
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
This example acts as a **BAP Broadcast Source**. It creates a BAP broadcast source from the LC3 `16_2_1` broadcast preset, encodes the BASE into the periodic advertising payload, places the Broadcast Audio Announcement Service UUID and a fixed 24-bit Broadcast ID (`0x123456`) in the extended advertising payload, and then starts the BIG so that BIS streams transmit synthetic SDU data on a fixed cadence.
|
||||
|
||||
The build runs on top of the NimBLE host stack and the ESP BLE Audio component set. Source-side APIs used: `esp_ble_audio_common_init` / `esp_ble_audio_common_start` (common layer), `esp_ble_audio_bap_broadcast_source_create` / `_get_base` / `_start` (BAP), `esp_ble_audio_bap_broadcast_adv_add` (BAP/ISO glue), and the BAP stream callbacks (`started`, `stopped`, `sent`, `disconnected`). PACS, GAP scanner, and the scan delegator are **not** used on this side. Encryption is enabled because the broadcast code `"1234"` is non-empty; packing is `ESP_BLE_ISO_PACKING_SEQUENTIAL`. Channel allocation per stream is hard-coded as `FRONT_LEFT` for stream 0 and `FRONT_RIGHT` for stream 1.
|
||||
The build runs on top of the selected BLE host stack (Bluedroid by default; NimBLE via the `sdkconfig.defaults.nimble` overlay) and the ESP BLE Audio component set. Source-side APIs used: `esp_ble_audio_common_init` / `esp_ble_audio_common_start` (common layer), `esp_ble_audio_bap_broadcast_source_create` / `_get_base` / `_start` (BAP), `esp_ble_audio_bap_broadcast_adv_add` (BAP/ISO glue), and the BAP stream callbacks (`started`, `stopped`, `sent`, `disconnected`). PACS, GAP scanner, and the scan delegator are **not** used on this side. Encryption is enabled because the broadcast code `"1234"` is non-empty; packing is `ESP_BLE_ISO_PACKING_SEQUENTIAL`. Channel allocation per stream is hard-coded as `FRONT_LEFT` for stream 0 and `FRONT_RIGHT` for stream 1.
|
||||
|
||||
The TX scheduler is built on `example_audio_tx_scheduler_*` helpers; the source comment notes that ESP timer resolution is not accurate enough for the SDU interval, so a `k_work_delayable`-based scheduler is used instead.
|
||||
|
||||
@@ -34,11 +34,24 @@ The example inherits a Just-Works pairing model (LE Secure Connections, no MITM,
|
||||
|
||||
## Build & Flash
|
||||
|
||||
The base `sdkconfig.defaults` defaults to the **Bluedroid** host; idf.py automatically merges the per-target overlay (`sdkconfig.defaults.$IDF_TARGET`). To build with **NimBLE** host instead, layer `sdkconfig.defaults.nimble` on top via `-DSDKCONFIG_DEFAULTS`.
|
||||
|
||||
### Bluedroid host (default)
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4 # or esp32s31
|
||||
idf.py set-target esp32h4
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
### NimBLE host
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4
|
||||
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32h4;sdkconfig.defaults.nimble" -p PORT flash monitor
|
||||
```
|
||||
|
||||
For `esp32s31`, replace the chip overlay accordingly.
|
||||
|
||||
(Exit serial monitor with `Ctrl-]`.)
|
||||
|
||||
## Example Flow
|
||||
@@ -46,7 +59,7 @@ idf.py -p PORT flash monitor
|
||||
1. `app_main` initializes NVS, calls `bluetooth_init()`, and calls `esp_ble_audio_common_init(NULL)` (no GAP callback for this role).
|
||||
2. `broadcast_source_setup()` registers `source_started` / `source_stopped` callbacks, populates per-stream channel-allocation BIS metadata (left/right), registers `stream_ops` on each stream, and calls `esp_ble_audio_bap_broadcast_source_create()` with the encrypted preset.
|
||||
3. `esp_ble_audio_common_start(NULL)` starts the audio stack; each stream's `example_audio_tx_scheduler_init()` is wired with `tx_scheduler_cb`.
|
||||
4. `ext_adv_start()` configures non-connectable extended adv (1M primary / 2M secondary, 200 ms interval), writes Broadcast Audio Service Data + Broadcast ID + complete name, configures periodic adv (100 ms), writes the BASE returned by `esp_ble_audio_bap_broadcast_source_get_base()`, then starts periodic and extended advertising.
|
||||
4. `adv_init()` performs host-specific GAP setup (Bluedroid: registers the GAP callback for `*_COMPLETE_EVT` semaphore signalling; NimBLE: no-op — adv-instance callback is passed at configure time). `ext_adv_start()` builds the extended (Broadcast Audio Service Data + Broadcast ID + complete name) and periodic (BASE from `esp_ble_audio_bap_broadcast_source_get_base()`) payloads in host-agnostic bytes, then calls `adv_start(ext_data, ext_len, per_data, per_len)`. The host-specific implementation in `main/bluedroid/adv.c` or `main/nimble/adv.c` configures non-connectable extended adv (1M primary / 2M secondary, 200 ms interval), configures periodic adv (100 ms), writes both payloads, and starts periodic and extended advertising.
|
||||
5. `broadcast_start()` calls `esp_ble_audio_bap_broadcast_adv_add()` and `esp_ble_audio_bap_broadcast_source_start()` on the same `ADV_HANDLE`, which kicks off BIGInfo + BIS creation.
|
||||
6. When each BIS stream goes streaming, `stream_started_cb` allocates an SDU-sized buffer and calls `example_audio_tx_scheduler_start()` at `preset_active.qos.interval`; the scheduler invokes `broadcast_source_tx()`, which fills the buffer with the low byte of `seq_num` and calls `esp_ble_audio_bap_stream_send()`.
|
||||
7. `stream_sent_cb` forwards completions to `example_audio_tx_scheduler_on_sent()` for drift accounting; `stream_stopped_cb` and `stream_disconnected_cb` stop the scheduler; `source_stopped_cb` frees all per-stream buffers.
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
set(srcs "main.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
list(APPEND srcs "bluedroid/adv.c")
|
||||
else()
|
||||
list(APPEND srcs "nimble/adv.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES bt nvs_flash)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSRC"
|
||||
|
||||
#define ADV_HANDLE 0
|
||||
#define ADV_SID 0
|
||||
#define ADV_TX_POWER 127
|
||||
#define ADV_INTERVAL_MS 200
|
||||
#define PER_ADV_INTERVAL_MS 100
|
||||
|
||||
int app_host_init(void);
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len);
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
|
||||
#include "adv.h"
|
||||
|
||||
static SemaphoreHandle_t adv_sem;
|
||||
|
||||
/* Controller status latched by gap_event_handler for EXAMPLE_WAIT_API_CHECK. */
|
||||
static esp_bt_status_t adv_op_status;
|
||||
|
||||
#define WAIT_API(_call) EXAMPLE_WAIT_API_CHECK(_call, adv_sem, portMAX_DELAY, adv_op_status)
|
||||
|
||||
static esp_ble_gap_ext_adv_params_t ext_adv_params = {
|
||||
.type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED,
|
||||
.interval_min = ESP_BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS),
|
||||
.interval_max = ESP_BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS),
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
.primary_phy = ESP_BLE_GAP_PHY_1M,
|
||||
.max_skip = 0,
|
||||
.secondary_phy = ESP_BLE_GAP_PHY_2M,
|
||||
.sid = ADV_SID,
|
||||
.scan_req_notif = false,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.tx_power = ADV_TX_POWER,
|
||||
};
|
||||
|
||||
static esp_ble_gap_periodic_adv_params_t periodic_adv_params = {
|
||||
.interval_min = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(PER_ADV_INTERVAL_MS),
|
||||
.interval_max = ESP_BLE_GAP_PERIODIC_ADV_ITVL_MS(PER_ADV_INTERVAL_MS),
|
||||
.properties = 0,
|
||||
};
|
||||
|
||||
static esp_ble_gap_ext_adv_t ext_adv_inst[1] = {
|
||||
[0] = { ADV_HANDLE, 0, 0 },
|
||||
};
|
||||
|
||||
static void gap_event_handler(esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_set_params.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_data_set.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT:
|
||||
adv_op_status = param->ext_adv_start.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT:
|
||||
adv_op_status = param->peroid_adv_set_params.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT:
|
||||
adv_op_status = param->period_adv_data_set.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT:
|
||||
adv_op_status = param->period_adv_start.status;
|
||||
xSemaphoreGive(adv_sem);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
adv_sem = xSemaphoreCreateBinary();
|
||||
if (adv_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create adv semaphore");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to register GAP callback, err %d", err);
|
||||
vSemaphoreDelete(adv_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len)
|
||||
{
|
||||
WAIT_API(esp_ble_gap_ext_adv_set_params(ADV_HANDLE, &ext_adv_params));
|
||||
WAIT_API(esp_ble_gap_config_ext_adv_data_raw(ADV_HANDLE, ext_len, ext_data));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_set_params(ADV_HANDLE, &periodic_adv_params));
|
||||
#if CONFIG_BT_BLE_FEAT_PERIODIC_ADV_ENH
|
||||
WAIT_API(esp_ble_gap_config_periodic_adv_data_raw(ADV_HANDLE, per_len, per_data, false));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_start(ADV_HANDLE, true));
|
||||
#else
|
||||
WAIT_API(esp_ble_gap_config_periodic_adv_data_raw(ADV_HANDLE, per_len, per_data));
|
||||
WAIT_API(esp_ble_gap_periodic_adv_start(ADV_HANDLE));
|
||||
#endif
|
||||
WAIT_API(esp_ble_gap_ext_adv_start(1, ext_adv_inst));
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
return 0;
|
||||
}
|
||||
@@ -9,17 +9,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
|
||||
#include "esp_ble_audio_lc3_defs.h"
|
||||
#include "esp_ble_audio_bap_api.h"
|
||||
@@ -29,7 +22,7 @@
|
||||
#include "ble_audio_example_init.h"
|
||||
#include "ble_audio_example_utils.h"
|
||||
|
||||
#define TAG "BAP_BSRC"
|
||||
#include "adv.h"
|
||||
|
||||
ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(preset_active,
|
||||
ESP_BLE_AUDIO_LOCATION_FRONT_LEFT |
|
||||
@@ -42,16 +35,6 @@ ESP_BLE_AUDIO_BAP_LC3_BROADCAST_PRESET_16_2_1_DEFINE(preset_active,
|
||||
#define LOCAL_BROADCAST_CODE "1234" /* Maximum length is 16 */
|
||||
#define LOCAL_BROADCAST_ID 0x123456
|
||||
|
||||
#define ADV_HANDLE 0x00
|
||||
#define ADV_SID 0
|
||||
#define ADV_TX_POWER 127
|
||||
#define ADV_ADDRESS BLE_OWN_ADDR_PUBLIC
|
||||
#define ADV_PRIMARY_PHY BLE_HCI_LE_PHY_1M
|
||||
#define ADV_SECONDARY_PHY BLE_HCI_LE_PHY_2M
|
||||
#define ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(200)
|
||||
|
||||
#define PER_ADV_INTERVAL BLE_GAP_ADV_ITVL_MS(100)
|
||||
|
||||
#define STREAM_COUNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT
|
||||
#define SUBGROUP_COUNT CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT
|
||||
|
||||
@@ -369,138 +352,55 @@ static uint8_t *per_adv_data_get(uint8_t *data_len)
|
||||
return data;
|
||||
}
|
||||
|
||||
static int ext_adv_start(void)
|
||||
static int broadcast_start(void)
|
||||
{
|
||||
struct ble_gap_periodic_adv_params per_params = {0};
|
||||
struct ble_gap_ext_adv_params ext_params = {0};
|
||||
struct os_mbuf *data = NULL;
|
||||
esp_ble_audio_bap_broadcast_adv_info_t info = {
|
||||
.adv_handle = ADV_HANDLE,
|
||||
};
|
||||
/* BASE (per_adv_data_get) needs broadcast_source to exist — built earlier
|
||||
* by broadcast_source_setup(), so safe to call here. */
|
||||
uint8_t *ext_data = NULL;
|
||||
uint8_t *per_data = NULL;
|
||||
uint8_t data_len = 0;
|
||||
int err;
|
||||
uint8_t ext_len = 0;
|
||||
uint8_t per_len = 0;
|
||||
int err = 0;
|
||||
|
||||
ext_params.connectable = 0;
|
||||
ext_params.scannable = 0;
|
||||
ext_params.legacy_pdu = 0;
|
||||
ext_params.own_addr_type = ADV_ADDRESS;
|
||||
ext_params.primary_phy = ADV_PRIMARY_PHY;
|
||||
ext_params.secondary_phy = ADV_SECONDARY_PHY;
|
||||
ext_params.tx_power = ADV_TX_POWER;
|
||||
ext_params.sid = ADV_SID;
|
||||
ext_params.itvl_min = ADV_INTERVAL;
|
||||
ext_params.itvl_max = ADV_INTERVAL;
|
||||
|
||||
err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL,
|
||||
example_audio_gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ext_data = ext_adv_data_get(&data_len);
|
||||
ext_data = ext_adv_data_get(&ext_len);
|
||||
if (ext_data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(data_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get ext adv mbuf");
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, ext_data, data_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
per_params.include_tx_power = 0;
|
||||
per_params.itvl_min = PER_ADV_INTERVAL;
|
||||
per_params.itvl_max = PER_ADV_INTERVAL;
|
||||
|
||||
err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
per_data = per_adv_data_get(&data_len);
|
||||
per_data = per_adv_data_get(&per_len);
|
||||
if (per_data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(data_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get per adv mbuf");
|
||||
err = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, per_data, data_len);
|
||||
err = ext_adv_start(ext_data, ext_len, per_data, per_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append per adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set per adv data, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_start(ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start per advertising, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
|
||||
end:
|
||||
if (ext_data) {
|
||||
free(ext_data);
|
||||
}
|
||||
if (per_data) {
|
||||
free(per_data);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void broadcast_start(void)
|
||||
{
|
||||
esp_ble_audio_bap_broadcast_adv_info_t info = {
|
||||
.adv_handle = ADV_HANDLE,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = esp_ble_audio_bap_broadcast_adv_add(&info);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to add adv for broadcast source, err %d", err);
|
||||
return;
|
||||
goto end;
|
||||
}
|
||||
|
||||
err = esp_ble_audio_bap_broadcast_source_start(broadcast_source, ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start broadcast source, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ext_data != NULL) {
|
||||
free(ext_data);
|
||||
}
|
||||
if (per_data != NULL) {
|
||||
free(per_data);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
@@ -521,6 +421,12 @@ void app_main(void)
|
||||
return;
|
||||
}
|
||||
|
||||
err = app_host_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to init host, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_ble_audio_common_init(NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize audio, err %d", err);
|
||||
@@ -548,10 +454,9 @@ void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
err = ext_adv_start();
|
||||
err = broadcast_start();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start broadcast, err %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
broadcast_start();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "host/ble_gap.h"
|
||||
|
||||
#include "adv.h"
|
||||
|
||||
/* Non-connectable broadcaster: no GAP events for the application. */
|
||||
static int gap_event_cb(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_host_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext_adv_start(const uint8_t *ext_data, uint8_t ext_len,
|
||||
const uint8_t *per_data, uint8_t per_len)
|
||||
{
|
||||
struct ble_gap_periodic_adv_params per_params = {0};
|
||||
struct ble_gap_ext_adv_params ext_params = {0};
|
||||
struct os_mbuf *data;
|
||||
int err;
|
||||
|
||||
ext_params.connectable = 0;
|
||||
ext_params.scannable = 0;
|
||||
ext_params.legacy_pdu = 0;
|
||||
ext_params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
ext_params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
ext_params.secondary_phy = BLE_HCI_LE_PHY_2M;
|
||||
ext_params.tx_power = ADV_TX_POWER;
|
||||
ext_params.sid = ADV_SID;
|
||||
ext_params.itvl_min = BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS);
|
||||
ext_params.itvl_max = BLE_GAP_ADV_ITVL_MS(ADV_INTERVAL_MS);
|
||||
|
||||
err = ble_gap_ext_adv_configure(ADV_HANDLE, &ext_params, NULL,
|
||||
gap_event_cb, NULL);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure ext adv params, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(ext_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get ext adv mbuf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, ext_data, ext_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append ext adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set ext adv data, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
per_params.include_tx_power = 0;
|
||||
per_params.itvl_min = BLE_GAP_PERIODIC_ITVL_MS(PER_ADV_INTERVAL_MS);
|
||||
per_params.itvl_max = BLE_GAP_PERIODIC_ITVL_MS(PER_ADV_INTERVAL_MS);
|
||||
|
||||
err = ble_gap_periodic_adv_configure(ADV_HANDLE, &per_params);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to configure per adv params, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = os_msys_get_pkthdr(per_len, 0);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to get per adv mbuf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = os_mbuf_append(data, per_data, per_len);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to append per adv data, err %d", err);
|
||||
os_mbuf_free_chain(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_set_data(ADV_HANDLE, data);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to set per adv data, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_periodic_adv_start(ADV_HANDLE);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start per advertising, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ble_gap_ext_adv_start(ADV_HANDLE, 0, 0);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start ext advertising, err %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,14 +3,19 @@
|
||||
#
|
||||
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_BT_NIMBLE_ISO=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
CONFIG_BT_CLASSIC_ENABLED=n
|
||||
CONFIG_BT_CONTROLLER_ENABLED=y
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_ACL_CONNECTIONS=1
|
||||
CONFIG_BT_BLE_FEAT_ISO_EN=y
|
||||
|
||||
CONFIG_BT_ISO_MAX_CHAN=2
|
||||
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user