Bluetooth: Controller: Fix overlapping advertising events

When multiple advertising sets are support then use advanced
scheduling implementation to place multiple auxiliary PDUs
and periodic advertising PDUs in a non-overlapping schedule.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2022-05-13 16:44:49 +05:30 committed by Carles Cufí
commit fab4511164
10 changed files with 326 additions and 122 deletions

View file

@ -114,8 +114,7 @@ if(CONFIG_BT_LL_SW_SPLIT)
) )
endif() endif()
endif() endif()
if(CONFIG_BT_CTLR_SCHED_ADVANCED AND if(CONFIG_BT_CTLR_SCHED_ADVANCED)
(CONFIG_BT_CONN OR CONFIG_BT_CTLR_ADV_ISO))
zephyr_library_sources( zephyr_library_sources(
ll_sw/ull_sched.c ll_sw/ull_sched.c
) )

View file

@ -341,8 +341,11 @@ config BT_CTLR_XTAL_THRESHOLD
config BT_CTLR_SCHED_ADVANCED config BT_CTLR_SCHED_ADVANCED
bool "Advanced scheduling" bool "Advanced scheduling"
depends on (BT_MAX_CONN != 0) && BT_CTLR_SCHED_ADVANCED_SUPPORT depends on BT_CTLR_SCHED_ADVANCED_SUPPORT && \
default y if !(BT_PERIPHERAL && !BT_CENTRAL) (BT_CONN || \
(BT_CTLR_ADV_EXT && (BT_CTLR_ADV_AUX_SET > 1)) || \
BT_CTLR_ADV_ISO)
default y if BT_CENTRAL || (BT_BROADCASTER && BT_CTLR_ADV_EXT) || BT_CTLR_ADV_ISO
help help
Enable non-overlapping placement of observer, initiator and central Enable non-overlapping placement of observer, initiator and central
roles in timespace. Uses window offset in connection updates and uses roles in timespace. Uses window offset in connection updates and uses

View file

@ -101,7 +101,8 @@ static inline void lll_adv_aux_data_enqueue(struct lll_adv_aux *lll,
lll_adv_pdu_enqueue(&lll->data, idx); lll_adv_pdu_enqueue(&lll->data, idx);
} }
static inline struct pdu_adv *lll_adv_aux_data_peek(struct lll_adv_aux *lll) static inline struct pdu_adv *
lll_adv_aux_data_peek(const struct lll_adv_aux *const lll)
{ {
return (void *)lll->data.pdu[lll->data.last]; return (void *)lll->data.pdu[lll->data.last];
} }

View file

@ -1407,7 +1407,8 @@ uint8_t ll_adv_enable(uint8_t enable)
EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_START_US +
(EVENT_TICKER_RES_MARGIN_US << 1)); (EVENT_TICKER_RES_MARGIN_US << 1));
ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux); ticks_slot_overhead_aux =
ull_adv_aux_evt_init(aux, &ticks_anchor_aux);
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) #if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
/* Start periodic advertising if enabled and not already /* Start periodic advertising if enabled and not already

View file

@ -39,6 +39,7 @@
#include "ull_internal.h" #include "ull_internal.h"
#include "ull_chan_internal.h" #include "ull_chan_internal.h"
#include "ull_adv_internal.h" #include "ull_adv_internal.h"
#include "ull_sched_internal.h"
#include "ll.h" #include "ll.h"
@ -168,7 +169,8 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref,
*/ */
ticks_anchor = ticker_ticks_now_get(); ticks_anchor = ticker_ticks_now_get();
ticks_slot_overhead = ull_adv_aux_evt_init(aux); ticks_slot_overhead =
ull_adv_aux_evt_init(aux, &ticks_anchor);
ret = ull_adv_aux_start(aux, ticks_anchor, ret = ull_adv_aux_start(aux, ticks_anchor,
ticks_slot_overhead); ticks_slot_overhead);
@ -1039,7 +1041,8 @@ uint8_t ull_adv_aux_lll_handle_get(struct lll_adv_aux *lll)
return ull_adv_aux_handle_get((void *)lll->hdr.parent); return ull_adv_aux_handle_get((void *)lll->hdr.parent);
} }
uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux) uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux,
uint32_t *ticks_anchor)
{ {
uint32_t ticks_slot_overhead; uint32_t ticks_slot_overhead;
struct lll_adv_aux *lll_aux; struct lll_adv_aux *lll_aux;
@ -1071,6 +1074,26 @@ uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux)
ticks_slot_overhead = 0; ticks_slot_overhead = 0;
} }
#if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
uint32_t ticks_anchor_aux;
uint32_t ticks_slot;
int err;
time_us = ull_adv_aux_time_get(aux, PDU_AC_PAYLOAD_SIZE_MAX,
PDU_AC_PAYLOAD_SIZE_MAX);
ticks_slot = HAL_TICKER_US_TO_TICKS(time_us);
err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD,
(ticks_slot +
ticks_slot_overhead),
&ticks_anchor_aux);
if (!err) {
*ticks_anchor = ticks_anchor_aux;
*ticks_anchor += HAL_TICKER_US_TO_TICKS(
EVENT_TICKER_RES_MARGIN_US);
}
#endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
return ticks_slot_overhead; return ticks_slot_overhead;
} }
@ -1082,15 +1105,14 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
uint8_t aux_handle; uint8_t aux_handle;
uint32_t ret; uint32_t ret;
interval_us = aux->interval * PERIODIC_INT_UNIT_US;
ull_hdr_init(&aux->ull); ull_hdr_init(&aux->ull);
aux_handle = ull_adv_aux_handle_get(aux); aux_handle = ull_adv_aux_handle_get(aux);
interval_us = aux->interval * PERIODIC_INT_UNIT_US;
ret_cb = TICKER_STATUS_BUSY; ret_cb = TICKER_STATUS_BUSY;
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD, ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
(TICKER_ID_ADV_AUX_BASE + aux_handle), (TICKER_ID_ADV_AUX_BASE + aux_handle),
ticks_anchor, 0, ticks_anchor, 0U,
HAL_TICKER_US_TO_TICKS(interval_us), HAL_TICKER_US_TO_TICKS(interval_us),
TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
(aux->ull.ticks_slot + ticks_slot_overhead), (aux->ull.ticks_slot + ticks_slot_overhead),
@ -1168,6 +1190,59 @@ void ull_adv_aux_release(struct ll_adv_aux_set *aux)
aux_release(aux); aux_release(aux);
} }
struct ll_adv_aux_set *ull_adv_aux_get(uint8_t handle)
{
if (handle >= CONFIG_BT_CTLR_ADV_AUX_SET) {
return NULL;
}
return &ll_adv_aux_pool[handle];
}
uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len,
uint8_t pdu_scan_len)
{
const struct lll_adv_aux *lll_aux;
const struct lll_adv *lll;
const struct pdu_adv *pdu;
uint32_t time_us;
lll_aux = &aux->lll;
lll = lll_aux->adv;
/* NOTE: 16-bit values are sufficient for minimum radio event time
* reservation, 32-bit are used here so that reservations for
* whole back-to-back chaining of PDUs can be accomodated where
* the required microseconds could overflow 16-bits, example,
* back-to-back chained Coded PHY PDUs.
*/
time_us = PDU_AC_US(pdu_len, lll->phy_s, lll->phy_flags) +
EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
pdu = lll_adv_aux_data_peek(lll_aux);
if ((pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_CONN) ==
BT_HCI_LE_ADV_PROP_CONN) {
const uint16_t conn_req_us =
PDU_AC_MAX_US((INITA_SIZE + ADVA_SIZE + LLDATA_SIZE),
lll->phy_s);
const uint16_t conn_rsp_us =
PDU_AC_US((PDU_AC_EXT_HEADER_SIZE_MIN + ADVA_SIZE +
TARGETA_SIZE), lll->phy_s, lll->phy_flags);
time_us += EVENT_IFS_MAX_US * 2 + conn_req_us + conn_rsp_us;
} else if ((pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_SCAN) ==
BT_HCI_LE_ADV_PROP_SCAN) {
const uint16_t scan_req_us =
PDU_AC_MAX_US((SCANA_SIZE + ADVA_SIZE), lll->phy_s);
const uint16_t scan_rsp_us =
PDU_AC_US(pdu_scan_len, lll->phy_s, lll->phy_flags);
time_us += EVENT_IFS_MAX_US * 2 + scan_req_us + scan_rsp_us;
}
return time_us;
}
void ull_adv_aux_offset_get(struct ll_adv_set *adv) void ull_adv_aux_offset_get(struct ll_adv_set *adv)
{ {
static memq_link_t link; static memq_link_t link;

View file

@ -84,7 +84,8 @@ uint8_t ull_adv_aux_handle_get(struct ll_adv_aux_set *aux);
uint8_t ull_adv_aux_chm_update(void); uint8_t ull_adv_aux_chm_update(void);
/* helper function to initialize event timings */ /* helper function to initialize event timings */
uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux); uint32_t ull_adv_aux_evt_init(struct ll_adv_aux_set *aux,
uint32_t *ticks_anchor);
/* helper function to start auxiliary advertising */ /* helper function to start auxiliary advertising */
uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
@ -99,6 +100,13 @@ struct ll_adv_aux_set *ull_adv_aux_acquire(struct lll_adv *lll);
/* helper function to release auxiliary advertising instance */ /* helper function to release auxiliary advertising instance */
void ull_adv_aux_release(struct ll_adv_aux_set *aux); void ull_adv_aux_release(struct ll_adv_aux_set *aux);
/* helper function to give the auxiliary context */
struct ll_adv_aux_set *ull_adv_aux_get(uint8_t handle);
/* helper function to return time reservation for auxiliary PDU */
uint32_t ull_adv_aux_time_get(const struct ll_adv_aux_set *aux, uint8_t pdu_len,
uint8_t pdu_scan_len);
/* helper function to schedule a mayfly to get aux offset */ /* helper function to schedule a mayfly to get aux offset */
void ull_adv_aux_offset_get(struct ll_adv_set *adv); void ull_adv_aux_offset_get(struct ll_adv_set *adv);

View file

@ -805,7 +805,7 @@ static uint32_t adv_iso_start(struct ll_adv_iso_set *adv_iso,
ticks_slot = adv_iso->ull.ticks_slot + ticks_slot_overhead; ticks_slot = adv_iso->ull.ticks_slot + ticks_slot_overhead;
/* Find the slot after Periodic Advertisings events */ /* Find the slot after Periodic Advertisings events */
err = ull_sched_after_adv_sync_slot_get(TICKER_USER_ID_THREAD, err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD,
ticks_slot, &ticks_anchor); ticks_slot, &ticks_anchor);
if (err) { if (err) {
ticks_anchor = ticker_ticks_now_get(); ticks_anchor = ticker_ticks_now_get();

View file

@ -740,11 +740,15 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
lll_aux = adv->lll.aux; lll_aux = adv->lll.aux;
aux = HDR_LLL2ULL(lll_aux); aux = HDR_LLL2ULL(lll_aux);
ticks_anchor_aux = ticker_ticks_now_get(); ticks_anchor_aux = ticker_ticks_now_get();
ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux); ticks_slot_overhead_aux =
ticks_anchor_sync = ull_adv_aux_evt_init(aux, &ticks_anchor_aux);
ticks_anchor_aux + ticks_slot_overhead_aux + ticks_anchor_sync = ticks_anchor_aux +
aux->ull.ticks_slot + ticks_slot_overhead_aux + aux->ull.ticks_slot +
HAL_TICKER_US_TO_TICKS(EVENT_MAFS_US); HAL_TICKER_US_TO_TICKS(
MAX(EVENT_MAFS_US,
EVENT_OVERHEAD_START_US) -
EVENT_OVERHEAD_START_US +
(EVENT_TICKER_RES_MARGIN_US << 1));
} }
ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync); ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync);

View file

@ -49,8 +49,6 @@
#include "common/log.h" #include "common/log.h"
#include "hal/debug.h" #include "hal/debug.h"
typedef struct ull_hdr *(*ull_hdr_get_func)(uint8_t ticker_id);
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) #if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select, static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select,
@ -60,6 +58,14 @@ static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select,
#endif #endif
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CONN)
static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
uint32_t ticks_anchor,
uint32_t *win_offset_us);
#endif /* CONFIG_BT_CONN */
typedef struct ull_hdr *(*ull_hdr_get_func)(uint8_t ticker_id,
uint32_t *ticks_slot);
static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
ticker_op_match_func ticker_match_op_cb, ticker_op_match_func ticker_match_op_cb,
ull_hdr_get_func ull_hdr_get_cb, ull_hdr_get_func ull_hdr_get_cb,
@ -67,23 +73,13 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint32_t *ticks_to_expire_match, uint32_t *ticks_to_expire_match,
uint32_t *ticks_slot_match); uint32_t *ticks_slot_match);
static void ticker_op_cb(uint32_t status, void *param); static void ticker_op_cb(uint32_t status, void *param);
static bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
#if defined(CONFIG_BT_CONN)
static bool ticker_conn_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire, void *op_context); uint32_t ticks_to_expire, void *op_context);
static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id); static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot);
static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
uint32_t ticks_anchor,
uint32_t *win_offset_us);
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_ISO) #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)
static bool ticker_adv_sync_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot, int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id,
uint32_t ticks_to_expire, uint32_t ticks_slot_abs,
void *op_context);
static struct ull_hdr *adv_sync_ull_hdr_get_cb(uint8_t ticker_id);
int ull_sched_after_adv_sync_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint32_t *ticks_anchor) uint32_t *ticks_anchor)
{ {
uint32_t ticks_to_expire; uint32_t ticks_to_expire;
@ -91,25 +87,63 @@ int ull_sched_after_adv_sync_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint8_t ticker_id; uint8_t ticker_id;
ticker_id = after_match_slot_get(user_id, ticks_slot_abs, ticker_id = after_match_slot_get(user_id, ticks_slot_abs,
ticker_adv_sync_match_op_cb, ticker_match_op_cb, ull_hdr_get_cb,
adv_sync_ull_hdr_get_cb, ticks_anchor, ticks_anchor, &ticks_to_expire,
&ticks_to_expire, &ticks_slot); &ticks_slot);
if (ticker_id != TICKER_NULL) { if (ticker_id != TICKER_NULL) {
const struct ll_adv_sync_set *sync = if (false) {
(void *)adv_sync_ull_hdr_get_cb(ticker_id);
uint32_t time_us;
time_us = ull_adv_sync_time_get(sync, PDU_AC_PAYLOAD_SIZE_MAX); } else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE,
TICKER_ID_ADV_AUX_LAST)) {
const struct ll_adv_aux_set *aux;
aux = (void *)ull_hdr_get_cb(ticker_id, &ticks_slot);
*ticks_anchor += ticks_to_expire; *ticks_anchor += ticks_to_expire;
*ticks_anchor += HAL_TICKER_US_TO_TICKS(time_us); *ticks_anchor += ticks_slot;
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
*ticks_anchor +=
MAX(aux->ull.ticks_active_to_start,
aux->ull.ticks_prepare_to_start);
}
return 0; return 0;
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
} else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE,
TICKER_ID_ADV_SYNC_LAST)) {
const struct ll_adv_sync_set *sync;
sync = (void *)ull_hdr_get_cb(ticker_id, &ticks_slot);
*ticks_anchor += ticks_to_expire;
*ticks_anchor += ticks_slot;
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
*ticks_anchor +=
MAX(sync->ull.ticks_active_to_start,
sync->ull.ticks_prepare_to_start);
}
return 0;
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#if defined(CONFIG_BT_CONN)
} else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE,
TICKER_ID_CONN_LAST)) {
*ticks_anchor += ticks_to_expire;
*ticks_anchor += ticks_slot;
return 0;
#endif /* CONFIG_BT_CONN */
}
} }
return -ECHILD; return -ECHILD;
} }
#endif /* CONFIG_BT_CTLR_ADV_ISO */ #endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */
#if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CONN)
int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
@ -120,9 +154,9 @@ int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint8_t ticker_id; uint8_t ticker_id;
ticker_id = after_match_slot_get(user_id, ticks_slot_abs, ticker_id = after_match_slot_get(user_id, ticks_slot_abs,
ticker_conn_match_op_cb, ticker_match_op_cb, ull_hdr_get_cb,
conn_ull_hdr_get_cb, ticks_anchor, ticks_anchor, &ticks_to_expire,
&ticks_to_expire, &ticks_slot); &ticks_slot);
if (ticker_id != TICKER_NULL) { if (ticker_id != TICKER_NULL) {
*us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire + *us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire +
ticks_slot) + ticks_slot) +
@ -560,6 +594,45 @@ static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select,
} }
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
uint32_t ticks_anchor,
uint32_t *win_offset_us)
{
uint32_t ticks_anchor_offset = ticks_anchor;
int err;
err = ull_sched_after_cen_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot,
&ticks_anchor_offset,
win_offset_us);
if (err) {
return;
}
if ((ticks_anchor_offset - ticks_anchor) & BIT(HAL_TICKER_CNTR_MSBIT)) {
*win_offset_us -= HAL_TICKER_TICKS_TO_US(
ticker_ticks_diff_get(ticks_anchor,
ticks_anchor_offset));
} else {
*win_offset_us += HAL_TICKER_TICKS_TO_US(
ticker_ticks_diff_get(ticks_anchor_offset,
ticks_anchor));
}
/* Round positive offset value in the future to within one connection
* interval value.
* Offsets in the past, value with MSBit set, are handled by caller by
* adding radio end time and connection interval as necessary to get a
* window offset in future when establishing a connection.
*/
if ((*win_offset_us & BIT(31)) == 0) {
uint32_t conn_interval_us = conn_interval * CONN_INT_UNIT_US;
while (*win_offset_us > conn_interval_us) {
*win_offset_us -= conn_interval_us;
}
}
}
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
@ -571,19 +644,40 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
{ {
uint32_t ticks_to_expire_prev; uint32_t ticks_to_expire_prev;
uint32_t ticks_slot_abs_prev; uint32_t ticks_slot_abs_prev;
uint32_t ticks_anchor_prev;
uint32_t ticks_to_expire; uint32_t ticks_to_expire;
uint8_t ticker_id_prev; uint8_t ticker_id_prev;
uint8_t ticker_id; uint8_t ticker_id;
uint8_t retry;
/* As we may place the event between two other events, ensure there is
* space for 3 times +/- 16 us jitter. I.e. with 32KHz sleep clock,
* ~30.517 us after previous event, ~30.517 us before and after current
* event, and an ~30.517 us before next event. Hence 8 time of ceil
* value 16 us (30.517 / 2).
*/
ticks_slot_abs += HAL_TICKER_US_TO_TICKS(EVENT_JITTER_US << 3); ticks_slot_abs += HAL_TICKER_US_TO_TICKS(EVENT_JITTER_US << 3);
/* There is a possibility that ticker nodes expire during iterations in
* this function causing the reference ticks_anchor returned for the
* found ticker to change. In this case the iterations have to be
* restarted with the new reference ticks_anchor value.
* Simultaneous continuous scanning on 1M and Coded PHY, alongwith
* directed advertising and one other state/role could expire in quick
* succession, hence have a retry count of 4.
*/
retry = 4U;
/* Initialize variable required for iterations to find a free slot */
ticker_id = ticker_id_prev = TICKER_NULL; ticker_id = ticker_id_prev = TICKER_NULL;
ticks_anchor_prev = 0U;
ticks_to_expire = ticks_to_expire_prev = 0U; ticks_to_expire = ticks_to_expire_prev = 0U;
ticks_slot_abs_prev = 0U; ticks_slot_abs_prev = 0U;
while (1) { while (1) {
uint32_t ticks_slot_abs_curr = 0U; uint32_t ticks_slot_abs_curr = 0U;
uint32_t ticks_to_expire_normal; uint32_t ticks_to_expire_normal;
uint32_t volatile ret_cb; uint32_t volatile ret_cb;
uint32_t ticks_slot;
struct ull_hdr *hdr; struct ull_hdr *hdr;
uint32_t ret; uint32_t ret;
bool success; bool success;
@ -619,6 +713,21 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
success = (ret_cb == TICKER_STATUS_SUCCESS); success = (ret_cb == TICKER_STATUS_SUCCESS);
LL_ASSERT(success); LL_ASSERT(success);
/* There is a possibility that tickers expire while we
* iterate through the active list of tickers, start over with
* a fresh iteration.
*/
if ((ticker_id_prev != TICKER_NULL) &&
(*ticks_anchor != ticks_anchor_prev)) {
LL_ASSERT(retry);
retry--;
ticker_id = ticker_id_prev = TICKER_NULL;
continue;
}
/* No more active tickers with slot */
if (ticker_id == TICKER_NULL) { if (ticker_id == TICKER_NULL) {
break; break;
} }
@ -629,7 +738,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
} }
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */ #endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
hdr = ull_hdr_get_cb(ticker_id); hdr = ull_hdr_get_cb(ticker_id, &ticks_slot);
if (!hdr) { if (!hdr) {
continue; continue;
} }
@ -658,7 +767,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
} }
#endif #endif
ticks_slot_abs_curr += hdr->ticks_slot; ticks_slot_abs_curr += ticks_slot;
if ((ticker_id_prev != TICKER_NULL) && if ((ticker_id_prev != TICKER_NULL) &&
(ticker_ticks_diff_get(ticks_to_expire_normal, (ticker_ticks_diff_get(ticks_to_expire_normal,
@ -667,6 +776,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
break; break;
} }
ticks_anchor_prev = *ticks_anchor;
ticker_id_prev = ticker_id; ticker_id_prev = ticker_id;
ticks_to_expire_prev = ticks_to_expire_normal; ticks_to_expire_prev = ticks_to_expire_normal;
ticks_slot_abs_prev = ticks_slot_abs_curr; ticks_slot_abs_prev = ticks_slot_abs_curr;
@ -685,86 +795,88 @@ static void ticker_op_cb(uint32_t status, void *param)
*((uint32_t volatile *)param) = status; *((uint32_t volatile *)param) = status;
} }
#if defined(CONFIG_BT_CONN) static bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
static bool ticker_conn_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire, void *op_context) uint32_t ticks_to_expire, void *op_context)
{ {
ARG_UNUSED(ticks_slot); ARG_UNUSED(ticks_slot);
ARG_UNUSED(ticks_to_expire); ARG_UNUSED(ticks_to_expire);
ARG_UNUSED(op_context); ARG_UNUSED(op_context);
return (ticker_id >= TICKER_ID_CONN_BASE) && return false ||
(ticker_id <= TICKER_ID_CONN_LAST);
}
static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id) #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)
{ IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE,
struct ll_conn *conn; TICKER_ID_ADV_AUX_LAST) ||
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE); #if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
if (!conn || conn->lll.role) { IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE,
return NULL; TICKER_ID_ADV_SYNC_LAST) ||
} #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */
return &conn->ull; #if defined(CONFIG_BT_CONN)
} IN_RANGE(ticker_id, TICKER_ID_CONN_BASE,
TICKER_ID_CONN_LAST) ||
static void after_cen_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
uint32_t ticks_anchor,
uint32_t *win_offset_us)
{
uint32_t ticks_anchor_offset = ticks_anchor;
int err;
err = ull_sched_after_cen_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot,
&ticks_anchor_offset,
win_offset_us);
if (err) {
return;
}
if ((ticks_anchor_offset - ticks_anchor) & BIT(HAL_TICKER_CNTR_MSBIT)) {
*win_offset_us -= HAL_TICKER_TICKS_TO_US(
ticker_ticks_diff_get(ticks_anchor,
ticks_anchor_offset));
} else {
*win_offset_us += HAL_TICKER_TICKS_TO_US(
ticker_ticks_diff_get(ticks_anchor_offset,
ticks_anchor));
}
if ((*win_offset_us & BIT(31)) == 0) {
uint32_t conn_interval_us = conn_interval * CONN_INT_UNIT_US;
while (*win_offset_us > conn_interval_us) {
*win_offset_us -= conn_interval_us;
}
}
}
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_ISO) false;
static bool ticker_adv_sync_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire,
void *op_context)
{
ARG_UNUSED(ticks_slot);
ARG_UNUSED(ticks_to_expire);
ARG_UNUSED(op_context);
return (ticker_id >= TICKER_ID_ADV_SYNC_BASE) &&
(ticker_id <= TICKER_ID_ADV_SYNC_LAST);
} }
static struct ull_hdr *adv_sync_ull_hdr_get_cb(uint8_t ticker_id) static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot)
{ {
if (false) {
#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)
} else if (IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE,
TICKER_ID_ADV_AUX_LAST)) {
struct ll_adv_aux_set *aux;
aux = ull_adv_aux_get(ticker_id - TICKER_ID_ADV_AUX_BASE);
if (aux) {
uint32_t time_us;
time_us = ull_adv_aux_time_get(aux,
PDU_AC_PAYLOAD_SIZE_MAX,
PDU_AC_PAYLOAD_SIZE_MAX);
*ticks_slot = HAL_TICKER_US_TO_TICKS(time_us);
return &aux->ull;
}
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
} else if (IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE,
TICKER_ID_ADV_SYNC_LAST)) {
struct ll_adv_sync_set *sync; struct ll_adv_sync_set *sync;
sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE); sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE);
if (!sync) { if (sync) {
return NULL; uint32_t time_us;
}
time_us = ull_adv_sync_time_get(sync,
PDU_AC_PAYLOAD_SIZE_MAX);
*ticks_slot = HAL_TICKER_US_TO_TICKS(time_us);
return &sync->ull; return &sync->ull;
}
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */
#if defined(CONFIG_BT_CONN)
} else if (IN_RANGE(ticker_id, TICKER_ID_CONN_BASE,
TICKER_ID_CONN_LAST)) {
struct ll_conn *conn;
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
if (conn && !conn->lll.role) {
*ticks_slot = conn->ull.ticks_slot;
return &conn->ull;
}
#endif /* CONFIG_BT_CONN */
}
return NULL;
} }
#endif /* CONFIG_BT_CTLR_ADV_ISO */

View file

@ -4,10 +4,11 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id,
uint32_t ticks_slot_abs,
uint32_t *ticks_anchor);
int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, int ull_sched_after_cen_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint32_t *ticks_anchor, uint32_t *us_offset); uint32_t *ticks_anchor, uint32_t *us_offset);
void ull_sched_mfy_win_offset_use(void *param); void ull_sched_mfy_win_offset_use(void *param);
void ull_sched_mfy_free_win_offset_calc(void *param); void ull_sched_mfy_free_win_offset_calc(void *param);
void ull_sched_mfy_win_offset_select(void *param); void ull_sched_mfy_win_offset_select(void *param);
int ull_sched_after_adv_sync_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint32_t *ticks_anchor);