Bluetooth: Controller: df: Add disable support for CTE REQ and RSP proc

Add missing implementation for disabling CTE request and resposne
control procedures.
If any of these commands is active in LLL then ULL context has
to wait before return. The wait mechanism is based on semaphore.
The semaphore is initialized in ULL context and given by code
responsible for command completion.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
This commit is contained in:
Piotr Pryga 2022-01-19 22:29:02 +01:00 committed by Christopher Friedt
commit 32c9a01680
4 changed files with 60 additions and 14 deletions

View file

@ -420,22 +420,29 @@ struct llcp_struct {
/* Procedure may be active periodically, active state must be stored. /* Procedure may be active periodically, active state must be stored.
* If procedure is active, request parameters update may not be issued. * If procedure is active, request parameters update may not be issued.
*/ */
uint8_t is_enabled; uint8_t is_enabled:1;
uint8_t is_active:1;
uint8_t cte_type; uint8_t cte_type;
/* Minimum requested CTE length in 8us units */ /* Minimum requested CTE length in 8us units */
uint8_t min_cte_len; uint8_t min_cte_len;
uint16_t req_interval; uint16_t req_interval;
uint16_t req_expire; uint16_t req_expire;
void *disable_param;
void (*disable_cb)(void *param);
} cte_req; } cte_req;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
struct llcp_df_rsp_cfg { struct llcp_df_rsp_cfg {
uint8_t is_enabled; uint8_t is_enabled:1;
uint8_t is_active:1;
uint8_t cte_types; uint8_t cte_types;
uint8_t max_cte_len; uint8_t max_cte_len;
void *disable_param;
void (*disable_cb)(void *param);
} cte_rsp; } cte_rsp;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
#if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) &&\ #if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) &&\
(CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM <\ (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM <\
CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX) CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX)

View file

@ -1120,6 +1120,13 @@ uint8_t ll_df_set_conn_cte_rx_params(uint16_t handle, uint8_t sampling_enable,
} }
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
static void df_conn_cte_req_disable(void *param)
{
k_sem_give(param);
}
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ || CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
/* @brief Function enables or disables CTE request control procedure for a connection. /* @brief Function enables or disables CTE request control procedure for a connection.
* *
@ -1156,10 +1163,18 @@ uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable,
conn->llcp.cte_req.is_enabled = false; conn->llcp.cte_req.is_enabled = false;
conn->llcp.cte_req.req_interval = 0U; conn->llcp.cte_req.req_interval = 0U;
/* There is no verification if the command is pending. If it is already disabled if (conn->llcp.cte_req.is_active) {
* there is no change to the state. struct k_sem sem;
*/
/* TODO: How handle command pending in LLL? */ k_sem_init(&sem, 0U, 1U);
conn->llcp.cte_req.disable_param = &sem;
conn->llcp.cte_req.disable_cb = df_conn_cte_req_disable;
if (!conn->llcp.cte_req.is_active) {
k_sem_take(&sem, K_FOREVER);
}
}
return BT_HCI_ERR_SUCCESS; return BT_HCI_ERR_SUCCESS;
} else { } else {
if (!conn->lll.df_rx_cfg.is_initialized) { if (!conn->lll.df_rx_cfg.is_initialized) {
@ -1206,7 +1221,7 @@ uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable,
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
} }
conn->llcp.cte_req.is_enabled = true; conn->llcp.cte_req.is_enabled = 0U;
conn->llcp.cte_req.req_interval = cte_request_interval; conn->llcp.cte_req.req_interval = cte_request_interval;
conn->llcp.cte_req.cte_type = requested_cte_type; conn->llcp.cte_req.cte_type = requested_cte_type;
conn->llcp.cte_req.min_cte_len = requested_cte_length; conn->llcp.cte_req.min_cte_len = requested_cte_length;
@ -1250,11 +1265,19 @@ uint8_t ll_df_set_conn_cte_rsp_enable(uint16_t handle, uint8_t enable)
ull_cp_cte_rsp_enable(conn, enable, LLL_DF_MAX_CTE_LEN, ull_cp_cte_rsp_enable(conn, enable, LLL_DF_MAX_CTE_LEN,
conn->lll.df_tx_cfg.cte_types_allowed); conn->lll.df_tx_cfg.cte_types_allowed);
} else { } else {
/* There is no parameter validation for disable operation. */ conn->lll.df_tx_cfg.cte_rsp_en = false;
/* TODO: Add missing implementation of disable CTE request. if (conn->llcp.cte_rsp.is_active) {
* Requires refactored LLCPs. struct k_sem sem;
*/
k_sem_init(&sem, 0U, 1U);
conn->llcp.cte_rsp.disable_param = &sem;
conn->llcp.cte_rsp.disable_cb = df_conn_cte_req_disable;
if (!conn->llcp.cte_rsp.is_active) {
k_sem_take(&sem, K_FOREVER);
}
}
} }
return BT_HCI_ERR_SUCCESS; return BT_HCI_ERR_SUCCESS;

View file

@ -458,9 +458,15 @@ void ull_llcp_init(struct ll_conn *conn)
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
conn->llcp.cte_req.is_enabled = 0U; conn->llcp.cte_req.is_enabled = 0U;
conn->llcp.cte_req.req_expire = 0U; conn->llcp.cte_req.req_expire = 0U;
conn->llcp.cte_req.is_active = 0U;
conn->llcp.cte_req.disable_param = NULL;
conn->llcp.cte_req.disable_cb = NULL;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
conn->llcp.cte_rsp.is_enabled = 0U; conn->llcp.cte_rsp.is_enabled = 0U;
conn->llcp.cte_rsp.is_active = 0U;
conn->llcp.cte_rsp.disable_param = NULL;
conn->llcp.cte_rsp.disable_cb = NULL;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
#if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE)
@ -904,6 +910,9 @@ uint8_t ull_cp_cte_req(struct ll_conn *conn, uint8_t min_cte_len, uint8_t cte_ty
ctx->data.cte_req.min_len = min_cte_len; ctx->data.cte_req.min_len = min_cte_len;
ctx->data.cte_req.type = cte_type; ctx->data.cte_req.type = cte_type;
conn->llcp.cte_req.is_active = 1U;
llcp_lr_enqueue(conn, ctx); llcp_lr_enqueue(conn, ctx);
return BT_HCI_ERR_SUCCESS; return BT_HCI_ERR_SUCCESS;

View file

@ -356,18 +356,24 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
conn->llcp.cte_req.is_enabled = 0U; conn->llcp.cte_req.is_enabled = 0U;
lp_comm_ntf(conn, ctx); lp_comm_ntf(conn, ctx);
} }
ctx->state = LP_COMMON_STATE_IDLE;
} else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND && } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND &&
ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ) { ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ) {
lp_comm_ntf(conn, ctx); lp_comm_ntf(conn, ctx);
conn->llcp.cte_req.is_enabled = 0U; conn->llcp.cte_req.is_enabled = 0U;
ctx->state = LP_COMMON_STATE_IDLE;
} }
ctx->state = LP_COMMON_STATE_IDLE;
if (ctx->state == LP_COMMON_STATE_IDLE) { if (ctx->state == LP_COMMON_STATE_IDLE) {
llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_set_paused_cmd(conn, PROC_NONE);
llcp_lr_complete(conn); llcp_lr_complete(conn);
} }
conn->llcp.cte_req.is_active = 0U;
if (conn->llcp.cte_req.disable_cb) {
conn->llcp.cte_req.disable_cb(conn->llcp.cte_req.disable_param);
}
break; break;
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
default: default:
@ -1008,6 +1014,7 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
case PROC_CTE_REQ: { case PROC_CTE_REQ: {
/* add PHY update pause = false here */ /* add PHY update pause = false here */
ctx->tx_ack = NULL;
llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_set_paused_cmd(conn, PROC_NONE);
llcp_rr_complete(conn); llcp_rr_complete(conn);
ctx->state = RP_COMMON_STATE_IDLE; ctx->state = RP_COMMON_STATE_IDLE;