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:
parent
2ea4516a4a
commit
fab4511164
10 changed files with 326 additions and 122 deletions
|
@ -114,8 +114,7 @@ if(CONFIG_BT_LL_SW_SPLIT)
|
|||
)
|
||||
endif()
|
||||
endif()
|
||||
if(CONFIG_BT_CTLR_SCHED_ADVANCED AND
|
||||
(CONFIG_BT_CONN OR CONFIG_BT_CTLR_ADV_ISO))
|
||||
if(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||
zephyr_library_sources(
|
||||
ll_sw/ull_sched.c
|
||||
)
|
||||
|
|
|
@ -341,8 +341,11 @@ config BT_CTLR_XTAL_THRESHOLD
|
|||
|
||||
config BT_CTLR_SCHED_ADVANCED
|
||||
bool "Advanced scheduling"
|
||||
depends on (BT_MAX_CONN != 0) && BT_CTLR_SCHED_ADVANCED_SUPPORT
|
||||
default y if !(BT_PERIPHERAL && !BT_CENTRAL)
|
||||
depends on BT_CTLR_SCHED_ADVANCED_SUPPORT && \
|
||||
(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
|
||||
Enable non-overlapping placement of observer, initiator and central
|
||||
roles in timespace. Uses window offset in connection updates and uses
|
||||
|
|
|
@ -101,7 +101,8 @@ static inline void lll_adv_aux_data_enqueue(struct lll_adv_aux *lll,
|
|||
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];
|
||||
}
|
||||
|
|
|
@ -1407,7 +1407,8 @@ uint8_t ll_adv_enable(uint8_t enable)
|
|||
EVENT_OVERHEAD_START_US +
|
||||
(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)
|
||||
/* Start periodic advertising if enabled and not already
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "ull_internal.h"
|
||||
#include "ull_chan_internal.h"
|
||||
#include "ull_adv_internal.h"
|
||||
#include "ull_sched_internal.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_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,
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -1082,15 +1105,14 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
|
|||
uint8_t aux_handle;
|
||||
uint32_t ret;
|
||||
|
||||
interval_us = aux->interval * PERIODIC_INT_UNIT_US;
|
||||
|
||||
ull_hdr_init(&aux->ull);
|
||||
aux_handle = ull_adv_aux_handle_get(aux);
|
||||
interval_us = aux->interval * PERIODIC_INT_UNIT_US;
|
||||
|
||||
ret_cb = TICKER_STATUS_BUSY;
|
||||
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
|
||||
(TICKER_ID_ADV_AUX_BASE + aux_handle),
|
||||
ticks_anchor, 0,
|
||||
ticks_anchor, 0U,
|
||||
HAL_TICKER_US_TO_TICKS(interval_us),
|
||||
TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
|
||||
(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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
static memq_link_t link;
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
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 */
|
||||
void ull_adv_aux_offset_get(struct ll_adv_set *adv);
|
||||
|
||||
|
|
|
@ -805,8 +805,8 @@ static uint32_t adv_iso_start(struct ll_adv_iso_set *adv_iso,
|
|||
ticks_slot = adv_iso->ull.ticks_slot + ticks_slot_overhead;
|
||||
|
||||
/* Find the slot after Periodic Advertisings events */
|
||||
err = ull_sched_after_adv_sync_slot_get(TICKER_USER_ID_THREAD,
|
||||
ticks_slot, &ticks_anchor);
|
||||
err = ull_sched_adv_aux_sync_free_slot_get(TICKER_USER_ID_THREAD,
|
||||
ticks_slot, &ticks_anchor);
|
||||
if (err) {
|
||||
ticks_anchor = ticker_ticks_now_get();
|
||||
}
|
||||
|
|
|
@ -740,11 +740,15 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
|
|||
lll_aux = adv->lll.aux;
|
||||
aux = HDR_LLL2ULL(lll_aux);
|
||||
ticks_anchor_aux = ticker_ticks_now_get();
|
||||
ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux);
|
||||
ticks_anchor_sync =
|
||||
ticks_anchor_aux + ticks_slot_overhead_aux +
|
||||
aux->ull.ticks_slot +
|
||||
HAL_TICKER_US_TO_TICKS(EVENT_MAFS_US);
|
||||
ticks_slot_overhead_aux =
|
||||
ull_adv_aux_evt_init(aux, &ticks_anchor_aux);
|
||||
ticks_anchor_sync = ticks_anchor_aux +
|
||||
ticks_slot_overhead_aux + aux->ull.ticks_slot +
|
||||
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);
|
||||
|
|
|
@ -49,8 +49,6 @@
|
|||
#include "common/log.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_LL_SW_LLCP_LEGACY)
|
||||
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 /* 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,
|
||||
ticker_op_match_func ticker_match_op_cb,
|
||||
ull_hdr_get_func ull_hdr_get_cb,
|
||||
|
@ -67,49 +73,77 @@ 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_slot_match);
|
||||
static void ticker_op_cb(uint32_t status, void *param);
|
||||
static bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
|
||||
uint32_t ticks_to_expire, void *op_context);
|
||||
static struct ull_hdr *ull_hdr_get_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);
|
||||
static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id);
|
||||
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)
|
||||
static bool ticker_adv_sync_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
|
||||
uint32_t ticks_to_expire,
|
||||
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)
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)
|
||||
int ull_sched_adv_aux_sync_free_slot_get(uint8_t user_id,
|
||||
uint32_t ticks_slot_abs,
|
||||
uint32_t *ticks_anchor)
|
||||
{
|
||||
uint32_t ticks_to_expire;
|
||||
uint32_t ticks_slot;
|
||||
uint8_t ticker_id;
|
||||
|
||||
ticker_id = after_match_slot_get(user_id, ticks_slot_abs,
|
||||
ticker_adv_sync_match_op_cb,
|
||||
adv_sync_ull_hdr_get_cb, ticks_anchor,
|
||||
&ticks_to_expire, &ticks_slot);
|
||||
ticker_match_op_cb, ull_hdr_get_cb,
|
||||
ticks_anchor, &ticks_to_expire,
|
||||
&ticks_slot);
|
||||
if (ticker_id != TICKER_NULL) {
|
||||
const struct ll_adv_sync_set *sync =
|
||||
(void *)adv_sync_ull_hdr_get_cb(ticker_id);
|
||||
uint32_t time_us;
|
||||
if (false) {
|
||||
|
||||
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;
|
||||
|
||||
*ticks_anchor += ticks_to_expire;
|
||||
*ticks_anchor += HAL_TICKER_US_TO_TICKS(time_us);
|
||||
aux = (void *)ull_hdr_get_cb(ticker_id, &ticks_slot);
|
||||
|
||||
return 0;
|
||||
*ticks_anchor += ticks_to_expire;
|
||||
*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;
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO */
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */
|
||||
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
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;
|
||||
|
||||
ticker_id = after_match_slot_get(user_id, ticks_slot_abs,
|
||||
ticker_conn_match_op_cb,
|
||||
conn_ull_hdr_get_cb, ticks_anchor,
|
||||
&ticks_to_expire, &ticks_slot);
|
||||
ticker_match_op_cb, ull_hdr_get_cb,
|
||||
ticks_anchor, &ticks_to_expire,
|
||||
&ticks_slot);
|
||||
if (ticker_id != TICKER_NULL) {
|
||||
*us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire +
|
||||
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_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 */
|
||||
|
||||
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_slot_abs_prev;
|
||||
uint32_t ticks_anchor_prev;
|
||||
uint32_t ticks_to_expire;
|
||||
uint8_t ticker_id_prev;
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
ticks_anchor_prev = 0U;
|
||||
ticks_to_expire = ticks_to_expire_prev = 0U;
|
||||
ticks_slot_abs_prev = 0U;
|
||||
while (1) {
|
||||
uint32_t ticks_slot_abs_curr = 0U;
|
||||
uint32_t ticks_to_expire_normal;
|
||||
uint32_t volatile ret_cb;
|
||||
uint32_t ticks_slot;
|
||||
struct ull_hdr *hdr;
|
||||
uint32_t ret;
|
||||
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);
|
||||
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) {
|
||||
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 */
|
||||
|
||||
hdr = ull_hdr_get_cb(ticker_id);
|
||||
hdr = ull_hdr_get_cb(ticker_id, &ticks_slot);
|
||||
if (!hdr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -658,7 +767,7 @@ static uint8_t after_match_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
|
|||
}
|
||||
#endif
|
||||
|
||||
ticks_slot_abs_curr += hdr->ticks_slot;
|
||||
ticks_slot_abs_curr += ticks_slot;
|
||||
|
||||
if ((ticker_id_prev != TICKER_NULL) &&
|
||||
(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;
|
||||
}
|
||||
|
||||
ticks_anchor_prev = *ticks_anchor;
|
||||
ticker_id_prev = ticker_id;
|
||||
ticks_to_expire_prev = ticks_to_expire_normal;
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
static bool ticker_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_CONN_BASE) &&
|
||||
(ticker_id <= TICKER_ID_CONN_LAST);
|
||||
}
|
||||
return false ||
|
||||
|
||||
static struct ull_hdr *conn_ull_hdr_get_cb(uint8_t ticker_id)
|
||||
{
|
||||
struct ll_conn *conn;
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_BROADCASTER)
|
||||
IN_RANGE(ticker_id, TICKER_ID_ADV_AUX_BASE,
|
||||
TICKER_ID_ADV_AUX_LAST) ||
|
||||
|
||||
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
|
||||
if (!conn || conn->lll.role) {
|
||||
return NULL;
|
||||
}
|
||||
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
|
||||
IN_RANGE(ticker_id, TICKER_ID_ADV_SYNC_BASE,
|
||||
TICKER_ID_ADV_SYNC_LAST) ||
|
||||
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_BROADCASTER */
|
||||
|
||||
return &conn->ull;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
IN_RANGE(ticker_id, TICKER_ID_CONN_BASE,
|
||||
TICKER_ID_CONN_LAST) ||
|
||||
#endif /* CONFIG_BT_CONN */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_ISO)
|
||||
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);
|
||||
false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ll_adv_sync_set *sync;
|
||||
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;
|
||||
|
||||
sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE);
|
||||
if (sync) {
|
||||
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;
|
||||
}
|
||||
#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 */
|
||||
|
||||
sync = ull_adv_sync_get(ticker_id - TICKER_ID_ADV_SYNC_BASE);
|
||||
if (!sync) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &sync->ull;
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO */
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* 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,
|
||||
uint32_t *ticks_anchor, uint32_t *us_offset);
|
||||
void ull_sched_mfy_win_offset_use(void *param);
|
||||
void ull_sched_mfy_free_win_offset_calc(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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue