diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 0b2c1b1a3976..4f9b77f9ef0c 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -706,6 +706,7 @@ struct bt_hci_cp_le_set_tx_power_report_enable { uint8_t remote_enable; } __packed; +#define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS BT_OP(BT_OGF_LE, 0x0078) /* 0x2078 */ struct bt_hci_cp_le_set_path_loss_reporting_parameters { uint16_t handle; uint8_t high_threshold; @@ -715,17 +716,28 @@ struct bt_hci_cp_le_set_path_loss_reporting_parameters { uint16_t min_time_spent; } __packed; -struct bt_hci_cp_le_set_path_loss_reporting_enable { +struct bt_hci_rp_le_set_path_loss_reporting_parameters { uint16_t handle; - uint8_t enable; + uint8_t status; } __packed; -#define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS BT_OP(BT_OGF_LE, 0x0078) /* 0x2078 */ #define BT_HCI_LE_PATH_LOSS_REPORTING_DISABLE 0x00 #define BT_HCI_LE_PATH_LOSS_REPORTING_ENABLE 0x01 #define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE BT_OP(BT_OGF_LE, 0x0079) /* 0x2079 */ +struct bt_hci_cp_le_set_path_loss_reporting_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +struct bt_hci_rp_le_set_path_loss_reporting_enable { + uint16_t handle; + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_SET_DEFAULT_SUBRATE BT_OP(BT_OGF_LE, 0x007D) /* 0x207D */ + struct bt_hci_cp_le_set_default_subrate { uint16_t subrate_min; uint16_t subrate_max; @@ -734,6 +746,8 @@ struct bt_hci_cp_le_set_default_subrate { uint16_t supervision_timeout; } __packed; +#define BT_HCI_OP_LE_SUBRATE_REQUEST BT_OP(BT_OGF_LE, 0x007E) /* 0x207E */ + struct bt_hci_cp_le_subrate_request { uint16_t handle; uint16_t subrate_min; @@ -743,9 +757,6 @@ struct bt_hci_cp_le_subrate_request { uint16_t supervision_timeout; } __packed; -#define BT_HCI_OP_LE_SET_DEFAULT_SUBRATE BT_OP(BT_OGF_LE, 0x007D) /* 0x207D */ -#define BT_HCI_OP_LE_SUBRATE_REQUEST BT_OP(BT_OGF_LE, 0x007E) /* 0x207E */ - #define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00 #define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01 #define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) /* 0x0c31 */ diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4fd542a5a09e..c056f62ae7c0 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -119,7 +119,6 @@ config BT_CTLR_LE_POWER_CONTROL_SUPPORT bool config BT_CTLR_LE_PATH_LOSS_MONITORING_SUPPORT - depends on BT_CTLR_LE_POWER_CONTROL_SUPPORT bool config BT_CTLR_SUBRATING_SUPPORT @@ -661,7 +660,6 @@ config BT_CTLR_LE_PATH_LOSS_MONITORING bool "LE Path Loss Monitoring Feature" depends on BT_CTLR_LE_PATH_LOSS_MONITORING_SUPPORT default y if BT_PATH_LOSS_MONITORING - select BT_CTLR_LE_POWER_CONTROL help Enable support for LE Path Loss Monitoring feature that is defined in the Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.32. diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index b9190761cb3b..683c4cadf919 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -2793,6 +2793,55 @@ static void le_set_phy(struct net_buf *buf, struct net_buf **evt) *evt = cmd_status(status); } #endif /* CONFIG_BT_CTLR_PHY */ + + +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) + +#define PATH_LOSS_FACTOR_INVALID 0xFF +static void le_path_loss_set_parameters(struct net_buf *buf, struct net_buf **evt) +{ + struct bt_hci_cp_le_set_path_loss_reporting_parameters *cmd = (void *)buf->data; + struct bt_hci_rp_le_set_path_loss_reporting_parameters *rp; + + uint16_t handle = sys_le16_to_cpu(cmd->handle); + uint16_t min_time_spent = sys_le16_to_cpu(cmd->min_time_spent); + + rp = hci_cmd_complete(evt, sizeof(*rp)); + rp->handle = handle; + + if (cmd->high_threshold + cmd->high_hysteresis > PATH_LOSS_FACTOR_INVALID || + cmd->low_threshold < cmd->low_hysteresis || + cmd->low_threshold > cmd->high_threshold || + cmd->low_threshold + cmd->low_hysteresis > cmd->high_threshold - cmd->high_hysteresis) { + rp->status = BT_HCI_ERR_INVALID_PARAM; + return; + } + + rp->status = ll_conn_set_path_loss_parameters(handle, cmd->high_threshold, + cmd->high_hysteresis, cmd->low_threshold, + cmd->low_hysteresis, min_time_spent); +} + +#define PATH_LOSS_ENABLED 0x01 +#define PATH_LOSS_DISABLED 0x00 +static void le_path_loss_enable(struct net_buf *buf, struct net_buf **evt) +{ + struct bt_hci_cp_le_set_path_loss_reporting_enable *cmd = (void *)buf->data; + struct bt_hci_rp_le_set_path_loss_reporting_enable *rp; + + uint16_t handle = sys_le16_to_cpu(cmd->handle); + + rp = hci_cmd_complete(evt, sizeof(*rp)); + rp->handle = handle; + + if (cmd->enable != PATH_LOSS_ENABLED && + cmd->enable != PATH_LOSS_DISABLED) { + rp->status = BT_HCI_ERR_INVALID_PARAM; + } + + rp->status = ll_conn_set_path_loss_reporting(handle, cmd->enable); +} +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_PRIVACY) @@ -4767,6 +4816,17 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd, le_set_phy(cmd, evt); break; #endif /* CONFIG_BT_CTLR_PHY */ + +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) + case BT_OCF(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_PARAMETERS): + le_path_loss_set_parameters(cmd, evt); + break; + + case BT_OCF(BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE): + le_path_loss_enable(cmd, evt); + break; + +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_ADV_EXT) @@ -8645,6 +8705,28 @@ static void le_req_peer_sca_complete(struct pdu_data *pdu, uint16_t handle, sep->sca = scau->sca; } #endif /* CONFIG_BT_CTLR_SCA_UPDATE */ +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) +static void le_path_loss_threshold(struct pdu_data *pdu, + uint16_t handle, + struct net_buf *buf) +{ + struct bt_hci_evt_le_path_loss_threshold *sep; + struct node_rx_path_loss *pl_pdu; + + pl_pdu = (void *)pdu; + + if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || + !(le_event_mask & BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD)) { + return; + } + + sep = meta_evt(buf, BT_HCI_EVT_LE_PATH_LOSS_THRESHOLD, sizeof(*sep)); + + sep->handle = sys_cpu_to_le16(handle); + sep->current_path_loss = pl_pdu->current_path_loss; + sep->zone_entered = pl_pdu->zone_entered; +} +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_HCI_MESH_EXT) @@ -8847,6 +8929,12 @@ static void encode_control(struct node_rx_pdu *node_rx, #endif /* CONFIG_BT_CTLR_DF_VS_CONN_IQ_REPORT_16_BITS_IQ_SAMPLES */ return; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ + +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) + case NODE_RX_TYPE_PATH_LOSS: + le_path_loss_threshold(pdu_data, handle, buf); + return; +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_ADV_INDICATION) @@ -9332,6 +9420,10 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #endif /* CONFIG_BT_CTLR_PHY */ return HCI_CLASS_EVT_CONNECTION; +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) + case NODE_RX_TYPE_PATH_LOSS: + return HCI_CLASS_EVT_REQUIRED; +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 482a585e9621..378686064e15 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -343,3 +343,12 @@ void ll_coex_ticker_id_get(uint8_t * const instance_index, uint8_t * const ticker_id); void ll_radio_state_abort(void); uint32_t ll_radio_state_is_idle(void); + +uint8_t ll_conn_set_path_loss_parameters(uint16_t handle, + uint8_t high_threshold, + uint8_t high_hysteresis, + uint8_t low_threshold, + uint8_t low_hysteresis, + uint16_t min_time_spent); + +uint8_t ll_conn_set_path_loss_reporting(uint16_t handle, uint8_t enable); diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 9b890315cfd9..b5d8fffeac37 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -309,6 +309,7 @@ enum node_rx_type { NODE_RX_TYPE_IQ_SAMPLE_REPORT_ULL_RELEASE, NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE, NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED, + NODE_RX_TYPE_PATH_LOSS, /* Signals retention (ie non-release) of rx node */ NODE_RX_TYPE_RETAIN, diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index bcaaa4d2d2e6..98177652ba0a 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -14,6 +14,22 @@ #define LLL_CONN_MIC_PASS 1 #define LLL_CONN_MIC_FAIL 2 + +struct path_loss_params { + uint16_t min_time_spent; + uint8_t enabled; + uint8_t high_threshold; + uint8_t high_hysteresis; + uint8_t low_threshold; + uint8_t low_hysteresis; +} __packed; + +struct path_loss_state { + uint16_t conn_handle; + uint16_t min_time_counter; + uint8_t new_zone; +} __packed; + struct lll_tx { uint16_t handle; void *node; @@ -157,6 +173,11 @@ struct lll_conn { uint8_t rssi_sample_count; #endif /* CONFIG_BT_CTLR_CONN_RSSI_EVENT */ #endif /* CONFIG_BT_CTLR_CONN_RSSI */ +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) + struct path_loss_params pl_params; + struct path_loss_state pl_state; + uint8_t pl_current_zone; +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ #if defined(CONFIG_BT_CTLR_CONN_META) struct lll_conn_meta conn_meta; diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 14784d27e0d0..b1589f62bece 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -1392,6 +1392,7 @@ void ll_rx_dequeue(void) #if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT) case NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT: #endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */ + case NODE_RX_TYPE_PATH_LOSS: /* Ensure that at least one 'case' statement is present for this * code block. @@ -1582,6 +1583,7 @@ void ll_rx_mem_release(void **node_rx) #if defined(CONFIG_BT_CTLR_ISO) case NODE_RX_TYPE_ISO_PDU: #endif + case NODE_RX_TYPE_PATH_LOSS: /* Ensure that at least one 'case' statement is present for this * code block. @@ -2965,6 +2967,7 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) case NODE_RX_TYPE_SCAN_INDICATION: #endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ + case NODE_RX_TYPE_PATH_LOSS: case NODE_RX_TYPE_RELEASE: { diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index c6dd93efd8ec..63c995c09d0a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -2910,6 +2910,56 @@ uint8_t ull_conn_lll_phy_active(struct ll_conn *conn, uint8_t phys) return 1; } +#if defined(CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING) +uint8_t ll_conn_set_path_loss_parameters(uint16_t handle, + uint8_t high_threshold, + uint8_t high_hysteresis, + uint8_t low_threshold, + uint8_t low_hysteresis, + uint16_t min_time_spent) +{ + struct ll_conn *conn; + + conn = ll_connected_get(handle); + + if (!conn) { + return BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + conn->lll.pl_params.high_threshold = high_threshold; + conn->lll.pl_params.high_hysteresis = high_hysteresis; + conn->lll.pl_params.low_threshold = low_threshold; + conn->lll.pl_params.low_hysteresis = low_hysteresis; + conn->lll.pl_params.min_time_spent = min_time_spent; + + /* Reset the counter and zone after any update from the host */ + conn->lll.pl_state.min_time_counter = 0; + conn->lll.pl_current_zone = BT_HCI_LE_ZONE_ENTERED_LOW; + + return BT_HCI_ERR_SUCCESS; +} + +uint8_t ll_conn_set_path_loss_reporting(uint16_t handle, uint8_t enable) +{ + struct ll_conn *conn; + + conn = ll_connected_get(handle); + + if (!conn) { + return BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + conn->lll.pl_params.enabled = enable; + + /* Reset the counter and zone after any update from the host */ + conn->lll.pl_state.min_time_counter = 0; + conn->lll.pl_current_zone = BT_HCI_LE_ZONE_ENTERED_LOW; + + return BT_HCI_ERR_SUCCESS; + +} +#endif /* CONFIG_BT_CTLR_LE_PATH_LOSS_MONITORING */ + uint8_t ull_is_lll_tx_queue_empty(struct ll_conn *conn) { return (memq_peek(conn->lll.memq_tx.head, conn->lll.memq_tx.tail, NULL) == NULL); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h index dad6d5e29e0e..33fcf0469ffe 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h @@ -138,3 +138,13 @@ void ull_conn_resume_rx_data(struct ll_conn *conn); * @brief Check if the lower link layer transmit queue is empty */ uint8_t ull_is_lll_tx_queue_empty(struct ll_conn *conn); + +/** + * @brief Set path loss parameters + */ +void ull_path_loss_set_parameters(void); + +/** + * @brief Enable path loss reporting + */ +void ull_enable_path_loss_reporting(void); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index e105ef277e64..f901f2ad3cad 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -301,3 +301,8 @@ struct node_rx_sca { uint8_t status; uint8_t sca; }; + +struct node_rx_path_loss { + uint8_t current_path_loss; + uint8_t zone_entered; +};