From 8cc4733df52270b33bf39180fb5dea4f4e31ee68 Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Tue, 18 Jan 2022 16:39:39 +0100 Subject: [PATCH 1/5] 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 --- include/bluetooth/hci.h | 73 ++- subsys/bluetooth/controller/Kconfig | 16 +- subsys/bluetooth/controller/Kconfig.dtm | 61 +++ subsys/bluetooth/controller/hci/hci.c | 165 +++++- subsys/bluetooth/controller/ll_sw/ll_test.h | 10 +- subsys/bluetooth/controller/ll_sw/lll.h | 1 + .../controller/ll_sw/nordic/lll/lll_test.c | 502 ++++++++++++++++-- subsys/bluetooth/controller/ll_sw/pdu.h | 35 ++ subsys/bluetooth/controller/ll_sw/ull.c | 12 +- subsys/bluetooth/controller/ll_sw/ull_df.c | 9 +- .../bluetooth/controller/ll_sw/ull_df_types.h | 8 +- subsys/bluetooth/shell/ll.c | 14 +- 12 files changed, 802 insertions(+), 104 deletions(-) create mode 100644 subsys/bluetooth/controller/Kconfig.dtm diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 34858f60c27d..0d57e06c37f5 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -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 diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 3e301ed70a98..92fac125e819 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -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" diff --git a/subsys/bluetooth/controller/Kconfig.dtm b/subsys/bluetooth/controller/Kconfig.dtm new file mode 100644 index 000000000000..b0a04f2be99d --- /dev/null +++ b/subsys/bluetooth/controller/Kconfig.dtm @@ -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 diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 193d9783c463..f61a7b4f4631 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -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,18 +2834,42 @@ 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 @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/ll_test.h b/subsys/bluetooth/controller/ll_sw/ll_test.h index c0dd8993b2da..773fc9436086 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_test.h +++ b/subsys/bluetooth/controller/ll_sw/ll_test.h @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 4c6b26b729b8..534eaf6aa3bd 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -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 */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c index d58d23daf9b7..e39eb1f493c3 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c @@ -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 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 uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *)) +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)); - - return 0; + 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 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) { - uint32_t start_us; - uint8_t *payload; - uint8_t *pdu; - uint32_t err; + struct pdu_dtm *pdu = radio_pkt_scratch_get(); - if ((type > 0x07) || !phy || (phy > 0x04)) { - return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL; - } + pdu->type = type; + pdu->length = len; - err = init(chan, phy, isr_tx); - if (err) { - return err; - } - - tx_req++; - - pdu = radio_pkt_scratch_get(); - payload = &pdu[2]; +#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 0x00: - memcpy(payload, prbs9, len); + case BT_HCI_TEST_PKT_PAYLOAD_PRBS9: + (void)memcpy(pdu->payload, prbs9, len); break; - case 0x01: - memset(payload, 0x0f, len); + case BT_HCI_TEST_PKT_PAYLOAD_11110000: + (void)memset(pdu->payload, PAYLOAD_11110000, len); break; - case 0x02: - memset(payload, 0x55, len); + case BT_HCI_TEST_PKT_PAYLOAD_10101010: + (void)memset(pdu->payload, PAYLOAD_10101010, len); break; - case 0x03: - memcpy(payload, prbs15, len); + case BT_HCI_TEST_PKT_PAYLOAD_PRBS15: + (void)memcpy(pdu->payload, prbs15, len); break; - case 0x04: - memset(payload, 0xff, len); + case BT_HCI_TEST_PKT_PAYLOAD_11111111: + (void)memset(pdu->payload, PAYLOAD_11111111, len); break; - case 0x05: - memset(payload, 0x00, len); + case BT_HCI_TEST_PKT_PAYLOAD_00000000: + (void)memset(pdu->payload, PAYLOAD_00000000, len); break; - case 0x06: - memset(payload, 0xf0, len); + case BT_HCI_TEST_PKT_PAYLOAD_00001111: + (void)memset(pdu->payload, PAYLOAD_00001111, len); break; - case 0x07: - memset(payload, 0xaa, len); + case BT_HCI_TEST_PKT_PAYLOAD_01010101: + (void)memset(pdu->payload, PAYLOAD_01010101, len); break; } - pdu[0] = type; - pdu[1] = len; - 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 err; + const bool cte_request = (cte_len > 0) ? true : false; + + 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, tx_power, cte_request, isr_tx); + if (err) { + return err; + } + + /* 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; + } + + 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 */ + } + + 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_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; } diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index afc124f50279..167512b1b95e 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -1043,3 +1043,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 diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 6efbe1dbc830..368f9803db86 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 37320c3ffa63..9f95e42f90f3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -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)) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_df_types.h b/subsys/bluetooth/controller/ll_sw/ull_df_types.h index d7a38eda5a12..f75b54bef7ad 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_df_types.h @@ -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) diff --git a/subsys/bluetooth/shell/ll.c b/subsys/bluetooth/shell/ll.c index 4acdfb511cdd..4777fcf12645 100644 --- a/subsys/bluetooth/shell/ll.c +++ b/subsys/bluetooth/shell/ll.c @@ -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) { From 3109b17b63e115e5ba41a9ef360938798b17d50b Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Tue, 25 Jan 2022 11:01:22 +0100 Subject: [PATCH 2/5] bluetooth: controller: Align the Openisa test ll API Alignes the Openisa ll_test_tx and ll_test_rx functions with the new test API. Signed-off-by: Kamil Gawor --- .../controller/ll_sw/openisa/lll/lll_test.c | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_test.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_test.c index 1e805a38f2f5..6ddc6f1080fa 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_test.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_test.c @@ -158,7 +158,7 @@ static void isr_rx(void *param) } } -static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *)) +static uint8_t init(uint8_t chan, uint8_t phy, void (*isr)(void *)) { int err; @@ -198,12 +198,20 @@ static uint32_t init(uint8_t chan, uint8_t phy, void (*isr)(void *)) return 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, + 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; + + ARG_UNUSED(cte_len); + ARG_UNUSED(cte_type); + ARG_UNUSED(switch_pattern_len); + ARG_UNUSED(ant_id); + ARG_UNUSED(tx_power); if ((type > 0x07) || !phy || (phy > 0x04)) { return 1; @@ -277,14 +285,22 @@ uint32_t ll_test_tx(uint8_t chan, uint8_t len, uint8_t type, uint8_t phy) return 0; } -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; if (!phy || (phy > 0x03)) { return 1; } + ARG_UNUSED(expected_cte_len); + ARG_UNUSED(expected_cte_type); + ARG_UNUSED(slot_duration); + ARG_UNUSED(switch_pattern_len); + ARG_UNUSED(ant_ids); + err = init(chan, phy, isr_rx); if (err) { return err; @@ -303,7 +319,7 @@ uint32_t ll_test_rx(uint8_t chan, uint8_t phy, uint8_t mod_idx) return 0; } -uint32_t ll_test_end(uint16_t *num_rx) +uint8_t ll_test_end(uint16_t *num_rx) { int err; uint8_t ack; From 68240a0f20d4f4893b665e17587262c1e4b11287 Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Tue, 25 Jan 2022 11:08:40 +0100 Subject: [PATCH 3/5] bluetooth: samples: hci_uart: Add support for nrf52833dk Adds support for the nrf52833dk_nrf52833 which supports the Direction Finding feature. It allows also to perform the Direct Test Mode with the CTE feature. Signed-off-by: Kamil Gawor --- .../boards/nrf52833dk_nrf52833.overlay | 12 +++++++ .../boards/nrf52833dk_nrf52833_df.overlay | 33 +++++++++++++++++++ samples/bluetooth/hci_uart/sample.yaml | 15 +++++++++ 3 files changed, 60 insertions(+) create mode 100644 samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833.overlay create mode 100644 samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833_df.overlay diff --git a/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 000000000000..1dd3aea1b3ac --- /dev/null +++ b/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + &uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; + status = "okay"; + hw-flow-control; +}; diff --git a/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833_df.overlay b/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833_df.overlay new file mode 100644 index 000000000000..50d31f0f1312 --- /dev/null +++ b/samples/bluetooth/hci_uart/boards/nrf52833dk_nrf52833_df.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + &uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; + status = "okay"; + hw-flow-control; +}; + +&radio { + status = "okay"; + /* This is an example number of antennas that may be available + * on antenna matrix board. + */ + dfe-antenna-num = <10>; + /* This is an example switch pattern that will be used to set an + * antenna for Tx PDU (period before start of Tx CTE). + */ + dfe-pdu-antenna = <0x0>; + + /* These are example GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoD is enabled. + */ + dfegpio0-gpios = <&gpio0 3 0>; + dfegpio1-gpios = <&gpio0 4 0>; + dfegpio2-gpios = <&gpio0 28 0>; + dfegpio3-gpios = <&gpio0 29 0>; +}; diff --git a/samples/bluetooth/hci_uart/sample.yaml b/samples/bluetooth/hci_uart/sample.yaml index 774690d55e15..1b5d7187eb61 100644 --- a/samples/bluetooth/hci_uart/sample.yaml +++ b/samples/bluetooth/hci_uart/sample.yaml @@ -12,3 +12,18 @@ tests: platform_allow: 96b_nitrogen nrf51dk_nrf51422 nrf52dk_nrf52832 tags: uart bluetooth + sample.bluetooth.hci_uart.nrf52833.df: + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + extra_args: DTC_OVERLAY_FILE=./boards/nrf52833dk_nrf52833_df.overlay + extra_configs: + - CONFIG_BT_CTLR_DF=y + tags: uart bluetooth + sample.bluetooth.hci_uart.nrf52833.df.iq_report: + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + extra_args: DTC_OVERLAY_FILE=./boards/nrf52833dk_nrf52833_df.overlay + extra_configs: + - CONFIG_BT_CTLR_DF=y + - CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT=y + tags: uart bluetooth From 170f9fbab1c987e6d8e9cad1e37364f085cb112f Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Wed, 9 Feb 2022 15:43:50 +0100 Subject: [PATCH 4/5] bluetooth: samples: hci_uart: Add nrf5340 antenna description Adds antenna description for the nrf5340dk_nrf5340_cpunet target. It allows to performthe Direct Test Mode with the CTE feature on this target. Signed-off-by: Kamil Gawor --- .../nrf5340dk_nrf5340_cpunet_df.overlay | 33 +++++++++++++++++++ samples/bluetooth/hci_uart/sample.yaml | 15 +++++++++ 2 files changed, 48 insertions(+) create mode 100644 samples/bluetooth/hci_uart/boards/nrf5340dk_nrf5340_cpunet_df.overlay diff --git a/samples/bluetooth/hci_uart/boards/nrf5340dk_nrf5340_cpunet_df.overlay b/samples/bluetooth/hci_uart/boards/nrf5340dk_nrf5340_cpunet_df.overlay new file mode 100644 index 000000000000..fdef6321f72c --- /dev/null +++ b/samples/bluetooth/hci_uart/boards/nrf5340dk_nrf5340_cpunet_df.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + &uart0 { + compatible = "nordic,nrf-uarte"; + current-speed = <1000000>; + status = "okay"; + hw-flow-control; +}; + +&radio { + status = "okay"; + /* This is an example number of antennas that may be available + * on antenna matrix board. + */ + dfe-antenna-num = <10>; + /* This is an example switch pattern that will be used to set an + * antenna for Tx PDU (period before start of Tx CTE). + */ + dfe-pdu-antenna = <0x0>; + + /* These are example GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoD is enabled. + */ + dfegpio0-gpios = <&gpio0 4 0>; + dfegpio1-gpios = <&gpio0 5 0>; + dfegpio2-gpios = <&gpio0 6 0>; + dfegpio3-gpios = <&gpio0 7 0>; +}; diff --git a/samples/bluetooth/hci_uart/sample.yaml b/samples/bluetooth/hci_uart/sample.yaml index 1b5d7187eb61..2477c7452c74 100644 --- a/samples/bluetooth/hci_uart/sample.yaml +++ b/samples/bluetooth/hci_uart/sample.yaml @@ -19,6 +19,13 @@ tests: extra_configs: - CONFIG_BT_CTLR_DF=y tags: uart bluetooth + sample.bluetooth.hci_uart.nrf5340_netcore.df: + harness: bluetooth + platform_allow: nrf5340dk_nrf5340_cpunet + extra_args: DTC_OVERLAY_FILE=./boards/nrf5340dk_nrf5340_cpunet_df.overlay + extra_configs: + - CONFIG_BT_CTLR_DF=y + tags: uart bluetooth sample.bluetooth.hci_uart.nrf52833.df.iq_report: harness: bluetooth platform_allow: nrf52833dk_nrf52833 @@ -27,3 +34,11 @@ tests: - CONFIG_BT_CTLR_DF=y - CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT=y tags: uart bluetooth + sample.bluetooth.hci_uart.nrf5340_netcore.df.iq_report: + harness: bluetooth + platform_allow: nrf5340dk_nrf5340_cpunet + extra_args: DTC_OVERLAY_FILE=./boards/nrf5340dk_nrf5340_cpunet_df.overlay + extra_configs: + - CONFIG_BT_CTLR_DF=y + - CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT=y + tags: uart bluetooth From 72e89fee799fef95f930cc01b31cdbf3a139230b Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Mon, 7 Mar 2022 11:59:46 +0100 Subject: [PATCH 5/5] bluetooth: samples: hci_uart: Add Direction Finding doc Add the Direction Finding documentation section into the sample README.rst file. Signed-off-by: Kamil Gawor --- samples/bluetooth/hci_uart/README.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/samples/bluetooth/hci_uart/README.rst b/samples/bluetooth/hci_uart/README.rst index 60e719fd6310..85b1cfa86fe8 100644 --- a/samples/bluetooth/hci_uart/README.rst +++ b/samples/bluetooth/hci_uart/README.rst @@ -125,3 +125,21 @@ application. To enable debug over RTT the debug configuration file can be used. west build samples/bluetooth/hci_uart -- -DOVERLAY_CONFIG='debug.conf' Then attach RTT as described here: :ref:`Using Segger J-Link ` + +Support for the Direction Finding +================================= + +The sample can be built with the support for the BLE Direction Finding. +To enable this feature build this sample for specific board variants that provide +required hardware configuration for the Radio. + +.. code-block:: console + + west build samples/bluetooth/hci_uart -b nrf52833dk_nrf52833@df -- -DCONFIG_BT_CTLR_DF=y + +You can use following targets: + +* ``nrf5340dk_nrf5340_cpunet@df`` +* ``nrf52833dk_nrf52833@df`` + +Check the :ref:`bluetooth_direction_finding_connectionless_rx` and the :ref:`bluetooth_direction_finding_connectionless_tx` for more details.