项目文件夹

文件
2026-07-13 13:04:25 +08:00

565 行
15 KiB
C

/*
* SPDX-FileCopyrightText: 2017-2021 Nordic Semiconductor
* SPDX-FileCopyrightText: 2015-2016 Intel Corporation
* SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/common/bt_str.h>
#include <../host/conn_internal.h>
#include <../host/hci_core.h>
#include "common/host.h"
LOG_MODULE_REGISTER(ISO_SCAN, CONFIG_BT_ISO_LOG_LEVEL);
static sys_slist_t scan_cbs = SYS_SLIST_STATIC_INIT(&scan_cbs);
_LIB_ONLY
int bt_le_scan_cb_register(struct bt_le_scan_cb *cb)
{
LOG_DBG("ScanCbReg");
if (cb == NULL) {
LOG_ERR("ScanCbNull");
return -EINVAL;
}
if (sys_slist_find(&scan_cbs, &cb->node, NULL)) {
LOG_WRN("ScanCbExist");
return -EEXIST;
}
sys_slist_append(&scan_cbs, &cb->node);
return 0;
}
_NOT_USED
void bt_le_scan_cb_unregister(struct bt_le_scan_cb *cb)
{
LOG_DBG("ScanCbUnreg");
if (cb == NULL) {
LOG_ERR("ScanCbNull");
return;
}
sys_slist_find_and_remove(&scan_cbs, &cb->node);
}
static uint8_t get_adv_type(uint8_t evt_type)
{
/* LOG_DBG("GetAdvType[%02x]", evt_type); */
switch (evt_type) {
case (BT_HCI_LE_ADV_EVT_TYPE_CONN |
BT_HCI_LE_ADV_EVT_TYPE_SCAN |
BT_HCI_LE_ADV_EVT_TYPE_LEGACY):
return BT_GAP_ADV_TYPE_ADV_IND;
case (BT_HCI_LE_ADV_EVT_TYPE_CONN |
BT_HCI_LE_ADV_EVT_TYPE_DIRECT |
BT_HCI_LE_ADV_EVT_TYPE_LEGACY):
return BT_GAP_ADV_TYPE_ADV_DIRECT_IND;
case (BT_HCI_LE_ADV_EVT_TYPE_SCAN |
BT_HCI_LE_ADV_EVT_TYPE_LEGACY):
return BT_GAP_ADV_TYPE_ADV_SCAN_IND;
case BT_HCI_LE_ADV_EVT_TYPE_LEGACY:
return BT_GAP_ADV_TYPE_ADV_NONCONN_IND;
case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP |
BT_HCI_LE_ADV_EVT_TYPE_CONN |
BT_HCI_LE_ADV_EVT_TYPE_SCAN |
BT_HCI_LE_ADV_EVT_TYPE_LEGACY):
case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP |
BT_HCI_LE_ADV_EVT_TYPE_SCAN |
BT_HCI_LE_ADV_EVT_TYPE_LEGACY):
return BT_GAP_ADV_TYPE_SCAN_RSP;
default:
return BT_GAP_ADV_TYPE_EXT_ADV;
}
}
_IDF_ONLY
void bt_le_scan_recv_listener(uint16_t event_type,
uint8_t addr_type,
uint8_t addr_val[6],
int8_t rssi,
int8_t tx_power,
uint8_t sid,
uint8_t pri_phy,
uint8_t sec_phy,
uint16_t per_adv_itvl,
uint8_t data_len,
uint8_t *data)
{
struct net_buf_simple_state state = {0};
struct bt_le_scan_recv_info info = {0};
struct bt_le_scan_cb *listener = NULL;
struct net_buf_simple buf = {0};
bt_addr_le_t addr = {0};
/* LOG_DBG("ScanRecvListener[%u]", data_len); */
if (data == NULL || data_len == 0) {
LOG_DBG("ScanRecvDataNull[%u]", data_len);
return;
}
addr.type = addr_type;
memcpy(addr.a.val, addr_val, BT_ADDR_SIZE);
info.addr = &addr;
info.sid = sid;
info.rssi = rssi;
info.tx_power = tx_power;
info.adv_type = get_adv_type(event_type);
info.adv_props = event_type;
info.interval = per_adv_itvl;
info.primary_phy = pri_phy;
info.secondary_phy = sec_phy;
net_buf_simple_init_with_data(&buf, (void *)data, data_len);
SYS_SLIST_FOR_EACH_CONTAINER(&scan_cbs, listener, node) {
if (listener->recv) {
net_buf_simple_save(&buf, &state);
listener->recv(&info, &buf);
net_buf_simple_restore(&buf, &state);
}
}
}
static struct bt_le_per_adv_sync per_adv_sync_pool[CONFIG_BT_PER_ADV_SYNC_MAX];
static sys_slist_t pa_sync_cbs = SYS_SLIST_STATIC_INIT(&pa_sync_cbs);
_LIB_ONLY
int bt_le_per_adv_sync_cb_register(struct bt_le_per_adv_sync_cb *cb)
{
LOG_DBG("PaSyncCbReg");
if (cb == NULL) {
LOG_ERR("PaSyncCbNull");
return -EINVAL;
}
if (sys_slist_find(&pa_sync_cbs, &cb->node, NULL)) {
LOG_WRN("PaSyncCbExist");
return -EEXIST;
}
sys_slist_append(&pa_sync_cbs, &cb->node);
return 0;
}
_LIB_ONLY
int bt_le_per_adv_sync_get_info(struct bt_le_per_adv_sync *per_adv_sync,
struct bt_le_per_adv_sync_info *info)
{
LOG_DBG("PaSyncGetInfo");
if (per_adv_sync == NULL || info == NULL) {
LOG_ERR("PaSyncInfoNull[%p][%p]", per_adv_sync, info);
return -EINVAL;
}
bt_addr_le_copy(&info->addr, &per_adv_sync->addr);
info->sid = per_adv_sync->sid;
info->phy = per_adv_sync->phy;
info->interval = per_adv_sync->interval;
LOG_DBG("[%s][%u][%u][%u]",
bt_addr_le_str(&info->addr), info->sid, info->phy, info->interval);
return 0;
}
_LIB_ONLY
struct bt_le_per_adv_sync *bt_le_per_adv_sync_lookup_addr(const bt_addr_le_t *adv_addr,
uint8_t sid)
{
struct bt_le_per_adv_sync *per_adv_sync = NULL;
assert(adv_addr);
LOG_DBG("PaSyncLookupAddr[%s][%u]", bt_addr_le_str(adv_addr), sid);
for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) {
if (atomic_test_bit(per_adv_sync_pool[i].flags, BT_PER_ADV_SYNC_SYNCED) &&
bt_addr_le_eq(&per_adv_sync_pool[i].addr, adv_addr) &&
per_adv_sync_pool[i].sid == sid) {
per_adv_sync = &per_adv_sync_pool[i];
break;
}
}
if (per_adv_sync == NULL) {
LOG_INF("PaSyncNotFound");
}
return per_adv_sync;
}
static struct bt_le_per_adv_sync *per_adv_sync_find(uint16_t handle)
{
struct bt_le_per_adv_sync *per_adv_sync = NULL;
for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) {
if (atomic_test_bit(per_adv_sync_pool[i].flags, BT_PER_ADV_SYNC_SYNCED) &&
per_adv_sync_pool[i].handle == handle) {
per_adv_sync = &per_adv_sync_pool[i];
break;
}
}
return per_adv_sync;
}
_IDF_ONLY
struct bt_le_per_adv_sync *bt_le_per_adv_sync_find_safe(uint16_t sync_handle)
{
struct bt_le_per_adv_sync *per_adv_sync = NULL;
LOG_DBG("PaSyncFind[%u]", sync_handle);
bt_le_host_lock();
per_adv_sync = per_adv_sync_find(sync_handle);
bt_le_host_unlock();
return per_adv_sync;
}
static struct bt_le_per_adv_sync *per_adv_sync_new(void)
{
struct bt_le_per_adv_sync *per_adv_sync = NULL;
for (size_t i = 0; i < ARRAY_SIZE(per_adv_sync_pool); i++) {
if (atomic_test_bit(per_adv_sync_pool[i].flags,
BT_PER_ADV_SYNC_SYNCED) == false) {
per_adv_sync = &per_adv_sync_pool[i];
break;
}
}
if (per_adv_sync) {
(void)memset(per_adv_sync, 0, sizeof(*per_adv_sync));
atomic_set_bit(per_adv_sync->flags, BT_PER_ADV_SYNC_SYNCED);
}
return per_adv_sync;
}
_IDF_ONLY
int bt_le_per_adv_sync_new(uint16_t sync_handle,
uint8_t sid,
uint8_t phy,
uint16_t interval,
uint8_t addr_type,
const uint8_t addr[6],
uint16_t conn_handle,
struct bt_le_per_adv_sync **out_sync)
{
struct bt_le_per_adv_sync *per_adv_sync;
LOG_DBG("PaSyncNew[%u][%u][%u][%u][%u]",
sync_handle, sid, phy, interval, conn_handle);
if (addr_type > BT_ADDR_LE_RANDOM_ID || addr == NULL) {
LOG_ERR("InvAddr[%02x][%p]", addr_type, addr);
return -EINVAL;
}
per_adv_sync = per_adv_sync_find(sync_handle);
if (per_adv_sync) {
LOG_WRN("PaSyncExist[%u]", sync_handle);
return -EEXIST;
}
per_adv_sync = per_adv_sync_new();
if (per_adv_sync == NULL) {
LOG_ERR("NoFreePaSync[%u]", sync_handle);
return -ENOMEM;
}
per_adv_sync->handle = sync_handle;
per_adv_sync->sid = sid;
per_adv_sync->phy = phy;
per_adv_sync->interval = interval;
per_adv_sync->conn_handle = conn_handle;
per_adv_sync->addr.type = addr_type;
memcpy(per_adv_sync->addr.a.val, addr, BT_ADDR_SIZE);
LOG_DBG("Addr[%s]", bt_addr_le_str(&per_adv_sync->addr));
if (out_sync) {
*out_sync = per_adv_sync;
}
return 0;
}
_IDF_ONLY
int bt_le_per_adv_sync_delete(uint16_t sync_handle)
{
struct bt_le_per_adv_sync *per_adv_sync = NULL;
LOG_DBG("PaSyncDelete[%u]", sync_handle);
per_adv_sync = per_adv_sync_find(sync_handle);
if (per_adv_sync == NULL) {
LOG_ERR("PaSyncNotFound[%u]", sync_handle);
return -ENODEV;
}
(void)memset(per_adv_sync, 0, sizeof(*per_adv_sync));
return 0;
}
_IDF_ONLY
int bt_le_per_adv_sync_establish_listener(uint16_t sync_handle)
{
struct bt_le_per_adv_sync_synced_info info = {0};
struct bt_le_per_adv_sync *per_adv_sync = NULL;
struct bt_le_per_adv_sync_cb *listener = NULL;
LOG_DBG("PaSyncEstabListener[%u]", sync_handle);
per_adv_sync = per_adv_sync_find(sync_handle);
if (per_adv_sync == NULL) {
LOG_ERR("PaSyncNotFound[%u]", sync_handle);
return -ENODEV;
}
info.addr = &per_adv_sync->addr;
info.sid = per_adv_sync->sid;
info.interval = per_adv_sync->interval;
info.phy = per_adv_sync->phy;
/* PAST path: a valid conn_handle means PAST delivered the sync. NULL
* lookup here is a race — the ACL disconnected between PAST event
* enqueue and host processing. Synced cb still fires with conn=NULL.
*/
if (per_adv_sync->conn_handle != BT_CONN_HANDLE_INVALID) {
info.conn = bt_conn_lookup_handle(per_adv_sync->conn_handle, BT_CONN_TYPE_LE);
if (info.conn == NULL) {
LOG_WRN("PaSyncConnGone[%u][%u]", sync_handle, per_adv_sync->conn_handle);
}
}
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
if (listener->synced) {
listener->synced(per_adv_sync, &info);
}
}
if (info.conn) {
bt_conn_unref(info.conn);
}
return 0;
}
_IDF_ONLY
int bt_le_per_adv_sync_lost_listener(uint16_t sync_handle)
{
struct bt_le_per_adv_sync_term_info info = {0};
struct bt_le_per_adv_sync *per_adv_sync = NULL;
struct bt_le_per_adv_sync_cb *listener = NULL;
LOG_DBG("PaSyncLostListener[%u]", sync_handle);
per_adv_sync = per_adv_sync_find(sync_handle);
if (per_adv_sync == NULL) {
LOG_ERR("PaSyncNotFound[%u]", sync_handle);
return -ENODEV;
}
info.addr = &per_adv_sync->addr;
info.sid = per_adv_sync->sid;
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
if (listener->term) {
listener->term(per_adv_sync, &info);
}
}
return 0;
}
_IDF_ONLY
int bt_le_per_adv_sync_report_recv_listener(uint16_t sync_handle,
const uint8_t *data,
size_t data_length)
{
struct bt_le_per_adv_sync_recv_info info = {0};
struct bt_le_per_adv_sync *per_adv_sync = NULL;
struct bt_le_per_adv_sync_cb *listener = NULL;
struct net_buf_simple_state state = {0};
struct net_buf_simple buf = {0};
/* LOG_DBG("PaSyncReportRecvListener[%u][%u]", sync_handle, data_length); */
if (data == NULL || data_length == 0) {
LOG_DBG("PaSyncRecvDataNull[%u]", data_length);
return -EINVAL;
}
per_adv_sync = per_adv_sync_find(sync_handle);
if (per_adv_sync == NULL) {
LOG_ERR("PaSyncNotFound[%u]", sync_handle);
return -ENODEV;
}
info.addr = &per_adv_sync->addr;
info.sid = per_adv_sync->sid;
net_buf_simple_init_with_data(&buf, (void *)data, data_length);
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
if (listener->recv) {
net_buf_simple_save(&buf, &state);
listener->recv(per_adv_sync, &info, &buf);
net_buf_simple_restore(&buf, &state);
}
}
return 0;
}
_IDF_ONLY
void hci_le_biginfo_adv_report(struct net_buf *buf)
{
struct bt_hci_evt_le_biginfo_adv_report *evt = (void *)buf->data;
struct bt_le_per_adv_sync *per_adv_sync = NULL;
struct bt_le_per_adv_sync_cb *listener = NULL;
struct bt_iso_biginfo biginfo = {0};
/* LOG_DBG("BigInfoRecvListener[%u]", evt->sync_handle); */
per_adv_sync = per_adv_sync_find(evt->sync_handle);
if (per_adv_sync == NULL) {
LOG_ERR("PaSyncNotFound[%u]", evt->sync_handle);
return;
}
biginfo.addr = &per_adv_sync->addr;
biginfo.sid = per_adv_sync->sid;
biginfo.num_bis = evt->num_bis;
biginfo.sub_evt_count = evt->nse;
biginfo.iso_interval = evt->iso_interval;
biginfo.burst_number = evt->bn;
biginfo.offset = evt->pto;
biginfo.rep_count = evt->irc;
biginfo.max_pdu = evt->max_pdu;
biginfo.sdu_interval = sys_get_le24(evt->sdu_interval);
biginfo.max_sdu = evt->max_sdu;
biginfo.phy = evt->phy;
biginfo.framing = evt->framing;
biginfo.encryption = (evt->encryption ? true : false);
SYS_SLIST_FOR_EACH_CONTAINER(&pa_sync_cbs, listener, node) {
if (listener->biginfo) {
listener->biginfo(per_adv_sync, &biginfo);
}
}
}
_LIB_ONLY
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);
}
} else {
err = -EALREADY;
}
return err;
}
_LIB_ONLY
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);
}
}
return err;
}
static void past_features_set(void)
{
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER
BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_SEND);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER
BT_LE_FEAT_SET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_RECV);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER */
LOG_DBG("PastFeatSet[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features)));
}
static void past_features_unset(void)
{
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER
BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_SEND);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
#if CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER
BT_LE_FEAT_UNSET(bt_dev.le.features, BT_LE_FEAT_BIT_PAST_RECV);
#endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER */
LOG_DBG("PastFeatUnset[%s]", bt_hex(bt_dev.le.features, sizeof(bt_dev.le.features)));
}
_IDF_ONLY
int bt_le_scan_init(void)
{
LOG_DBG("ScanInit");
past_features_set();
return 0;
}
_IDF_ONLY
void bt_le_scan_deinit(void)
{
LOG_DBG("ScanDeinit");
past_features_unset();
}