Bluetooth: controller: split: Port advanced scheduling
Port advanced scheduling implementation from legacy controller. This implementation schedules - non-overlapping scan window when there are simulataneous central connections active - central connection establishment with similar connection intervals be placed in a non-overlapping group, temporally - connection parameter request with calculated window offset hints to have non-overlapping BLE radio events. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
0b6664fc3d
commit
6dce205b95
6 changed files with 558 additions and 43 deletions
|
@ -30,6 +30,7 @@
|
|||
#include "lll_conn.h"
|
||||
#include "lll_chan.h"
|
||||
#include "lll_filter.h"
|
||||
#include "lll_sched.h"
|
||||
|
||||
#include "lll_internal.h"
|
||||
#include "lll_tim_internal.h"
|
||||
|
@ -117,11 +118,11 @@ static int init_reset(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_cb(struct lll_prepare_param *prepare_param)
|
||||
static int prepare_cb(struct lll_prepare_param *p)
|
||||
{
|
||||
struct lll_scan *lll = prepare_param->param;
|
||||
uint32_t aa = sys_cpu_to_le32(PDU_AC_ACCESS_ADDR);
|
||||
uint32_t ticks_at_event, ticks_at_start;
|
||||
struct lll_scan *lll = p->param;
|
||||
struct node_rx_pdu *node_rx;
|
||||
struct evt_hdr *evt;
|
||||
uint32_t remainder_us;
|
||||
|
@ -200,14 +201,14 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
|
|||
(uint8_t *)wl->bdaddr);
|
||||
}
|
||||
|
||||
ticks_at_event = prepare_param->ticks_at_expire;
|
||||
ticks_at_event = p->ticks_at_expire;
|
||||
evt = HDR_LLL2EVT(lll);
|
||||
ticks_at_event += lll_evt_offset_get(evt);
|
||||
|
||||
ticks_at_start = ticks_at_event;
|
||||
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
|
||||
|
||||
remainder = prepare_param->remainder;
|
||||
remainder = p->remainder;
|
||||
remainder_us = radio_tmr_start(0, ticks_at_start, remainder);
|
||||
|
||||
/* capture end of Rx-ed PDU, for initiator to calculate first
|
||||
|
@ -256,6 +257,26 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
|
|||
(ret == TICKER_STATUS_BUSY));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||
/* calc next group in us for the anchor where first connection
|
||||
* event to be placed.
|
||||
*/
|
||||
if (lll->conn) {
|
||||
static memq_link_t link;
|
||||
static struct mayfly mfy_after_mstr_offset_get = {
|
||||
0, 0, &link, NULL,
|
||||
ull_sched_mfy_after_mstr_offset_get};
|
||||
uint32_t retval;
|
||||
|
||||
mfy_after_mstr_offset_get.param = p;
|
||||
|
||||
retval = mayfly_enqueue(TICKER_USER_ID_LLL,
|
||||
TICKER_USER_ID_ULL_LOW, 1,
|
||||
&mfy_after_mstr_offset_get);
|
||||
LL_ASSERT(!retval);
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||
|
||||
ret = lll_prepare_done(lll);
|
||||
LL_ASSERT(!ret);
|
||||
}
|
||||
|
|
7
subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sched.h
Normal file
7
subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sched.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
extern void ull_sched_mfy_after_mstr_offset_get(void *param);
|
|
@ -14,6 +14,8 @@
|
|||
*/
|
||||
#define EVENT_OVERHEAD_END_US 40
|
||||
#define EVENT_JITTER_US 16
|
||||
/* Inter-Event Space (IES) */
|
||||
#define EVENT_TIES_US 625
|
||||
/* Ticker resolution margin
|
||||
* Needed due to the lack of fine timing resolution in ticker_start
|
||||
* and ticker_update. Set to 32 us, which is ~1 tick with 32768 Hz
|
||||
|
|
|
@ -167,7 +167,6 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan)
|
|||
volatile uint32_t ret_cb = TICKER_STATUS_BUSY;
|
||||
struct lll_scan *lll = &scan->lll;
|
||||
uint32_t ticks_slot_overhead;
|
||||
uint32_t ticks_slot_offset;
|
||||
uint32_t ticks_interval;
|
||||
uint32_t ticks_anchor;
|
||||
uint32_t ret;
|
||||
|
@ -205,11 +204,9 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan)
|
|||
lll->ticks_window = 0;
|
||||
}
|
||||
|
||||
ticks_slot_offset = MAX(scan->evt.ticks_active_to_start,
|
||||
scan->evt.ticks_xtal_to_start);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
||||
ticks_slot_overhead = ticks_slot_offset;
|
||||
ticks_slot_overhead = MAX(scan->evt.ticks_active_to_start,
|
||||
scan->evt.ticks_xtal_to_start);
|
||||
} else {
|
||||
ticks_slot_overhead = 0U;
|
||||
}
|
||||
|
@ -222,8 +219,8 @@ uint8_t ull_scan_enable(struct ll_scan_set *scan)
|
|||
uint32_t offset_us = 0U;
|
||||
|
||||
ull_sched_after_mstr_slot_get(TICKER_USER_ID_THREAD,
|
||||
(ticks_slot_offset +
|
||||
scan->evt.ticks_slot),
|
||||
(scan->evt.ticks_slot +
|
||||
ticks_slot_overhead),
|
||||
&ticks_ref, &offset_us);
|
||||
|
||||
/* Use the ticks_ref as scanner's anchor if a free time space
|
||||
|
@ -403,26 +400,6 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t laz
|
|||
0, &mfy);
|
||||
LL_ASSERT(!ret);
|
||||
|
||||
#if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
|
||||
/* calc next group in us for the anchor where first connection event
|
||||
* to be placed
|
||||
*/
|
||||
if (scan->lll.conn) {
|
||||
static memq_link_t s_link;
|
||||
static struct mayfly s_mfy_sched_after_mstr_offset_get = {
|
||||
0, 0, &s_link, NULL,
|
||||
ull_sched_mfy_after_mstr_offset_get};
|
||||
uint32_t retval;
|
||||
|
||||
s_mfy_sched_after_mstr_offset_get.param = (void *)scan;
|
||||
|
||||
retval = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
|
||||
TICKER_USER_ID_ULL_LOW, 1,
|
||||
&s_mfy_sched_after_mstr_offset_get);
|
||||
LL_ASSERT(!retval);
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */
|
||||
|
||||
DEBUG_RADIO_PREPARE_O(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,43 +4,552 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <toolchain.h>
|
||||
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
#include <hal/ticker.h>
|
||||
|
||||
#include "util/memq.h"
|
||||
#include "util/mayfly.h"
|
||||
|
||||
#include "ticker/ticker.h"
|
||||
|
||||
#include "pdu.h"
|
||||
|
||||
#include "lll.h"
|
||||
#include "lll_vendor.h"
|
||||
#include "lll_scan.h"
|
||||
#include "lll_conn.h"
|
||||
|
||||
#include "ull_scan_types.h"
|
||||
#include "ull_conn_types.h"
|
||||
|
||||
#include "ull_internal.h"
|
||||
#include "ull_conn_internal.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#define LOG_MODULE_NAME bt_ctlr_ull_sched
|
||||
#include "common/log.h"
|
||||
#include "hal/debug.h"
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select,
|
||||
uint32_t *ticks_to_offset_next,
|
||||
uint16_t conn_interval, uint8_t *offset_max,
|
||||
uint8_t *win_offset);
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
static void after_mstr_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
|
||||
uint32_t ticks_anchor,
|
||||
uint32_t *win_offset_us);
|
||||
static void ticker_op_cb(uint32_t status, void *param);
|
||||
|
||||
void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
|
||||
uint32_t *ticks_anchor, uint32_t *us_offset)
|
||||
{
|
||||
/* TODO: */
|
||||
uint32_t ticks_to_expire_prev;
|
||||
uint32_t ticks_slot_abs_prev;
|
||||
uint32_t ticks_to_expire;
|
||||
uint8_t ticker_id_prev;
|
||||
uint8_t ticker_id;
|
||||
|
||||
ticks_slot_abs += HAL_TICKER_US_TO_TICKS(EVENT_JITTER_US << 3);
|
||||
|
||||
ticker_id = ticker_id_prev = 0xff;
|
||||
ticks_to_expire = ticks_to_expire_prev = *us_offset = 0U;
|
||||
ticks_slot_abs_prev = 0U;
|
||||
while (1) {
|
||||
uint32_t volatile ret_cb = TICKER_STATUS_BUSY;
|
||||
struct ll_conn *conn;
|
||||
uint32_t ret;
|
||||
|
||||
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id,
|
||||
&ticker_id, ticks_anchor,
|
||||
&ticks_to_expire, ticker_op_cb,
|
||||
(void *)&ret_cb);
|
||||
|
||||
if (ret == TICKER_STATUS_BUSY) {
|
||||
while (ret_cb == TICKER_STATUS_BUSY) {
|
||||
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
|
||||
user_id);
|
||||
}
|
||||
}
|
||||
|
||||
LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
|
||||
|
||||
if (ticker_id == 0xff) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ticker_id < TICKER_ID_CONN_BASE) ||
|
||||
(ticker_id > TICKER_ID_CONN_LAST)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
|
||||
if (conn && !conn->lll.role) {
|
||||
uint32_t ticks_to_expire_normal = ticks_to_expire;
|
||||
uint32_t ticks_slot_abs_curr = 0;
|
||||
#if defined(CONFIG_BT_CTLR_LOW_LAT)
|
||||
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
|
||||
if (conn->evt.ticks_xtal_to_start & XON_BITMASK) {
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn->evt.ticks_active_to_start,
|
||||
conn->evt.ticks_preempt_to_start);
|
||||
|
||||
ticks_slot_abs_curr =
|
||||
conn->evt.ticks_xtal_to_start &
|
||||
~XON_BITMASK;
|
||||
ticks_to_expire_normal -=
|
||||
ticks_slot_abs_curr -
|
||||
ticks_prepare_to_start;
|
||||
} else
|
||||
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
||||
{
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn->evt.ticks_active_to_start,
|
||||
conn->evt.ticks_xtal_to_start);
|
||||
|
||||
ticks_slot_abs_curr = ticks_prepare_to_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
ticks_slot_abs_curr +=
|
||||
conn->evt.ticks_slot +
|
||||
HAL_TICKER_US_TO_TICKS(EVENT_JITTER_US << 3);
|
||||
|
||||
if ((ticker_id_prev != 0xff) &&
|
||||
(ticker_ticks_diff_get(ticks_to_expire_normal,
|
||||
ticks_to_expire_prev) >
|
||||
(ticks_slot_abs_prev + ticks_slot_abs))) {
|
||||
break;
|
||||
}
|
||||
|
||||
ticker_id_prev = ticker_id;
|
||||
ticks_to_expire_prev = ticks_to_expire_normal;
|
||||
ticks_slot_abs_prev = ticks_slot_abs_curr;
|
||||
}
|
||||
}
|
||||
|
||||
if (ticker_id_prev != 0xff) {
|
||||
*us_offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire_prev +
|
||||
ticks_slot_abs_prev) +
|
||||
(EVENT_JITTER_US << 3);
|
||||
}
|
||||
}
|
||||
|
||||
void ull_sched_mfy_after_mstr_offset_get(void *param)
|
||||
{
|
||||
struct ll_scan_set *scan = param;
|
||||
struct lll_prepare_param *p = param;
|
||||
struct lll_scan *lll = p->param;
|
||||
struct evt_hdr *conn_evt = HDR_LLL2EVT(lll->conn);
|
||||
uint32_t ticks_slot_overhead;
|
||||
|
||||
/* TODO: */
|
||||
scan->lll.conn_win_offset_us = 0;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
||||
ticks_slot_overhead = MAX(conn_evt->ticks_active_to_start,
|
||||
conn_evt->ticks_xtal_to_start);
|
||||
} else {
|
||||
ticks_slot_overhead = 0U;
|
||||
}
|
||||
|
||||
void ull_sched_mfy_free_win_offset_calc(void *param)
|
||||
{
|
||||
/* TODO: */
|
||||
after_mstr_offset_get(lll->conn->interval,
|
||||
(ticks_slot_overhead + conn_evt->ticks_slot),
|
||||
p->ticks_at_expire, &lll->conn_win_offset_us);
|
||||
}
|
||||
|
||||
void ull_sched_mfy_win_offset_use(void *param)
|
||||
{
|
||||
/* TODO: */
|
||||
struct ll_conn *conn = param;
|
||||
uint32_t ticks_slot_overhead;
|
||||
uint16_t win_offset;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
||||
ticks_slot_overhead = MAX(conn->evt.ticks_active_to_start,
|
||||
conn->evt.ticks_xtal_to_start);
|
||||
} else {
|
||||
ticks_slot_overhead = 0U;
|
||||
}
|
||||
|
||||
after_mstr_offset_get(conn->lll.interval,
|
||||
(ticks_slot_overhead + conn->evt.ticks_slot),
|
||||
conn->llcp.conn_upd.ticks_anchor,
|
||||
&conn->llcp_cu.win_offset_us);
|
||||
|
||||
win_offset = conn->llcp_cu.win_offset_us / 1250;
|
||||
|
||||
/* TODO: endianness */
|
||||
memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset,
|
||||
sizeof(uint16_t));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
void ull_sched_mfy_free_win_offset_calc(void *param)
|
||||
{
|
||||
uint32_t ticks_to_offset_default = 0U;
|
||||
uint32_t *ticks_to_offset_next;
|
||||
struct ll_conn *conn = param;
|
||||
uint8_t offset_max = 6U;
|
||||
|
||||
ticks_to_offset_next = &ticks_to_offset_default;
|
||||
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
if (conn->lll.role) {
|
||||
conn->llcp_conn_param.ticks_to_offset_next =
|
||||
conn->slave.ticks_to_offset;
|
||||
|
||||
ticks_to_offset_next =
|
||||
&conn->llcp_conn_param.ticks_to_offset_next;
|
||||
}
|
||||
#endif /* CONFIG_BT_PERIPHERAL */
|
||||
|
||||
win_offset_calc(conn, 0, ticks_to_offset_next,
|
||||
conn->llcp_conn_param.interval_max, &offset_max,
|
||||
(void *)conn->llcp_conn_param.pdu_win_offset0);
|
||||
}
|
||||
|
||||
void ull_sched_mfy_win_offset_select(void *param)
|
||||
{
|
||||
/* TODO: */
|
||||
#define OFFSET_S_MAX 6
|
||||
#define OFFSET_M_MAX 6
|
||||
uint16_t win_offset_m[OFFSET_M_MAX] = {0, };
|
||||
uint8_t offset_m_max = OFFSET_M_MAX;
|
||||
struct ll_conn *conn = param;
|
||||
uint8_t offset_index_s = 0U;
|
||||
uint8_t has_offset_s = 0U;
|
||||
uint32_t ticks_to_offset;
|
||||
uint16_t win_offset_s;
|
||||
|
||||
ticks_to_offset = HAL_TICKER_US_TO_TICKS(conn->llcp_conn_param.offset0 *
|
||||
1250);
|
||||
|
||||
win_offset_calc(conn, 1, &ticks_to_offset,
|
||||
conn->llcp_conn_param.interval_max, &offset_m_max,
|
||||
(void *)win_offset_m);
|
||||
|
||||
while (offset_index_s < OFFSET_S_MAX) {
|
||||
uint8_t offset_index_m = 0U;
|
||||
|
||||
memcpy((uint8_t *)&win_offset_s,
|
||||
((uint8_t *)&conn->llcp_conn_param.offset0 +
|
||||
(sizeof(uint16_t) * offset_index_s)), sizeof(uint16_t));
|
||||
|
||||
while (offset_index_m < offset_m_max) {
|
||||
if (win_offset_s != 0xffff) {
|
||||
if (win_offset_s ==
|
||||
win_offset_m[offset_index_m]) {
|
||||
break;
|
||||
}
|
||||
|
||||
has_offset_s = 1U;
|
||||
}
|
||||
|
||||
offset_index_m++;
|
||||
}
|
||||
|
||||
if (offset_index_m < offset_m_max) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset_index_s++;
|
||||
}
|
||||
|
||||
if (offset_index_s < OFFSET_S_MAX) {
|
||||
conn->llcp_cu.win_offset_us = win_offset_s * 1250;
|
||||
memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_s,
|
||||
sizeof(uint16_t));
|
||||
} else if (!has_offset_s) {
|
||||
conn->llcp_cu.win_offset_us = win_offset_m[0] * 1250;
|
||||
memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_m[0],
|
||||
sizeof(uint16_t));
|
||||
} else {
|
||||
struct pdu_data *pdu_ctrl_tx;
|
||||
|
||||
/* procedure request acked */
|
||||
conn->llcp_ack = conn->llcp_req;
|
||||
|
||||
/* CPR request acked */
|
||||
conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
|
||||
|
||||
/* reset mutex */
|
||||
ull_conn_upd_curr_reset();
|
||||
|
||||
/* send reject_ind_ext */
|
||||
pdu_ctrl_tx = (void *)
|
||||
((uint8_t *)conn->llcp.conn_upd.pdu_win_offset -
|
||||
offsetof(struct pdu_data,
|
||||
llctrl.conn_update_ind.win_offset));
|
||||
pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL;
|
||||
pdu_ctrl_tx->len =
|
||||
offsetof(struct pdu_data_llctrl, reject_ext_ind) +
|
||||
sizeof(struct pdu_data_llctrl_reject_ext_ind);
|
||||
pdu_ctrl_tx->llctrl.opcode =
|
||||
PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND;
|
||||
pdu_ctrl_tx->llctrl.reject_ext_ind.reject_opcode =
|
||||
PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
||||
pdu_ctrl_tx->llctrl.reject_ext_ind.error_code =
|
||||
BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
|
||||
}
|
||||
#undef OFFSET_S_MAX
|
||||
#undef OFFSET_M_MAX
|
||||
}
|
||||
|
||||
static void win_offset_calc(struct ll_conn *conn_curr, uint8_t is_select,
|
||||
uint32_t *ticks_to_offset_next,
|
||||
uint16_t conn_interval, uint8_t *offset_max,
|
||||
uint8_t *win_offset)
|
||||
{
|
||||
uint32_t ticks_prepare_reduced = 0U;
|
||||
uint32_t ticks_to_expire_prev;
|
||||
uint32_t ticks_slot_abs_prev;
|
||||
uint32_t ticks_slot_abs = 0U;
|
||||
uint32_t ticks_anchor_prev;
|
||||
uint32_t ticks_to_expire;
|
||||
uint8_t ticker_id_other;
|
||||
uint8_t ticker_id_prev;
|
||||
uint32_t ticks_anchor;
|
||||
uint8_t offset_index;
|
||||
uint8_t ticker_id;
|
||||
uint16_t offset;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LOW_LAT)
|
||||
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
|
||||
if (conn_curr->evt.ticks_xtal_to_start & XON_BITMASK) {
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn_curr->evt.ticks_active_to_start,
|
||||
conn_curr->evt.ticks_preempt_to_start);
|
||||
|
||||
ticks_slot_abs = conn_curr->evt.ticks_xtal_to_start &
|
||||
~XON_BITMASK;
|
||||
ticks_prepare_reduced = ticks_slot_abs - ticks_prepare_to_start;
|
||||
} else
|
||||
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
||||
{
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn_curr->evt.ticks_active_to_start,
|
||||
conn_curr->evt.ticks_xtal_to_start);
|
||||
|
||||
ticks_slot_abs = ticks_prepare_to_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
ticks_slot_abs += conn_curr->evt.ticks_slot;
|
||||
|
||||
if (conn_curr->lll.role) {
|
||||
ticks_slot_abs += HAL_TICKER_US_TO_TICKS(EVENT_TIES_US);
|
||||
}
|
||||
|
||||
ticker_id = ticker_id_prev = ticker_id_other = 0xff;
|
||||
ticks_to_expire = ticks_to_expire_prev = ticks_anchor =
|
||||
ticks_anchor_prev = offset_index = offset = 0U;
|
||||
ticks_slot_abs_prev = 0U;
|
||||
do {
|
||||
uint32_t volatile ret_cb = TICKER_STATUS_BUSY;
|
||||
struct ll_conn *conn;
|
||||
uint32_t ret;
|
||||
|
||||
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR,
|
||||
TICKER_USER_ID_ULL_LOW,
|
||||
&ticker_id, &ticks_anchor,
|
||||
&ticks_to_expire, ticker_op_cb,
|
||||
(void *)&ret_cb);
|
||||
if (ret == TICKER_STATUS_BUSY) {
|
||||
while (ret_cb == TICKER_STATUS_BUSY) {
|
||||
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
|
||||
TICKER_USER_ID_ULL_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
|
||||
|
||||
if (ticker_id == 0xff) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* ticks_anchor shall not change during this loop */
|
||||
if ((ticker_id_prev != 0xff) &&
|
||||
(ticks_anchor != ticks_anchor_prev)) {
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
|
||||
/* consider advertiser time as available. Any other time used by
|
||||
* tickers declared outside the controller is also available.
|
||||
*/
|
||||
#if defined(CONFIG_BT_BROADCASTER)
|
||||
if ((ticker_id < TICKER_ID_ADV_BASE) ||
|
||||
(ticker_id > TICKER_ID_CONN_LAST))
|
||||
#else /* !CONFIG_BT_BROADCASTER */
|
||||
if ((ticker_id < TICKER_ID_SCAN_BASE) ||
|
||||
(ticker_id > TICKER_ID_CONN_LAST))
|
||||
#endif /* !CONFIG_BT_BROADCASTER */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ticker_id < TICKER_ID_CONN_BASE) {
|
||||
/* non conn role found which could have preempted a
|
||||
* conn role, hence do not consider this free space
|
||||
* and any further as free slot for offset,
|
||||
*/
|
||||
ticker_id_other = ticker_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: handle scanner; for now we exit with as much we
|
||||
* where able to fill (offsets).
|
||||
*/
|
||||
if (ticker_id_other != 0xff) {
|
||||
break;
|
||||
}
|
||||
|
||||
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
|
||||
if ((conn != conn_curr) && (is_select || !conn->lll.role)) {
|
||||
uint32_t ticks_to_expire_normal =
|
||||
ticks_to_expire + ticks_prepare_reduced;
|
||||
uint32_t ticks_slot_margin = 0U;
|
||||
uint32_t ticks_slot_abs_curr = 0U;
|
||||
#if defined(CONFIG_BT_CTLR_LOW_LAT)
|
||||
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED)
|
||||
if (conn->evt.ticks_xtal_to_start & XON_BITMASK) {
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn->evt.ticks_active_to_start,
|
||||
conn->evt.ticks_preempt_to_start);
|
||||
|
||||
ticks_slot_abs_curr =
|
||||
conn->evt.ticks_xtal_to_start &
|
||||
~XON_BITMASK;
|
||||
ticks_to_expire_normal -=
|
||||
ticks_slot_abs_curr -
|
||||
ticks_prepare_to_start;
|
||||
} else
|
||||
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
||||
{
|
||||
uint32_t ticks_prepare_to_start =
|
||||
MAX(conn->evt.ticks_active_to_start,
|
||||
conn->evt.ticks_xtal_to_start);
|
||||
|
||||
ticks_slot_abs_curr = ticks_prepare_to_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
ticks_slot_abs_curr += conn->evt.ticks_slot +
|
||||
HAL_TICKER_US_TO_TICKS(1250);
|
||||
|
||||
if (conn->lll.role) {
|
||||
ticks_slot_margin =
|
||||
HAL_TICKER_US_TO_TICKS(EVENT_TIES_US);
|
||||
ticks_slot_abs_curr += ticks_slot_margin;
|
||||
}
|
||||
|
||||
if (*ticks_to_offset_next < ticks_to_expire_normal) {
|
||||
if (ticks_to_expire_prev <
|
||||
*ticks_to_offset_next) {
|
||||
ticks_to_expire_prev =
|
||||
*ticks_to_offset_next;
|
||||
}
|
||||
|
||||
while ((offset_index < *offset_max) &&
|
||||
(ticker_ticks_diff_get(
|
||||
ticks_to_expire_normal,
|
||||
ticks_to_expire_prev) >=
|
||||
(ticks_slot_abs_prev + ticks_slot_abs +
|
||||
ticks_slot_margin))) {
|
||||
offset = HAL_TICKER_TICKS_TO_US(
|
||||
ticks_to_expire_prev +
|
||||
ticks_slot_abs_prev) / 1250;
|
||||
if (offset >= conn_interval) {
|
||||
ticks_to_expire_prev = 0U;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(win_offset + (sizeof(uint16_t) *
|
||||
offset_index),
|
||||
&offset, sizeof(uint16_t));
|
||||
offset_index++;
|
||||
|
||||
ticks_to_expire_prev +=
|
||||
HAL_TICKER_US_TO_TICKS(1250);
|
||||
}
|
||||
|
||||
*ticks_to_offset_next = ticks_to_expire_prev;
|
||||
|
||||
if (offset >= conn_interval) {
|
||||
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;
|
||||
}
|
||||
} while (offset_index < *offset_max);
|
||||
|
||||
if (ticker_id == 0xff) {
|
||||
if (ticks_to_expire_prev < *ticks_to_offset_next) {
|
||||
ticks_to_expire_prev = *ticks_to_offset_next;
|
||||
}
|
||||
|
||||
while (offset_index < *offset_max) {
|
||||
offset = HAL_TICKER_TICKS_TO_US(ticks_to_expire_prev +
|
||||
ticks_slot_abs_prev) /
|
||||
1250;
|
||||
if (offset >= conn_interval) {
|
||||
ticks_to_expire_prev = 0U;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(win_offset + (sizeof(uint16_t) * offset_index),
|
||||
&offset, sizeof(uint16_t));
|
||||
offset_index++;
|
||||
|
||||
ticks_to_expire_prev += HAL_TICKER_US_TO_TICKS(1250);
|
||||
}
|
||||
|
||||
*ticks_to_offset_next = ticks_to_expire_prev;
|
||||
}
|
||||
|
||||
*offset_max = offset_index;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
static void after_mstr_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;
|
||||
|
||||
ull_sched_after_mstr_slot_get(TICKER_USER_ID_ULL_LOW, ticks_slot,
|
||||
&ticks_anchor_offset, win_offset_us);
|
||||
|
||||
if (!*win_offset_us) {
|
||||
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 * 1250;
|
||||
|
||||
while (*win_offset_us > conn_interval_us) {
|
||||
*win_offset_us -= conn_interval_us;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ticker_op_cb(uint32_t status, void *param)
|
||||
{
|
||||
*((uint32_t volatile *)param) = status;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
|
||||
uint32_t *ticks_anchor, uint32_t *us_offset);
|
||||
void ull_sched_mfy_after_mstr_offset_get(void *param);
|
||||
void ull_sched_mfy_free_win_offset_calc(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_win_offset_select(void *param);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue