bluetooth: controller: Add support for all DTM commands
This adds support for the following Direct Test mode commands: - HCI LE Receiver Test [v3] - HCI LE Transmitter Test [v3] - HCI LE Transmitter Test [v4] Those commands set add a possibility to test an CTE reception and transmission. The HCI LE Transmitter Test [v4] commands allows also setting a transmit power. Signed-off-by: Kamil Gawor <Kamil.Gawor@nordicsemi.no>
This commit is contained in:
parent
a5364567ec
commit
5db0302c99
12 changed files with 810 additions and 112 deletions
|
@ -891,6 +891,17 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
|
|||
rp->commands[35] |= BIT(7);
|
||||
/* LE Enhanced TX Test. */
|
||||
rp->commands[36] |= BIT(0);
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_RX_V3)
|
||||
rp->commands[39] |= BIT(3);
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_RX_V3 */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V3)
|
||||
rp->commands[39] |= BIT(4);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V4)
|
||||
rp->commands[45] |= BIT(0);
|
||||
#endif
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
||||
|
@ -2797,17 +2808,23 @@ static void le_df_set_cl_iq_sampling_enable(struct net_buf *buf, struct net_buf
|
|||
rp->status = status;
|
||||
rp->sync_handle = sys_cpu_to_le16(sync_handle);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
|
||||
static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx,
|
||||
struct node_rx_pdu *node_rx,
|
||||
struct net_buf *buf)
|
||||
{
|
||||
struct bt_hci_evt_le_connectionless_iq_report *sep;
|
||||
struct node_rx_iq_report *iq_report;
|
||||
struct ll_sync_set *sync;
|
||||
struct lll_sync *lll;
|
||||
uint8_t samples_cnt;
|
||||
int16_t rssi;
|
||||
uint16_t sync_handle;
|
||||
uint16_t per_evt_counter;
|
||||
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
|
||||
struct ll_sync_set *sync = NULL;
|
||||
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
||||
|
||||
iq_report = (struct node_rx_iq_report *)node_rx;
|
||||
|
||||
|
@ -2817,19 +2834,43 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx,
|
|||
}
|
||||
|
||||
lll = iq_report->hdr.rx_ftr.param;
|
||||
sync = HDR_LLL2ULL(lll);
|
||||
|
||||
/* TX LL thread has higher priority than RX thread. It may happen that
|
||||
* host successfully disables CTE sampling in the meantime.
|
||||
* It should be verified here, to avoid reporting IQ samples after
|
||||
* the functionality was disabled or if sync was lost.
|
||||
/* If there is not LLL context and CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT is enabled
|
||||
* the controller is in the Direct Test Mode and may generate
|
||||
* the Connectionless IQ Report.
|
||||
*/
|
||||
if (ull_df_sync_cfg_is_not_enabled(&lll->df_cfg) ||
|
||||
!sync->timeout_reload) {
|
||||
/* Drop further processing of the event. */
|
||||
return;
|
||||
if (!lll && IS_ENABLED(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)) {
|
||||
/* Set sync_handle to 0x0FFF according to the BT Core 5.3 specification
|
||||
* Vol 4 7.7.65.21
|
||||
*/
|
||||
sync_handle = 0x0FFF;
|
||||
/* Set periodic event counter to 0 since there is not periodic advertising train. */
|
||||
per_evt_counter = 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
|
||||
else {
|
||||
sync = HDR_LLL2ULL(lll);
|
||||
|
||||
/* TX LL thread has higher priority than RX thread. It may happen that
|
||||
* host successfully disables CTE sampling in the meantime.
|
||||
* It should be verified here, to avoid reporting IQ samples after
|
||||
* the functionality was disabled or if sync was lost.
|
||||
*/
|
||||
if (ull_df_sync_cfg_is_not_enabled(&lll->df_cfg) ||
|
||||
!sync->timeout_reload) {
|
||||
/* Drop further processing of the event. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the sync handle corresponding to the LLL context passed in the
|
||||
* node rx footer field.
|
||||
*/
|
||||
sync_handle = ull_sync_handle_get(sync);
|
||||
per_evt_counter = lll->event_counter;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
||||
|
||||
/* If there are no IQ samples due to insufficient resources
|
||||
* HCI event should inform about it by storing single octet with
|
||||
* special I_sample and Q_sample data.
|
||||
|
@ -2842,16 +2883,14 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx,
|
|||
|
||||
rssi = RSSI_DBM_TO_DECI_DBM(iq_report->hdr.rx_ftr.rssi);
|
||||
|
||||
/* Get the sync handle corresponding to the LLL context passed in the
|
||||
* node rx footer field.
|
||||
*/
|
||||
sep->sync_handle = sys_cpu_to_le16(ull_sync_handle_get(sync));
|
||||
|
||||
sep->sync_handle = sys_cpu_to_le16(sync_handle);
|
||||
sep->rssi = sys_cpu_to_le16(rssi);
|
||||
sep->rssi_ant_id = iq_report->rssi_ant_id;
|
||||
sep->cte_type = iq_report->cte_info.type;
|
||||
|
||||
sep->chan_idx = iq_report->chan_idx;
|
||||
sep->per_evt_counter = sys_cpu_to_le16(lll->event_counter);
|
||||
sep->per_evt_counter = sys_cpu_to_le16(per_evt_counter);
|
||||
|
||||
if (sep->cte_type == BT_HCI_LE_AOA_CTE) {
|
||||
sep->slot_durations = iq_report->local_slot_durations;
|
||||
|
@ -2876,7 +2915,7 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx,
|
|||
sep->sample_count = samples_cnt;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
||||
#endif /* defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT) */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX)
|
||||
static void le_df_set_conn_cte_tx_params(struct net_buf *buf,
|
||||
|
@ -3082,7 +3121,10 @@ static void le_rx_test(struct net_buf *buf, struct net_buf **evt)
|
|||
struct bt_hci_cp_le_rx_test *cmd = (void *)buf->data;
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_rx(cmd->rx_ch, 0x01, 0);
|
||||
status = ll_test_rx(cmd->rx_ch, BT_HCI_LE_RX_PHY_1M, BT_HCI_LE_MOD_INDEX_STANDARD,
|
||||
BT_HCI_LE_TEST_CTE_DISABLED, BT_HCI_LE_TEST_CTE_TYPE_ANY,
|
||||
BT_HCI_LE_TEST_SLOT_DURATION_ANY, BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY,
|
||||
NULL);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
|
@ -3093,7 +3135,9 @@ static void le_tx_test(struct net_buf *buf, struct net_buf **evt)
|
|||
uint8_t status;
|
||||
|
||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload,
|
||||
0x01);
|
||||
BT_HCI_LE_TX_PHY_1M, BT_HCI_LE_TEST_CTE_DISABLED,
|
||||
BT_HCI_LE_TEST_CTE_TYPE_ANY, BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY,
|
||||
NULL, BT_HCI_TX_TEST_POWER_MAX_SET);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
|
@ -3102,11 +3146,12 @@ static void le_test_end(struct net_buf *buf, struct net_buf **evt)
|
|||
{
|
||||
struct bt_hci_rp_le_test_end *rp;
|
||||
uint16_t rx_pkt_count;
|
||||
uint8_t status;
|
||||
|
||||
ll_test_end(&rx_pkt_count);
|
||||
status = ll_test_end(&rx_pkt_count);
|
||||
|
||||
rp = hci_cmd_complete(evt, sizeof(*rp));
|
||||
rp->status = 0x00;
|
||||
rp->status = status;
|
||||
rp->rx_pkt_count = sys_cpu_to_le16(rx_pkt_count);
|
||||
}
|
||||
|
||||
|
@ -3115,21 +3160,69 @@ static void le_enh_rx_test(struct net_buf *buf, struct net_buf **evt)
|
|||
struct bt_hci_cp_le_enh_rx_test *cmd = (void *)buf->data;
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_rx(cmd->rx_ch, cmd->phy, cmd->mod_index);
|
||||
status = ll_test_rx(cmd->rx_ch, cmd->phy, cmd->mod_index, BT_HCI_LE_TEST_CTE_DISABLED,
|
||||
BT_HCI_LE_TEST_CTE_TYPE_ANY, BT_HCI_LE_TEST_SLOT_DURATION_ANY,
|
||||
BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY, NULL);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_RX_V3)
|
||||
static void le_rx_test_v3(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_le_rx_test_v3 *cmd = (void *)buf->data;
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_rx(cmd->rx_ch, cmd->phy, cmd->mod_index, cmd->expected_cte_len,
|
||||
cmd->expected_cte_type, cmd->slot_durations, cmd->switch_pattern_len,
|
||||
cmd->ant_ids);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_RX_V3 */
|
||||
|
||||
static void le_enh_tx_test(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_le_enh_tx_test *cmd = (void *)buf->data;
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload,
|
||||
cmd->phy);
|
||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, cmd->phy,
|
||||
BT_HCI_LE_TEST_CTE_DISABLED, BT_HCI_LE_TEST_CTE_TYPE_ANY,
|
||||
BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY, NULL,
|
||||
BT_HCI_TX_TEST_POWER_MAX_SET);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V3)
|
||||
static void le_tx_test_v3(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_le_tx_test_v3 *cmd = (void *)buf->data;
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, cmd->phy,
|
||||
cmd->cte_len, cmd->cte_type, cmd->switch_pattern_len, cmd->ant_ids,
|
||||
BT_HCI_TX_TEST_POWER_MAX_SET);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_TX_V3 */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V4)
|
||||
static void le_tx_test_v4(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_le_tx_test_v4 *cmd = (void *)buf->data;
|
||||
struct bt_hci_cp_le_tx_test_v4_tx_power *tx_power = (void *)(buf->data +
|
||||
sizeof(struct bt_hci_cp_le_tx_test_v4) + cmd->switch_pattern_len);
|
||||
uint8_t status;
|
||||
|
||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, cmd->phy,
|
||||
cmd->cte_len, cmd->cte_type, cmd->switch_pattern_len, cmd->ant_ids,
|
||||
tx_power->tx_power);
|
||||
|
||||
*evt = cmd_complete_status(status);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_TX_V4 */
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
|
@ -4429,9 +4522,24 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd,
|
|||
case BT_OCF(BT_HCI_OP_LE_ENH_RX_TEST):
|
||||
le_enh_rx_test(cmd, evt);
|
||||
break;
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_RX_V3)
|
||||
case BT_OCF(BT_HCI_OP_LE_RX_TEST_V3):
|
||||
le_rx_test_v3(cmd, evt);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_RX_V3 */
|
||||
case BT_OCF(BT_HCI_OP_LE_ENH_TX_TEST):
|
||||
le_enh_tx_test(cmd, evt);
|
||||
break;
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V3)
|
||||
case BT_OCF(BT_HCI_OP_LE_TX_TEST_V3):
|
||||
le_tx_test_v3(cmd, evt);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_TX_V3 */
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_TX_V4)
|
||||
case BT_OCF(BT_HCI_OP_LE_TX_TEST_V4):
|
||||
le_tx_test_v4(cmd, evt);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_TX_V4 */
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||
|
||||
default:
|
||||
|
@ -7487,6 +7595,12 @@ static void encode_control(struct node_rx_pdu *node_rx,
|
|||
return;
|
||||
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
|
||||
case NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT:
|
||||
le_df_connectionless_iq_report(pdu_data, node_rx, buf);
|
||||
return;
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
|
||||
|
||||
#if defined(CONFIG_BT_HCI_MESH_EXT)
|
||||
case NODE_RX_TYPE_MESH_ADV_CPLT:
|
||||
mesh_adv_cplt(pdu_data, node_rx, buf);
|
||||
|
@ -7935,6 +8049,11 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx)
|
|||
return HCI_CLASS_ISO_DATA;
|
||||
#endif /* CONFIG_BT_CTLR_SYNC_ISO || CONFIG_BT_CTLR_CONN_ISO */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
|
||||
case NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT:
|
||||
return HCI_CLASS_EVT_REQUIRED;
|
||||
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
|
||||
|
||||
#if CONFIG_BT_CTLR_USER_EVT_RANGE > 0
|
||||
case NODE_RX_TYPE_USER_START ... NODE_RX_TYPE_USER_END - 1:
|
||||
return hci_user_ext_get_class(node_rx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue