From 85790c95a9d99f65c8ef1f87db2ec89953792463 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 21 Jul 2024 04:40:16 +0200 Subject: [PATCH] Bluetooth: Controller: Introduce EVENT_MAFS_MIN_US value Introduce Controller dependent EVENT_MAFS_MIN_US value to use as the value when populating the aux offset between Extended Advertising primary and auxiliary channel PDUs. This can be used as workaround for peers having difficulty receiving Extended Advertising PDUs with near 300 us MAFS values used in aux offset calculations. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll_adv_pdu.h | 3 + .../ll_sw/openisa/lll/lll_adv_pdu.h | 3 + subsys/bluetooth/controller/ll_sw/pdu.h | 4 +- .../bluetooth/controller/ll_sw/ull_adv_aux.c | 60 +++++++++++++++---- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h index 14ce6a29d6d5..5d36fd0598e0 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* The Aux Offset shall be at least the length of the packet plus T_MAFS */ +#define PDU_ADV_AUX_OFFSET_MIN_US 300 + #if defined(CONFIG_BT_CTLR_ADV_PDU_LINK) #define PDU_ADV_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \ PDU_AC_PAYLOAD_SIZE_MAX + \ diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv_pdu.h b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv_pdu.h index 21f0bed21349..ddae0e6739cd 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv_pdu.h +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv_pdu.h @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* The Aux Offset shall be at least the length of the packet plus T_MAFS */ +#define PDU_ADV_AUX_OFFSET_MIN_US 300 + int lll_adv_data_init(struct lll_adv_pdu *pdu); int lll_adv_data_reset(struct lll_adv_pdu *pdu); int lll_adv_data_release(struct lll_adv_pdu *pdu); diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index 4450f3a1682c..18ae111d8ae2 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -187,8 +187,10 @@ #define EVENT_IFS_US 150 /* Standard allows 2 us timing uncertainty inside the event */ #define EVENT_IFS_MAX_US (EVENT_IFS_US + EVENT_CLOCK_JITTER_US) -/* Controller will layout extended adv with minimum separation */ +/* Specification defined Minimum AUX Frame Space (MAFS) */ #define EVENT_MAFS_US 300 +/* Controller dependent MAFS minimum used to populate aux_offset */ +#define EVENT_MAFS_MIN_US MAX(EVENT_MAFS_US, PDU_ADV_AUX_OFFSET_MIN_US) /* Standard allows 2 us timing uncertainty inside the event */ #define EVENT_MAFS_MAX_US (EVENT_MAFS_US + EVENT_CLOCK_JITTER_US) /* Controller defined back to back transmit MAFS for extended advertising */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index d2c673b91347..482239a617a4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -3120,14 +3120,18 @@ void ull_adv_aux_lll_auxptr_fill(struct pdu_adv *pdu, struct lll_adv *adv) chan_counter = lll_aux->data_chan_counter; - /* The offset has to be at least T_MAFS microseconds from the end of packet + /* The offset has to be at least T_MAFS microseconds from the end of packet. + * + * BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 6, Part B, Section 2.3.4.5 AuxPtr field, + * The Aux Offset shall be at least the length of the packet plus T_MAFS + * * In addition, the offset recorded in the aux ptr has the same requirement and this * offset is in steps of 30 microseconds; So use the quantized value in check */ pdu_us = PDU_AC_US(pdu->len, adv->phy_p, adv->phy_flags); offset_us = HAL_TICKER_TICKS_TO_US(lll_aux->ticks_pri_pdu_offset) + lll_aux->us_pri_pdu_offset; - if ((offset_us/OFFS_UNIT_30_US)*OFFS_UNIT_30_US < EVENT_MAFS_US + pdu_us) { + if (((offset_us / OFFS_UNIT_30_US) * OFFS_UNIT_30_US) < (EVENT_MAFS_MIN_US + pdu_us)) { uint32_t interval_us; /* Offset too small, point to next aux packet instead */ @@ -3165,10 +3169,13 @@ static void mfy_aux_offset_get(void *param) uint32_t ticks_current; uint32_t ticks_elapsed; struct ll_adv_set *adv; + uint16_t chan_counter; struct pdu_adv *pdu; uint32_t ticks_now; uint32_t remainder; + uint32_t offset_us; uint8_t ticker_id; + uint16_t pdu_us; uint8_t retry; uint8_t id; @@ -3226,13 +3233,6 @@ static void mfy_aux_offset_get(void *param) */ lll_aux->ticks_pri_pdu_offset = ticks_to_expire; - /* NOTE: as first primary channel PDU does not use remainder, the packet - * timer is started one tick in advance to start the radio with - * microsecond precision, hence compensate for the higher start_us value - * captured at radio start of the first primary channel PDU. - */ - lll_aux->ticks_pri_pdu_offset += 1U; - /* Store the microsecond remainder offset for population in other * advertising primary channel PDUs. */ @@ -3241,8 +3241,43 @@ static void mfy_aux_offset_get(void *param) /* Fill the aux offset in the first Primary channel PDU */ /* FIXME: we are in ULL_LOW context, fill offset in LLL context? */ pdu = lll_adv_data_latest_peek(&adv->lll); - aux_ptr = ull_adv_aux_lll_offset_fill(pdu, ticks_to_expire, remainder, - 0U); + + /* data channel counter that will be used for auxiliary PDU channel */ + chan_counter = lll_aux->data_chan_counter; + + /* The offset has to be at least T_MAFS microseconds from the end of packet. + * + * BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 6, Part B, Section 2.3.4.5 AuxPtr field, + * The Aux Offset shall be at least the length of the packet plus T_MAFS + * + * In addition, the offset recorded in the aux ptr has the same requirement and this + * offset is in steps of 30 microseconds; So use the quantized value in check + */ + pdu_us = PDU_AC_US(pdu->len, adv->lll.phy_p, adv->lll.phy_flags); + offset_us = HAL_TICKER_TICKS_TO_US(lll_aux->ticks_pri_pdu_offset) + + lll_aux->us_pri_pdu_offset; + if (((offset_us / OFFS_UNIT_30_US) * OFFS_UNIT_30_US) < (EVENT_MAFS_MIN_US + pdu_us)) { + uint32_t interval_us; + + /* Offset too small, point to next aux packet instead */ + interval_us = aux->interval * PERIODIC_INT_UNIT_US; + offset_us = offset_us + interval_us; + lll_aux->ticks_pri_pdu_offset = HAL_TICKER_US_TO_TICKS(offset_us); + lll_aux->us_pri_pdu_offset = offset_us - + HAL_TICKER_TICKS_TO_US(lll_aux->ticks_pri_pdu_offset); + chan_counter++; + } + + /* Fill the aux offset */ + aux_ptr = ull_adv_aux_lll_offset_fill(pdu, lll_aux->ticks_pri_pdu_offset, + lll_aux->us_pri_pdu_offset, 0U); + + /* NOTE: as first primary channel PDU does not use remainder, the packet + * timer is started one tick in advance to start the radio with + * microsecond precision, hence compensate for the higher start_us value + * captured at radio start of the first primary channel PDU. + */ + lll_aux->ticks_pri_pdu_offset += 1U; /* Process channel map update, if any */ if (aux->chm_first != aux->chm_last) { @@ -3253,10 +3288,11 @@ static void mfy_aux_offset_get(void *param) /* Calculate the radio channel to use */ data_chan_map = aux->chm[aux->chm_first].data_chan_map; data_chan_count = aux->chm[aux->chm_first].data_chan_count; - aux_ptr->chan_idx = lll_chan_sel_2(lll_aux->data_chan_counter, + aux_ptr->chan_idx = lll_chan_sel_2(chan_counter, aux->data_chan_id, data_chan_map, data_chan_count); + /* Assertion check for delayed aux_offset calculations */ ticks_now = ticker_ticks_now_get(); ticks_elapsed = ticker_ticks_diff_get(ticks_now, ticks_current); ticks_to_start = MAX(adv->ull.ticks_active_to_start,