Bluetooth: controller: implementing SCA update procedure PDU flow
Adding PDU flow and unittest for Sleep clock accuracy procedure Signed-off-by: Erik Brockhoff <erbr@oticon.com> wip kconf
This commit is contained in:
parent
661ff0527f
commit
b3b4b9e322
24 changed files with 969 additions and 4 deletions
|
@ -172,6 +172,13 @@ config BT_PER_ADV_SYNC_TRANSFER_RECEIVER
|
||||||
config BT_PER_ADV_SYNC_TRANSFER_SENDER
|
config BT_PER_ADV_SYNC_TRANSFER_SENDER
|
||||||
bool "Periodic Advertising Sync Transfer sender"
|
bool "Periodic Advertising Sync Transfer sender"
|
||||||
depends on !BT_CTLR || BT_CTLR_SYNC_TRANSFER_SENDER_SUPPORT
|
depends on !BT_CTLR || BT_CTLR_SYNC_TRANSFER_SENDER_SUPPORT
|
||||||
|
|
||||||
|
config BT_SCA_UPDATE
|
||||||
|
bool "Sleep Clock Accuracy Update"
|
||||||
|
default y if BT_ISO_PERIPHERAL || BT_ISO_CENTRAL
|
||||||
|
depends on !BT_CTLR || BT_CTLR_SCA_UPDATE_SUPPORT
|
||||||
|
help
|
||||||
|
Enable support for Bluetooth 5.1 Sleep Clock Accuracy Update Procedure
|
||||||
endif # BT_CONN
|
endif # BT_CONN
|
||||||
|
|
||||||
rsource "Kconfig.iso"
|
rsource "Kconfig.iso"
|
||||||
|
|
|
@ -78,6 +78,9 @@ config BT_CTLR_MIN_USED_CHAN_SUPPORT
|
||||||
config BT_CTLR_SMI_SUPPORT
|
config BT_CTLR_SMI_SUPPORT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config BT_CTLR_SCA_UPDATE_SUPPORT
|
||||||
|
bool
|
||||||
|
|
||||||
config BT_CTLR_CONN_RSSI_SUPPORT
|
config BT_CTLR_CONN_RSSI_SUPPORT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
@ -450,6 +453,14 @@ config BT_CTLR_MIN_USED_CHAN
|
||||||
Enable support for Bluetooth 5.0 Minimum Number of Used Channels
|
Enable support for Bluetooth 5.0 Minimum Number of Used Channels
|
||||||
Procedure in the Controller.
|
Procedure in the Controller.
|
||||||
|
|
||||||
|
config BT_CTLR_SCA_UPDATE
|
||||||
|
bool "Sleep Clock Accuracy Update procedure"
|
||||||
|
depends on BT_SCA_UPDATE && BT_CTLR_SCA_UPDATE_SUPPORT
|
||||||
|
default y if BT_CTLR_CONN_ISO
|
||||||
|
help
|
||||||
|
Enable support for Bluetooth 5.1 Sleep Clock Accuracy
|
||||||
|
Update procedure in the Controller.
|
||||||
|
|
||||||
config BT_CTLR_CONN_RSSI
|
config BT_CTLR_CONN_RSSI
|
||||||
bool "Connection RSSI"
|
bool "Connection RSSI"
|
||||||
depends on BT_CTLR_CONN_RSSI_SUPPORT
|
depends on BT_CTLR_CONN_RSSI_SUPPORT
|
||||||
|
|
|
@ -35,6 +35,7 @@ config BT_LLL_VENDOR_NORDIC
|
||||||
select BT_CTLR_CTEINLINE_SUPPORT if HAS_HW_NRF_RADIO_DFE
|
select BT_CTLR_CTEINLINE_SUPPORT if HAS_HW_NRF_RADIO_DFE
|
||||||
select BT_CTLR_CHAN_SEL_2_SUPPORT
|
select BT_CTLR_CHAN_SEL_2_SUPPORT
|
||||||
select BT_CTLR_MIN_USED_CHAN_SUPPORT
|
select BT_CTLR_MIN_USED_CHAN_SUPPORT
|
||||||
|
select BT_CTLR_SCA_UPDATE_SUPPORT
|
||||||
select BT_CTLR_DTM_HCI_SUPPORT
|
select BT_CTLR_DTM_HCI_SUPPORT
|
||||||
select BT_CTLR_CONN_RSSI_SUPPORT
|
select BT_CTLR_CONN_RSSI_SUPPORT
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,12 @@
|
||||||
#define LL_FEAT_BIT_RX_CTE 0
|
#define LL_FEAT_BIT_RX_CTE 0
|
||||||
#endif /* !CONFIG_BT_CTLR_DF && !CONFIG_BT_CTLR_DF_CTE_RX */
|
#endif /* !CONFIG_BT_CTLR_DF && !CONFIG_BT_CTLR_DF_CTE_RX */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
#define LL_FEAT_BIT_SCA_UPDATE BIT64(BT_LE_FEAT_BIT_SCA_UPDATE)
|
||||||
|
#else /* !CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
#define LL_FEAT_BIT_SCA_UPDATE 0
|
||||||
|
#endif /* !CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO)
|
#if defined(CONFIG_BT_CTLR_CENTRAL_ISO)
|
||||||
#define LL_FEAT_BIT_CIS_CENTRAL BIT64(BT_LE_FEAT_BIT_CIS_CENTRAL)
|
#define LL_FEAT_BIT_CIS_CENTRAL BIT64(BT_LE_FEAT_BIT_CIS_CENTRAL)
|
||||||
#else /* !CONFIG_BT_CTLR_CENTRAL_ISO */
|
#else /* !CONFIG_BT_CTLR_CENTRAL_ISO */
|
||||||
|
@ -252,6 +258,7 @@
|
||||||
LL_FEAT_BIT_ANT_SWITCH_TX_AOD | \
|
LL_FEAT_BIT_ANT_SWITCH_TX_AOD | \
|
||||||
LL_FEAT_BIT_ANT_SWITCH_RX_AOA | \
|
LL_FEAT_BIT_ANT_SWITCH_RX_AOA | \
|
||||||
LL_FEAT_BIT_RX_CTE | \
|
LL_FEAT_BIT_RX_CTE | \
|
||||||
|
LL_FEAT_BIT_SCA_UPDATE | \
|
||||||
LL_FEAT_BIT_CHAN_SEL_2 | \
|
LL_FEAT_BIT_CHAN_SEL_2 | \
|
||||||
LL_FEAT_BIT_MIN_USED_CHAN | \
|
LL_FEAT_BIT_MIN_USED_CHAN | \
|
||||||
LL_FEAT_BIT_CIS_CENTRAL | \
|
LL_FEAT_BIT_CIS_CENTRAL | \
|
||||||
|
|
|
@ -308,6 +308,7 @@ enum node_rx_type {
|
||||||
NODE_RX_TYPE_SCAN_INDICATION,
|
NODE_RX_TYPE_SCAN_INDICATION,
|
||||||
NODE_RX_TYPE_CIS_REQUEST,
|
NODE_RX_TYPE_CIS_REQUEST,
|
||||||
NODE_RX_TYPE_CIS_ESTABLISHED,
|
NODE_RX_TYPE_CIS_ESTABLISHED,
|
||||||
|
NODE_RX_TYPE_REQ_PEER_SCA_COMPLETE,
|
||||||
NODE_RX_TYPE_MESH_ADV_CPLT,
|
NODE_RX_TYPE_MESH_ADV_CPLT,
|
||||||
NODE_RX_TYPE_MESH_REPORT,
|
NODE_RX_TYPE_MESH_REPORT,
|
||||||
NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT,
|
NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT,
|
||||||
|
|
|
@ -524,6 +524,8 @@ enum pdu_data_llctrl_type {
|
||||||
PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND = 0x19,
|
PDU_DATA_LLCTRL_TYPE_MIN_USED_CHAN_IND = 0x19,
|
||||||
PDU_DATA_LLCTRL_TYPE_CTE_REQ = 0x1A,
|
PDU_DATA_LLCTRL_TYPE_CTE_REQ = 0x1A,
|
||||||
PDU_DATA_LLCTRL_TYPE_CTE_RSP = 0x1B,
|
PDU_DATA_LLCTRL_TYPE_CTE_RSP = 0x1B,
|
||||||
|
PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ = 0x1D,
|
||||||
|
PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP = 0x1E,
|
||||||
PDU_DATA_LLCTRL_TYPE_CIS_REQ = 0x1F,
|
PDU_DATA_LLCTRL_TYPE_CIS_REQ = 0x1F,
|
||||||
PDU_DATA_LLCTRL_TYPE_CIS_RSP = 0x20,
|
PDU_DATA_LLCTRL_TYPE_CIS_RSP = 0x20,
|
||||||
PDU_DATA_LLCTRL_TYPE_CIS_IND = 0x21,
|
PDU_DATA_LLCTRL_TYPE_CIS_IND = 0x21,
|
||||||
|
@ -697,6 +699,14 @@ struct pdu_data_llctrl_cte_rsp {
|
||||||
/* no members */
|
/* no members */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req {
|
||||||
|
uint8_t sca;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp {
|
||||||
|
uint8_t sca;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct pdu_data_llctrl_cis_req {
|
struct pdu_data_llctrl_cis_req {
|
||||||
uint8_t cig_id;
|
uint8_t cig_id;
|
||||||
uint8_t cis_id;
|
uint8_t cis_id;
|
||||||
|
@ -787,6 +797,8 @@ struct pdu_data_llctrl {
|
||||||
struct pdu_data_llctrl_min_used_chans_ind min_used_chans_ind;
|
struct pdu_data_llctrl_min_used_chans_ind min_used_chans_ind;
|
||||||
struct pdu_data_llctrl_cte_req cte_req;
|
struct pdu_data_llctrl_cte_req cte_req;
|
||||||
struct pdu_data_llctrl_cte_rsp cte_rsp;
|
struct pdu_data_llctrl_cte_rsp cte_rsp;
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req sca_req;
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp sca_rsp;
|
||||||
struct pdu_data_llctrl_cis_req cis_req;
|
struct pdu_data_llctrl_cis_req cis_req;
|
||||||
struct pdu_data_llctrl_cis_rsp cis_rsp;
|
struct pdu_data_llctrl_cis_rsp cis_rsp;
|
||||||
struct pdu_data_llctrl_cis_ind cis_ind;
|
struct pdu_data_llctrl_cis_ind cis_ind;
|
||||||
|
|
|
@ -598,3 +598,8 @@ struct node_rx_pu {
|
||||||
uint8_t tx;
|
uint8_t tx;
|
||||||
uint8_t rx;
|
uint8_t rx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct node_rx_sca {
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t sca;
|
||||||
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "ll_settings.h"
|
#include "ll_settings.h"
|
||||||
|
|
||||||
#include "lll.h"
|
#include "lll.h"
|
||||||
|
#include "lll_clock.h"
|
||||||
#include "lll/lll_df_types.h"
|
#include "lll/lll_df_types.h"
|
||||||
#include "lll_conn.h"
|
#include "lll_conn.h"
|
||||||
#include "lll_conn_iso.h"
|
#include "lll_conn_iso.h"
|
||||||
|
@ -370,6 +371,11 @@ struct proc_ctx *llcp_create_local_procedure(enum llcp_proc proc)
|
||||||
llcp_lp_comm_init_proc(ctx);
|
llcp_lp_comm_init_proc(ctx);
|
||||||
break;
|
break;
|
||||||
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_lp_comm_init_proc(ctx);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -451,6 +457,11 @@ struct proc_ctx *llcp_create_remote_procedure(enum llcp_proc proc)
|
||||||
llcp_rp_comm_init_proc(ctx);
|
llcp_rp_comm_init_proc(ctx);
|
||||||
break;
|
break;
|
||||||
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_rp_comm_init_proc(ctx);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
|
@ -910,6 +921,27 @@ uint8_t ull_cp_data_length_update(struct ll_conn *conn, uint16_t max_tx_octets,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
uint8_t ull_cp_req_peer_sca(struct ll_conn *conn)
|
||||||
|
{
|
||||||
|
struct proc_ctx *ctx;
|
||||||
|
|
||||||
|
if (!feature_sca(conn)) {
|
||||||
|
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = llcp_create_local_procedure(PROC_SCA_UPDATE);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
llcp_lr_enqueue(conn, ctx);
|
||||||
|
|
||||||
|
return BT_HCI_ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||||
uint8_t ull_cp_ltk_req_reply(struct ll_conn *conn, const uint8_t ltk[16])
|
uint8_t ull_cp_ltk_req_reply(struct ll_conn *conn, const uint8_t ltk[16])
|
||||||
{
|
{
|
||||||
|
@ -1462,6 +1494,26 @@ static bool pdu_validate_cte_resp(struct pdu_data *pdu)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
static bool pdu_validate_clock_accuracy_req(struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
if (pdu->len != sizeof(pdu->llctrl.sca_req) + 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||||
|
|
||||||
|
static bool pdu_validate_clock_accuracy_rsp(struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
if (pdu->len != sizeof(pdu->llctrl.sca_rsp) + 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
typedef bool (*pdu_param_validate_t)(struct pdu_data *pdu);
|
typedef bool (*pdu_param_validate_t)(struct pdu_data *pdu);
|
||||||
|
|
||||||
struct pdu_validate {
|
struct pdu_validate {
|
||||||
|
@ -1530,6 +1582,10 @@ static const struct pdu_validate pdu_validate[] = {
|
||||||
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP)
|
||||||
[PDU_DATA_LLCTRL_TYPE_CTE_RSP] = { pdu_validate_cte_resp },
|
[PDU_DATA_LLCTRL_TYPE_CTE_RSP] = { pdu_validate_cte_resp },
|
||||||
#endif /* PDU_DATA_LLCTRL_TYPE_CTE_RSP */
|
#endif /* PDU_DATA_LLCTRL_TYPE_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
[PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ] = { pdu_validate_clock_accuracy_req },
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
[PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP] = { pdu_validate_clock_accuracy_rsp },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool pdu_is_valid(struct pdu_data *pdu)
|
static bool pdu_is_valid(struct pdu_data *pdu)
|
||||||
|
|
|
@ -216,3 +216,10 @@ void ull_cp_cte_req_set_disable(struct ll_conn *conn);
|
||||||
*/
|
*/
|
||||||
void ull_cp_cte_rsp_enable(struct ll_conn *conn, bool enable, uint8_t max_cte_len,
|
void ull_cp_cte_rsp_enable(struct ll_conn *conn, bool enable, uint8_t max_cte_len,
|
||||||
uint8_t cte_types);
|
uint8_t cte_types);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
/**
|
||||||
|
* @brief Initiate a Sleep Clock Accuracy Update Procedure.
|
||||||
|
*/
|
||||||
|
uint8_t ull_cp_req_peer_sca(struct ll_conn *conn);
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
|
@ -196,6 +196,12 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||||
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP;
|
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP;
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_pdu_encode_clock_accuracy_req(ctx, pdu);
|
||||||
|
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP;
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -351,6 +357,29 @@ static void lp_comm_complete_cte_req(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
static void lp_sca_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct node_rx_pdu *ntf;
|
||||||
|
struct node_rx_sca *pdu;
|
||||||
|
|
||||||
|
/* Allocate ntf node */
|
||||||
|
ntf = llcp_ntf_alloc();
|
||||||
|
LL_ASSERT(ntf);
|
||||||
|
|
||||||
|
ntf->hdr.type = NODE_RX_TYPE_REQ_PEER_SCA_COMPLETE;
|
||||||
|
ntf->hdr.handle = conn->lll.handle;
|
||||||
|
pdu = (struct node_rx_sca *)ntf->pdu;
|
||||||
|
|
||||||
|
pdu->status = ctx->data.sca_update.error_code;
|
||||||
|
pdu->sca = ctx->data.sca_update.sca;
|
||||||
|
|
||||||
|
/* Enqueue notification towards LL */
|
||||||
|
ll_rx_put(ntf->hdr.link, ntf);
|
||||||
|
ll_rx_sched();
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
||||||
static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct node_rx_pdu *ntf;
|
struct node_rx_pdu *ntf;
|
||||||
|
@ -506,6 +535,25 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
||||||
lp_comm_complete_cte_req(conn, ctx);
|
lp_comm_complete_cte_req(conn, ctx);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
switch (ctx->response_opcode) {
|
||||||
|
case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP:
|
||||||
|
/* Peer does not support SCA update, so disable on current connection */
|
||||||
|
feature_unmask_features(conn, LL_FEAT_BIT_SCA_UPDATE);
|
||||||
|
ctx->data.sca_update.error_code = BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
||||||
|
/* Fall through to complete procedure */
|
||||||
|
case PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP:
|
||||||
|
lp_sca_ntf(conn, ctx);
|
||||||
|
llcp_lr_complete(conn);
|
||||||
|
ctx->state = LP_COMMON_STATE_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Illegal response opcode */
|
||||||
|
lp_comm_terminate_invalid_pdu(conn, ctx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -642,6 +690,16 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
|
||||||
|
ctx->state = LP_COMMON_STATE_WAIT_TX;
|
||||||
|
} else {
|
||||||
|
lp_comm_tx(conn, ctx);
|
||||||
|
ctx->state = LP_COMMON_STATE_WAIT_RX;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -766,6 +824,11 @@ static void lp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct
|
||||||
llcp_pdu_decode_cte_rsp(ctx, pdu);
|
llcp_pdu_decode_cte_rsp(ctx, pdu);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP:
|
||||||
|
llcp_pdu_decode_clock_accuracy_rsp(ctx, pdu);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
|
case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
|
||||||
llcp_pdu_decode_reject_ext_ind(ctx, pdu);
|
llcp_pdu_decode_reject_ext_ind(ctx, pdu);
|
||||||
break;
|
break;
|
||||||
|
@ -955,6 +1018,11 @@ static void rp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct
|
||||||
llcp_pdu_decode_cte_req(ctx, pdu);
|
llcp_pdu_decode_cte_req(ctx, pdu);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ:
|
||||||
|
llcp_pdu_decode_clock_accuracy_req(ctx, pdu);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown opcode */
|
/* Unknown opcode */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -1029,6 +1097,13 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_pdu_encode_clock_accuracy_rsp(ctx, pdu);
|
||||||
|
ctx->tx_ack = tx;
|
||||||
|
ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED;
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -1217,6 +1292,19 @@ static void rp_comm_send_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
/* Always respond to remote SCA */
|
||||||
|
if (llcp_rr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
|
||||||
|
ctx->state = RP_COMMON_STATE_WAIT_TX;
|
||||||
|
} else {
|
||||||
|
rp_comm_tx(conn, ctx);
|
||||||
|
|
||||||
|
/* Wait for the peer to have ack'ed the RSP before completing */
|
||||||
|
ctx->state = RP_COMMON_STATE_WAIT_TX_ACK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -1303,6 +1391,13 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u
|
||||||
ctx->state = RP_COMMON_STATE_IDLE;
|
ctx->state = RP_COMMON_STATE_IDLE;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE: {
|
||||||
|
ctx->tx_ack = NULL;
|
||||||
|
llcp_rr_complete(conn);
|
||||||
|
ctx->state = RP_COMMON_STATE_IDLE;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Ignore other procedures */
|
/* Ignore other procedures */
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -120,7 +120,16 @@ static inline bool feature_phy_coded(struct ll_conn *conn)
|
||||||
static inline bool feature_cte_req(struct ll_conn *conn)
|
static inline bool feature_cte_req(struct ll_conn *conn)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_BT_CTLR_DF) && defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
#if defined(CONFIG_BT_CTLR_DF) && defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
||||||
return conn->llcp.fex.features_used & LL_FEAT_BIT_CONNECTION_CTE_REQ;
|
return (conn->llcp.fex.features_used & LL_FEAT_BIT_CONNECTION_CTE_REQ) != 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool feature_sca(struct ll_conn *conn)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
return (conn->llcp.fex.features_used & LL_FEAT_BIT_SCA_UPDATE) != 0;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -162,7 +171,6 @@ static inline bool feature_peer_smi_tx(struct ll_conn *conn)
|
||||||
* tone_ext
|
* tone_ext
|
||||||
* per_adv_sync_tx
|
* per_adv_sync_tx
|
||||||
* per_adv_sync_rx
|
* per_adv_sync_rx
|
||||||
* sleep_upd
|
|
||||||
* rpk_valid
|
* rpk_valid
|
||||||
* iso_central
|
* iso_central
|
||||||
* iso_periph
|
* iso_periph
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum llcp_proc {
|
||||||
PROC_CTE_REQ,
|
PROC_CTE_REQ,
|
||||||
PROC_CIS_CREATE,
|
PROC_CIS_CREATE,
|
||||||
PROC_CIS_TERMINATE,
|
PROC_CIS_TERMINATE,
|
||||||
|
PROC_SCA_UPDATE,
|
||||||
/* A helper enum entry, to use in pause procedure context */
|
/* A helper enum entry, to use in pause procedure context */
|
||||||
PROC_NONE = 0x0,
|
PROC_NONE = 0x0,
|
||||||
};
|
};
|
||||||
|
@ -295,6 +296,12 @@ struct proc_ctx {
|
||||||
uint8_t cis_id;
|
uint8_t cis_id;
|
||||||
uint8_t error_code;
|
uint8_t error_code;
|
||||||
} cis_term;
|
} cis_term;
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
struct {
|
||||||
|
uint8_t sca;
|
||||||
|
uint8_t error_code;
|
||||||
|
} sca_update;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -670,6 +677,17 @@ void llcp_ntf_encode_length_change(struct ll_conn *conn,
|
||||||
|
|
||||||
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
/*
|
||||||
|
* Sleep Clock Accuracy Update Procedure Helper
|
||||||
|
*/
|
||||||
|
void llcp_pdu_encode_clock_accuracy_req(struct proc_ctx *ctx, struct pdu_data *pdu);
|
||||||
|
void llcp_pdu_encode_clock_accuracy_rsp(struct proc_ctx *ctx, struct pdu_data *pdu);
|
||||||
|
void llcp_pdu_decode_clock_accuracy_req(struct proc_ctx *ctx, struct pdu_data *pdu);
|
||||||
|
void llcp_pdu_decode_clock_accuracy_rsp(struct proc_ctx *ctx, struct pdu_data *pdu);
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ)
|
||||||
/*
|
/*
|
||||||
* Constant Tone Request Procedure Helper
|
* Constant Tone Request Procedure Helper
|
||||||
|
|
|
@ -201,6 +201,11 @@ void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *
|
||||||
llcp_lp_comm_rx(conn, ctx, rx);
|
llcp_lp_comm_rx(conn, ctx, rx);
|
||||||
break;
|
break;
|
||||||
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_lp_comm_rx(conn, ctx, rx);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -321,6 +326,11 @@ static void lr_act_run(struct ll_conn *conn)
|
||||||
llcp_lp_comm_run(conn, ctx, NULL);
|
llcp_lp_comm_run(conn, ctx, NULL);
|
||||||
break;
|
break;
|
||||||
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_lp_comm_run(conn, ctx, NULL);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "ll_settings.h"
|
#include "ll_settings.h"
|
||||||
|
|
||||||
#include "lll.h"
|
#include "lll.h"
|
||||||
|
#include "lll_clock.h"
|
||||||
#include "lll/lll_df_types.h"
|
#include "lll/lll_df_types.h"
|
||||||
#include "lll_conn.h"
|
#include "lll_conn.h"
|
||||||
#include "lll_conn_iso.h"
|
#include "lll_conn_iso.h"
|
||||||
|
@ -904,3 +905,46 @@ void llcp_pdu_decode_cis_terminate_ind(struct proc_ctx *ctx, struct pdu_data *pd
|
||||||
ctx->data.cis_term.error_code = pdu->llctrl.cis_terminate_ind.error_code;
|
ctx->data.cis_term.error_code = pdu->llctrl.cis_terminate_ind.error_code;
|
||||||
}
|
}
|
||||||
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
#endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) || defined(CONFIG_BT_CTLR_PERIPHERAL_ISO) */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
/*
|
||||||
|
* SCA Update Procedure Helpers
|
||||||
|
*/
|
||||||
|
void llcp_pdu_encode_clock_accuracy_req(struct proc_ctx *ctx, struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req *p = &pdu->llctrl.sca_req;
|
||||||
|
|
||||||
|
pdu->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
|
pdu->len = offsetof(struct pdu_data_llctrl, sca_req) +
|
||||||
|
sizeof(struct pdu_data_llctrl_clock_accuracy_req);
|
||||||
|
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ;
|
||||||
|
/* Currently we do not support variable SCA, so we always 'report' current SCA */
|
||||||
|
p->sca = lll_clock_sca_local_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void llcp_pdu_encode_clock_accuracy_rsp(struct proc_ctx *ctx, struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp *p = &pdu->llctrl.sca_rsp;
|
||||||
|
|
||||||
|
pdu->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
|
pdu->len = offsetof(struct pdu_data_llctrl, sca_rsp) +
|
||||||
|
sizeof(struct pdu_data_llctrl_clock_accuracy_rsp);
|
||||||
|
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP;
|
||||||
|
/* Currently we do not support variable SCA, so we always 'report' current SCA */
|
||||||
|
p->sca = lll_clock_sca_local_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void llcp_pdu_decode_clock_accuracy_req(struct proc_ctx *ctx, struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req *p = &pdu->llctrl.sca_req;
|
||||||
|
|
||||||
|
ctx->data.sca_update.sca = p->sca;
|
||||||
|
}
|
||||||
|
|
||||||
|
void llcp_pdu_decode_clock_accuracy_rsp(struct proc_ctx *ctx, struct pdu_data *pdu)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp *p = &pdu->llctrl.sca_rsp;
|
||||||
|
|
||||||
|
ctx->data.sca_update.sca = p->sca;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
|
|
|
@ -94,6 +94,7 @@ static bool proc_with_instant(struct proc_ctx *ctx)
|
||||||
case PROC_CTE_REQ:
|
case PROC_CTE_REQ:
|
||||||
case PROC_CIS_TERMINATE:
|
case PROC_CIS_TERMINATE:
|
||||||
case PROC_CIS_CREATE:
|
case PROC_CIS_CREATE:
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
return 0U;
|
return 0U;
|
||||||
case PROC_PHY_UPDATE:
|
case PROC_PHY_UPDATE:
|
||||||
case PROC_CONN_UPDATE:
|
case PROC_CONN_UPDATE:
|
||||||
|
@ -278,6 +279,11 @@ void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *
|
||||||
llcp_rp_comm_rx(conn, ctx, rx);
|
llcp_rp_comm_rx(conn, ctx, rx);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_rp_comm_rx(conn, ctx, rx);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -303,6 +309,11 @@ void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *
|
||||||
case PROC_CTE_REQ:
|
case PROC_CTE_REQ:
|
||||||
llcp_rp_comm_tx_ack(conn, ctx, tx);
|
llcp_rp_comm_tx_ack(conn, ctx, tx);
|
||||||
break;
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_rp_comm_tx_ack(conn, ctx, tx);
|
||||||
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */
|
||||||
default:
|
default:
|
||||||
/* Ignore tx_ack */
|
/* Ignore tx_ack */
|
||||||
|
@ -399,6 +410,11 @@ static void rr_act_run(struct ll_conn *conn)
|
||||||
llcp_rp_comm_run(conn, ctx, NULL);
|
llcp_rp_comm_run(conn, ctx, NULL);
|
||||||
break;
|
break;
|
||||||
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO || CONFIG_BT_CTLR_PERIPHERAL_ISO */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
case PROC_SCA_UPDATE:
|
||||||
|
llcp_rp_comm_run(conn, ctx, NULL);
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
default:
|
default:
|
||||||
/* Unknown procedure */
|
/* Unknown procedure */
|
||||||
LL_ASSERT(0);
|
LL_ASSERT(0);
|
||||||
|
@ -831,6 +847,9 @@ static const struct proc_role new_proc_lut[] = {
|
||||||
#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
|
#if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO)
|
||||||
[PDU_DATA_LLCTRL_TYPE_CIS_REQ] = { PROC_CIS_CREATE, ACCEPT_ROLE_PERIPHERAL },
|
[PDU_DATA_LLCTRL_TYPE_CIS_REQ] = { PROC_CIS_CREATE, ACCEPT_ROLE_PERIPHERAL },
|
||||||
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */
|
#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */
|
||||||
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
|
[PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ] = { PROC_SCA_UPDATE, ACCEPT_ROLE_BOTH },
|
||||||
|
#endif /* CONFIG_BT_CTLR_SCA_UPDATE */
|
||||||
};
|
};
|
||||||
|
|
||||||
void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu)
|
void llcp_rr_new(struct ll_conn *conn, struct node_rx_pdu *rx, bool valid_pdu)
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
#define FEAT_PER_ADV_SYNC_RX 0x00
|
#define FEAT_PER_ADV_SYNC_RX 0x00
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_MISSING)
|
#if defined(CONFIG_BT_CTLR_SCA_UPDATE)
|
||||||
#define FEAT_SLEEP_UPD 0x4000000
|
#define FEAT_SLEEP_UPD 0x4000000
|
||||||
#else
|
#else
|
||||||
#define FEAT_SLEEP_UPD 0x00
|
#define FEAT_SLEEP_UPD 0x00
|
||||||
|
|
|
@ -59,6 +59,9 @@ void helper_pdu_encode_cis_rsp(struct pdu_data *pdu, void *param);
|
||||||
void helper_pdu_encode_cis_ind(struct pdu_data *pdu, void *param);
|
void helper_pdu_encode_cis_ind(struct pdu_data *pdu, void *param);
|
||||||
void helper_pdu_encode_cis_terminate_ind(struct pdu_data *pdu, void *param);
|
void helper_pdu_encode_cis_terminate_ind(struct pdu_data *pdu, void *param);
|
||||||
|
|
||||||
|
void helper_pdu_encode_sca_req(struct pdu_data *pdu, void *param);
|
||||||
|
void helper_pdu_encode_sca_rsp(struct pdu_data *pdu, void *param);
|
||||||
|
|
||||||
void helper_pdu_verify_ping_req(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
void helper_pdu_verify_ping_req(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
||||||
void helper_pdu_verify_ping_rsp(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
void helper_pdu_verify_ping_rsp(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
||||||
|
|
||||||
|
@ -149,6 +152,12 @@ void helper_pdu_verify_cis_ind(const char *file, uint32_t line, struct pdu_data
|
||||||
void helper_pdu_verify_cis_terminate_ind(const char *file, uint32_t line, struct pdu_data *pdu,
|
void helper_pdu_verify_cis_terminate_ind(const char *file, uint32_t line, struct pdu_data *pdu,
|
||||||
void *param);
|
void *param);
|
||||||
|
|
||||||
|
void helper_pdu_verify_sca_req(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
||||||
|
void helper_pdu_verify_sca_rsp(const char *file, uint32_t line, struct pdu_data *pdu, void *param);
|
||||||
|
|
||||||
|
void helper_node_verify_peer_sca_update(const char *file, uint32_t line, struct node_rx_pdu *rx,
|
||||||
|
void *param);
|
||||||
|
|
||||||
enum helper_pdu_opcode {
|
enum helper_pdu_opcode {
|
||||||
LL_VERSION_IND,
|
LL_VERSION_IND,
|
||||||
LL_LE_PING_REQ,
|
LL_LE_PING_REQ,
|
||||||
|
@ -178,6 +187,8 @@ enum helper_pdu_opcode {
|
||||||
LL_LENGTH_RSP,
|
LL_LENGTH_RSP,
|
||||||
LL_CTE_REQ,
|
LL_CTE_REQ,
|
||||||
LL_CTE_RSP,
|
LL_CTE_RSP,
|
||||||
|
LL_CLOCK_ACCURACY_REQ,
|
||||||
|
LL_CLOCK_ACCURACY_RSP,
|
||||||
LL_CIS_REQ,
|
LL_CIS_REQ,
|
||||||
LL_CIS_RSP,
|
LL_CIS_RSP,
|
||||||
LL_CIS_IND,
|
LL_CIS_IND,
|
||||||
|
@ -192,7 +203,7 @@ enum helper_node_opcode {
|
||||||
NODE_CTE_RSP,
|
NODE_CTE_RSP,
|
||||||
NODE_CIS_REQUEST,
|
NODE_CIS_REQUEST,
|
||||||
NODE_CIS_ESTABLISHED,
|
NODE_CIS_ESTABLISHED,
|
||||||
|
NODE_PEER_SCA_UPDATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void(helper_pdu_encode_func_t)(struct pdu_data *data, void *param);
|
typedef void(helper_pdu_encode_func_t)(struct pdu_data *data, void *param);
|
||||||
|
|
|
@ -480,6 +480,28 @@ void helper_pdu_encode_cis_terminate_ind(struct pdu_data *pdu, void *param)
|
||||||
pdu->llctrl.cis_terminate_ind.error_code = p->error_code;
|
pdu->llctrl.cis_terminate_ind.error_code = p->error_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void helper_pdu_encode_sca_req(struct pdu_data *pdu, void *param)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req *p = param;
|
||||||
|
|
||||||
|
pdu->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
|
pdu->len = offsetof(struct pdu_data_llctrl, sca_req) +
|
||||||
|
sizeof(struct pdu_data_llctrl_clock_accuracy_req);
|
||||||
|
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ;
|
||||||
|
pdu->llctrl.sca_req.sca = p->sca;
|
||||||
|
}
|
||||||
|
|
||||||
|
void helper_pdu_encode_sca_rsp(struct pdu_data *pdu, void *param)
|
||||||
|
{
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp *p = param;
|
||||||
|
|
||||||
|
pdu->ll_id = PDU_DATA_LLID_CTRL;
|
||||||
|
pdu->len = offsetof(struct pdu_data_llctrl, sca_rsp) +
|
||||||
|
sizeof(struct pdu_data_llctrl_clock_accuracy_rsp);
|
||||||
|
pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP;
|
||||||
|
pdu->llctrl.sca_rsp.sca = p->sca;
|
||||||
|
}
|
||||||
|
|
||||||
void helper_pdu_verify_version_ind(const char *file, uint32_t line, struct pdu_data *pdu,
|
void helper_pdu_verify_version_ind(const char *file, uint32_t line, struct pdu_data *pdu,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
|
@ -763,6 +785,18 @@ void helper_node_verify_phy_update(const char *file, uint32_t line, struct node_
|
||||||
zassert_equal(pdu->status, p->status, "Status mismatch.\nCalled at %s:%d\n", file, line);
|
zassert_equal(pdu->status, p->status, "Status mismatch.\nCalled at %s:%d\n", file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void helper_node_verify_peer_sca_update(const char *file, uint32_t line, struct node_rx_pdu *rx,
|
||||||
|
void *param)
|
||||||
|
{
|
||||||
|
struct node_rx_sca *pdu = (struct node_rx_sca *)rx->pdu;
|
||||||
|
struct node_rx_sca *p = param;
|
||||||
|
|
||||||
|
zassert_equal(rx->hdr.type, NODE_RX_TYPE_REQ_PEER_SCA_COMPLETE,
|
||||||
|
"Not an SCA node.\nCalled at %s:%d\n", file, line);
|
||||||
|
zassert_equal(pdu->status, p->status, "Status mismatch.\nCalled at %s:%d\n", file, line);
|
||||||
|
zassert_equal(pdu->sca, p->sca, "SCA mismatch.\nCalled at %s:%d\n", file, line);
|
||||||
|
}
|
||||||
|
|
||||||
void helper_pdu_verify_unknown_rsp(const char *file, uint32_t line, struct pdu_data *pdu,
|
void helper_pdu_verify_unknown_rsp(const char *file, uint32_t line, struct pdu_data *pdu,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
|
@ -1201,3 +1235,19 @@ void helper_pdu_verify_cis_terminate_ind(const char *file, uint32_t line, struct
|
||||||
zassert_equal(pdu->llctrl.cis_terminate_ind.error_code, p->error_code,
|
zassert_equal(pdu->llctrl.cis_terminate_ind.error_code, p->error_code,
|
||||||
"Error code mismatch.\nCalled at %s:%d\n", file, line);
|
"Error code mismatch.\nCalled at %s:%d\n", file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void helper_pdu_verify_sca_req(const char *file, uint32_t line, struct pdu_data *pdu, void *param)
|
||||||
|
{
|
||||||
|
zassert_equal(pdu->ll_id, PDU_DATA_LLID_CTRL, "Not a Control PDU.\nCalled at %s:%d\n", file,
|
||||||
|
line);
|
||||||
|
zassert_equal(pdu->llctrl.opcode, PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ,
|
||||||
|
"Not a LL_CLOCK_ACCURACY_REQ. Called at %s:%d\n", file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void helper_pdu_verify_sca_rsp(const char *file, uint32_t line, struct pdu_data *pdu, void *param)
|
||||||
|
{
|
||||||
|
zassert_equal(pdu->ll_id, PDU_DATA_LLID_CTRL, "Not a Control PDU.\nCalled at %s:%d\n", file,
|
||||||
|
line);
|
||||||
|
zassert_equal(pdu->llctrl.opcode, PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_RSP,
|
||||||
|
"Not a LL_CLOCK_ACCURACY_RSP.\nCalled at %s:%d\n", file, line);
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,8 @@ helper_pdu_encode_func_t *const helper_pdu_encode[] = {
|
||||||
[LL_LENGTH_RSP] = helper_pdu_encode_length_rsp,
|
[LL_LENGTH_RSP] = helper_pdu_encode_length_rsp,
|
||||||
[LL_CTE_REQ] = helper_pdu_encode_cte_req,
|
[LL_CTE_REQ] = helper_pdu_encode_cte_req,
|
||||||
[LL_CTE_RSP] = helper_pdu_encode_cte_rsp,
|
[LL_CTE_RSP] = helper_pdu_encode_cte_rsp,
|
||||||
|
[LL_CLOCK_ACCURACY_REQ] = helper_pdu_encode_sca_req,
|
||||||
|
[LL_CLOCK_ACCURACY_RSP] = helper_pdu_encode_sca_rsp,
|
||||||
[LL_CIS_REQ] = helper_pdu_encode_cis_req,
|
[LL_CIS_REQ] = helper_pdu_encode_cis_req,
|
||||||
[LL_CIS_RSP] = helper_pdu_encode_cis_rsp,
|
[LL_CIS_RSP] = helper_pdu_encode_cis_rsp,
|
||||||
[LL_CIS_IND] = helper_pdu_encode_cis_ind,
|
[LL_CIS_IND] = helper_pdu_encode_cis_ind,
|
||||||
|
@ -123,6 +125,8 @@ helper_pdu_verify_func_t *const helper_pdu_verify[] = {
|
||||||
[LL_LENGTH_RSP] = helper_pdu_verify_length_rsp,
|
[LL_LENGTH_RSP] = helper_pdu_verify_length_rsp,
|
||||||
[LL_CTE_REQ] = helper_pdu_verify_cte_req,
|
[LL_CTE_REQ] = helper_pdu_verify_cte_req,
|
||||||
[LL_CTE_RSP] = helper_pdu_verify_cte_rsp,
|
[LL_CTE_RSP] = helper_pdu_verify_cte_rsp,
|
||||||
|
[LL_CLOCK_ACCURACY_REQ] = helper_pdu_verify_sca_req,
|
||||||
|
[LL_CLOCK_ACCURACY_RSP] = helper_pdu_verify_sca_rsp,
|
||||||
[LL_CIS_REQ] = helper_pdu_verify_cis_req,
|
[LL_CIS_REQ] = helper_pdu_verify_cis_req,
|
||||||
[LL_CIS_RSP] = helper_pdu_verify_cis_rsp,
|
[LL_CIS_RSP] = helper_pdu_verify_cis_rsp,
|
||||||
[LL_CIS_IND] = helper_pdu_verify_cis_ind,
|
[LL_CIS_IND] = helper_pdu_verify_cis_ind,
|
||||||
|
@ -157,6 +161,8 @@ helper_pdu_ntf_verify_func_t *const helper_pdu_ntf_verify[] = {
|
||||||
[LL_CTE_REQ] = NULL,
|
[LL_CTE_REQ] = NULL,
|
||||||
[LL_CTE_RSP] = helper_pdu_ntf_verify_cte_rsp,
|
[LL_CTE_RSP] = helper_pdu_ntf_verify_cte_rsp,
|
||||||
[LL_CTE_RSP] = NULL,
|
[LL_CTE_RSP] = NULL,
|
||||||
|
[LL_CLOCK_ACCURACY_REQ] = NULL,
|
||||||
|
[LL_CLOCK_ACCURACY_RSP] = NULL,
|
||||||
[LL_CIS_REQ] = NULL,
|
[LL_CIS_REQ] = NULL,
|
||||||
[LL_CIS_RSP] = NULL,
|
[LL_CIS_RSP] = NULL,
|
||||||
[LL_CIS_IND] = NULL,
|
[LL_CIS_IND] = NULL,
|
||||||
|
@ -188,6 +194,8 @@ helper_node_encode_func_t *const helper_node_encode[] = {
|
||||||
[LL_CHAN_MAP_UPDATE_IND] = NULL,
|
[LL_CHAN_MAP_UPDATE_IND] = NULL,
|
||||||
[LL_CTE_REQ] = NULL,
|
[LL_CTE_REQ] = NULL,
|
||||||
[LL_CTE_RSP] = helper_node_encode_cte_rsp,
|
[LL_CTE_RSP] = helper_node_encode_cte_rsp,
|
||||||
|
[LL_CLOCK_ACCURACY_REQ] = NULL,
|
||||||
|
[LL_CLOCK_ACCURACY_RSP] = NULL,
|
||||||
[LL_CIS_REQ] = NULL,
|
[LL_CIS_REQ] = NULL,
|
||||||
[LL_CIS_RSP] = NULL,
|
[LL_CIS_RSP] = NULL,
|
||||||
[LL_CIS_IND] = NULL,
|
[LL_CIS_IND] = NULL,
|
||||||
|
@ -201,6 +209,7 @@ helper_node_verify_func_t *const helper_node_verify[] = {
|
||||||
[NODE_CTE_RSP] = helper_node_verify_cte_rsp,
|
[NODE_CTE_RSP] = helper_node_verify_cte_rsp,
|
||||||
[NODE_CIS_REQUEST] = helper_node_verify_cis_request,
|
[NODE_CIS_REQUEST] = helper_node_verify_cis_request,
|
||||||
[NODE_CIS_ESTABLISHED] = helper_node_verify_cis_established,
|
[NODE_CIS_ESTABLISHED] = helper_node_verify_cis_established,
|
||||||
|
[NODE_PEER_SCA_UPDATE] = helper_node_verify_peer_sca_update,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
12
tests/bluetooth/controller/ctrl_sca_update/CMakeLists.txt
Normal file
12
tests/bluetooth/controller/ctrl_sca_update/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
|
FILE(GLOB SOURCES
|
||||||
|
src/*.c
|
||||||
|
)
|
||||||
|
|
||||||
|
project(bluetooth_ull_llcp_sca_update)
|
||||||
|
find_package(Zephyr COMPONENTS unittest HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
include(${ZEPHYR_BASE}/tests/bluetooth/controller/common/defaults_cmake.txt)
|
||||||
|
target_sources(testbinary PRIVATE ${ll_sw_sources} ${mock_sources} ${common_sources})
|
568
tests/bluetooth/controller/ctrl_sca_update/src/main.c
Normal file
568
tests/bluetooth/controller/ctrl_sca_update/src/main.c
Normal file
|
@ -0,0 +1,568 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Demant
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include "kconfig.h"
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/hci.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/sys/slist.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include "hal/ccm.h"
|
||||||
|
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "util/mem.h"
|
||||||
|
#include "util/memq.h"
|
||||||
|
#include "util/dbuf.h"
|
||||||
|
|
||||||
|
#include "pdu.h"
|
||||||
|
#include "ll.h"
|
||||||
|
#include "ll_feat.h"
|
||||||
|
#include "ll_settings.h"
|
||||||
|
|
||||||
|
#include "lll.h"
|
||||||
|
#include "lll_df_types.h"
|
||||||
|
#include "lll_conn.h"
|
||||||
|
#include "lll_conn_iso.h"
|
||||||
|
|
||||||
|
#include "ull_tx_queue.h"
|
||||||
|
|
||||||
|
#include "isoal.h"
|
||||||
|
#include "ull_iso_types.h"
|
||||||
|
#include "ull_conn_iso_types.h"
|
||||||
|
#include "ull_conn_types.h"
|
||||||
|
#include "ull_llcp.h"
|
||||||
|
#include "ull_conn_internal.h"
|
||||||
|
#include "ull_llcp_internal.h"
|
||||||
|
#include "ull_llcp_features.h"
|
||||||
|
|
||||||
|
#include "helper_pdu.h"
|
||||||
|
#include "helper_util.h"
|
||||||
|
|
||||||
|
struct ll_conn conn;
|
||||||
|
|
||||||
|
static void setup(void)
|
||||||
|
{
|
||||||
|
test_setup(&conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | Start | |
|
||||||
|
* | SCA Update Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_RSP |
|
||||||
|
* | |<-------------------------------|
|
||||||
|
* | | |
|
||||||
|
* | Start | |
|
||||||
|
* | SCA UPdate Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_UNKNOWN_RSP |
|
||||||
|
* | |<-------------------------------|
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_sca_central_loc(void)
|
||||||
|
{
|
||||||
|
uint8_t err;
|
||||||
|
struct node_tx *tx;
|
||||||
|
struct node_rx_pdu *ntf;
|
||||||
|
struct node_rx_sca scau = { .status = BT_HCI_ERR_SUCCESS, .sca = 2 };
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = { };
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp remote_sca_rsp = { .sca = 2 };
|
||||||
|
struct pdu_data_llctrl_unknown_rsp unknown_rsp = {
|
||||||
|
.type = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Initiate an SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Confirm SCA Update is indicated as supported */
|
||||||
|
zassert_equal(feature_sca(&conn), true, "SCA Update Feature masked out");
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_CLOCK_ACCURACY_RSP, &conn, &remote_sca_rsp);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination not 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, 0,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* There should be one notification due to Peer SCA Request */
|
||||||
|
ut_rx_node(NODE_PEER_SCA_UPDATE, &ntf, &scau);
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
/* Initiate another SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_UNKNOWN_RSP, &conn, &unknown_rsp);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Confirm SCA Update is now indicated as NOT supported */
|
||||||
|
zassert_equal(feature_sca(&conn), false, "SCA Update Feature masked in");
|
||||||
|
|
||||||
|
/* Termination not 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, 0,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
scau.status = BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
||||||
|
scau.sca = 0;
|
||||||
|
|
||||||
|
/* There should be one notification due to Peer SCA Request */
|
||||||
|
ut_rx_node(NODE_PEER_SCA_UPDATE, &ntf, &scau);
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | Start | |
|
||||||
|
* | SCA Update Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_<INVALID>_RSP |
|
||||||
|
* | |<-------------------------|
|
||||||
|
* | | |
|
||||||
|
* ~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_sca_central_loc_invalid_rsp(void)
|
||||||
|
{
|
||||||
|
uint8_t err;
|
||||||
|
struct node_tx *tx;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||||
|
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||||
|
};
|
||||||
|
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||||
|
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ,
|
||||||
|
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||||
|
};
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = {};
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Initiate an SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* Clear termination flag for subsequent test cycle */
|
||||||
|
conn.llcp_terminate.reason_final = 0;
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
/* Initiate another SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | Start | |
|
||||||
|
* | SCA Update Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_<INVALID>_RSP |
|
||||||
|
* | |<-------------------------|
|
||||||
|
* | | |
|
||||||
|
* ~~~~~~~~~~~~~~~~~ TERMINATE CONNECTION ~~~~~~~~~~~~~~
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_sca_peripheral_loc_invalid_rsp(void)
|
||||||
|
{
|
||||||
|
uint8_t err;
|
||||||
|
struct node_tx *tx;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_reject_ind reject_ind = {
|
||||||
|
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||||
|
};
|
||||||
|
struct pdu_data_llctrl_reject_ext_ind reject_ext_ind = {
|
||||||
|
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CLOCK_ACCURACY_REQ,
|
||||||
|
.error_code = BT_HCI_ERR_LL_PROC_COLLISION
|
||||||
|
};
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = {};
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Initiate an SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_REJECT_EXT_IND, &conn, &reject_ext_ind);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* Clear termination flag for subsequent test cycle */
|
||||||
|
conn.llcp_terminate.reason_final = 0;
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
/* Initiate another SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_REJECT_IND, &conn, &reject_ind);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, BT_HCI_ERR_LMP_PDU_NOT_ALLOWED,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | Start | |
|
||||||
|
* | SCA Update Proc. | |
|
||||||
|
* |--------------------------->| |
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_RSP |
|
||||||
|
* | |<-------------------------|
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_ping_periph_loc(void)
|
||||||
|
{
|
||||||
|
uint8_t err;
|
||||||
|
struct node_tx *tx;
|
||||||
|
struct node_rx_pdu *ntf;
|
||||||
|
struct node_rx_sca scau = { .status = BT_HCI_ERR_SUCCESS, .sca = 2 };
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = { };
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp remote_sca_rsp = { .sca = 2 };
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Initiate an SCA Procedure */
|
||||||
|
err = ull_cp_req_peer_sca(&conn);
|
||||||
|
zassert_equal(err, BT_HCI_ERR_SUCCESS);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_REQ, &conn, &tx, &local_sca_req);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
/* Rx */
|
||||||
|
lt_tx(LL_CLOCK_ACCURACY_RSP, &conn, &remote_sca_rsp);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* Termination not 'triggered' */
|
||||||
|
zassert_equal(conn.llcp_terminate.reason_final, 0,
|
||||||
|
"Terminate reason %d", conn.llcp_terminate.reason_final);
|
||||||
|
|
||||||
|
/* There should be one notification due to Peer SCA Request */
|
||||||
|
ut_rx_node(NODE_PEER_SCA_UPDATE, &ntf, &scau);
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_RSP |
|
||||||
|
* | |<-------------------------|
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_ping_central_rem(void)
|
||||||
|
{
|
||||||
|
struct node_tx *tx;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = { };
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp remote_sca_rsp = { };
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_CENTRAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx */
|
||||||
|
lt_tx(LL_CLOCK_ACCURACY_REQ, &conn, &local_sca_req);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_RSP, &conn, &tx, &remote_sca_rsp);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
event_tx_ack(&conn, tx);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* +-----+ +-------+ +-----+
|
||||||
|
* | UT | | LL_A | | LT |
|
||||||
|
* +-----+ +-------+ +-----+
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_REQ |
|
||||||
|
* | |------------------------->|
|
||||||
|
* | | |
|
||||||
|
* | | LL_CLOCK_ACCURACY_RSP |
|
||||||
|
* | |<-------------------------|
|
||||||
|
* | | |
|
||||||
|
* | | |
|
||||||
|
*/
|
||||||
|
void test_ping_periph_rem(void)
|
||||||
|
{
|
||||||
|
struct node_tx *tx;
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_req local_sca_req = { };
|
||||||
|
|
||||||
|
struct pdu_data_llctrl_clock_accuracy_rsp remote_sca_rsp = { };
|
||||||
|
|
||||||
|
/* Role */
|
||||||
|
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||||
|
|
||||||
|
/* Connect */
|
||||||
|
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx */
|
||||||
|
lt_tx(LL_CLOCK_ACCURACY_REQ, &conn, &local_sca_req);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Prepare */
|
||||||
|
event_prepare(&conn);
|
||||||
|
|
||||||
|
/* Tx Queue should have one LL Control PDU */
|
||||||
|
lt_rx(LL_CLOCK_ACCURACY_RSP, &conn, &tx, &remote_sca_rsp);
|
||||||
|
lt_rx_q_is_empty(&conn);
|
||||||
|
|
||||||
|
event_tx_ack(&conn, tx);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
event_done(&conn);
|
||||||
|
|
||||||
|
/* Release tx node */
|
||||||
|
ull_cp_release_tx(&conn, tx);
|
||||||
|
|
||||||
|
/* There should not be a host notifications */
|
||||||
|
ut_rx_q_is_empty();
|
||||||
|
|
||||||
|
zassert_equal(ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||||
|
"Free CTX buffers %d", ctx_buffers_free());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_main(void)
|
||||||
|
{
|
||||||
|
ztest_test_suite(sca,
|
||||||
|
ztest_unit_test_setup_teardown(test_sca_central_loc, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_sca_central_loc_invalid_rsp, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_ping_periph_loc, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_sca_peripheral_loc_invalid_rsp, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_ping_central_rem, setup,
|
||||||
|
unit_test_noop),
|
||||||
|
ztest_unit_test_setup_teardown(test_ping_periph_rem, setup,
|
||||||
|
unit_test_noop)
|
||||||
|
);
|
||||||
|
|
||||||
|
ztest_run_test_suite(sca);
|
||||||
|
}
|
5
tests/bluetooth/controller/ctrl_sca_update/testcase.yaml
Normal file
5
tests/bluetooth/controller/ctrl_sca_update/testcase.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
common:
|
||||||
|
tags: test_framework bluetooth bt_sca_update bt_ull_llcp
|
||||||
|
tests:
|
||||||
|
bluetooth.controller.ctrl_sca_update.test:
|
||||||
|
type: unit
|
|
@ -162,6 +162,10 @@
|
||||||
#define CONFIG_BT_CTLR_DF_CTE_RX y
|
#define CONFIG_BT_CTLR_DF_CTE_RX y
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_BT_CTLR_SCA_UPDATE
|
||||||
|
#define CONFIG_BT_CTLR_SCA_UPDATE y
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN
|
#ifndef CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN
|
||||||
#define CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN 38
|
#define CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN 38
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,6 +41,11 @@ int lll_hfclock_off(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t lll_clock_sca_local_get(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t lll_clock_ppm_local_get(void)
|
uint32_t lll_clock_ppm_local_get(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue