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:
Kamil Gawor 2022-01-18 16:39:39 +01:00 committed by Carles Cufí
commit 5db0302c99
12 changed files with 810 additions and 112 deletions

View file

@ -1045,6 +1045,15 @@ struct bt_hci_cp_le_rx_test {
uint8_t rx_ch;
} __packed;
#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00
#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01
#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02
#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03
#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04
#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05
#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06
#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07
#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e)
struct bt_hci_cp_le_tx_test {
uint8_t tx_ch;
@ -1231,6 +1240,10 @@ struct bt_hci_cp_le_set_phy {
#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00
#define BT_HCI_LE_MOD_INDEX_STABLE 0x01
#define BT_HCI_LE_RX_PHY_1M 0x01
#define BT_HCI_LE_RX_PHY_2M 0x02
#define BT_HCI_LE_RX_PHY_CODED 0x03
#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033)
struct bt_hci_cp_le_enh_rx_test {
uint8_t rx_ch;
@ -1238,7 +1251,8 @@ struct bt_hci_cp_le_enh_rx_test {
uint8_t mod_index;
} __packed;
/* Extends BT_HCI_LE_PHY */
#define BT_HCI_LE_TX_PHY_1M 0x01
#define BT_HCI_LE_TX_PHY_2M 0x02
#define BT_HCI_LE_TX_PHY_CODED_S8 0x03
#define BT_HCI_LE_TX_PHY_CODED_S2 0x04
@ -1518,6 +1532,36 @@ struct bt_hci_cp_le_set_privacy_mode {
uint8_t mode;
} __packed;
#define BT_HCI_LE_TEST_CTE_DISABLED 0x00
#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00
#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00
#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00
#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f)
struct bt_hci_cp_le_rx_test_v3 {
uint8_t rx_ch;
uint8_t phy;
uint8_t mod_index;
uint8_t expected_cte_len;
uint8_t expected_cte_type;
uint8_t slot_durations;
uint8_t switch_pattern_len;
uint8_t ant_ids[0];
} __packed;
#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050)
struct bt_hci_cp_le_tx_test_v3 {
uint8_t tx_ch;
uint8_t test_data_len;
uint8_t pkt_payload;
uint8_t phy;
uint8_t cte_len;
uint8_t cte_type;
uint8_t switch_pattern_len;
uint8_t ant_ids[0];
} __packed;
/* Min and max Constant Tone Extension length in 8us units */
#define BT_HCI_LE_CTE_LEN_MIN 0x2
#define BT_HCI_LE_CTE_LEN_MAX 0x14
@ -2019,6 +2063,33 @@ struct bt_hci_rp_le_read_iso_link_quality {
uint32_t duplicate_packets;
} __packed;
#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B)
struct bt_hci_cp_le_tx_test_v4 {
uint8_t tx_ch;
uint8_t test_data_len;
uint8_t pkt_payload;
uint8_t phy;
uint8_t cte_len;
uint8_t cte_type;
uint8_t switch_pattern_len;
uint8_t ant_ids[0];
} __packed;
#define BT_HCI_TX_TEST_POWER_MIN -0x7F
#define BT_HCI_TX_TEST_POWER_MAX 0x14
#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E
#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F
/* Helper structure for Tx power parameter in the HCI Tx Test v4 command.
* Previous parameter of this command is variable size so having separated structure
* for this parameter helps in command parameters unpacking.
*/
struct bt_hci_cp_le_tx_test_v4_tx_power {
int8_t tx_power;
} __packed;
/* Event definitions */
#define BT_HCI_EVT_UNKNOWN 0x00

View file

@ -67,9 +67,6 @@ config BT_CTLR_CHAN_SEL_2_SUPPORT
config BT_CTLR_MIN_USED_CHAN_SUPPORT
bool
config BT_CTLR_DTM_HCI_SUPPORT
bool
config BT_CTLR_SMI_SUPPORT
bool
@ -747,18 +744,6 @@ config BT_CTLR_READ_ISO_LINK_QUALITY
help
Enable support for LE Read ISO Link Quality command.
config BT_CTLR_DTM
bool
help
Enable support for Direct Test Mode in the Controller.
config BT_CTLR_DTM_HCI
bool "Direct Test Mode over HCI"
depends on BT_CTLR_DTM_HCI_SUPPORT
select BT_CTLR_DTM
help
Enable support for Direct Test Mode over the HCI transport.
config BT_CTLR_SMI_RX
bool "Stable modulation index - Receiver"
depends on BT_CTLR_SMI_SUPPORT
@ -785,6 +770,7 @@ config BT_CTLR_HCI_CODEC_AND_DELAY_INFO
rsource "Kconfig.df"
rsource "Kconfig.ll_sw_split"
rsource "Kconfig.dtm"
config BT_CTLR_ASSERT_HANDLER
bool "Application Defined Assertion Handler"

View file

@ -0,0 +1,61 @@
# Zephyr Bluetooth Controller configuration options
# Copyright (c) 2022 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config BT_CTLR_DTM_HCI_SUPPORT
bool
config BT_CTLR_DTM
bool
help
Enable support for Direct Test Mode in the Controller.
menuconfig BT_CTLR_DTM_HCI
bool "Direct Test Mode over HCI"
depends on BT_CTLR_DTM_HCI_SUPPORT
select BT_CTLR_DTM
help
Enable support for Direct Test Mode over the HCI transport.
if BT_CTLR_DTM_HCI
config BT_CTLR_DTM_HCI_RX_V3
bool "HCI LE Receiver Test v3"
default y
help
Enable support for the DTM Receiver test command v3.
config BT_CTLR_DTM_HCI_TX_V3
bool "HCI LE Transmitter Test v3"
default y
help
Enable support for the DTM Transmitter test command v3.
config BT_CTLR_DTM_HCI_TX_V4
bool "HCI LE Transmitter Test v4"
default y
help
Enable support for the DTM Transmitter test command v4.
menuconfig BT_CTLR_DTM_HCI_DF_IQ_REPORT
bool "Connectionless IQ report HCI event [EXPERIMENTAL]"
depends on BT_CTLR_DF_CTE_RX && BT_CTLR_DTM_HCI_RX_V3
select EXPERIMENTAL
help
Enable generation of the HCI LE Connectionless IQ Report event
after the Constant Tone Extension reception.
if BT_CTLR_DTM_HCI_DF_IQ_REPORT
config BT_CTLR_DTM_HCI_DF_IQ_REPORT_NUM_MAX
int "IQ Report pool size"
default 32
help
Maximum number of the DTM IQ Reports in pool. It depends on the upper tester
test packets transmission interval.
endif # BT_CTLR_DTM_HCI_DF_IQ_REPORT
endif # BT_CTLR_DTM_HCI

View file

@ -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);

View file

@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
uint32_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy);
uint32_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx);
uint32_t ll_test_end(uint16_t *num_rx);
uint8_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy,
uint8_t cte_len, uint8_t cte_type, uint8_t switch_pattern_len,
const uint8_t *ant_id, int8_t tx_power);
uint8_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx, uint8_t expected_cte_len,
uint8_t expected_cte_type, uint8_t slot_duration, uint8_t switch_pattern_len,
const uint8_t *ant_ids);
uint8_t ll_test_end(uint16_t *num_rx);

View file

@ -303,6 +303,7 @@ enum node_rx_type {
NODE_RX_TYPE_MESH_REPORT,
NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT,
NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT,
NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT,
#if defined(CONFIG_BT_CTLR_USER_EXT)
/* No entries shall be added after the NODE_RX_TYPE_USER_START/END */

View file

@ -15,8 +15,11 @@
#include "hal/cntr.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/radio_df.h"
#include "util/memq.h"
#include "util/util.h"
#include "util/dbuf.h"
#include "pdu.h"
@ -24,8 +27,18 @@
#include "lll_clock.h"
#include "lll_internal.h"
#if defined(CONFIG_BT_CTLR_DF)
#include "lll_df_types.h"
#include "lll_df.h"
#endif /* CONFIG_BT_CTLR_DF */
#include "ll_test.h"
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
#include "ull_df_types.h"
#include "ull_df_internal.h"
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
#define LOG_MODULE_NAME bt_ctlr_lll_test
#include "common/log.h"
@ -33,9 +46,31 @@
#define CNTR_MIN_DELTA 3
/* Helper definitions for repeated payload sequence */
#define PAYLOAD_11110000 0x0f
#define PAYLOAD_10101010 0x55
#define PAYLOAD_11111111 0xff
#define PAYLOAD_00000000 0x00
#define PAYLOAD_00001111 0xf0
#define PAYLOAD_01010101 0xaa
static const uint32_t test_sync_word = 0x71764129;
static uint8_t test_phy;
static uint8_t test_phy_flags;
#if defined(CONFIG_BT_CTLR_DF_CTE_RX)
static uint8_t test_cte_type;
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
#if defined(CONFIG_BT_CTLR_DF_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CTE_RX)
static uint8_t test_cte_len;
#endif /* CONFIG_BT_CTLR_DF_CTE_TX || CONFIG_BT_CTLR_DF_CTE_RX */
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
static uint8_t test_chan;
static uint8_t test_slot_duration;
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
static uint16_t test_num_rx;
static bool started;
@ -85,6 +120,54 @@ static const uint8_t prbs15[255] = { 0x00, };
static uint8_t tx_req;
static uint8_t volatile tx_ack;
#if defined(CONFIG_BT_CTLR_DF_CTE_RX)
static bool check_rx_cte(bool cte_ready);
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
static int create_iq_report(bool crc_ok)
{
struct node_rx_iq_report *iq_report;
struct node_rx_ftr *ftr;
uint8_t sample_cnt;
uint8_t cte_info;
uint8_t ant;
sample_cnt = radio_df_iq_samples_amount_get();
/* If there are no samples available, the CTEInfo was
* not detected and sampling was not started.
*/
if (!sample_cnt) {
return -EINVAL;
}
cte_info = radio_df_cte_status_get();
ant = radio_df_pdu_antenna_switch_pattern_get();
iq_report = ull_df_iq_report_alloc();
if (!iq_report) {
return -ENOBUFS;
}
iq_report->hdr.type = NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT;
iq_report->sample_count = sample_cnt;
iq_report->packet_status = ((crc_ok) ? BT_HCI_LE_CTE_CRC_OK :
BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME);
iq_report->rssi_ant_id = ant;
iq_report->cte_info = *(struct pdu_cte_info *)&cte_info;
iq_report->local_slot_durations = test_slot_duration;
iq_report->chan_idx = test_chan;
ftr = &iq_report->hdr.rx_ftr;
ftr->param = NULL;
ftr->rssi = BT_HCI_LE_RSSI_NOT_AVAILABLE;
ull_rx_put(iq_report->hdr.link, iq_report);
return 0;
}
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
static void isr_tx(void *param)
{
uint32_t l, i, s, t;
@ -106,7 +189,14 @@ static void isr_tx(void *param)
/* LE Test Packet Interval */
l = radio_tmr_end_get() - radio_tmr_ready_get();
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
i = ceiling_fraction((l + CTE_LEN_US(test_cte_len) + 249), SCAN_INT_UNIT_US) *
SCAN_INT_UNIT_US;
#else
i = ceiling_fraction((l + 249), SCAN_INT_UNIT_US) * SCAN_INT_UNIT_US;
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
t = radio_tmr_end_get() - l + i;
t -= radio_tx_ready_delay_get(test_phy, test_phy_flags);
@ -138,10 +228,22 @@ static void isr_rx(void *param)
uint8_t crc_ok = 0U;
uint8_t trx_done;
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
struct node_rx_iq_report *node_rx;
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
bool cte_ready;
bool cte_ok = 0;
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
/* Read radio status and events */
trx_done = radio_is_done();
if (trx_done) {
crc_ok = radio_crc_is_valid();
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
cte_ready = radio_df_cte_ready();
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
}
/* Clear radio status and events */
@ -153,18 +255,235 @@ static void isr_rx(void *param)
return;
}
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
/* Get free iq report node for next Rx operation. */
node_rx = ull_df_iq_report_alloc_peek(1);
LL_ASSERT(node_rx);
radio_df_iq_data_packet_set(node_rx->pdu, IQ_SAMPLE_TOTAL_CNT);
/* Setup next Rx */
radio_switch_complete_and_rx(test_phy);
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
/* Count Rx-ed packets */
if (crc_ok) {
test_num_rx++;
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
if (test_cte_len > 0) {
cte_ok = check_rx_cte(cte_ready);
if (cte_ok) {
test_num_rx++;
}
} else
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
{
test_num_rx++;
}
}
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
if (cte_ok) {
int err;
err = create_iq_report(crc_ok);
if (!err) {
ull_rx_sched();
}
}
#endif
}
static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *))
static uint8_t tx_power_check(int8_t tx_power)
{
if ((tx_power != BT_HCI_TX_TEST_POWER_MIN_SET) &&
(tx_power != BT_HCI_TX_TEST_POWER_MAX_SET) &&
((tx_power < BT_HCI_TX_TEST_POWER_MIN) || (tx_power > BT_HCI_TX_TEST_POWER_MAX))) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
return BT_HCI_ERR_SUCCESS;
}
static uint8_t tx_power_set(int8_t tx_power)
{
uint8_t err;
err = tx_power_check(tx_power);
if (err) {
return err;
}
if (tx_power == BT_HCI_TX_TEST_POWER_MAX_SET) {
tx_power = radio_tx_power_max_get();
} else if (tx_power == BT_HCI_TX_TEST_POWER_MIN_SET) {
tx_power = radio_tx_power_min_get();
} else {
tx_power = radio_tx_power_floor(tx_power);
}
radio_tx_power_set(tx_power);
return err;
}
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
static uint8_t cte_tx_parameters_check(uint8_t cte_len, uint8_t cte_type,
uint8_t switch_pattern_len)
{
if ((cte_type > BT_HCI_LE_AOD_CTE_2US) ||
(cte_len < BT_HCI_LE_CTE_LEN_MIN) ||
(cte_len > BT_HCI_LE_CTE_LEN_MAX)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
if (cte_type != BT_HCI_LE_AOA_CTE) {
if ((switch_pattern_len < BT_HCI_LE_SWITCH_PATTERN_LEN_MIN) ||
(switch_pattern_len > BT_HCI_LE_SWITCH_PATTERN_LEN_MAX)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
}
if ((cte_type == BT_HCI_LE_AOD_CTE_1US) &&
!IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_1US)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
return BT_HCI_ERR_SUCCESS;
}
static uint8_t cte_tx_init(uint8_t cte_len, uint8_t cte_type, uint8_t switch_pattern_len,
const uint8_t *ant_id)
{
uint8_t err;
err = cte_tx_parameters_check(cte_len, cte_type, switch_pattern_len);
if (err) {
return err;
}
if (cte_type == BT_HCI_LE_AOA_CTE) {
radio_df_mode_set_aoa();
radio_df_cte_tx_aoa_set(cte_len);
} else {
#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX)
radio_df_mode_set_aod();
if (cte_type == BT_HCI_LE_AOD_CTE_1US) {
radio_df_cte_tx_aod_2us_set(cte_len);
} else {
radio_df_cte_tx_aod_4us_set(cte_len);
}
radio_df_ant_switching_pin_sel_cfg();
radio_df_ant_switch_pattern_clear();
radio_df_ant_switch_pattern_set(ant_id, switch_pattern_len);
#else
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_TX */
}
return err;
}
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
#if defined(CONFIG_BT_CTLR_DF_CTE_RX)
static uint8_t cte_rx_parameters_check(uint8_t expected_cte_len, uint8_t expected_cte_type,
uint8_t slot_duration, uint8_t switch_pattern_len)
{
if ((expected_cte_type > BT_HCI_LE_AOD_CTE_2US) ||
(expected_cte_len < BT_HCI_LE_CTE_LEN_MIN) ||
(expected_cte_len > BT_HCI_LE_CTE_LEN_MAX)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
if (expected_cte_type == BT_HCI_LE_AOA_CTE) {
if ((switch_pattern_len < BT_HCI_LE_SWITCH_PATTERN_LEN_MIN) ||
(switch_pattern_len > BT_HCI_LE_SWITCH_PATTERN_LEN_MAX)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
if ((slot_duration == 0) ||
(slot_duration > BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
}
if ((slot_duration == BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US) &&
(!IS_ENABLED(CONFIG_BT_CTLR_DF_CTE_RX_SAMPLE_1US))) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
return BT_HCI_ERR_SUCCESS;
}
static uint8_t cte_rx_init(uint8_t expected_cte_len, uint8_t expected_cte_type,
uint8_t slot_duration, uint8_t switch_pattern_len,
const uint8_t *ant_ids, uint8_t phy)
{
uint8_t err;
uint8_t cte_phy = (phy == BT_HCI_LE_RX_PHY_1M) ? PHY_1M : PHY_2M;
err = cte_rx_parameters_check(expected_cte_len, expected_cte_type,
slot_duration, switch_pattern_len);
if (err) {
return err;
}
if (slot_duration == BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US) {
#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_1US)
radio_df_cte_rx_2us_switching(true, cte_phy);
#else
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_1US */
} else {
radio_df_cte_rx_4us_switching(true, cte_phy);
}
#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX)
radio_df_ant_switching_pin_sel_cfg();
radio_df_ant_switch_pattern_clear();
radio_df_ant_switch_pattern_set(ant_ids, switch_pattern_len);
#else
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_RX */
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
struct node_rx_iq_report *node_rx;
node_rx = ull_df_iq_report_alloc_peek(1);
LL_ASSERT(node_rx);
radio_df_iq_data_packet_set(node_rx->pdu, IQ_SAMPLE_TOTAL_CNT);
#else
radio_df_iq_data_packet_set(NULL, 0);
#endif
return err;
}
static bool check_rx_cte(bool cte_ready)
{
uint8_t cte_status;
struct pdu_cte_info *cte_info;
cte_status = radio_df_cte_status_get();
cte_info = (struct pdu_cte_info *)&cte_status;
if ((cte_info->type != test_cte_type) || (cte_info->time != test_cte_len)) {
return false;
}
return true;
}
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
static uint8_t init(uint8_t chan, uint8_t phy, int8_t tx_power,
bool cte, void (*isr)(void *))
{
int err;
uint8_t ret;
if (started) {
return BT_HCI_ERR_CMD_DISALLOWED;
@ -175,13 +494,19 @@ static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *))
/* Setup resources required by Radio */
err = lll_hfclock_on_wait();
LL_ASSERT(err >= 0);
/* Reset Radio h/w */
radio_reset();
radio_isr_set(isr, NULL);
#if defined(CONFIG_BT_CTLR_DF)
/* Reset Radio DF */
radio_df_reset();
#endif
/* Store value needed in Tx/Rx ISR */
if (phy < 0x04) {
if (phy < BT_HCI_LE_TX_PHY_CODED_S2) {
test_phy = BIT(phy - 1);
test_phy_flags = 1U;
} else {
@ -193,74 +518,119 @@ static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *))
/* NOTE: No whitening in test mode. */
radio_phy_set(test_phy, test_phy_flags);
radio_tmr_tifs_set(150);
radio_tx_power_max_set();
ret = tx_power_set(tx_power);
radio_freq_chan_set((chan << 1) + 2);
radio_aa_set((uint8_t *)&test_sync_word);
radio_crc_configure(0x65b, PDU_AC_CRC_IV);
radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, 255, RADIO_PKT_CONF_PHY(test_phy));
radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, PDU_DTM_PAYLOAD_SIZE_MAX,
RADIO_PKT_CONF_PHY(test_phy) |
RADIO_PKT_CONF_PDU_TYPE(IS_ENABLED(CONFIG_BT_CTLR_DF_CTE_TX) ?
RADIO_PKT_CONF_PDU_TYPE_DC :
RADIO_PKT_CONF_PDU_TYPE_AC) |
RADIO_PKT_CONF_CTE(cte ? RADIO_PKT_CONF_CTE_ENABLED :
RADIO_PKT_CONF_CTE_DISABLED));
return 0;
return ret;
}
uint32_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy)
static void payload_set(uint8_t type, uint8_t len, uint8_t cte_len, uint8_t cte_type)
{
struct pdu_dtm *pdu = radio_pkt_scratch_get();
pdu->type = type;
pdu->length = len;
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
pdu->cp = cte_len ? 1U : 0U;
pdu->cte_info.time = cte_len;
pdu->cte_info.type = cte_type;
#else
ARG_UNUSED(cte_len);
ARG_UNUSED(cte_type);
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
switch (type) {
case BT_HCI_TEST_PKT_PAYLOAD_PRBS9:
(void)memcpy(pdu->payload, prbs9, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_11110000:
(void)memset(pdu->payload, PAYLOAD_11110000, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_10101010:
(void)memset(pdu->payload, PAYLOAD_10101010, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_PRBS15:
(void)memcpy(pdu->payload, prbs15, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_11111111:
(void)memset(pdu->payload, PAYLOAD_11111111, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_00000000:
(void)memset(pdu->payload, PAYLOAD_00000000, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_00001111:
(void)memset(pdu->payload, PAYLOAD_00001111, len);
break;
case BT_HCI_TEST_PKT_PAYLOAD_01010101:
(void)memset(pdu->payload, PAYLOAD_01010101, len);
break;
}
radio_pkt_tx_set(pdu);
}
uint8_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy,
uint8_t cte_len, uint8_t cte_type, uint8_t switch_pattern_len,
const uint8_t *ant_id, int8_t tx_power)
{
uint32_t start_us;
uint8_t *payload;
uint8_t *pdu;
uint32_t err;
uint8_t err;
const bool cte_request = (cte_len > 0) ? true : false;
if ((type > 0x07) || !phy || (phy > 0x04)) {
if ((type > BT_HCI_TEST_PKT_PAYLOAD_01010101) || !phy ||
(phy > BT_HCI_LE_TX_PHY_CODED_S2)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
err = init(chan, phy, isr_tx);
err = init(chan, phy, tx_power, cte_request, isr_tx);
if (err) {
return err;
}
tx_req++;
/* Configure Constant Tone Extension */
if (cte_request) {
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
if (phy > BT_HCI_LE_TX_PHY_2M) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
pdu = radio_pkt_scratch_get();
payload = &pdu[2];
switch (type) {
case 0x00:
memcpy(payload, prbs9, len);
break;
case 0x01:
memset(payload, 0x0f, len);
break;
case 0x02:
memset(payload, 0x55, len);
break;
case 0x03:
memcpy(payload, prbs15, len);
break;
case 0x04:
memset(payload, 0xff, len);
break;
case 0x05:
memset(payload, 0x00, len);
break;
case 0x06:
memset(payload, 0xf0, len);
break;
case 0x07:
memset(payload, 0xaa, len);
break;
err = cte_tx_init(cte_len, cte_type, switch_pattern_len, ant_id);
if (err) {
return err;
}
#else
return BT_HCI_ERR_CMD_DISALLOWED;
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
}
pdu[0] = type;
pdu[1] = len;
tx_req++;
payload_set(type, len, cte_len, cte_type);
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
/* Store CTE parameters needed in Tx ISR */
test_cte_len = cte_len;
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
radio_pkt_tx_set(pdu);
radio_switch_complete_and_disable();
start_us = radio_tmr_start(1, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
radio_tmr_aa_capture();
@ -278,22 +648,52 @@ uint32_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy)
started = true;
return 0;
return BT_HCI_ERR_SUCCESS;
}
uint32_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx)
uint8_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx, uint8_t expected_cte_len,
uint8_t expected_cte_type, uint8_t slot_duration, uint8_t switch_pattern_len,
const uint8_t *ant_ids)
{
uint32_t err;
uint8_t err;
const bool cte_expected = (expected_cte_len > 0) ? true : false;
if (!phy || (phy > 0x03)) {
if (!phy || (phy > BT_HCI_LE_RX_PHY_CODED)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
err = init(chan, phy, isr_rx);
err = init(chan, phy, BT_HCI_TX_TEST_POWER_MAX_SET, cte_expected, isr_rx);
if (err) {
return err;
}
if (cte_expected) {
#if defined(CONFIG_BT_CTLR_DF_CTE_RX)
if (phy == BT_HCI_LE_RX_PHY_CODED) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
err = cte_rx_init(expected_cte_len, expected_cte_type, slot_duration,
switch_pattern_len, ant_ids, phy);
if (err) {
return err;
}
#else
return BT_HCI_ERR_CMD_DISALLOWED;
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
}
#if defined(CONFIG_BT_CTLR_DF_CTE_RX)
/* Store CTE parameters needed in Rx ISR */
test_cte_type = expected_cte_type;
test_cte_len = expected_cte_len;
#endif /* CONFIG_BT_CTLR_DF_CTE_RX */
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
test_chan = chan;
test_slot_duration = slot_duration;
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
radio_pkt_rx_set(radio_pkt_scratch_get());
radio_switch_complete_and_rx(test_phy);
radio_tmr_start(0, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
@ -304,10 +704,10 @@ uint32_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx)
started = true;
return 0;
return BT_HCI_ERR_SUCCESS;
}
uint32_t ll_test_end(uint16_t *num_rx)
uint8_t ll_test_end(uint16_t *num_rx)
{
int err;
uint8_t ack;
@ -348,5 +748,5 @@ uint32_t ll_test_end(uint16_t *num_rx)
started = false;
return 0;
return BT_HCI_ERR_SUCCESS;
}

View file

@ -1044,3 +1044,38 @@ struct pdu_big_info {
#define PDU_BIG_INFO_ENCRYPTED_SIZE sizeof(struct pdu_big_info)
#define PDU_BIG_BN_MAX 0x07
#define PDU_BIG_PAYLOAD_COUNT_MAX 28
struct pdu_dtm {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t type:4;
uint8_t rfu0:1;
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
uint8_t cp:1;
uint8_t rfu1:2;
#else
uint8_t rfu1:3;
#endif
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
uint8_t rfu1:2;
uint8_t cp:1;
#else
uint8_t rfu1:3;
#endif
uint8_t rfu0:1;
uint8_t type:4;
#else
#error "Unsupported endianness"
#endif
uint8_t length;
#if defined(CONFIG_BT_CTLR_DF_CTE_TX)
union {
uint8_t resv; /* TODO: remove nRF specific code */
struct pdu_cte_info cte_info; /* BT 5.1 Core spec. CTEInfo storage */
};
#endif
uint8_t payload[0];
} __packed;
/* Direct Test Mode maximum payload size */
#define PDU_DTM_PAYLOAD_SIZE_MAX 255

View file

@ -1232,6 +1232,10 @@ void ll_rx_dequeue(void)
case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT:
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
#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 */
/* Ensure that at least one 'case' statement is present for this
* code block.
*/
@ -1511,9 +1515,11 @@ void ll_rx_mem_release(void **node_rx)
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT:
case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT:
case NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT:
{
const uint8_t report_cnt = 1U;
@ -2519,9 +2525,11 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx)
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT:
case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT:
case NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT:
{
(void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL);
ll_rx_put(link, rx);

View file

@ -53,7 +53,8 @@
#include "common/log.h"
#include "hal/debug.h"
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
#define CTE_LEN_MAX_US 160U
@ -168,7 +169,8 @@ static int init_reset(void)
&df_adv_cfg_free);
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
/* Re-initialize the free IQ report mfifo */
MFIFO_INIT(iq_report_free);
@ -499,7 +501,8 @@ bool ull_df_sync_cfg_is_not_enabled(struct lll_df_sync *df_cfg)
}
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) || \
defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
void *ull_df_iq_report_alloc_peek(uint8_t count)
{
if (count > MFIFO_AVAIL_COUNT_GET(iq_report_free)) {

View file

@ -39,4 +39,10 @@ enum df_switch_sample_support {
#define CONN_IQ_REPORT_CNT 0U
#endif
#define IQ_REPORT_CNT (SYNC_IQ_REPORT_CNT + CONN_IQ_REPORT_CNT)
#if defined(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)
#define DTM_IQ_REPORT_CNT CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT_NUM_MAX
#else
#define DTM_IQ_REPORT_CNT 0U
#endif
#define IQ_REPORT_CNT (SYNC_IQ_REPORT_CNT + CONN_IQ_REPORT_CNT + DTM_IQ_REPORT_CNT)

View file

@ -58,7 +58,7 @@ int cmd_ll_addr_read(const struct shell *sh, size_t argc, char *argv[])
int cmd_test_tx(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t chan, len, type, phy;
uint32_t err;
uint8_t err;
if (argc < 5) {
return -EINVAL;
@ -69,7 +69,9 @@ int cmd_test_tx(const struct shell *sh, size_t argc, char *argv[])
type = strtoul(argv[3], NULL, 16);
phy = strtoul(argv[4], NULL, 16);
err = ll_test_tx(chan, len, type, phy);
err = ll_test_tx(chan, len, type, 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);
if (err) {
return -EINVAL;
}
@ -82,7 +84,7 @@ int cmd_test_tx(const struct shell *sh, size_t argc, char *argv[])
int cmd_test_rx(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t chan, phy, mod_idx;
uint32_t err;
uint8_t err;
if (argc < 4) {
return -EINVAL;
@ -92,7 +94,9 @@ int cmd_test_rx(const struct shell *sh, size_t argc, char *argv[])
phy = strtoul(argv[2], NULL, 16);
mod_idx = strtoul(argv[3], NULL, 16);
err = ll_test_rx(chan, phy, mod_idx);
err = ll_test_rx(chan, phy, mod_idx, 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);
if (err) {
return -EINVAL;
}
@ -105,7 +109,7 @@ int cmd_test_rx(const struct shell *sh, size_t argc, char *argv[])
int cmd_test_end(const struct shell *sh, size_t argc, char *argv[])
{
uint16_t num_rx;
uint32_t err;
uint8_t err;
err = ll_test_end(&num_rx);
if (err) {