From b76b5750ee799e920c8685b72c6042f2409a84c3 Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Wed, 22 Dec 2021 12:50:06 +0100 Subject: [PATCH] Bluetooth: host: Add API to HCI CTE conn request enable procedure There were no implementation for HCI_LE_Connection_CTE_Request_Enable command from BT 5.3 Core specification. The PR adds implementation and API to be used by applications. Signed-off-by: Piotr Pryga --- include/bluetooth/direction.h | 54 +++++++++- subsys/bluetooth/host/Kconfig | 7 ++ subsys/bluetooth/host/conn_internal.h | 2 + subsys/bluetooth/host/direction.c | 137 ++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 4 deletions(-) diff --git a/include/bluetooth/direction.h b/include/bluetooth/direction.h index 53b6eb1fee3..3236dbbfd84 100644 --- a/include/bluetooth/direction.h +++ b/include/bluetooth/direction.h @@ -13,12 +13,16 @@ enum bt_df_cte_type { BT_DF_CTE_TYPE_NONE = 0, /** Angle of Arrival mode. Antenna switching done on receiver site. */ BT_DF_CTE_TYPE_AOA = BIT(0), - /** Angle of Departure mode with 1 us antenna switching slots. - * Antenna switching done on transmitter site. + /** + * @brief Angle of Departure mode with 1 us antenna switching slots. + * + * Antenna switching done on transmitter site. */ BT_DF_CTE_TYPE_AOD_1US = BIT(1), - /** Angle of Departure mode with 2 us antenna switching slots. - * Antenna switching done on transmitter site. + /** + * @brief Angle of Departure mode with 2 us antenna switching slots. + * + * Antenna switching done on transmitter site. */ BT_DF_CTE_TYPE_AOD_2US = BIT(2), /** Convenience value that collects all possible CTE types in one entry. */ @@ -155,6 +159,25 @@ struct bt_df_conn_cte_tx_param { const uint8_t *ant_ids; }; +struct bt_df_conn_cte_req_params { + /** + * @brief Requested interval for initiating the CTE Request procedure. + * + * Value 0x0 means, run the procedure once. Other values are intervals in number of + * connection events, to run the command periodically. + */ + uint8_t interval; + /** Requested length of the CTE in 8 us units. */ + uint8_t cte_length; + /** + * @brief Requested type of the CTE. + * + * Allowed values are defined by @ref bt_df_cte_type, except BT_DF_CTE_TYPE_NONE and + * BT_DF_CTE_TYPE_ALL. + */ + uint8_t cte_type; +}; + /** * @brief Set or update the Constant Tone Extension parameters for periodic advertising set. * @@ -246,6 +269,29 @@ int bt_df_conn_cte_rx_disable(struct bt_conn *conn); */ int bt_df_set_conn_cte_tx_param(struct bt_conn *conn, const struct bt_df_conn_cte_tx_param *params); +/** + * @brief Enable Constant Tone Extension request procedure for a connection. + * + * The function is available if @kconfig{CONFIG_BT_DF_CONNECTION_CTE_REQ} is enabled. + * + * @param conn Connection object. + * @param params CTE receive and sampling parameters. + * + * @return Zero in case of success, other value in case of failure. + */ +int bt_df_conn_cte_req_enable(struct bt_conn *conn, const struct bt_df_conn_cte_req_params *params); + +/** + * @brief Disable Constant Tone Extension request procedure for a connection. + * + * The function is available if @kconfig{CONFIG_BT_DF_CONNECTION_CTE_REQ} is enabled. + * + * @param conn Connection object. + * + * @return Zero in case of success, other value in case of failure. + */ +int bt_df_conn_cte_req_disable(struct bt_conn *conn); + /** * @brief Enable Constant Tone Extension response procedure for a connection. * diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 70f510de9f4..3468a6d462d 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -566,6 +566,13 @@ config BT_DF_CONNECTION_CTE_TX Enable support for transmission of Constant Tone Extension in connection mode. +config BT_DF_CONNECTION_CTE_REQ + bool "Enable support for CTE request procedure in connection mode" + depends on BT_DF_CONNECTION_CTE_RX + help + Enable support for request of Constant Tone Extension in connection + mode. + config BT_DF_CONNECTION_CTE_RSP bool "Enable support for CTE request procedure in connection mode" depends on BT_DF_CONNECTION_CTE_TX diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 5e590ada62d..b1241342688 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -44,7 +44,9 @@ enum { BT_CONN_AUTO_DATA_LEN_COMPLETE, BT_CONN_CTE_RX_ENABLED, /* CTE receive and sampling is enabled */ + BT_CONN_CTE_RX_PARAMS_SET, /* CTE parameters are set */ BT_CONN_CTE_TX_PARAMS_SET, /* CTE transmission parameters are set */ + BT_CONN_CTE_REQ_ENABLED, /* CTE request procedure is enabled */ BT_CONN_CTE_RSP_ENABLED, /* CTE response procedure is enabled */ /* Total number of flags - must be at the end of the enum */ diff --git a/subsys/bluetooth/host/direction.c b/subsys/bluetooth/host/direction.c index 72ee8c76396..43612db2689 100644 --- a/subsys/bluetooth/host/direction.c +++ b/subsys/bluetooth/host/direction.c @@ -69,6 +69,21 @@ static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, const struct bt_df_conn_cte_rx_param *params); #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +static uint8_t get_hci_cte_type(enum bt_df_cte_type type) +{ + switch (type) { + case BT_DF_CTE_TYPE_AOA: + return BT_HCI_LE_AOA_CTE; + case BT_DF_CTE_TYPE_AOD_1US: + return BT_HCI_LE_AOD_CTE_1US; + case BT_DF_CTE_TYPE_AOD_2US: + return BT_HCI_LE_AOD_CTE_2US; + default: + BT_ERR("Wrong CTE type"); + return BT_HCI_LE_NO_CTE; + } +} + static int hci_df_set_cl_cte_tx_params(const struct bt_le_ext_adv *adv, const struct bt_df_adv_cte_tx_param *params) { @@ -564,6 +579,11 @@ static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, err = -EIO; } else { conn->cte_type = (enable ? params->cte_type : 0); + /* This flag is set once for connection object. It is never cleared because CTE RX + * params must be set at least once for connection object to successfully execute + * CTE REQ procedure. + */ + atomic_set_bit(conn->flags, BT_CONN_CTE_RX_PARAMS_SET); } net_buf_unref(rsp); @@ -621,6 +641,78 @@ int hci_df_prepare_connection_iq_report(struct net_buf *buf, } #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +#if defined(CONFIG_BT_DF_CONNECTION_CTE_REQ) +static bool valid_cte_req_params(const struct bt_conn *conn, uint8_t cte_type, + uint8_t cte_length) +{ + if (!(conn->cte_type & cte_type)) { + return false; + } + + if (cte_length < BT_HCI_LE_CTE_LEN_MIN || cte_length > BT_HCI_LE_CTE_LEN_MAX) { + return false; + } + + return true; +} + +static void prepare_conn_cte_req_enable_cmd_params(struct net_buf *buf, const struct bt_conn *conn, + const struct bt_df_conn_cte_req_params *params, + bool enable) +{ + struct bt_hci_cp_le_conn_cte_req_enable *cp; + + cp = net_buf_add(buf, sizeof(*cp)); + (void)memset(cp, 0, sizeof(*cp)); + + cp->handle = sys_cpu_to_le16(conn->handle); + cp->enable = enable ? 1 : 0; + + if (enable) { + cp->cte_request_interval = params->interval; + cp->requested_cte_length = params->cte_length; + cp->requested_cte_type = get_hci_cte_type(params->cte_type); + } +} + +static int hci_df_set_conn_cte_req_enable(struct bt_conn *conn, bool enable, + const struct bt_df_conn_cte_req_params *params) +{ + struct bt_hci_cp_le_conn_cte_req_enable *rp; + struct bt_hci_cmd_state_set state; + struct net_buf *buf, *rsp; + int err; + + if (enable && !valid_cte_req_params(conn, params->cte_length, params->cte_type)) { + return -EINVAL; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE, + sizeof(struct bt_hci_cp_le_conn_cte_req_enable)); + if (!buf) { + return -ENOBUFS; + } + + prepare_conn_cte_req_enable_cmd_params(buf, conn, params, enable); + + bt_hci_cmd_state_set_init(buf, &state, conn->flags, BT_CONN_CTE_REQ_ENABLED, enable); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS, buf, &rsp); + if (err) { + return err; + } + + rp = (void *)rsp->data; + if (conn->handle != sys_le16_to_cpu(rp->handle)) { + err = -EIO; + } + + net_buf_unref(rsp); + + return err; +} +#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ + #if defined(CONFIG_BT_DF_CONNECTION_CTE_RSP) static void prepare_conn_cte_rsp_enable_cmd_params(struct net_buf *buf, const struct bt_conn *conn, bool enable) @@ -866,6 +958,51 @@ int bt_df_set_conn_cte_tx_param(struct bt_conn *conn, const struct bt_df_conn_ct #endif /* CONFIG_BT_DF_CONNECTION_CTE_TX */ +#if defined(CONFIG_BT_DF_CONNECTION_CTE_REQ) +static int bt_df_set_conn_cte_req_enable(struct bt_conn *conn, bool enable, + const struct bt_df_conn_cte_req_params *params) +{ + if (!BT_FEAT_LE_CONNECTION_CTE_REQ(bt_dev.le.features)) { + BT_WARN("Constant Tone Extensions request procedure is not supported"); + return -ENOTSUP; + } + + if (conn->state != BT_CONN_CONNECTED) { + BT_ERR("not connected!"); + return -ENOTCONN; + } + + if (!atomic_test_bit(conn->flags, BT_CONN_CTE_RX_PARAMS_SET)) { + BT_ERR("Can't start CTE requres procedure before CTE RX params setup"); + return -EINVAL; + } + + return hci_df_set_conn_cte_req_enable(conn, enable, params); +} + +int bt_df_conn_cte_req_enable(struct bt_conn *conn, const struct bt_df_conn_cte_req_params *params) +{ + CHECKIF(!conn) { + return -EINVAL; + } + + CHECKIF(!params) { + return -EINVAL; + } + + return bt_df_set_conn_cte_req_enable(conn, true, params); +} + +int bt_df_conn_cte_req_disable(struct bt_conn *conn) +{ + CHECKIF(!conn) { + return -EINVAL; + } + + return bt_df_set_conn_cte_req_enable(conn, false, NULL); +} +#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ + #if defined(CONFIG_BT_DF_CONNECTION_CTE_RSP) static int bt_df_set_conn_cte_rsp_enable(struct bt_conn *conn, bool enable) {