espressif--esp-idf
565 行
15 KiB
C
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();
|
|
}
|