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
|
@ -1045,6 +1045,15 @@ struct bt_hci_cp_le_rx_test {
|
||||||
uint8_t rx_ch;
|
uint8_t rx_ch;
|
||||||
} __packed;
|
} __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)
|
#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e)
|
||||||
struct bt_hci_cp_le_tx_test {
|
struct bt_hci_cp_le_tx_test {
|
||||||
uint8_t tx_ch;
|
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_STANDARD 0x00
|
||||||
#define BT_HCI_LE_MOD_INDEX_STABLE 0x01
|
#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)
|
#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033)
|
||||||
struct bt_hci_cp_le_enh_rx_test {
|
struct bt_hci_cp_le_enh_rx_test {
|
||||||
uint8_t rx_ch;
|
uint8_t rx_ch;
|
||||||
|
@ -1238,7 +1251,8 @@ struct bt_hci_cp_le_enh_rx_test {
|
||||||
uint8_t mod_index;
|
uint8_t mod_index;
|
||||||
} __packed;
|
} __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_S8 0x03
|
||||||
#define BT_HCI_LE_TX_PHY_CODED_S2 0x04
|
#define BT_HCI_LE_TX_PHY_CODED_S2 0x04
|
||||||
|
|
||||||
|
@ -1518,6 +1532,36 @@ struct bt_hci_cp_le_set_privacy_mode {
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
} __packed;
|
} __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 */
|
/* Min and max Constant Tone Extension length in 8us units */
|
||||||
#define BT_HCI_LE_CTE_LEN_MIN 0x2
|
#define BT_HCI_LE_CTE_LEN_MIN 0x2
|
||||||
#define BT_HCI_LE_CTE_LEN_MAX 0x14
|
#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;
|
uint32_t duplicate_packets;
|
||||||
} __packed;
|
} __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 */
|
/* Event definitions */
|
||||||
|
|
||||||
#define BT_HCI_EVT_UNKNOWN 0x00
|
#define BT_HCI_EVT_UNKNOWN 0x00
|
||||||
|
|
|
@ -67,9 +67,6 @@ config BT_CTLR_CHAN_SEL_2_SUPPORT
|
||||||
config BT_CTLR_MIN_USED_CHAN_SUPPORT
|
config BT_CTLR_MIN_USED_CHAN_SUPPORT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config BT_CTLR_DTM_HCI_SUPPORT
|
|
||||||
bool
|
|
||||||
|
|
||||||
config BT_CTLR_SMI_SUPPORT
|
config BT_CTLR_SMI_SUPPORT
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
@ -747,18 +744,6 @@ config BT_CTLR_READ_ISO_LINK_QUALITY
|
||||||
help
|
help
|
||||||
Enable support for LE Read ISO Link Quality command.
|
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
|
config BT_CTLR_SMI_RX
|
||||||
bool "Stable modulation index - Receiver"
|
bool "Stable modulation index - Receiver"
|
||||||
depends on BT_CTLR_SMI_SUPPORT
|
depends on BT_CTLR_SMI_SUPPORT
|
||||||
|
@ -785,6 +770,7 @@ config BT_CTLR_HCI_CODEC_AND_DELAY_INFO
|
||||||
|
|
||||||
rsource "Kconfig.df"
|
rsource "Kconfig.df"
|
||||||
rsource "Kconfig.ll_sw_split"
|
rsource "Kconfig.ll_sw_split"
|
||||||
|
rsource "Kconfig.dtm"
|
||||||
|
|
||||||
config BT_CTLR_ASSERT_HANDLER
|
config BT_CTLR_ASSERT_HANDLER
|
||||||
bool "Application Defined Assertion Handler"
|
bool "Application Defined Assertion Handler"
|
||||||
|
|
61
subsys/bluetooth/controller/Kconfig.dtm
Normal file
61
subsys/bluetooth/controller/Kconfig.dtm
Normal 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
|
|
@ -891,6 +891,17 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
|
||||||
rp->commands[35] |= BIT(7);
|
rp->commands[35] |= BIT(7);
|
||||||
/* LE Enhanced TX Test. */
|
/* LE Enhanced TX Test. */
|
||||||
rp->commands[36] |= BIT(0);
|
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 */
|
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_PRIVACY)
|
#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->status = status;
|
||||||
rp->sync_handle = sys_cpu_to_le16(sync_handle);
|
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,
|
static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx,
|
||||||
struct node_rx_pdu *node_rx,
|
struct node_rx_pdu *node_rx,
|
||||||
struct net_buf *buf)
|
struct net_buf *buf)
|
||||||
{
|
{
|
||||||
struct bt_hci_evt_le_connectionless_iq_report *sep;
|
struct bt_hci_evt_le_connectionless_iq_report *sep;
|
||||||
struct node_rx_iq_report *iq_report;
|
struct node_rx_iq_report *iq_report;
|
||||||
struct ll_sync_set *sync;
|
|
||||||
struct lll_sync *lll;
|
struct lll_sync *lll;
|
||||||
uint8_t samples_cnt;
|
uint8_t samples_cnt;
|
||||||
int16_t rssi;
|
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;
|
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;
|
lll = iq_report->hdr.rx_ftr.param;
|
||||||
sync = HDR_LLL2ULL(lll);
|
|
||||||
|
|
||||||
/* TX LL thread has higher priority than RX thread. It may happen that
|
/* If there is not LLL context and CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT is enabled
|
||||||
* host successfully disables CTE sampling in the meantime.
|
* the controller is in the Direct Test Mode and may generate
|
||||||
* It should be verified here, to avoid reporting IQ samples after
|
* the Connectionless IQ Report.
|
||||||
* the functionality was disabled or if sync was lost.
|
|
||||||
*/
|
*/
|
||||||
if (ull_df_sync_cfg_is_not_enabled(&lll->df_cfg) ||
|
if (!lll && IS_ENABLED(CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT)) {
|
||||||
!sync->timeout_reload) {
|
/* Set sync_handle to 0x0FFF according to the BT Core 5.3 specification
|
||||||
/* Drop further processing of the event. */
|
* Vol 4 7.7.65.21
|
||||||
return;
|
*/
|
||||||
|
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
|
/* If there are no IQ samples due to insufficient resources
|
||||||
* HCI event should inform about it by storing single octet with
|
* HCI event should inform about it by storing single octet with
|
||||||
* special I_sample and Q_sample data.
|
* 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);
|
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(sync_handle);
|
||||||
*/
|
|
||||||
sep->sync_handle = sys_cpu_to_le16(ull_sync_handle_get(sync));
|
|
||||||
sep->rssi = sys_cpu_to_le16(rssi);
|
sep->rssi = sys_cpu_to_le16(rssi);
|
||||||
sep->rssi_ant_id = iq_report->rssi_ant_id;
|
sep->rssi_ant_id = iq_report->rssi_ant_id;
|
||||||
sep->cte_type = iq_report->cte_info.type;
|
sep->cte_type = iq_report->cte_info.type;
|
||||||
|
|
||||||
sep->chan_idx = iq_report->chan_idx;
|
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) {
|
if (sep->cte_type == BT_HCI_LE_AOA_CTE) {
|
||||||
sep->slot_durations = iq_report->local_slot_durations;
|
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;
|
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)
|
#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX)
|
||||||
static void le_df_set_conn_cte_tx_params(struct net_buf *buf,
|
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;
|
struct bt_hci_cp_le_rx_test *cmd = (void *)buf->data;
|
||||||
uint8_t status;
|
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);
|
*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;
|
uint8_t status;
|
||||||
|
|
||||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload,
|
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);
|
*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;
|
struct bt_hci_rp_le_test_end *rp;
|
||||||
uint16_t rx_pkt_count;
|
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 = hci_cmd_complete(evt, sizeof(*rp));
|
||||||
rp->status = 0x00;
|
rp->status = status;
|
||||||
rp->rx_pkt_count = sys_cpu_to_le16(rx_pkt_count);
|
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;
|
struct bt_hci_cp_le_enh_rx_test *cmd = (void *)buf->data;
|
||||||
uint8_t status;
|
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);
|
*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)
|
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;
|
struct bt_hci_cp_le_enh_tx_test *cmd = (void *)buf->data;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload,
|
status = ll_test_tx(cmd->tx_ch, cmd->test_data_len, cmd->pkt_payload, cmd->phy,
|
||||||
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);
|
*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 */
|
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
#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):
|
case BT_OCF(BT_HCI_OP_LE_ENH_RX_TEST):
|
||||||
le_enh_rx_test(cmd, evt);
|
le_enh_rx_test(cmd, evt);
|
||||||
break;
|
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):
|
case BT_OCF(BT_HCI_OP_LE_ENH_TX_TEST):
|
||||||
le_enh_tx_test(cmd, evt);
|
le_enh_tx_test(cmd, evt);
|
||||||
break;
|
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 */
|
#endif /* CONFIG_BT_CTLR_DTM_HCI */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -7487,6 +7595,12 @@ static void encode_control(struct node_rx_pdu *node_rx,
|
||||||
return;
|
return;
|
||||||
#endif /* CONFIG_BT_CTLR_PROFILE_ISR */
|
#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)
|
#if defined(CONFIG_BT_HCI_MESH_EXT)
|
||||||
case NODE_RX_TYPE_MESH_ADV_CPLT:
|
case NODE_RX_TYPE_MESH_ADV_CPLT:
|
||||||
mesh_adv_cplt(pdu_data, node_rx, buf);
|
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;
|
return HCI_CLASS_ISO_DATA;
|
||||||
#endif /* CONFIG_BT_CTLR_SYNC_ISO || CONFIG_BT_CTLR_CONN_ISO */
|
#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
|
#if CONFIG_BT_CTLR_USER_EVT_RANGE > 0
|
||||||
case NODE_RX_TYPE_USER_START ... NODE_RX_TYPE_USER_END - 1:
|
case NODE_RX_TYPE_USER_START ... NODE_RX_TYPE_USER_END - 1:
|
||||||
return hci_user_ext_get_class(node_rx);
|
return hci_user_ext_get_class(node_rx);
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy);
|
uint8_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);
|
uint8_t cte_len, uint8_t cte_type, uint8_t switch_pattern_len,
|
||||||
uint32_t ll_test_end(uint16_t *num_rx);
|
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);
|
||||||
|
|
|
@ -303,6 +303,7 @@ enum node_rx_type {
|
||||||
NODE_RX_TYPE_MESH_REPORT,
|
NODE_RX_TYPE_MESH_REPORT,
|
||||||
NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT,
|
NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT,
|
||||||
NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT,
|
NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT,
|
||||||
|
NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT,
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_USER_EXT)
|
#if defined(CONFIG_BT_CTLR_USER_EXT)
|
||||||
/* No entries shall be added after the NODE_RX_TYPE_USER_START/END */
|
/* No entries shall be added after the NODE_RX_TYPE_USER_START/END */
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
#include "hal/cntr.h"
|
#include "hal/cntr.h"
|
||||||
#include "hal/ccm.h"
|
#include "hal/ccm.h"
|
||||||
#include "hal/radio.h"
|
#include "hal/radio.h"
|
||||||
|
#include "hal/radio_df.h"
|
||||||
|
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "util/dbuf.h"
|
||||||
|
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
|
|
||||||
|
@ -24,8 +27,18 @@
|
||||||
#include "lll_clock.h"
|
#include "lll_clock.h"
|
||||||
#include "lll_internal.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"
|
#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 BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||||
#define LOG_MODULE_NAME bt_ctlr_lll_test
|
#define LOG_MODULE_NAME bt_ctlr_lll_test
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -33,9 +46,31 @@
|
||||||
|
|
||||||
#define CNTR_MIN_DELTA 3
|
#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 const uint32_t test_sync_word = 0x71764129;
|
||||||
static uint8_t test_phy;
|
static uint8_t test_phy;
|
||||||
static uint8_t test_phy_flags;
|
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 uint16_t test_num_rx;
|
||||||
static bool started;
|
static bool started;
|
||||||
|
|
||||||
|
@ -85,6 +120,54 @@ static const uint8_t prbs15[255] = { 0x00, };
|
||||||
static uint8_t tx_req;
|
static uint8_t tx_req;
|
||||||
static uint8_t volatile tx_ack;
|
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)
|
static void isr_tx(void *param)
|
||||||
{
|
{
|
||||||
uint32_t l, i, s, t;
|
uint32_t l, i, s, t;
|
||||||
|
@ -106,7 +189,14 @@ static void isr_tx(void *param)
|
||||||
|
|
||||||
/* LE Test Packet Interval */
|
/* LE Test Packet Interval */
|
||||||
l = radio_tmr_end_get() - radio_tmr_ready_get();
|
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;
|
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_tmr_end_get() - l + i;
|
||||||
t -= radio_tx_ready_delay_get(test_phy, test_phy_flags);
|
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 crc_ok = 0U;
|
||||||
uint8_t trx_done;
|
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 */
|
/* Read radio status and events */
|
||||||
trx_done = radio_is_done();
|
trx_done = radio_is_done();
|
||||||
if (trx_done) {
|
if (trx_done) {
|
||||||
crc_ok = radio_crc_is_valid();
|
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 */
|
/* Clear radio status and events */
|
||||||
|
@ -153,18 +255,235 @@ static void isr_rx(void *param)
|
||||||
return;
|
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 */
|
/* Setup next Rx */
|
||||||
radio_switch_complete_and_rx(test_phy);
|
radio_switch_complete_and_rx(test_phy);
|
||||||
|
#endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */
|
||||||
|
|
||||||
/* Count Rx-ed packets */
|
/* Count Rx-ed packets */
|
||||||
if (crc_ok) {
|
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;
|
int err;
|
||||||
|
uint8_t ret;
|
||||||
|
|
||||||
if (started) {
|
if (started) {
|
||||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
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 */
|
/* Setup resources required by Radio */
|
||||||
err = lll_hfclock_on_wait();
|
err = lll_hfclock_on_wait();
|
||||||
|
LL_ASSERT(err >= 0);
|
||||||
|
|
||||||
/* Reset Radio h/w */
|
/* Reset Radio h/w */
|
||||||
radio_reset();
|
radio_reset();
|
||||||
radio_isr_set(isr, NULL);
|
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 */
|
/* 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 = BIT(phy - 1);
|
||||||
test_phy_flags = 1U;
|
test_phy_flags = 1U;
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,74 +518,119 @@ static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *))
|
||||||
/* NOTE: No whitening in test mode. */
|
/* NOTE: No whitening in test mode. */
|
||||||
radio_phy_set(test_phy, test_phy_flags);
|
radio_phy_set(test_phy, test_phy_flags);
|
||||||
radio_tmr_tifs_set(150);
|
radio_tmr_tifs_set(150);
|
||||||
radio_tx_power_max_set();
|
|
||||||
|
ret = tx_power_set(tx_power);
|
||||||
|
|
||||||
radio_freq_chan_set((chan << 1) + 2);
|
radio_freq_chan_set((chan << 1) + 2);
|
||||||
radio_aa_set((uint8_t *)&test_sync_word);
|
radio_aa_set((uint8_t *)&test_sync_word);
|
||||||
radio_crc_configure(0x65b, PDU_AC_CRC_IV);
|
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;
|
uint32_t start_us;
|
||||||
uint8_t *payload;
|
uint8_t err;
|
||||||
uint8_t *pdu;
|
const bool cte_request = (cte_len > 0) ? true : false;
|
||||||
uint32_t err;
|
|
||||||
|
|
||||||
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;
|
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) {
|
if (err) {
|
||||||
return 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();
|
err = cte_tx_init(cte_len, cte_type, switch_pattern_len, ant_id);
|
||||||
payload = &pdu[2];
|
if (err) {
|
||||||
|
return err;
|
||||||
switch (type) {
|
}
|
||||||
case 0x00:
|
#else
|
||||||
memcpy(payload, prbs9, len);
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||||
break;
|
#endif /* CONFIG_BT_CTLR_DF_CTE_TX */
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pdu[0] = type;
|
tx_req++;
|
||||||
pdu[1] = len;
|
|
||||||
|
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();
|
radio_switch_complete_and_disable();
|
||||||
start_us = radio_tmr_start(1, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
|
start_us = radio_tmr_start(1, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
|
||||||
radio_tmr_aa_capture();
|
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;
|
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;
|
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) {
|
if (err) {
|
||||||
return 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_pkt_rx_set(radio_pkt_scratch_get());
|
||||||
radio_switch_complete_and_rx(test_phy);
|
radio_switch_complete_and_rx(test_phy);
|
||||||
radio_tmr_start(0, cntr_cnt_get() + CNTR_MIN_DELTA, 0);
|
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;
|
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;
|
int err;
|
||||||
uint8_t ack;
|
uint8_t ack;
|
||||||
|
@ -348,5 +748,5 @@ uint32_t ll_test_end(uint16_t *num_rx)
|
||||||
|
|
||||||
started = false;
|
started = false;
|
||||||
|
|
||||||
return 0;
|
return BT_HCI_ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1044,3 +1044,38 @@ struct pdu_big_info {
|
||||||
#define PDU_BIG_INFO_ENCRYPTED_SIZE sizeof(struct pdu_big_info)
|
#define PDU_BIG_INFO_ENCRYPTED_SIZE sizeof(struct pdu_big_info)
|
||||||
#define PDU_BIG_BN_MAX 0x07
|
#define PDU_BIG_BN_MAX 0x07
|
||||||
#define PDU_BIG_PAYLOAD_COUNT_MAX 28
|
#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
|
||||||
|
|
|
@ -1232,6 +1232,10 @@ void ll_rx_dequeue(void)
|
||||||
case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT:
|
case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT:
|
||||||
#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
|
#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
|
/* Ensure that at least one 'case' statement is present for this
|
||||||
* code block.
|
* 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_ISO */
|
||||||
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
|
#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_SYNC_IQ_SAMPLE_REPORT:
|
||||||
case NODE_RX_TYPE_CONN_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;
|
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_CTLR_ADV_EXT */
|
||||||
#endif /* CONFIG_BT_OBSERVER */
|
#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_SYNC_IQ_SAMPLE_REPORT:
|
||||||
case NODE_RX_TYPE_CONN_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);
|
(void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL);
|
||||||
ll_rx_put(link, rx);
|
ll_rx_put(link, rx);
|
||||||
|
|
|
@ -53,7 +53,8 @@
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "hal/debug.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
|
#define CTE_LEN_MAX_US 160U
|
||||||
|
|
||||||
|
@ -168,7 +169,8 @@ static int init_reset(void)
|
||||||
&df_adv_cfg_free);
|
&df_adv_cfg_free);
|
||||||
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
#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 */
|
/* Re-initialize the free IQ report mfifo */
|
||||||
MFIFO_INIT(iq_report_free);
|
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 */
|
#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)
|
void *ull_df_iq_report_alloc_peek(uint8_t count)
|
||||||
{
|
{
|
||||||
if (count > MFIFO_AVAIL_COUNT_GET(iq_report_free)) {
|
if (count > MFIFO_AVAIL_COUNT_GET(iq_report_free)) {
|
||||||
|
|
|
@ -39,4 +39,10 @@ enum df_switch_sample_support {
|
||||||
#define CONN_IQ_REPORT_CNT 0U
|
#define CONN_IQ_REPORT_CNT 0U
|
||||||
#endif
|
#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)
|
||||||
|
|
|
@ -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[])
|
int cmd_test_tx(const struct shell *sh, size_t argc, char *argv[])
|
||||||
{
|
{
|
||||||
uint8_t chan, len, type, phy;
|
uint8_t chan, len, type, phy;
|
||||||
uint32_t err;
|
uint8_t err;
|
||||||
|
|
||||||
if (argc < 5) {
|
if (argc < 5) {
|
||||||
return -EINVAL;
|
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);
|
type = strtoul(argv[3], NULL, 16);
|
||||||
phy = strtoul(argv[4], 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) {
|
if (err) {
|
||||||
return -EINVAL;
|
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[])
|
int cmd_test_rx(const struct shell *sh, size_t argc, char *argv[])
|
||||||
{
|
{
|
||||||
uint8_t chan, phy, mod_idx;
|
uint8_t chan, phy, mod_idx;
|
||||||
uint32_t err;
|
uint8_t err;
|
||||||
|
|
||||||
if (argc < 4) {
|
if (argc < 4) {
|
||||||
return -EINVAL;
|
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);
|
phy = strtoul(argv[2], NULL, 16);
|
||||||
mod_idx = strtoul(argv[3], 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) {
|
if (err) {
|
||||||
return -EINVAL;
|
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[])
|
int cmd_test_end(const struct shell *sh, size_t argc, char *argv[])
|
||||||
{
|
{
|
||||||
uint16_t num_rx;
|
uint16_t num_rx;
|
||||||
uint32_t err;
|
uint8_t err;
|
||||||
|
|
||||||
err = ll_test_end(&num_rx);
|
err = ll_test_end(&num_rx);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue