Bluetooth: host: Add IQ reports handing in DF connecte mode

Add reception of IQ sample report from controller.
Add applications notification about received reports.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
This commit is contained in:
Piotr Pryga 2021-11-24 14:12:07 +01:00 committed by Christopher Friedt
commit a26ee7ce73
7 changed files with 123 additions and 0 deletions

View file

@ -23,6 +23,7 @@
#include <bluetooth/hci_err.h> #include <bluetooth/hci_err.h>
#include <bluetooth/addr.h> #include <bluetooth/addr.h>
#include <bluetooth/gap.h> #include <bluetooth/gap.h>
#include <bluetooth/direction.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -927,6 +928,17 @@ struct bt_conn_cb {
struct bt_conn_le_data_len_info *info); struct bt_conn_le_data_len_info *info);
#endif /* defined(CONFIG_BT_USER_DATA_LEN_UPDATE) */ #endif /* defined(CONFIG_BT_USER_DATA_LEN_UPDATE) */
#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)
/** @brief Callback for IQ samples report collected when sampling
* CTE received by data channel PDU.
*
* @param conn The connection object.
* @param iq_report Report data for collected IQ samples.
*/
void (*cte_report_cb)(struct bt_conn *conn,
const struct bt_df_conn_iq_samples_report *iq_report);
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */
struct bt_conn_cb *_next; struct bt_conn_cb *_next;
}; };

View file

@ -120,6 +120,28 @@ struct bt_df_conn_cte_rx_param {
const uint8_t *ant_ids; const uint8_t *ant_ids;
}; };
struct bt_df_conn_iq_samples_report {
/** PHY that was used to receive PDU with CTE that was sampled. */
uint8_t rx_phy;
/** Channel index used to receive PDU with CTE that was sampled. */
uint8_t chan_idx;
/** The RSSI of the PDU with CTE (excluding CTE). */
int16_t rssi;
/** Id of antenna used to measure the RSSI. */
uint8_t rssi_ant_id;
/** Type of CTE (@ref bt_df_cte_type). */
uint8_t cte_type;
/** Duration of slots when received CTE type is AoA (@ref bt_df_antenna_switching_slot). */
uint8_t slot_durations;
/** Status of received PDU with CTE (@ref bt_df_packet_status). */
uint8_t packet_status;
/** Value of connection event counter when the CTE was received and sampled. */
uint16_t conn_evt_counter;
/** Number of IQ samples in report. */
uint8_t sample_count;
/** Pinter to IQ samples data. */
struct bt_hci_le_iq_sample const *sample;
};
/** /**
* @brief Set or update the Constant Tone Extension parameters for periodic advertising set. * @brief Set or update the Constant Tone Extension parameters for periodic advertising set.
* *

View file

@ -19,6 +19,7 @@
#include <bluetooth/hci.h> #include <bluetooth/hci.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <bluetooth/direction.h>
#include <bluetooth/conn.h> #include <bluetooth/conn.h>
#include <drivers/bluetooth/hci_driver.h> #include <drivers/bluetooth/hci_driver.h>
#include <bluetooth/att.h> #include <bluetooth/att.h>
@ -38,6 +39,7 @@
#include "att_internal.h" #include "att_internal.h"
#include "gatt_internal.h" #include "gatt_internal.h"
#include "iso_internal.h" #include "iso_internal.h"
#include "direction_internal.h"
struct tx_meta { struct tx_meta {
struct bt_conn_tx *tx; struct bt_conn_tx *tx;
@ -2921,4 +2923,33 @@ int bt_conn_init(void)
return 0; return 0;
} }
#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)
void bt_hci_le_df_connection_iq_report(struct net_buf *buf)
{
struct bt_df_conn_iq_samples_report iq_report;
struct bt_conn *conn;
struct bt_conn_cb *cb;
int err;
err = hci_df_prepare_connection_iq_report(buf, &iq_report, &conn);
if (err) {
BT_ERR("Prepare CTE conn IQ report failed %d", err);
return;
}
for (cb = callback_list; cb; cb = cb->_next) {
if (cb->cte_report_cb) {
cb->cte_report_cb(conn, &iq_report);
}
}
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
{
if (cb->cte_report_cb) {
cb->cte_report_cb(conn, &iq_report);
}
}
}
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */

View file

@ -542,6 +542,55 @@ static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable,
return err; return err;
} }
int hci_df_prepare_connection_iq_report(struct net_buf *buf,
struct bt_df_conn_iq_samples_report *report,
struct bt_conn **conn_to_report)
{
struct bt_hci_evt_le_connection_iq_report *evt;
struct bt_conn *conn;
if (buf->len < sizeof(*evt)) {
BT_ERR("Unexpected end of buffer");
return -EINVAL;
}
evt = net_buf_pull_mem(buf, sizeof(*evt));
conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle));
if (!conn) {
BT_ERR("Unknown conn handle 0x%04X for iq samples report",
sys_le16_to_cpu(evt->conn_handle));
return -EINVAL;
}
if (!atomic_test_bit(conn->flags, BT_CONN_CTE_RX_ENABLED)) {
BT_ERR("Received conn CTE report when CTE receive disabled");
return -EINVAL;
}
if (!(conn->cte_type & BIT(evt->cte_type))) {
BT_DBG("CTE filtered out by cte_type: %u", evt->cte_type);
return -EINVAL;
}
report->chan_idx = evt->data_chan_idx;
report->rx_phy = evt->rx_phy;
report->chan_idx = evt->data_chan_idx;
report->rssi = evt->rssi;
report->rssi_ant_id = evt->rssi_ant_id;
report->cte_type = BIT(evt->cte_type);
report->packet_status = evt->packet_status;
report->slot_durations = evt->slot_durations;
report->conn_evt_counter = sys_le16_to_cpu(evt->conn_evt_counter);
report->sample_count = evt->sample_count;
report->sample = evt->sample;
*conn_to_report = conn;
return 0;
}
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */
/* @brief Function initializes Direction Finding in Host /* @brief Function initializes Direction Finding in Host

View file

@ -10,3 +10,6 @@ int le_df_init(void);
void hci_df_prepare_connectionless_iq_report(struct net_buf *buf, void hci_df_prepare_connectionless_iq_report(struct net_buf *buf,
struct bt_df_per_adv_sync_iq_samples_report *report, struct bt_df_per_adv_sync_iq_samples_report *report,
struct bt_le_per_adv_sync **per_adv_sync_to_report); struct bt_le_per_adv_sync **per_adv_sync_to_report);
int hci_df_prepare_connection_iq_report(struct net_buf *buf,
struct bt_df_conn_iq_samples_report *report,
struct bt_conn **conn_to_report);

View file

@ -2225,6 +2225,10 @@ static const struct event_handler meta_events[] = {
EVENT_HANDLER(BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT, bt_hci_le_df_connectionless_iq_report, EVENT_HANDLER(BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT, bt_hci_le_df_connectionless_iq_report,
sizeof(struct bt_hci_evt_le_connectionless_iq_report)), sizeof(struct bt_hci_evt_le_connectionless_iq_report)),
#endif /* CONFIG_BT_DF_CONNECTIONLESS_CTE_RX */ #endif /* CONFIG_BT_DF_CONNECTIONLESS_CTE_RX */
#if defined(CONFIG_BT_DF_CONNECTION_CTE_RX)
EVENT_HANDLER(BT_HCI_EVT_LE_CONNECTION_IQ_REPORT, bt_hci_le_df_connection_iq_report,
sizeof(struct bt_hci_evt_le_connection_iq_report)),
#endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */
}; };
static void hci_le_meta_event(struct net_buf *buf) static void hci_le_meta_event(struct net_buf *buf)

View file

@ -450,3 +450,5 @@ void bt_hci_read_remote_features_complete(struct net_buf *buf);
void bt_hci_read_remote_ext_features_complete(struct net_buf *buf); void bt_hci_read_remote_ext_features_complete(struct net_buf *buf);
void bt_hci_role_change(struct net_buf *buf); void bt_hci_role_change(struct net_buf *buf);
void bt_hci_synchronous_conn_complete(struct net_buf *buf); void bt_hci_synchronous_conn_complete(struct net_buf *buf);
void bt_hci_le_df_connection_iq_report(struct net_buf *buf);