diff --git a/samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.conf index 4bdd4fba240bf..7f1a2f6693a38 100644 --- a/samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.conf +++ b/samples/bluetooth/direction_finding_connectionless_rx/boards/nrf52833dk_nrf52833.conf @@ -10,3 +10,5 @@ CONFIG_BT_CTLR_DF=y # Disable Direction Fiding TX mode CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=n CONFIG_BT_CTLR_DF_ADV_CTE_TX=n + +CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX=16 diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 93e7ee96c5638..5ed56afcd9472 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -111,7 +111,7 @@ config BT_BUF_ACL_RX_COUNT config BT_BUF_EVT_RX_SIZE int "Maximum supported HCI Event buffer length" - default 255 if (BT_EXT_ADV && !(BT_BUF_EVT_DISCARDABLE_COUNT > 0)) + default 255 if (BT_EXT_ADV && !(BT_BUF_EVT_DISCARDABLE_COUNT > 0)) || BT_PER_ADV # LE Read Supported Commands command complete event. default 68 range 68 255 diff --git a/subsys/bluetooth/controller/Kconfig.df b/subsys/bluetooth/controller/Kconfig.df index 5e7f52ae634ed..47e22b08dfdf7 100644 --- a/subsys/bluetooth/controller/Kconfig.df +++ b/subsys/bluetooth/controller/Kconfig.df @@ -163,6 +163,16 @@ config BT_CTLR_DF_PER_ADV_CTE_NUM_MAX periodic advertising chain. The range is taken from BT Core spec 5.1, Vol 4 Part E section 7.8.82 HCI_LE_Set_Connectionless_IQ_Sampling_Enable Max_Sampled_CTEs parameter. +config BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX + int "Maximum number of received PDUs with Constant Tone Extension in connectionless mode" + depends on BT_CTLR_DF_SCAN_CTE_RX + range 1 16 + default 16 + help + Maximum supported number of PDUs, that have Constant Tone Extension, received in single + periodic advertising chain. The range is taken from BT Core spec 5.1, Vol 4 Part E + section 7.8.82 HCI_LE_Set_Connectionless_IQ_Sampling_Enable Max_Sampled_CTEs parameter. + config BT_CTLR_DF_DEBUG_ENABLE bool "Bluetooth Direction Finding debug support enable" help diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index b9b578f0f8336..b2d8e8dc18ff8 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -5523,222 +5523,193 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, struct net_buf *buf) { struct bt_hci_evt_le_per_advertising_report *sep; + struct node_rx_ftr *ftr = &node_rx->hdr.rx_ftr; int8_t tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; struct pdu_adv *adv = (void *)pdu_data; + struct pdu_adv_aux_ptr *aux_ptr = NULL; uint8_t cte_type = BT_HCI_LE_NO_CTE; - struct node_rx_pdu *node_rx_curr; - struct node_rx_pdu *node_rx_next; - uint8_t total_data_len = 0U; + struct pdu_adv_com_ext_adv *p; + struct pdu_adv_ext_hdr *h; uint8_t data_status = 0U; + struct net_buf *evt_buf; uint8_t data_len = 0U; uint8_t *data = NULL; uint8_t data_max_len; + uint8_t hdr_buf_len; + uint8_t hdr_len; + uint8_t *ptr; int8_t rssi; if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || !(le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT)) { - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); return; } - node_rx_curr = node_rx; - node_rx_next = node_rx_curr->hdr.rx_ftr.extra; - do { - struct pdu_adv_com_ext_adv *p; - uint8_t data_len_curr = 0U; - uint8_t *data_curr = NULL; - uint8_t sec_phy_curr = 0U; - struct pdu_adv_ext_hdr *h; - uint8_t hdr_buf_len; - uint8_t hdr_len; - uint8_t *ptr; - - /* The Link Layer currently returns RSSI as an absolute value */ - rssi = -(node_rx_curr->hdr.rx_ftr.rssi); + /* The Link Layer currently returns RSSI as an absolute value */ + rssi = -(node_rx->hdr.rx_ftr.rssi); - BT_DBG("len = %u, rssi = %d", adv->len, rssi); + BT_DBG("len = %u, rssi = %d", adv->len, rssi); - p = (void *)&adv->adv_ext_ind; - h = (void *)p->ext_hdr_adv_data; - ptr = (void *)h; + p = (void *)&adv->adv_ext_ind; + h = (void *)p->ext_hdr_adv_data; + ptr = (void *)h; - BT_DBG(" Ext. adv mode= 0x%x, hdr len= %u", p->adv_mode, - p->ext_hdr_len); + BT_DBG(" Per. adv mode= 0x%x, hdr len= %u", p->adv_mode, + p->ext_hdr_len); - if (!p->ext_hdr_len) { - hdr_len = PDU_AC_EXT_HEADER_SIZE_MIN; + if (!p->ext_hdr_len) { + hdr_len = PDU_AC_EXT_HEADER_SIZE_MIN; - goto no_ext_hdr; - } + goto no_ext_hdr; + } - ptr = h->data; + ptr = h->data; - /* No AdvA */ - /* No TargetA */ + if (h->adv_addr) { + ptr += BDADDR_SIZE; + } - if (h->cte_info) { - struct pdu_cte_info *cte_info; + if (h->tgt_addr) { + ptr += BDADDR_SIZE; + } - cte_info = (void *)ptr; - cte_type = cte_info->type; - ptr++; + if (h->cte_info) { + struct pdu_cte_info *cte_info; - BT_DBG(" CTE type= %d", cte_type); - } + cte_info = (void *)ptr; + cte_type = cte_info->type; + ptr++; - /* No ADI */ + BT_DBG(" CTE type= %d", cte_type); + } - /* AuxPtr */ - if (h->aux_ptr) { - struct pdu_adv_aux_ptr *aux_ptr; - uint8_t aux_phy; + if (h->adi) { + ptr += sizeof(struct pdu_adv_adi); + } - aux_ptr = (void *)ptr; - if (aux_ptr->phy > EXT_ADV_AUX_PHY_LE_CODED) { - struct node_rx_ftr *ftr; + /* AuxPtr */ + if (h->aux_ptr) { + uint8_t aux_phy; - ftr = &node_rx->hdr.rx_ftr; - node_rx_extra_list_release(ftr->extra); - return; - } + aux_ptr = (void *)ptr; + if (aux_ptr->phy > EXT_ADV_AUX_PHY_LE_CODED) { + struct node_rx_ftr *ftr; - ptr += sizeof(*aux_ptr); + ftr = &node_rx->hdr.rx_ftr; + node_rx_extra_list_release(ftr->extra); + return; + } - sec_phy_curr = aux_ptr->phy + 1; + ptr += sizeof(*aux_ptr); - aux_phy = BIT(aux_ptr->phy); + aux_phy = BIT(aux_ptr->phy); - BT_DBG(" AuxPtr chan_idx = %u, ca = %u, offs_units " - "= %u offs = 0x%x, phy = 0x%x", - aux_ptr->chan_idx, aux_ptr->ca, - aux_ptr->offs_units, aux_ptr->offs, aux_phy); - } + BT_DBG(" AuxPtr chan_idx = %u, ca = %u, offs_units " + "= %u offs = 0x%x, phy = 0x%x", + aux_ptr->chan_idx, aux_ptr->ca, + aux_ptr->offs_units, aux_ptr->offs, aux_phy); + } - /* No SyncInfo */ + /* No SyncInfo */ + if (h->sync_info) { + ptr += sizeof(struct pdu_adv_sync_info); + } - /* Tx Power */ - if (h->tx_pwr) { - tx_pwr = *(int8_t *)ptr; - ptr++; + /* Tx Power */ + if (h->tx_pwr) { + tx_pwr = *(int8_t *)ptr; + ptr++; - BT_DBG(" Tx pwr= %d dB", tx_pwr); - } + BT_DBG(" Tx pwr= %d dB", tx_pwr); + } - hdr_len = ptr - (uint8_t *)p; + hdr_len = ptr - (uint8_t *)p; if (hdr_len <= (PDU_AC_EXT_HEADER_SIZE_MIN + sizeof(struct pdu_adv_ext_hdr))) { hdr_len = PDU_AC_EXT_HEADER_SIZE_MIN; ptr = (uint8_t *)h; } - hdr_buf_len = PDU_AC_EXT_HEADER_SIZE_MIN + p->ext_hdr_len; - if (hdr_len > hdr_buf_len) { - BT_WARN(" Header length %u/%u, INVALID.", hdr_len, - p->ext_hdr_len); - } else { - uint8_t acad_len = hdr_buf_len - hdr_len; + hdr_buf_len = PDU_AC_EXT_HEADER_SIZE_MIN + p->ext_hdr_len; + if (hdr_len > hdr_buf_len) { + BT_WARN(" Header length %u/%u, INVALID.", hdr_len, + p->ext_hdr_len); + } else { + uint8_t acad_len = hdr_buf_len - hdr_len; - if (acad_len) { - ptr += acad_len; - hdr_len += acad_len; + if (acad_len) { + ptr += acad_len; + hdr_len += acad_len; - BT_DBG("ACAD: "); - } + BT_DBG("ACAD: "); } + } no_ext_hdr: - if (hdr_len < adv->len) { - data_len_curr = adv->len - hdr_len; - data_curr = ptr; - - BT_DBG(" AD Data (%u): ", data_len); - } - - if (node_rx_curr == node_rx) { - data_len = data_len_curr; - total_data_len = data_len; - data = data_curr; - } else { - /* TODO: Validate current value with previous ?? - */ - - if (!data) { - data_len = data_len_curr; - total_data_len = data_len; - data = data_curr; - } else { - total_data_len += data_len_curr; - - /* TODO: construct new HCI event for this - * fragment. - */ - } - } + if (hdr_len < adv->len) { + data_len = adv->len - hdr_len; + data = ptr; - if (!node_rx_next) { - bool has_aux_ptr = !!sec_phy_curr; - - if (has_aux_ptr) { - data_status = - BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; - } - - break; - } + BT_DBG(" AD Data (%u): ", data_len); + } - node_rx_curr = node_rx_next; - node_rx_next = node_rx_curr->hdr.rx_ftr.extra; - adv = (void *)node_rx_curr->pdu; - } while (1); + adv = (void *)node_rx->pdu; - /* FIXME: move most of below into above loop to dispatch fragments of - * data in HCI event. - */ data_max_len = ADV_REPORT_EVT_MAX_LEN - sizeof(struct bt_hci_evt_le_meta_event) - sizeof(*sep); - /* If data complete */ - if (!data_status) { - /* Only copy data that fit the event buffer size, - * mark it as incomplete - */ - if (data_len > data_max_len) { - data_len = data_max_len; - data_status = - BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; - } + evt_buf = buf; - /* else, data incomplete */ - } else { - /* Data incomplete and no more to come */ - if ((tx_pwr == BT_HCI_LE_ADV_TX_POWER_NO_PREF) && !data) { - /* No Tx Power value and no valid AD data parsed in this - * chain of PDUs, skip HCI event generation. + do { + uint8_t data_len_frag; + + data_len_frag = MIN(data_len, data_max_len); + + /* Start constructing periodic advertising report */ + sep = meta_evt(evt_buf, + BT_HCI_EVT_LE_PER_ADVERTISING_REPORT, + sizeof(*sep) + data_len_frag); + + memcpy(&sep->data[0], data, data_len_frag); + data += data_len_frag; + data_len -= data_len_frag; + + if (data_len > 0) { + /* Some data left in PDU, mark as partial data. */ + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; + } else if (!aux_ptr) { + /* No data left, no AuxPtr, mark as complete data. */ + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE; + } else if (ftr->aux_w4next) { + /* No data left, but have AuxPtr and scheduled aux scan, + * mark as partial data. */ - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); - return; - } - - /* Only copy data that fit the event buffer size */ - if (data_len > data_max_len) { - data_len = data_max_len; + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; + } else { + /* No data left, have AuxPtr but not aux scan scheduled, + * mark as incomplete data. + */ + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; } - } - /* Start constructing the event */ - sep = meta_evt(buf, BT_HCI_EVT_LE_PER_ADVERTISING_REPORT, - sizeof(*sep) + data_len); + sep->handle = sys_cpu_to_le16(node_rx->hdr.handle); + /* TODO: use actual TX power only on 1st report, subsequent + * reports can use 0x7F + */ + sep->tx_power = tx_pwr; + sep->rssi = rssi; + sep->cte_type = cte_type; + sep->data_status = data_status; + sep->length = data_len_frag; - sep->handle = sys_cpu_to_le16(node_rx->hdr.handle); - sep->tx_power = tx_pwr; - sep->rssi = rssi; - sep->cte_type = cte_type; - sep->data_status = data_status; - sep->length = data_len; - memcpy(&sep->data[0], data, data_len); + if (data_len > 0) { + evt_buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + net_buf_frag_add(buf, evt_buf); - node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); + tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; + } + } while (data_len > 0); } static void le_per_adv_sync_lost(struct pdu_data *pdu_data, diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 79cb7315e1a60..03951ba76e57e 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -276,12 +276,14 @@ struct node_rx_ftr { */ void *aux_ptr; uint8_t aux_phy; - uint8_t aux_sched; }; uint32_t ticks_anchor; uint32_t radio_end_us; uint8_t rssi; #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_OBSERVER) + uint8_t aux_lll_sched:1; + uint8_t aux_w4next:1; + uint8_t phy_flags:1; uint8_t scan_req:1; uint8_t scan_rsp:1; diff --git a/subsys/bluetooth/controller/ll_sw/lll_scan_aux.h b/subsys/bluetooth/controller/ll_sw/lll_scan_aux.h index 4f1d99a4e7f6f..6430abbd24c1f 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_scan_aux.h +++ b/subsys/bluetooth/controller/ll_sw/lll_scan_aux.h @@ -9,3 +9,5 @@ int lll_scan_aux_reset(void); void lll_scan_aux_prepare(void *param); extern uint8_t ull_scan_aux_lll_handle_get(struct lll_scan_aux *lll); +extern void *ull_scan_aux_lll_parent_get(struct lll_scan_aux *lll, + uint8_t *is_lll_scan); diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync.h b/subsys/bluetooth/controller/ll_sw/lll_sync.h index 1a0c8b0fc01ae..63ece0fba9c96 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync.h @@ -29,6 +29,9 @@ struct lll_sync { uint32_t window_widening_event_us; uint32_t window_size_event_us; + /* used to store lll_aux when chain is being scanned */ + struct lll_scan_aux *lll_aux; + uint8_t phy:3; uint8_t is_rx_enabled:1; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index b8e96edcf498e..87dda7e057870 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -29,8 +29,9 @@ #include "lll.h" #include "lll_vendor.h" #include "lll_clock.h" -#include "lll_scan.h" #include "lll_df_types.h" +#include "lll_scan.h" +#include "lll_sync.h" #include "lll_conn.h" #include "lll_chan.h" #include "lll_filter.h" @@ -1453,11 +1454,13 @@ static int isr_rx_scan_report(struct lll_scan *lll, uint8_t rssi_ready, radio_rx_chain_delay_get(lll->phy, phy_flags_rx); ftr->phy_flags = phy_flags_rx; - ftr->aux_sched = - lll_scan_aux_setup(lll, pdu_adv_rx, - lll->phy, - phy_flags_rx); - if (ftr->aux_sched) { + ftr->aux_lll_sched = + lll_scan_aux_setup(pdu_adv_rx, lll->phy, + phy_flags_rx, + lll_scan_aux_isr_aux_setup, + lll); + if (ftr->aux_lll_sched) { + lll->is_aux_sched = 1U; err = -EBUSY; } } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index db97b4715a032..ec16c60f4afb2 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -14,7 +14,9 @@ #include "hal/ccm.h" #include "hal/radio.h" #include "hal/ticker.h" +#include "hal/radio_df.h" +#include "util/util.h" #include "util/memq.h" #include "util/mayfly.h" @@ -26,6 +28,10 @@ #include "lll_filter.h" #include "lll_scan.h" #include "lll_scan_aux.h" +#include "lll_df_types.h" +#include "lll_df_internal.h" +#include "lll_sync.h" +#include "lll_sync_iso.h" #include "lll_conn.h" #include "lll_sched.h" @@ -33,6 +39,7 @@ #include "lll_tim_internal.h" #include "lll_prof_internal.h" #include "lll_scan_internal.h" +#include "lll_sync_internal.h" #include "ll_feat.h" @@ -40,17 +47,15 @@ #define LOG_MODULE_NAME bt_ctlr_lll_scan_aux #include "common/log.h" #include -#include #include "hal/debug.h" static int init_reset(void); static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_done(void *param); -static void isr_scan_aux_setup(void *param); static void isr_rx_ull_schedule(void *param); static void isr_rx_lll_schedule(void *param); -static void isr_rx(struct lll_scan *lll_scan, struct lll_scan_aux *lll_aux, +static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, uint8_t phy_aux); static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, uint8_t phy_aux, uint8_t phy_aux_flags_rx, @@ -106,12 +111,14 @@ void lll_scan_aux_prepare(void *param) LL_ASSERT(!err || err == -EINPROGRESS); } -uint8_t lll_scan_aux_setup(struct lll_scan *lll, struct pdu_adv *pdu, - uint8_t pdu_phy, uint8_t pdu_phy_flags_rx) +uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy, + uint8_t pdu_phy_flags_rx, radio_isr_cb_t setup_cb, + void *param) { struct pdu_adv_com_ext_adv *pri_com_hdr; struct pdu_adv_ext_hdr *pri_hdr; struct pdu_adv_aux_ptr *aux_ptr; + struct pdu_cte_info *cte_info; struct node_rx_pdu *node_rx; uint32_t window_widening_us; uint32_t window_size_us; @@ -140,7 +147,10 @@ uint8_t lll_scan_aux_setup(struct lll_scan *lll, struct pdu_adv *pdu, /* traverse through cte_info, if present */ if (pri_hdr->cte_info) { + cte_info = (void *)pri_dptr; pri_dptr += sizeof(struct pdu_cte_info); + } else { + cte_info = NULL; } /* traverse through adi, if present */ @@ -178,6 +188,13 @@ uint8_t lll_scan_aux_setup(struct lll_scan *lll, struct pdu_adv *pdu, * to be used for auxiliary PDU reception. */ overhead_us = PDU_AC_US(pdu->len, pdu_phy, pdu_phy_flags_rx); +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) + /* Add CTE time if samples are available (8us unit) */ + /* TODO: check if CTE was actually enabled for rx */ + if (cte_info && radio_df_iq_samples_amount_get()) { + overhead_us += cte_info->time << 3; + } +#endif overhead_us += lll_radio_rx_ready_delay_get(phy, 1); overhead_us += window_widening_us; overhead_us += EVENT_JITTER_US; @@ -201,17 +218,14 @@ uint8_t lll_scan_aux_setup(struct lll_scan *lll, struct pdu_adv *pdu, /* Store the lll context, aux_ptr and start of PDU in footer */ ftr = &(node_rx->hdr.rx_ftr); - ftr->param = lll; + ftr->param = param; ftr->aux_ptr = aux_ptr; ftr->radio_end_us = radio_tmr_end_get() - radio_rx_chain_delay_get(pdu_phy, pdu_phy_flags_rx) - PDU_AC_US(pdu->len, pdu_phy, pdu_phy_flags_rx); - /* Primary scanner switched to auxliary PDU scanning */ - lll->is_aux_sched = 1U; - - radio_isr_set(isr_scan_aux_setup, node_rx); + radio_isr_set(setup_cb, node_rx); radio_disable(); return 1; @@ -225,14 +239,13 @@ static int init_reset(void) static int prepare_cb(struct lll_prepare_param *p) { struct node_rx_pdu *node_rx; - struct ll_scan_aux_set *aux_set; - struct ll_scan_set *scan_set; - struct lll_scan *lll_scan; + struct lll_scan *scan_lll; struct lll_scan_aux *lll; uint32_t ticks_at_event; uint32_t ticks_at_start; struct ull_hdr *ull; uint32_t remainder_us; + uint8_t is_lll_scan; uint32_t remainder; uint32_t hcto; uint32_t aa; @@ -240,18 +253,33 @@ static int prepare_cb(struct lll_prepare_param *p) DEBUG_RADIO_START_O(1); lll = p->param; - aux_set = HDR_LLL2ULL(lll); - scan_set = HDR_LLL2ULL(aux_set->rx_head->rx_ftr.param); - lll_scan = &scan_set->lll; + scan_lll = ull_scan_aux_lll_parent_get(lll, &is_lll_scan); + + /* Initialize scanning state */ + lll->state = 0U; + + /* Reset Tx/rx count */ + trx_cnt = 0U; + +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + /* Check if this aux scan is for periodic advertising train */ + if (!is_lll_scan) { + lll_sync_aux_prepare_cb((void *) scan_lll, lll); + + scan_lll = NULL; + + goto sync_aux_prepare_done; + } +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #if defined(CONFIG_BT_CENTRAL) - /* Check if stopped (on connection establishment race between LLL and - * ULL. + /* Check if stopped (on connection establishment race between + * LL and ULL. */ - if (unlikely(lll_scan->is_stop || - (lll_scan->conn && - (lll_scan->conn->master.initiated || - lll_scan->conn->master.cancelled)))) { + if (unlikely(scan_lll->is_stop || + (scan_lll->conn && + (scan_lll->conn->master.initiated || + scan_lll->conn->master.cancelled)))) { radio_isr_set(isr_early_abort, lll); radio_disable(); @@ -259,12 +287,6 @@ static int prepare_cb(struct lll_prepare_param *p) } #endif /* CONFIG_BT_CENTRAL */ - /* Initialize scanning state */ - lll->state = 0U; - - /* Reset Tx/rx count */ - trx_cnt = 0U; - /* Start setting up Radio h/w */ radio_reset(); @@ -302,7 +324,7 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_PRIVACY) } else if (ull_filter_lll_rl_enabled()) { struct lll_filter *filter = ull_filter_lll_get( - !!(lll_scan->filter_policy & 0x1)); + !!(scan_lll->filter_policy & 0x1)); uint8_t count, *irks = ull_filter_lll_irks_get(&count); radio_filter_configure(filter->enable_bitmask, @@ -312,7 +334,7 @@ static int prepare_cb(struct lll_prepare_param *p) radio_ar_configure(count, irks, (lll->phy << 2) | BIT(1)); #endif /* CONFIG_BT_CTLR_PRIVACY */ } else if (IS_ENABLED(CONFIG_BT_CTLR_FILTER) && - lll_scan->filter_policy) { + scan_lll->filter_policy) { /* Setup Radio Filter */ struct lll_filter *wl = ull_filter_lll_get(true); @@ -321,6 +343,9 @@ static int prepare_cb(struct lll_prepare_param *p) (uint8_t *)wl->bdaddr); } +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) +sync_aux_prepare_done: +#endif /* Calculate event timings, coarse and fine */ ticks_at_event = p->ticks_at_expire; ull = HDR_LLL2ULL(lll); @@ -359,7 +384,7 @@ static int prepare_cb(struct lll_prepare_param *p) /* check if preempt to start has changed */ if (lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE + ull_scan_aux_lll_handle_get(lll)), - ticks_at_event)) { + ticks_at_event)) { radio_isr_set(isr_done, lll); radio_disable(); } else @@ -371,7 +396,7 @@ static int prepare_cb(struct lll_prepare_param *p) /* calc end of group in us for the anchor where next connection * event to be placed. */ - if (lll_scan->conn) { + if (scan_lll && scan_lll->conn) { static memq_link_t link; static struct mayfly mfy_after_mstr_offset_get = { 0, 0, &link, NULL, @@ -380,7 +405,7 @@ static int prepare_cb(struct lll_prepare_param *p) /* NOTE: LLL scan instance passed, as done when * establishing legacy connections. */ - p->param = lll_scan; + p->param = scan_lll; mfy_after_mstr_offset_get.param = p; ret = mayfly_enqueue(TICKER_USER_ID_LLL, @@ -439,7 +464,7 @@ static void isr_done(void *param) lll_isr_cleanup(param); } -static void isr_scan_aux_setup(void *param) +void lll_scan_aux_isr_aux_setup(void *param) { struct pdu_adv_aux_ptr *aux_ptr; struct node_rx_pdu *node_rx; @@ -456,11 +481,12 @@ static void isr_scan_aux_setup(void *param) node_rx = param; ftr = &node_rx->hdr.rx_ftr; - lll = ftr->param; aux_ptr = ftr->aux_ptr; phy_aux = BIT(aux_ptr->phy); ftr->aux_phy = phy_aux; + lll = ftr->param; + /* Determine the window size */ if (aux_ptr->offs_units) { window_size_us = OFFS_UNIT_300_US; @@ -560,34 +586,33 @@ static void isr_scan_aux_setup(void *param) static void isr_rx_ull_schedule(void *param) { - struct lll_scan_aux *lll_aux; - struct ll_scan_aux_set *aux; - struct ll_scan_set *scan; - struct lll_scan *lll; + struct lll_scan_aux *lll; + struct lll_scan *scan_lll; - lll_aux = param; - aux = HDR_LLL2ULL(lll_aux); - scan = HDR_LLL2ULL(aux->rx_head->rx_ftr.param); - lll = &scan->lll; + lll = param; + scan_lll = ull_scan_aux_lll_parent_get(lll, NULL); - isr_rx(lll, lll_aux, lll_aux->phy); + isr_rx(scan_lll, lll, lll->phy); } static void isr_rx_lll_schedule(void *param) { + struct lll_scan_aux *lll; struct node_rx_pdu *node_rx; - struct lll_scan *lll; + struct lll_scan *scan_lll; uint8_t phy_aux; node_rx = param; - lll = node_rx->hdr.rx_ftr.param; - if (lll->lll_aux) { - phy_aux = lll->lll_aux->phy; + scan_lll = node_rx->hdr.rx_ftr.param; + lll = scan_lll->lll_aux; + + if (lll) { + phy_aux = lll->phy; } else { phy_aux = node_rx->hdr.rx_ftr.aux_phy; } - isr_rx(lll, NULL, phy_aux); + isr_rx(scan_lll, NULL, phy_aux); } static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, @@ -659,7 +684,7 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, isr_rx_do_close: if (lll_aux) { - radio_isr_set(isr_done, lll_aux); + radio_isr_set(isr_done, NULL); } else { /* Send message to flush Auxiliary PDU list */ if (err != -ECANCELED) { @@ -670,12 +695,13 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - node_rx->hdr.rx_ftr.param = lll; + node_rx->hdr.rx_ftr.param = lll->lll_aux; ull_rx_put(node_rx->hdr.link, node_rx); ull_rx_sched(); } + /* Resume scan if scanning ADV_AUX_IND chain */ radio_isr_set(lll_scan_isr_resume, lll); } radio_disable(); @@ -901,7 +927,7 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, (pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_SCAN) && lll_scan_ext_tgta_check(lll, false, false, pdu, rl_idx)) { #else /* !CONFIG_BT_CENTRAL */ - } else if (lll->type && + } else if (lll && lll->type && ((lll_aux && !lll_aux->state) || (lll->lll_aux && !lll->lll_aux->state)) && (pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_SCAN) && @@ -1006,7 +1032,7 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, ftr->rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE; #endif /* CONFIG_BT_CTLR_PRIVACY */ - ftr->aux_sched = 0U; + ftr->aux_lll_sched = 0U; ull_rx_put(node_rx->hdr.link, node_rx); ull_rx_sched(); @@ -1058,12 +1084,15 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, ftr->rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE; #endif /* CONFIG_BT_CTLR_PRIVACY */ - ftr->aux_sched = lll_scan_aux_setup(lll, pdu, phy_aux, - phy_aux_flags_rx); + ftr->aux_lll_sched = lll_scan_aux_setup(pdu, phy_aux, + phy_aux_flags_rx, + lll_scan_aux_isr_aux_setup, + lll); node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_REPORT; ull_rx_put(node_rx->hdr.link, node_rx); + ull_rx_sched(); /* Increase trx count so as to not generate done extra event @@ -1074,7 +1103,8 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, /* Next aux scan is scheduled from LLL, we already handled radio * disable so prevent caller from doing it again. */ - if (ftr->aux_sched) { + if (ftr->aux_lll_sched) { + lll->is_aux_sched = 1U; return 0; } @@ -1181,8 +1211,6 @@ static void isr_tx_connect_req(void *param) static void isr_rx_connect_rsp(void *param) { struct lll_scan_aux *lll_aux; - struct ll_scan_aux_set *aux; - struct ll_scan_set *scan; struct pdu_adv *pdu_rx; struct node_rx_pdu *rx; struct lll_scan *lll; @@ -1212,9 +1240,7 @@ static void isr_rx_connect_rsp(void *param) /* Get the reference to primary scanner's LLL context */ lll_aux = param; - aux = HDR_LLL2ULL(lll_aux); - scan = HDR_LLL2ULL(aux->rx_head->rx_ftr.param); - lll = &scan->lll; + lll = ull_scan_aux_lll_parent_get(lll_aux, NULL); /* Use the reserved/saved node rx to generate connection complete or * release it if failed to receive AUX_CONNECT_RSP PDU. diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_internal.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_internal.h index 1eb4943929c3a..47379fa767bfe 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_internal.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_internal.h @@ -13,5 +13,7 @@ void lll_scan_prepare_connect_req(struct lll_scan *lll, struct pdu_adv *pdu_tx, uint8_t phy, uint8_t adv_tx_addr, uint8_t *adv_addr, uint8_t init_tx_addr, uint8_t *init_addr, uint32_t *conn_space_us); -uint8_t lll_scan_aux_setup(struct lll_scan *lll, struct pdu_adv *pdu, - uint8_t pdu_phy, uint8_t pdu_phy_flags_rx); +uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy, + uint8_t pdu_phy_flags_rx, radio_isr_cb_t setup_cb, + void *param); +void lll_scan_aux_isr_aux_setup(void *param); 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 2bf812d1bc843..3850e3ba45688 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -23,11 +23,13 @@ #include "lll_clock.h" #include "lll_chan.h" #include "lll_df_types.h" +#include "lll_scan.h" #include "lll_sync.h" #include "lll_internal.h" #include "lll_tim_internal.h" #include "lll_prof_internal.h" +#include "lll_scan_internal.h" #include "lll_df.h" #include "lll_df_internal.h" @@ -43,11 +45,13 @@ static int init_reset(void); static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); -static void isr_rx(void *param); - +static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t *trx_cnt, + uint8_t *crc_ok); +static void isr_rx_adv_sync(void *param); +static void isr_rx_aux_chain(void *param); #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) -static inline int create_iq_report(struct lll_sync *lll, uint8_t rssi_ready, - uint8_t packet_status); +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 */ int lll_sync_init(void) @@ -100,6 +104,57 @@ void lll_sync_prepare(void *param) LL_ASSERT(!err || err == -EINPROGRESS); } +void lll_sync_aux_prepare_cb(struct lll_sync *lll, + struct lll_scan_aux *lll_aux) +{ + struct node_rx_pdu *node_rx; + + /* Start setting up Radio h/w */ + radio_reset(); + +#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) + radio_tx_power_set(lll_aux->tx_pwr_lvl); +#else + radio_tx_power_set(RADIO_TXP_DEFAULT); +#endif + + radio_phy_set(lll_aux->phy, 1); + radio_pkt_configure(8, LL_EXT_OCTETS_RX_MAX, (lll_aux->phy << 1)); + + node_rx = ull_pdu_rx_alloc_peek(1); + LL_ASSERT(node_rx); + + radio_pkt_rx_set(node_rx->pdu); + + /* Set access address for sync */ + radio_aa_set(lll->access_addr); + radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)), + (((uint32_t)lll->crc_init[2] << 16) | + ((uint32_t)lll->crc_init[1] << 8) | + ((uint32_t)lll->crc_init[0]))); + + lll_chan_set(lll_aux->chan); + + radio_isr_set(isr_rx_aux_chain, lll); + +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) + struct lll_df_sync_cfg *cfg; + + cfg = lll_df_sync_cfg_latest_get(&lll->df_cfg, NULL); + + if (cfg->is_enabled) { + lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, + cfg->ant_ids, lll_aux->chan); + cfg->cte_count = 0; + + radio_switch_complete_and_phy_end_disable(); + } else +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ + { + radio_switch_complete_and_disable(); + } +} + static int init_reset(void) { return 0; @@ -191,18 +246,10 @@ static int prepare_cb(struct lll_prepare_param *p) cfg = lll_df_sync_cfg_latest_get(&lll->df_cfg, NULL); if (cfg->is_enabled) { - lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, cfg->ant_ids, - data_chan_use); + lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, + cfg->ant_ids, data_chan_use); cfg->cte_count = 0; - } -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ - radio_isr_set(isr_rx, lll); - - radio_tmr_tifs_set(EVENT_IFS_US); - -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) - if (cfg->is_enabled) { radio_switch_complete_and_phy_end_disable(); } else #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ @@ -210,6 +257,8 @@ static int prepare_cb(struct lll_prepare_param *p) radio_switch_complete_and_disable(); } + radio_isr_set(isr_rx_adv_sync, lll); + ticks_at_event = p->ticks_at_expire; ull = HDR_LLL2ULL(lll); ticks_at_event += lll_event_offset_get(ull); @@ -292,31 +341,129 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) lll_done(param); } -static void isr_rx(void *param) +static void isr_aux_setup(void *param) { - struct event_done_extra *e; + struct pdu_adv_aux_ptr *aux_ptr; + struct node_rx_pdu *node_rx; + uint32_t window_widening_us; + uint32_t window_size_us; + struct node_rx_ftr *ftr; + uint32_t aux_offset_us; + uint32_t aux_start_us; struct lll_sync *lll; + uint8_t phy_aux; + uint32_t hcto; + + lll_isr_status_reset(); + + node_rx = param; + ftr = &node_rx->hdr.rx_ftr; + aux_ptr = ftr->aux_ptr; + phy_aux = BIT(aux_ptr->phy); + ftr->aux_phy = phy_aux; + + lll = ftr->param; + + /* Determine the window size */ + if (aux_ptr->offs_units) { + window_size_us = OFFS_UNIT_300_US; + } else { + window_size_us = OFFS_UNIT_30_US; + } + + /* Calculate the aux offset from start of the scan window */ + aux_offset_us = (uint32_t) aux_ptr->offs * window_size_us; + + /* Calculate the window widening that needs to be deducted */ + if (aux_ptr->ca) { + window_widening_us = SCA_DRIFT_50_PPM_US(aux_offset_us); + } else { + window_widening_us = SCA_DRIFT_500_PPM_US(aux_offset_us); + } + + /* Setup radio for auxiliary PDU scan */ + radio_phy_set(phy_aux, 1); + radio_pkt_configure(8, LL_EXT_OCTETS_RX_MAX, (phy_aux << 1)); + + lll_chan_set(aux_ptr->chan_idx); + + radio_pkt_rx_set(node_rx->pdu); + + radio_isr_set(isr_rx_aux_chain, lll); + +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) + struct lll_df_sync_cfg *cfg; + + cfg = lll_df_sync_cfg_latest_get(&lll->df_cfg, NULL); + + if (cfg->is_enabled) { + lll_df_conf_cte_rx_enable(cfg->slot_durations, cfg->ant_sw_len, + cfg->ant_ids, aux_ptr->chan_idx); + cfg->cte_count = 0; + + radio_switch_complete_and_phy_end_disable(); + } else +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ + { + radio_switch_complete_and_disable(); + } + + /* Setup radio rx on micro second offset. Note that radio_end_us stores + * PDU start time in this case. + */ + aux_start_us = ftr->radio_end_us + aux_offset_us; + aux_start_us -= lll_radio_rx_ready_delay_get(phy_aux, 1); + aux_start_us -= window_widening_us; + aux_start_us -= EVENT_JITTER_US; + radio_tmr_start_us(0, aux_start_us); + + /* Setup header complete timeout */ + hcto = ftr->radio_end_us + aux_offset_us; + hcto += window_size_us; + hcto += window_widening_us; + hcto += EVENT_JITTER_US; + hcto += radio_rx_chain_delay_get(phy_aux, 1); + hcto += addr_us_get(phy_aux); + radio_tmr_hcto_configure(hcto); + + /* capture end of Rx-ed PDU, extended scan to schedule auxiliary + * channel chaining, create connection or to create periodic sync. + */ + radio_tmr_end_capture(); + + /* scanner always measures RSSI */ + radio_rssi_measure(); + +#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN) + radio_gpio_lna_setup(); + + radio_gpio_pa_lna_enable(aux_start_us + + radio_rx_ready_delay_get(phy_aux, 1) - + CONFIG_BT_CTLR_GPIO_LNA_OFFSET); +#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */ +} + +static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t *trx_cnt, + uint8_t *crc_ok) +{ uint8_t rssi_ready; uint8_t trx_done; - uint8_t trx_cnt; - uint8_t crc_ok; + int err = 0; /* Read radio status and events */ trx_done = radio_is_done(); if (trx_done) { - crc_ok = radio_crc_is_valid(); + *crc_ok = radio_crc_is_valid(); rssi_ready = radio_rssi_is_ready(); } else { - crc_ok = rssi_ready = 0U; + *crc_ok = rssi_ready = 0U; } /* Clear radio rx status and events */ lll_isr_rx_status_reset(); - lll = param; - /* No Rx */ - trx_cnt = 0U; + *trx_cnt = 0U; if (!trx_done) { /* TODO: Combine the early exit with above if-then-else block */ @@ -324,19 +471,20 @@ static void isr_rx(void *param) } /* Rx-ed */ - trx_cnt = 1U; + *trx_cnt = 1U; /* Check CRC and generate Periodic Advertising Report */ - if (crc_ok) { + if (*crc_ok) { struct node_rx_pdu *node_rx; node_rx = ull_pdu_rx_alloc_peek(3); if (node_rx) { struct node_rx_ftr *ftr; + struct pdu_adv *pdu; ull_pdu_rx_alloc(); - node_rx->hdr.type = NODE_RX_TYPE_SYNC_REPORT; + node_rx->hdr.type = node_type; ftr = &(node_rx->hdr.rx_ftr); ftr->param = lll; @@ -347,6 +495,16 @@ static void isr_rx(void *param) radio_rx_chain_delay_get(lll->phy, 1); + pdu = (void *)node_rx->pdu; + + ftr->aux_lll_sched = lll_scan_aux_setup(pdu, lll->phy, + 0, + isr_aux_setup, + lll); + if (ftr->aux_lll_sched) { + err = -EBUSY; + } + ull_rx_put(node_rx->hdr.link, node_rx); #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) @@ -358,17 +516,32 @@ static void isr_rx(void *param) } #if defined(CONFIG_BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC) else { - int err; - err = create_iq_report(lll, rssi_ready, BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME); if (!err) { ull_rx_sched(); } + + err = 0; } #endif /* CONFIG_BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC */ isr_rx_done: + return err; +} + +static void isr_rx_adv_sync(void *param) +{ + struct event_done_extra *e; + struct lll_sync *lll; + uint8_t trx_cnt; + uint8_t crc_ok; + int err; + + lll = param; + + err = isr_rx(lll, NODE_RX_TYPE_SYNC_REPORT, &trx_cnt, &crc_ok); + /* Calculate and place the drift information in done event */ e = ull_event_done_extra_get(); LL_ASSERT(e); @@ -387,6 +560,30 @@ static void isr_rx(void *param) lll->window_widening_event_us = 0U; lll->window_size_event_us = 0U; + if (err == -EBUSY) { + return; + } + + lll_isr_cleanup(param); +} + +static void isr_rx_aux_chain(void *param) +{ + struct lll_scan_aux *aux_lll; + struct lll_sync *lll; + uint8_t trx_cnt; + uint8_t crc_ok; + int err; + + lll = param; + aux_lll = lll->lll_aux; + + err = isr_rx(lll, NODE_RX_TYPE_EXT_AUX_REPORT, &trx_cnt, &crc_ok); + + if (err == -EBUSY) { + return; + } + lll_isr_cleanup(param); } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_internal.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_internal.h new file mode 100644 index 0000000000000..d60c34fde94ee --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_internal.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +void lll_sync_aux_prepare_cb(struct lll_sync *lll, + struct lll_scan_aux *lll_aux); diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index a23c92b6ecdbc..bd7095922230c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -208,14 +208,21 @@ #define BT_CTLR_MAX_CONNECTABLE 1 #endif #define BT_CTLR_MAX_CONN CONFIG_BT_MAX_CONN +#else +#define BT_CTLR_MAX_CONNECTABLE 0 +#define BT_CTLR_MAX_CONN 0 +#endif + #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_OBSERVER) -#define BT_CTLR_ADV_EXT_RX_CNT 1 +#if defined(CONFIG_BT_CTLR_DF_CTE_RX) +/* Note: Need node for PDU and CTE sample */ +#define BT_CTLR_ADV_EXT_RX_CNT (CONFIG_BT_CTLR_SCAN_AUX_SET * \ + CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX * 2) #else -#define BT_CTLR_ADV_EXT_RX_CNT 0 +/* Note: Assume up to 7 PDUs per advertising train (max data length) */ +#define BT_CTLR_ADV_EXT_RX_CNT (CONFIG_BT_CTLR_SCAN_AUX_SET * 7) #endif #else -#define BT_CTLR_MAX_CONNECTABLE 0 -#define BT_CTLR_MAX_CONN 0 #define BT_CTLR_ADV_EXT_RX_CNT 0 #endif @@ -687,11 +694,6 @@ void ll_reset(void) LL_ASSERT(!err); #endif /* CONFIG_BT_CTLR_ADV_ISO */ -#if defined(CONFIG_BT_CTLR_DF) - err = ull_df_reset(); - LL_ASSERT(!err); -#endif - #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) /* Reset initiator */ @@ -800,6 +802,15 @@ void ll_reset(void) /* Common to init and reset */ err = init_reset(); LL_ASSERT(!err); + +#if defined(CONFIG_BT_CTLR_DF) + /* Direction Finding has to be reset after ull init_reset call because + * it uses mem_link_rx for node_rx_iq_report. The mem_linx_rx is reset + * in common ull init_reset. + */ + err = ull_df_reset(); + LL_ASSERT(!err); +#endif } /** diff --git a/subsys/bluetooth/controller/ll_sw/ull_df_types.h b/subsys/bluetooth/controller/ll_sw/ull_df_types.h index 313674fa304ec..ec064c949cf52 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_df_types.h @@ -27,8 +27,8 @@ enum df_switch_sample_support { * - for LLL -> ULL * - for ULL -> LL(HCI). */ -#if defined(CONFIG_BT_PER_ADV_SYNC_MAX) -#define IQ_REPORT_CNT (CONFIG_BT_PER_ADV_SYNC_MAX * 2) +#if defined(CONFIG_BT_PER_ADV_SYNC_MAX) && defined(CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX) +#define IQ_REPORT_CNT (CONFIG_BT_PER_ADV_SYNC_MAX * CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX * 2) #else #define IQ_REPORT_CNT 0 #endif diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index 9c4e03f82c6a0..9f683ed13c456 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -46,7 +46,7 @@ static inline uint8_t aux_handle_get(struct ll_scan_aux_set *aux); static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan); static void last_disabled_cb(void *param); static void done_disabled_cb(void *param); -static void flush(struct ll_scan_aux_set *aux, struct node_rx_hdr *rx); +static void flush(struct ll_scan_aux_set *aux); static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); static void ticker_op_cb(uint32_t status, void *param); @@ -90,6 +90,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) uint32_t ticks_slot_offset; uint32_t ticks_aux_offset; struct pdu_adv_ext_hdr *h; + struct lll_sync *sync_lll; struct ll_scan_set *scan; struct ll_sync_set *sync; struct pdu_adv_adi *adi; @@ -100,18 +101,17 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) struct lll_scan *lll; struct pdu_adv *pdu; uint8_t aux_handle; - bool is_lll_sched; bool is_scan_req; uint8_t acad_len; - bool is_lll_aux; uint8_t hdr_len; uint8_t *ptr; uint8_t phy; is_scan_req = false; - is_lll_aux = false; ftr = &rx->rx_ftr; + sync_lll = NULL; + switch (rx->type) { case NODE_RX_TYPE_EXT_1M_REPORT: lll_aux = NULL; @@ -137,13 +137,12 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) lll_aux = ftr->param; aux = HDR_LLL2ULL(lll_aux); /* FIXME: pick the aux somehow */ - lll = aux->rx_head->rx_ftr.param; - LL_ASSERT(!lll->lll_aux); - } else { - /* Node that does not have valid aux context was - * scheduled from LLL. We can retrieve aux context - * from lll_scan as it was stored there when superior - * PDU was handled. + lll = aux->parent; + } else if (ull_scan_is_valid_get(HDR_LLL2ULL(ftr->param))) { + /* Node that does not have valid aux context but has + * valid scan set was scheduled from LLL. We can + * retrieve aux context from lll_scan as it was stored + * there when superior PDU was handled. */ lll = ftr->param; @@ -151,15 +150,28 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) LL_ASSERT(lll_aux); aux = HDR_LLL2ULL(lll_aux); - LL_ASSERT(lll == aux->rx_head->rx_ftr.param); + LL_ASSERT(lll == aux->parent); + } else { + /* If none of the above, node is part of sync scanning + */ + lll = NULL; + sync_lll = ftr->param; + lll_aux = sync_lll->lll_aux; + aux = HDR_LLL2ULL(lll_aux); + } - /* aux is retrieved from LLL Aux scheduling */ - is_lll_aux = true; + if (lll) { + scan = HDR_LLL2ULL(lll); + sync = (void *)scan; + scan = ull_scan_is_valid_get(scan); + if (scan) { + sync = NULL; + } + } else { + scan = NULL; + sync = HDR_LLL2ULL(sync_lll); } - scan = HDR_LLL2ULL(lll); - sync = (void *)scan; - scan = ull_scan_is_valid_get(scan); phy = lll_aux->phy; if (scan) { /* Here we are scanner context */ @@ -193,6 +205,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) rx->type = NODE_RX_TYPE_SYNC_REPORT; rx->handle = ull_sync_handle_get(sync); + sync_lll = &sync->lll; + /* lll_aux and aux are auxiliary channel context, * reuse the existing aux context to scan the chain. * hence lll_aux and aux are not released or set to NULL. @@ -204,25 +218,24 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) case NODE_RX_TYPE_SYNC_REPORT: { struct ll_sync_set *ull_sync; - struct lll_sync *lll_sync; /* set the sync handle corresponding to the LLL context * passed in the node rx footer field. */ - lll_sync = ftr->param; - ull_sync = HDR_LLL2ULL(lll_sync); + sync_lll = ftr->param; + ull_sync = HDR_LLL2ULL(sync_lll); rx->handle = ull_sync_handle_get(ull_sync); /* FIXME: we will need lll_scan if chain was scheduled * from LLL; should we store lll_scan_set in - * lll_sync instead? + * sync_lll instead? */ lll = NULL; lll_aux = NULL; aux = NULL; scan = NULL; sync = NULL; - phy = lll_sync->phy; + phy = sync_lll->phy; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } @@ -232,12 +245,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) return; } - /* Copy to local flag since we need to clear 'extra' field */ - is_lll_sched = !!ftr->aux_sched; - rx->link = link; ftr->extra = NULL; + ftr->aux_w4next = 0; + pdu = (void *)((struct node_rx_pdu *)rx)->pdu; p = (void *)&pdu->adv_ext_ind; if (!p->ext_hdr_len) { @@ -347,37 +359,67 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) goto ull_scan_aux_rx_flush; } - aux->rx_last = NULL; + aux->rx_head = aux->rx_last = NULL; lll_aux = &aux->lll; ull_hdr_init(&aux->ull); lll_hdr_init(lll_aux, aux); + + aux->parent = lll ? (void *)lll : (void *)sync_lll; } - /* Enqueue the rx in aux context */ - if (aux->rx_last) { - aux->rx_last->rx_ftr.extra = rx; + /* In sync context we can dispatch rx immediately, in scan context we + * enqueue rx in aux context and will flush them after scan is complete. + */ + if (0) { +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + } else if (sync_lll) { + ll_rx_put(link, rx); + ll_rx_sched(); +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } else { - aux->rx_head = rx; + if (aux->rx_last) { + aux->rx_last->rx_ftr.extra = rx; + } else { + aux->rx_head = rx; + } + aux->rx_last = rx; } - aux->rx_last = rx; lll_aux->chan = aux_ptr->chan_idx; lll_aux->phy = BIT(aux_ptr->phy); + ftr->aux_w4next = 1; + /* See if this was already scheduled from LLL. If so, store aux context * in global scan struct so we can pick it when scanned node is received * with a valid context. */ - if (is_lll_sched) { - lll->lll_aux = lll_aux; + if (ftr->aux_lll_sched) { + if (0) { +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + } else if (sync_lll) { + sync_lll->lll_aux = lll_aux; +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + } else { + lll->lll_aux = lll_aux; + } lll_aux->state = 0U; return; } /* Switching to ULL scheduling to receive auxiliary PDUs */ - lll->lll_aux = NULL; + if (lll) { + lll->lll_aux = NULL; + } else { + LL_ASSERT(sync_lll); + /* XXX: keep lll_aux for now since node scheduled from ULL has + * sync_lll as ftr->param and we still need to restore + * lll_aux somehow. + */ + /* sync_lll->lll_aux = NULL; */ + } /* Determine the window size */ if (aux_ptr->offs_units) { @@ -477,18 +519,37 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ if (aux) { - if (is_lll_aux) { - flush(aux, rx); + struct ull_hdr *hdr; + + hdr = &aux->ull; + + /* Enqueue last rx in aux context if possible, otherwise send + * immediately since we are in sync context. + */ + if (aux->rx_last) { + aux->rx_last->rx_ftr.extra = rx; } else { - struct ull_hdr *hdr; + LL_ASSERT(sync_lll); + ll_rx_put(link, rx); + ll_rx_sched(); + } - /* Setup the disabled callback to flush the - * auxiliary PDUs - */ - hdr = &aux->ull; + /* ref == 0 + * All PDUs were scheduled from LLL and there is no pending done + * event, we can flush here. + * + * ref == 1 + * There is pending done event so we need to flush from disabled + * callback. Flushing here would release aux context and thus + * ull_hdr before done event was processed. + */ + LL_ASSERT(ull_ref_get(hdr) < 2); + if (ull_ref_get(hdr) == 0) { + flush(aux); + } else { LL_ASSERT(!hdr->disabled_cb); - hdr->disabled_param = rx; + hdr->disabled_param = aux; hdr->disabled_cb = last_disabled_cb; } @@ -507,10 +568,27 @@ void ull_scan_aux_done(struct node_rx_event_done *done) /* Get reference to ULL context */ aux = CONTAINER_OF(done->param, struct ll_scan_aux_set, ull); - /* Setup the disabled callback to flush the auxiliary PDUs */ - hdr = &aux->ull; - LL_ASSERT(!hdr->disabled_cb); + if (0) { +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + } else if (!ull_scan_aux_is_valid_get(aux)) { + struct ll_sync_set *sync; + + sync = CONTAINER_OF(done->param, struct ll_sync_set, ull); + LL_ASSERT(ull_sync_is_valid_get(sync)); + hdr = &sync->ull; + + if (!sync->lll.lll_aux) { + return; + } + aux = HDR_LLL2ULL(sync->lll.lll_aux); +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + } else { + /* Setup the disabled callback to flush the auxiliary PDUs */ + hdr = &aux->ull; + } + + LL_ASSERT(!hdr->disabled_cb); hdr->disabled_param = aux; hdr->disabled_cb = done_disabled_cb; } @@ -520,6 +598,22 @@ uint8_t ull_scan_aux_lll_handle_get(struct lll_scan_aux *lll) return aux_handle_get((void *)lll->hdr.parent); } +void *ull_scan_aux_lll_parent_get(struct lll_scan_aux *lll, + uint8_t *is_lll_scan) +{ + struct ll_scan_aux_set *aux_set; + struct ll_scan_set *scan_set; + + aux_set = HDR_LLL2ULL(lll); + scan_set = HDR_LLL2ULL(aux_set->parent); + + if (is_lll_scan) { + *is_lll_scan = !!ull_scan_is_valid_get(scan_set); + } + + return aux_set->parent; +} + struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux) { if (((uint8_t *)aux < (uint8_t *)ll_scan_aux_pool) || @@ -535,14 +629,34 @@ struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux) void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) { struct lll_scan_aux *lll_aux; - struct ll_scan_aux_set *aux; - struct lll_scan *lll; + void *param_ull; + + param_ull = HDR_LLL2ULL(rx->rx_ftr.param); + + if (ull_scan_is_valid_get(param_ull)) { + struct lll_scan *lll; + + lll = rx->rx_ftr.param; + lll_aux = lll->lll_aux; + } else if (ull_scan_aux_is_valid_get(param_ull)) { + lll_aux = rx->rx_ftr.param; +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + } else if (ull_sync_is_valid_get(param_ull)) { + struct lll_sync *lll; + + lll = rx->rx_ftr.param; + lll_aux = lll->lll_aux; +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + } else { + LL_ASSERT(0); + lll_aux = NULL; + } - lll = rx->rx_ftr.param; - lll_aux = lll->lll_aux; if (lll_aux) { + struct ll_scan_aux_set *aux; + aux = HDR_LLL2ULL(lll_aux); - flush(aux, NULL); + flush(aux); } /* Mark for buffer for release */ @@ -589,38 +703,49 @@ static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan) static void last_disabled_cb(void *param) { - struct ll_scan_aux_set *aux; - struct node_rx_hdr *rx; - - rx = param; - aux = HDR_LLL2ULL(rx->rx_ftr.param); - - flush(aux, rx); + flush(param); } static void done_disabled_cb(void *param) { - flush(param, NULL); + struct ll_scan_aux_set *aux; + + aux = param; + LL_ASSERT(ull_scan_aux_is_valid_get(aux)); + + aux = ull_scan_aux_is_valid_get(aux); +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + if (!aux) { + struct lll_sync *sync_lll; + + sync_lll = param; + LL_ASSERT(sync_lll->lll_aux); + aux = HDR_LLL2ULL(sync_lll->lll_aux); + } +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + + flush(aux); } -static void flush(struct ll_scan_aux_set *aux, struct node_rx_hdr *rx) +static void flush(struct ll_scan_aux_set *aux) { - if (aux->rx_last) { - struct lll_scan *lll; + struct node_rx_hdr *rx; - if (rx) { - aux->rx_last->rx_ftr.extra = rx; - } + /* Nodes are enqueued only in scan context so need to send them now */ + rx = aux->rx_head; + if (rx) { + struct lll_scan *lll; - rx = aux->rx_head; - lll = rx->rx_ftr.param; + lll = aux->parent; lll->lll_aux = NULL; ll_rx_put(rx->link, rx); ll_rx_sched(); - } else if (rx) { - ll_rx_put(rx->link, rx); - ll_rx_sched(); + } else { + struct lll_sync *lll; + + lll = aux->parent; + lll->lll_aux = NULL; } aux_release(aux); @@ -677,5 +802,5 @@ static void ticker_op_cb(uint32_t status, void *param) static void ticker_op_aux_failure(void *param) { - flush(param, NULL); + flush(param); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h index 5a8cf1d0c8d15..0441283871700 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h @@ -41,6 +41,9 @@ struct ll_scan_aux_set { struct ull_hdr ull; struct lll_scan_aux lll; + /* lll_scan or lll_sync */ + void *parent; + struct node_rx_hdr *rx_head; struct node_rx_hdr *rx_last; }; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index f8001034d38c8..d906b255dc42b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -332,6 +332,17 @@ struct ll_sync_set *ull_sync_is_enabled_get(uint16_t handle) return sync; } +struct ll_sync_set *ull_sync_is_valid_get(struct ll_sync_set *sync) +{ + if (((uint8_t *)sync < (uint8_t *)ll_sync_pool) || + ((uint8_t *)sync > ((uint8_t *)ll_sync_pool + + (sizeof(struct ll_sync_set) * (CONFIG_BT_PER_ADV_SYNC_MAX - 1))))) { + return NULL; + } + + return sync; +} + uint16_t ull_sync_handle_get(struct ll_sync_set *sync) { return mem_index_get(sync, ll_sync_pool, sizeof(struct ll_sync_set)); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h index 7c9a685fb0089..f3a74cf44f806 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h @@ -15,3 +15,4 @@ void ull_sync_done(struct node_rx_event_done *done); void ull_sync_chm_update(uint8_t sync_handle, uint8_t *acad, uint8_t acad_len); int ull_sync_slot_update(struct ll_sync_set *sync, uint32_t slot_plus_us, uint32_t slot_minus_us); +struct ll_sync_set *ull_sync_is_valid_get(struct ll_sync_set *sync);