Pushes all work done in the topic-ble-llcp branch into main branch This is a refactoring of the LL control procedures; the refactored control procedures are hidden behind a KConfig option and per default disabled Goal of the refactoring: close issue Link Layer Control Procedure overhaul #15256 make it easier to add/update control procedures Refactoring consists in principal of writing explicit state machines for the control procedures. To reduce the risk of regression errors unit-tests have been added Following control procedures are implemented: Connection update procedure Channel map update procedure Encryption procedure Feature exchange procedure Version exchange procedure ACL termination procedure Connection parameters request procedure LE Ping procedure Data Length Update procedure PHY update procedure Min. nr. Of channels used procedure Constant Tone extension request procedure This is a joined work by the people listed in the signed-off-by list (in alphabetical order) Signed-off-by: Andries Kruithof Andries.Kruithof@nordicsemi.no Signed-off-by: Erik Brockhoff erbr@oticon.com Signed-off-by: Piotr Pryga piotr.pryga@nordicsemi.no Signed-off-by: Szymon Janc szymon.janc@codecoup.pl Signed-off-by: Thomas Ebert Hansen thoh@oticon.com Signed-off-by: Tommie Skriver tosk@demant.com Signed-off-by: Andries Kruithof <Andries.Kruithof@nordicsemi.no>
637 lines
17 KiB
C
637 lines
17 KiB
C
/*
|
|
* Copyright (c) 2018-2019 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
|
|
#include <sys/byteorder.h>
|
|
|
|
#include "hal/ccm.h"
|
|
#include "hal/radio.h"
|
|
#include "hal/ticker.h"
|
|
|
|
#include "util/util.h"
|
|
#include "util/memq.h"
|
|
#include "util/mayfly.h"
|
|
|
|
#include "ticker/ticker.h"
|
|
|
|
#include "pdu.h"
|
|
|
|
#include "lll.h"
|
|
#include "lll/lll_vendor.h"
|
|
#include "lll_scan.h"
|
|
#include "lll/lll_df_types.h"
|
|
#include "lll_conn.h"
|
|
|
|
#if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
#include "ull_tx_queue.h"
|
|
#endif
|
|
|
|
#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)
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
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
|
|
#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);
|
|
|
|
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
|
|
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);
|
|
|
|
bool match = ticker_id >= TICKER_ID_CONN_BASE &&
|
|
ticker_id <= TICKER_ID_CONN_LAST;
|
|
return match;
|
|
}
|
|
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
|
|
|
|
void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
|
|
uint32_t *ticks_anchor, uint32_t *us_offset)
|
|
{
|
|
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;
|
|
struct ll_conn *conn;
|
|
uint32_t ret;
|
|
bool success;
|
|
|
|
ret_cb = TICKER_STATUS_BUSY;
|
|
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
|
|
ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, user_id,
|
|
&ticker_id, ticks_anchor,
|
|
&ticks_to_expire,
|
|
NULL, /* lazy */
|
|
ticker_match_op_cb,
|
|
NULL, /* match_op_context */
|
|
ticker_op_cb, (void *)&ret_cb);
|
|
#else
|
|
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id,
|
|
&ticker_id, ticks_anchor,
|
|
&ticks_to_expire,
|
|
ticker_op_cb, (void *)&ret_cb);
|
|
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
|
|
if (ret == TICKER_STATUS_BUSY) {
|
|
while (ret_cb == TICKER_STATUS_BUSY) {
|
|
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
|
|
user_id);
|
|
}
|
|
}
|
|
|
|
success = (ret_cb == TICKER_STATUS_SUCCESS);
|
|
LL_ASSERT(success);
|
|
|
|
if (ticker_id == 0xff) {
|
|
break;
|
|
}
|
|
|
|
#if !defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
|
|
if ((ticker_id < TICKER_ID_CONN_BASE) ||
|
|
(ticker_id > TICKER_ID_CONN_LAST)) {
|
|
continue;
|
|
}
|
|
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
|
|
|
|
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->ull.ticks_prepare_to_start & XON_BITMASK) {
|
|
uint32_t ticks_prepare_to_start =
|
|
MAX(conn->ull.ticks_active_to_start,
|
|
conn->ull.ticks_preempt_to_start);
|
|
|
|
ticks_slot_abs_curr =
|
|
conn->ull.ticks_prepare_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->ull.ticks_active_to_start,
|
|
conn->ull.ticks_prepare_to_start);
|
|
|
|
ticks_slot_abs_curr = ticks_prepare_to_start;
|
|
}
|
|
#endif
|
|
|
|
ticks_slot_abs_curr += conn->ull.ticks_slot;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_BT_CENTRAL)
|
|
void ull_sched_mfy_after_mstr_offset_get(void *param)
|
|
{
|
|
struct lll_prepare_param *p = param;
|
|
struct lll_scan *lll = p->param;
|
|
uint32_t ticks_slot_overhead;
|
|
struct ll_conn *conn;
|
|
|
|
conn = HDR_LLL2ULL(lll->conn);
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
|
ticks_slot_overhead = MAX(conn->ull.ticks_active_to_start,
|
|
conn->ull.ticks_prepare_to_start);
|
|
} else {
|
|
ticks_slot_overhead = 0U;
|
|
}
|
|
|
|
after_mstr_offset_get(lll->conn->interval,
|
|
(ticks_slot_overhead + conn->ull.ticks_slot),
|
|
p->ticks_at_expire, &lll->conn_win_offset_us);
|
|
}
|
|
#endif /* CONFIG_BT_CENTRAL */
|
|
|
|
void ull_sched_mfy_win_offset_use(void *param)
|
|
{
|
|
struct ll_conn *conn = param;
|
|
uint32_t ticks_slot_overhead;
|
|
|
|
/*
|
|
* TODO: update when updating the connection update procedure
|
|
*/
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
uint16_t win_offset;
|
|
#endif
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
|
ticks_slot_overhead = MAX(conn->ull.ticks_active_to_start,
|
|
conn->ull.ticks_prepare_to_start);
|
|
} else {
|
|
ticks_slot_overhead = 0U;
|
|
}
|
|
|
|
/*
|
|
* TODO: update when updating the connection update procedure
|
|
*/
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
after_mstr_offset_get(conn->lll.interval,
|
|
(ticks_slot_overhead + conn->ull.ticks_slot),
|
|
conn->llcp.conn_upd.ticks_anchor,
|
|
&conn->llcp_cu.win_offset_us);
|
|
|
|
win_offset = conn->llcp_cu.win_offset_us / CONN_INT_UNIT_US;
|
|
|
|
sys_put_le16(win_offset, (void *)conn->llcp.conn_upd.pdu_win_offset);
|
|
|
|
/* move to offset calculated state */
|
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
|
#endif
|
|
}
|
|
|
|
#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;
|
|
|
|
/*
|
|
* TODO: update when updating the connection update procedure
|
|
*/
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
uint8_t offset_max = 6U;
|
|
struct ll_conn *conn = param;
|
|
#endif
|
|
|
|
ticks_to_offset_next = &ticks_to_offset_default;
|
|
|
|
/*
|
|
* TODO: update when updating the connection update procedure
|
|
*/
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
|
|
#if defined(CONFIG_BT_PERIPHERAL)
|
|
if (conn->lll.role) {
|
|
conn->llcp_conn_param.ticks_to_offset_next =
|
|
conn->periph.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);
|
|
|
|
/* move to offset calculated state */
|
|
conn->llcp_conn_param.state = LLCP_CPR_STATE_OFFS_RDY;
|
|
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
|
|
}
|
|
|
|
void ull_sched_mfy_win_offset_select(void *param)
|
|
{
|
|
#define OFFSET_S_MAX 6
|
|
#define OFFSET_M_MAX 6
|
|
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
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;
|
|
uint16_t win_offset_s;
|
|
uint32_t ticks_to_offset;
|
|
#endif
|
|
|
|
/*
|
|
* TODO: update when updating the connection update procedure
|
|
*/
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
|
|
ticks_to_offset = HAL_TICKER_US_TO_TICKS(conn->llcp_conn_param.offset0 *
|
|
CONN_INT_UNIT_US);
|
|
|
|
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;
|
|
|
|
win_offset_s =
|
|
sys_get_le16((uint8_t *)&conn->llcp_conn_param.offset0 +
|
|
(sizeof(uint16_t) * offset_index_s));
|
|
|
|
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 * CONN_INT_UNIT_US;
|
|
sys_put_le16(win_offset_s,
|
|
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
|
/* move to offset calculated state */
|
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
|
} else if (!has_offset_s) {
|
|
conn->llcp_cu.win_offset_us = win_offset_m[0] *
|
|
CONN_INT_UNIT_US;
|
|
sys_put_le16(win_offset_m[0],
|
|
(void *)conn->llcp.conn_upd.pdu_win_offset);
|
|
/* move to offset calculated state */
|
|
conn->llcp_cu.state = LLCP_CUI_STATE_OFFS_RDY;
|
|
} else {
|
|
struct pdu_data *pdu_ctrl_tx;
|
|
|
|
/* send reject_ind_ext */
|
|
pdu_ctrl_tx = CONTAINER_OF(conn->llcp.conn_upd.pdu_win_offset,
|
|
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;
|
|
/* move to conn param reject */
|
|
conn->llcp_cu.state = LLCP_CUI_STATE_REJECT;
|
|
}
|
|
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
|
|
|
|
|
|
#undef OFFSET_S_MAX
|
|
#undef OFFSET_M_MAX
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY)
|
|
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->ull.ticks_prepare_to_start & XON_BITMASK) {
|
|
uint32_t ticks_prepare_to_start =
|
|
MAX(conn_curr->ull.ticks_active_to_start,
|
|
conn_curr->ull.ticks_preempt_to_start);
|
|
|
|
ticks_slot_abs = conn_curr->ull.ticks_prepare_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->ull.ticks_active_to_start,
|
|
conn_curr->ull.ticks_prepare_to_start);
|
|
|
|
ticks_slot_abs = ticks_prepare_to_start;
|
|
}
|
|
#endif
|
|
|
|
ticks_slot_abs += conn_curr->ull.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;
|
|
struct ll_conn *conn;
|
|
uint32_t ret;
|
|
bool success;
|
|
|
|
ret_cb = TICKER_STATUS_BUSY;
|
|
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);
|
|
}
|
|
}
|
|
|
|
success = (ret_cb == TICKER_STATUS_SUCCESS);
|
|
LL_ASSERT(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->ull.ticks_prepare_to_start & XON_BITMASK) {
|
|
uint32_t ticks_prepare_to_start =
|
|
MAX(conn->ull.ticks_active_to_start,
|
|
conn->ull.ticks_preempt_to_start);
|
|
|
|
ticks_slot_abs_curr =
|
|
conn->ull.ticks_prepare_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->ull.ticks_active_to_start,
|
|
conn->ull.ticks_prepare_to_start);
|
|
|
|
ticks_slot_abs_curr = ticks_prepare_to_start;
|
|
}
|
|
#endif
|
|
|
|
ticks_slot_abs_curr += conn->ull.ticks_slot +
|
|
HAL_TICKER_US_TO_TICKS(CONN_INT_UNIT_US);
|
|
|
|
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 = (ticks_to_expire_prev +
|
|
ticks_slot_abs_prev) /
|
|
HAL_TICKER_US_TO_TICKS(
|
|
CONN_INT_UNIT_US);
|
|
if (offset >= conn_interval) {
|
|
ticks_to_expire_prev = 0U;
|
|
|
|
break;
|
|
}
|
|
|
|
sys_put_le16(offset,
|
|
(win_offset +
|
|
(sizeof(uint16_t) *
|
|
offset_index)));
|
|
offset_index++;
|
|
|
|
ticks_to_expire_prev +=
|
|
HAL_TICKER_US_TO_TICKS(
|
|
CONN_INT_UNIT_US);
|
|
}
|
|
|
|
*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 = (ticks_to_expire_prev + ticks_slot_abs_prev) /
|
|
HAL_TICKER_US_TO_TICKS(CONN_INT_UNIT_US);
|
|
if (offset >= conn_interval) {
|
|
ticks_to_expire_prev = 0U;
|
|
|
|
break;
|
|
}
|
|
|
|
sys_put_le16(offset, (win_offset + (sizeof(uint16_t) *
|
|
offset_index)));
|
|
offset_index++;
|
|
|
|
ticks_to_expire_prev += HAL_TICKER_US_TO_TICKS(
|
|
CONN_INT_UNIT_US);
|
|
}
|
|
|
|
*ticks_to_offset_next = ticks_to_expire_prev;
|
|
}
|
|
|
|
*offset_max = offset_index;
|
|
}
|
|
#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */
|
|
|
|
#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 * CONN_INT_UNIT_US;
|
|
|
|
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;
|
|
}
|