diff --git a/subsys/bluetooth/controller/Kconfig.df b/subsys/bluetooth/controller/Kconfig.df index 47e22b08dfd..d2e90af6be5 100644 --- a/subsys/bluetooth/controller/Kconfig.df +++ b/subsys/bluetooth/controller/Kconfig.df @@ -26,6 +26,9 @@ config BT_CTLR_DF_ANT_SWITCH_2US_SUPPORT config BT_CTLR_DF_ANT_SWITCH_1US_SUPPORT bool +config BT_CTLR_CTEINLINE_SUPPORT + bool + menuconfig BT_CTLR_DF bool "LE Direction Finding [Experimental]" depends on BT_CTLR_DF_SUPPORT diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 7bdb02b6e6e..1a394d38351 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -35,6 +35,7 @@ config BT_LLL_VENDOR_NORDIC select BT_CTLR_ADV_ISO_SUPPORT select BT_CTLR_SYNC_ISO_SUPPORT select BT_CTLR_DF_SUPPORT if $(DT_NORDIC_RADIO_DFE_SUPPORTED) + select BT_CTLR_CTEINLINE_SUPPORT if $(DT_NORDIC_RADIO_DFE_SUPPORTED) select BT_CTLR_CHAN_SEL_2_SUPPORT select BT_CTLR_MIN_USED_CHAN_SUPPORT select BT_CTLR_DTM_HCI_SUPPORT diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index cbf007cbbd1..9fbf80e46a0 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -404,12 +404,12 @@ struct event_done_extra { struct { uint16_t trx_cnt; uint8_t crc_valid:1; -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) && defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) /* Used to inform ULL that periodic advertising sync scan should be * terminated. */ uint8_t sync_term:1; -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC && CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ #if defined(CONFIG_BT_CTLR_LE_ENC) uint8_t mic_state; #endif /* CONFIG_BT_CTLR_LE_ENC */ diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync.h b/subsys/bluetooth/controller/ll_sw/lll_sync.h index 31e1dceda53..37fb9e224fa 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync.h @@ -6,8 +6,8 @@ /* Periodic advertisements synchronization status. */ enum sync_status { - SYNC_STAT_FOUND, - SYNC_STAT_READY, + SYNC_STAT_ALLOWED, + SYNC_STAT_READY_OR_CONT_SCAN, SYNC_STAT_TERM }; @@ -58,5 +58,6 @@ int lll_sync_init(void); int lll_sync_reset(void); void lll_sync_create_prepare(void *param); void lll_sync_prepare(void *param); - +enum sync_status lll_sync_cte_is_allowed(uint8_t cte_type_mask, uint8_t filter_policy, + uint8_t rx_cte_time, uint8_t rx_cte_type); extern uint16_t ull_sync_lll_handle_get(struct lll_sync *lll); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c index f8e9fde6334..f9351774e10 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c @@ -22,7 +22,6 @@ #include "ll_sw/pdu.h" #include "radio_internal.h" -#include "radio_df.h" #if defined(CONFIG_BT_CTLR_GPIO_PA_PIN) #if ((CONFIG_BT_CTLR_GPIO_PA_PIN) > 31) @@ -1518,7 +1517,7 @@ void radio_ar_resolve(uint8_t *addr) */ void radio_df_cte_inline_set_enabled(bool cte_info_in_s1) { -#if defined(HAS_CTEINLINE_SUPPORT) +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) const nrf_radio_cteinline_conf_t inline_conf = { .enable = true, /* Indicates whether CTEInfo is in S1 byte or not. */ @@ -1542,5 +1541,5 @@ void radio_df_cte_inline_set_enabled(bool cte_info_in_s1) }; nrf_radio_cteinline_configure(NRF_RADIO, &inline_conf); -#endif /* HAS_CTEINLINE_SUPPORT */ +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.c index dea1dba58af..d703179b320 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.c @@ -18,6 +18,9 @@ #include "radio_df.h" #include "radio_internal.h" +/* Devicetree node identifier for the radio node. */ +#define RADIO_NODE DT_NODELABEL(radio) + /* Value to set for unconnected antenna GPIO pins. */ #define DFE_PSEL_NOT_SET 0xFF /* Number of PSEL_DFEGPIO[n] registers in the radio peripheral. */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.h index 364c3815c25..3d85ec5f410 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_df.h @@ -4,13 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* Devicetree node identifier for the radio node. */ -#define RADIO_NODE DT_NODELABEL(radio) -/* Check if radio has hardware support to parse PDU for CTE info */ -#if IS_ENABLED(DT_PROP_OR(RADIO_NODE, dfe_supported, 0)) -#define HAS_CTEINLINE_SUPPORT -#endif - /* Function configures Radio with information about GPIO pins that may be * used to drive antenna switching during CTE Tx/RX. */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 7e0602bd8cb..fc853194587 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -42,13 +42,6 @@ #include #include "hal/debug.h" -/* Periodic advertisements filtering results. */ -enum sync_filtering_result { - SYNC_ALLOWED, - SYNC_SCAN_CONTINUE, - SYNC_SCAN_TERM -}; - static int init_reset(void); static void prepare(void *param); static int create_prepare_cb(struct lll_prepare_param *p); @@ -67,8 +60,7 @@ static int create_iq_report(struct lll_sync *lll, uint8_t rssi_ready, uint8_t packet_status); #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ static uint8_t data_channel_calc(struct lll_sync *lll); -static enum sync_filtering_result sync_filtrate_by_cte_type(uint8_t cte_type_mask, - uint8_t filter_policy); +static enum sync_status sync_filtrate_by_cte_type(uint8_t cte_type_mask, uint8_t filter_policy); static uint8_t trx_cnt; @@ -194,6 +186,57 @@ void lll_sync_aux_prepare_cb(struct lll_sync *lll, } } +enum sync_status lll_sync_cte_is_allowed(uint8_t cte_type_mask, uint8_t filter_policy, + uint8_t rx_cte_time, uint8_t rx_cte_type) +{ + bool cte_ok; + + if (cte_type_mask == BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING) { + return SYNC_STAT_ALLOWED; + } + + if (rx_cte_time > 0) { + if ((cte_type_mask & BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE) != 0) { + cte_ok = false; + } else { + switch (rx_cte_type) { + case BT_HCI_LE_AOA_CTE: + cte_ok = !(cte_type_mask & + BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA); + break; + case BT_HCI_LE_AOD_CTE_1US: + cte_ok = !(cte_type_mask & + BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US); + break; + case BT_HCI_LE_AOD_CTE_2US: + cte_ok = !(cte_type_mask & + BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US); + break; + default: + /* Unknown or forbidden CTE type */ + cte_ok = false; + } + } + } else { + /* If there is no CTEInfo in advertising PDU, Radio will not parse the S0 byte and + * CTESTATUS register will hold zeros only. + * Zero value in CTETime field of CTESTATUS may be used to distinguish between PDU + * that includes CTEInfo or not. Allowed range for CTETime is 2-20. + */ + if ((cte_type_mask & BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE) != 0) { + cte_ok = false; + } else { + cte_ok = true; + } + } + + if (!cte_ok) { + return filter_policy ? SYNC_STAT_READY_OR_CONT_SCAN : SYNC_STAT_TERM; + } + + return SYNC_STAT_ALLOWED; +} + static int init_reset(void) { return 0; @@ -630,7 +673,7 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8 static void isr_rx_adv_sync_estab(void *param) { - enum sync_filtering_result sync_ok; + enum sync_status sync_ok; struct lll_sync *lll; uint8_t rssi_ready; uint8_t trx_done; @@ -651,7 +694,7 @@ static void isr_rx_adv_sync_estab(void *param) /* Initiated as allowed, crc_ok takes precended during handling of PDU * reception in the situation. */ - sync_ok = SYNC_ALLOWED; + sync_ok = SYNC_STAT_ALLOWED; } /* Clear radio rx status and events */ @@ -671,12 +714,12 @@ static void isr_rx_adv_sync_estab(void *param) radio_tmr_ready_save(radio_tmr_ready_get()); /* Handle regular PDU reception if CTE type is acceptable */ - if (sync_ok == SYNC_ALLOWED) { - err = isr_rx(lll, NODE_RX_TYPE_SYNC, crc_ok, rssi_ready, SYNC_STAT_FOUND); + if (sync_ok == SYNC_STAT_ALLOWED) { + err = isr_rx(lll, NODE_RX_TYPE_SYNC, crc_ok, rssi_ready, SYNC_STAT_ALLOWED); if (err == -EBUSY) { return; } - } else if (sync_ok == SYNC_SCAN_TERM) { + } else if (sync_ok == SYNC_STAT_TERM) { struct node_rx_pdu *node_rx; /* Verify if there are free RX buffers for: @@ -702,7 +745,11 @@ static void isr_rx_adv_sync_estab(void *param) } isr_rx_done: - isr_rx_done_cleanup(lll, crc_ok, sync_ok == SYNC_SCAN_TERM); +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) + isr_rx_done_cleanup(lll, crc_ok, sync_ok == SYNC_STAT_TERM); +#else + isr_rx_done_cleanup(lll, crc_ok, false); +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ } static void isr_rx_adv_sync(void *param) @@ -745,7 +792,8 @@ static void isr_rx_adv_sync(void *param) * affect sychronization even when new CTE type is not allowed by sync parameters. * Hence the SYNC_STAT_READY is set. */ - err = isr_rx(lll, NODE_RX_TYPE_SYNC_REPORT, crc_ok, rssi_ready, SYNC_STAT_READY); + err = isr_rx(lll, NODE_RX_TYPE_SYNC_REPORT, crc_ok, rssi_ready, + SYNC_STAT_READY_OR_CONT_SCAN); if (err == -EBUSY) { return; } @@ -798,7 +846,8 @@ static void isr_rx_aux_chain(void *param) * affect sychronization even when new CTE type is not allowed by sync parameters. * Hence the SYNC_STAT_READY is set. */ - err = isr_rx(lll, NODE_RX_TYPE_EXT_AUX_REPORT, crc_ok, rssi_ready, SYNC_STAT_READY); + err = isr_rx(lll, NODE_RX_TYPE_EXT_AUX_REPORT, crc_ok, rssi_ready, + SYNC_STAT_READY_OR_CONT_SCAN); if (err == -EBUSY) { return; @@ -840,8 +889,9 @@ static void isr_rx_done_cleanup(struct lll_sync *lll, uint8_t crc_ok, bool sync_ e->type = EVENT_DONE_EXTRA_TYPE_SYNC; e->trx_cnt = trx_cnt; e->crc_valid = crc_ok; +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) e->sync_term = sync_term; - +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ if (trx_cnt) { e->drift.preamble_to_addr_us = addr_us_get(lll->phy); e->drift.start_to_address_actual_us = @@ -935,57 +985,17 @@ static uint8_t data_channel_calc(struct lll_sync *lll) data_chan_map, data_chan_count); } -static enum sync_filtering_result sync_filtrate_by_cte_type(uint8_t cte_type_mask, - uint8_t filter_policy) +static enum sync_status sync_filtrate_by_cte_type(uint8_t cte_type_mask, uint8_t filter_policy) { - if (cte_type_mask & BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING) { - return SYNC_ALLOWED; - } - -#if defined(HAS_CTEINLINE_SUPPORT) +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) uint8_t rx_cte_time; uint8_t rx_cte_type; - bool cte_ok; rx_cte_time = nrf_radio_cte_time_get(NRF_RADIO); rx_cte_type = nrf_radio_cte_type_get(NRF_RADIO); - /* If there is no CTEInfo in advertising PDU, Radio will not parse the S0 byte and - * CTESTATUS register will hold zeros only. - * Zero value in CTETime field of CTESTATUS may be used to distinguish between PDU that - * includes CTEInfo or not. Allowed range for CTETime is 2-20. - */ - if (rx_cte_time == 0 && cte_type_mask & BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE) { - cte_ok = false; - } + return lll_sync_cte_is_allowed(cte_type_mask, filter_policy, rx_cte_time, rx_cte_type); - if (rx_cte_time > 0) { - if (cte_type_mask & BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE) { - cte_ok = false; - } else { - switch (rx_cte_type) { - case BT_HCI_LE_AOA_CTE: - cte_ok = !(cte_type_mask & - BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA); - break; - case BT_HCI_LE_AOD_CTE_1US: - cte_ok = !(cte_type_mask & - BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US); - break; - case BT_HCI_LE_AOD_CTE_2US: - cte_ok = !(cte_type_mask & - BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US); - break; - default: - /* Unknown or forbidden CTE type */ - cte_ok = false; - } - } - } - - if (!cte_ok) { - return filter_policy ? SYNC_SCAN_CONTINUE : SYNC_SCAN_TERM; - } -#endif /* HAS_CTEINLINE_SUPPORT */ - return SYNC_ALLOWED; +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ + return SYNC_STAT_ALLOWED; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index b6fc96573e6..8d81a12906d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -60,6 +60,9 @@ static void ticker_op_cb(uint32_t status, void *param); static void ticker_update_sync_op_cb(uint32_t status, void *param); static void ticker_stop_op_cb(uint32_t status, void *param); static void sync_lost(void *param); +#if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) +static struct pdu_cte_info *pdu_cte_info_get(struct pdu_adv *pdu); +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) static void ticker_update_op_status_give(uint32_t status, void *param); @@ -591,6 +594,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) { + enum sync_status sync_status; struct node_rx_pdu *rx_establ; struct ll_sync_set *ull_sync; struct node_rx_ftr *ftr; @@ -599,14 +603,33 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) ftr = &rx->rx_ftr; +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) + sync_status = ftr->sync_status; +#else + struct pdu_cte_info *rx_cte_info; + + lll = ftr->param; + + rx_cte_info = pdu_cte_info_get((struct pdu_adv *)((struct node_rx_pdu *)rx)->pdu); + if (rx_cte_info != NULL) { + sync_status = lll_sync_cte_is_allowed(lll->cte_type, lll->filter_policy, + rx_cte_info->time, rx_cte_info->type); + } else { + sync_status = lll_sync_cte_is_allowed(lll->cte_type, lll->filter_policy, 0, + BT_HCI_LE_NO_CTE); + } +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ + /* Send periodic advertisement sync established report when sync has correct CTE type * or the CTE type is incorrect and filter policy doesn't allow to continue scanning. */ - if (ftr->sync_status != SYNC_STAT_READY) { + if (sync_status != SYNC_STAT_READY_OR_CONT_SCAN) { /* Set the sync handle corresponding to the LLL context passed in the node rx * footer field. */ +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) lll = ftr->param; +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ ull_sync = HDR_LLL2ULL(lll); /* Prepare and dispatch sync notification */ @@ -617,6 +640,10 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) BT_HCI_ERR_UNSUPP_REMOTE_FEATURE : BT_HCI_ERR_SUCCESS; + /* Notify done event handler to terminate sync scan */ +#if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) + ull_sync->sync_term = sync_status == SYNC_STAT_TERM; +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ ll_rx_put(rx_establ->hdr.link, rx_establ); ll_rx_sched(); } @@ -625,7 +652,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) * the sync was found or was established in the past. The report is not send if * scanning is terminated due to wrong CTE type. */ - if (ftr->sync_status != SYNC_STAT_TERM) { + if (sync_status != SYNC_STAT_TERM) { /* Switch sync event prepare function to one reposnsible for regular PDUs receive */ mfy_lll_prepare.fp = lll_sync_prepare; @@ -650,7 +677,11 @@ void ull_sync_done(struct node_rx_event_done *done) sync = CONTAINER_OF(done->param, struct ll_sync_set, ull); lll = &sync->lll; +#if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) if (done->extra.sync_term) { +#else + if (sync->sync_term) { +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ /* Stop periodic advertising scan ticker */ sync_ticker_cleanup(sync, NULL); } else { @@ -960,3 +991,28 @@ static void ticker_update_op_status_give(uint32_t status, void *param) k_sem_give(&sem_ticker_cb); } #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ + +#if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) +static struct pdu_cte_info *pdu_cte_info_get(struct pdu_adv *pdu) +{ + struct pdu_adv_com_ext_adv *com_hdr; + struct pdu_adv_ext_hdr *hdr; + uint8_t *dptr; + + com_hdr = &pdu->adv_ext_ind; + hdr = &com_hdr->ext_hdr; + + if (!com_hdr->ext_hdr_len || (com_hdr->ext_hdr_len != 0 && !hdr->cte_info)) { + return NULL; + } + + /* Skip flags in extended advertising header */ + dptr = hdr->data; + + /* Make sure there are no fields that are not allowd for AUX_SYNC_IND and AUX_CHAIN_IND */ + LL_ASSERT(!hdr->adv_addr); + LL_ASSERT(!hdr->tgt_addr); + + return (struct pdu_cte_info *)hdr->data; +} +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h index ae6886028ac..39326a12bd5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h @@ -21,6 +21,13 @@ struct ll_sync_set { uint16_t volatile timeout_reload; /* Non-zero when sync established */ uint16_t timeout_expire; +#if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) + /* Member used to notify event done handler to terminate sync scanning. + * Used only when no HW support for parsing PDU for CTEInfo. + */ + uint8_t sync_term:1; +#endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ + /* node rx type with memory aligned storage for sync lost reason. * HCI will reference the value using the pdu member of * struct node_rx_pdu.