From a26ee7ce733d6e1629fbf497779d1f6434542b28 Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Wed, 24 Nov 2021 14:12:07 +0100 Subject: [PATCH] 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 --- include/bluetooth/conn.h | 12 ++++++ include/bluetooth/direction.h | 22 ++++++++++ subsys/bluetooth/host/conn.c | 31 ++++++++++++++ subsys/bluetooth/host/direction.c | 49 ++++++++++++++++++++++ subsys/bluetooth/host/direction_internal.h | 3 ++ subsys/bluetooth/host/hci_core.c | 4 ++ subsys/bluetooth/host/hci_core.h | 2 + 7 files changed, 123 insertions(+) diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 8c6df6d28e9..00ae56ab214 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -927,6 +928,17 @@ struct bt_conn_cb { struct bt_conn_le_data_len_info *info); #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; }; diff --git a/include/bluetooth/direction.h b/include/bluetooth/direction.h index d5a847e32f9..59a3a906faf 100644 --- a/include/bluetooth/direction.h +++ b/include/bluetooth/direction.h @@ -120,6 +120,28 @@ struct bt_df_conn_cte_rx_param { 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. * diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index c2a19b6376d..a27ef52d74e 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include "att_internal.h" #include "gatt_internal.h" #include "iso_internal.h" +#include "direction_internal.h" struct tx_meta { struct bt_conn_tx *tx; @@ -2921,4 +2923,33 @@ int bt_conn_init(void) 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 */ diff --git a/subsys/bluetooth/host/direction.c b/subsys/bluetooth/host/direction.c index 6bef50b645a..acfcae57f57 100644 --- a/subsys/bluetooth/host/direction.c +++ b/subsys/bluetooth/host/direction.c @@ -542,6 +542,55 @@ static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, 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 */ /* @brief Function initializes Direction Finding in Host diff --git a/subsys/bluetooth/host/direction_internal.h b/subsys/bluetooth/host/direction_internal.h index 1adf2caeed2..424bc536df6 100644 --- a/subsys/bluetooth/host/direction_internal.h +++ b/subsys/bluetooth/host/direction_internal.h @@ -10,3 +10,6 @@ int le_df_init(void); void hci_df_prepare_connectionless_iq_report(struct net_buf *buf, struct bt_df_per_adv_sync_iq_samples_report *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); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 25ee6fcbf45..617ba3cc38b 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -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, sizeof(struct bt_hci_evt_le_connectionless_iq_report)), #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) diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 520b3cabd99..c0b1ad02825 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -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_role_change(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);