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()
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue