bluetooth: controller: Revised ticker for improved conflict resolution

Changed ticker behavior to resolve conflicts in ticker_worker instead of
in ticker_job. This allows better real-time slot allocation, as well as
allowing callbacks even if ticker node doesn't get air-time (for audio
stream housekeeping). A priority property now also allows prioritizing
one ticker node over others.
Compatibility mode enables lagacy ticker behavior if needed.

Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
Morten Priess 2019-08-07 11:12:26 +02:00 committed by Alberto Escolar
commit 3a9173afe1
3 changed files with 456 additions and 24 deletions

View file

@ -651,6 +651,15 @@ config BT_MAYFLY_YIELD_AFTER_CALL
If set to 'n', all pending mayflies for callee are executed before
yielding
config BT_TICKER_COMPATIBILITY_MODE
bool "Ticker compatibility mode"
default y if SOC_SERIES_NRF51X
help
This option enables legacy ticker scheduling which defers overlapping
ticker node timeouts and thereby prevents ticker interrupts during
radio RX/TX. Enabling this option disables the ticker priority- and
'must expire' features.
config BT_CTLR_USER_EXT
prompt "Enable proprietary extensions in Controller"
depends on BT_LL_SW_SPLIT

View file

@ -60,17 +60,26 @@ struct ticker_node {
u32_t remainder_current; /* Current sub-microsecond tick
* remainder
*/
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
u8_t must_expire; /* Node must expire, even if it
* collides with other nodes
*/
s8_t priority; /* Ticker node priority. 0 is default.
* Lower value is higher priority
*/
#endif /* CONFIG_BT_TICKER_COMPATIBILITY_MODE */
};
/* Operations to be performed in ticker_job.
* Possible values for field "op" in struct ticker_user_op
*/
#define TICKER_USER_OP_TYPE_NONE 0
#define TICKER_USER_OP_TYPE_IDLE_GET 1
#define TICKER_USER_OP_TYPE_SLOT_GET 2
#define TICKER_USER_OP_TYPE_START 3
#define TICKER_USER_OP_TYPE_UPDATE 4
#define TICKER_USER_OP_TYPE_STOP 5
#define TICKER_USER_OP_TYPE_NONE 0
#define TICKER_USER_OP_TYPE_IDLE_GET 1
#define TICKER_USER_OP_TYPE_SLOT_GET 2
#define TICKER_USER_OP_TYPE_PRIORITY_SET 3
#define TICKER_USER_OP_TYPE_START 4
#define TICKER_USER_OP_TYPE_UPDATE 5
#define TICKER_USER_OP_TYPE_STOP 6
/* User operation data structure for start opcode. Used for passing start
* requests to ticker_job
@ -117,6 +126,13 @@ struct ticker_user_op_slot_get {
u32_t *ticks_to_expire;
};
/* User operation data structure for priority_set opcode. Used for passing
* request to set ticker node priority via ticker_job
*/
struct ticker_user_op_priority_set {
s8_t priority; /* Node priority. Defaults to 0 */
};
/* User operation top level data structure. Used for passing requests to
* ticker_job
*/
@ -127,6 +143,7 @@ struct ticker_user_op {
struct ticker_user_op_start start;
struct ticker_user_op_update update;
struct ticker_user_op_slot_get slot_get;
struct ticker_user_op_priority_set priority_set;
} params; /* User operation parameters */
u32_t status; /* Operation result */
ticker_op_func fp_op_func; /* Operation completion callback */
@ -226,6 +243,7 @@ static inline void ticker_next_elapsed(u8_t *ticks_elapsed_index)
*ticks_elapsed_index = idx;
}
#if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Get ticker expiring in a specific slot
*
@ -267,6 +285,7 @@ static u8_t ticker_by_slot_get(struct ticker_node *node, u8_t ticker_id_head,
return ticker_id_head;
}
#endif /* CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Get next ticker with slot ticks
@ -325,6 +344,79 @@ static void ticker_by_next_slot_get(struct ticker_instance *instance,
*ticks_to_expire = _ticks_to_expire;
}
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Enqueue ticker node
*
* @details Finds insertion point for new ticker node and inserts the
* node in the linked node list.
*
* @param instance Pointer to ticker instance
* @param id Ticker node id to enqueue
*
* @return Id of enqueued ticker node
* @internal
*/
static u8_t ticker_enqueue(struct ticker_instance *instance, u8_t id)
{
struct ticker_node *ticker_current;
struct ticker_node *ticker_new;
u32_t ticks_to_expire_current;
struct ticker_node *node;
u32_t ticks_to_expire;
u8_t previous;
u8_t current;
node = &instance->nodes[0];
ticker_new = &node[id];
ticks_to_expire = ticker_new->ticks_to_expire;
current = instance->ticker_id_head;
previous = current;
/* Find insertion point for new ticker node and adjust ticks_to_expire
* relative to insertion point
*/
previous = TICKER_NULL;
while ((current != TICKER_NULL) && (ticks_to_expire >=
(ticks_to_expire_current =
(ticker_current = &node[current])->ticks_to_expire))) {
ticks_to_expire -= ticks_to_expire_current;
/* Check for timeout in same tick - prioritize according to
* latency
*/
if (ticks_to_expire == 0 && (ticker_new->lazy_current >
ticker_current->lazy_current)) {
ticks_to_expire = ticker_current->ticks_to_expire;
break;
}
previous = current;
current = ticker_current->next;
}
/* Link in new ticker node and adjust ticks_to_expire to relative value
*/
ticker_new->ticks_to_expire = ticks_to_expire;
ticker_new->next = current;
if (previous == TICKER_NULL) {
instance->ticker_id_head = id;
} else {
node[previous].next = id;
}
if (current != TICKER_NULL) {
node[current].ticks_to_expire -= ticks_to_expire;
}
return id;
}
#else /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Enqueue ticker node
*
@ -420,6 +512,7 @@ static u8_t ticker_enqueue(struct ticker_instance *instance, u8_t id)
return id;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Dequeue ticker node
@ -492,6 +585,126 @@ static u32_t ticker_dequeue(struct ticker_instance *instance, u8_t id)
return (total + timeout);
}
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Resolve ticker node collision
*
* @details Evaluates the provided ticker node against other queued nodes
* and returns non-zero if the ticker node collides and should be skipped.
* The following rules are checked:
* 1) If the periodic latency is not yet exhausted, node is skipped
* 2) If the node has highest possible priority, node is never skipped
* 2) If the node will starve next node due to slot reservation
* overlap, node is skipped if:
* a) Next node has higher priority than current node
* b) Next node has more accumulated latency than the current node
* c) Next node is 'older' than current node and has same priority
* d) Next node has force flag set, and the current does not
*
* @param nodes Pointer to ticker node array
* @param ticker Pointer to ticker to resolve
*
* @return 0 if no collision was detected. 1 if ticker node collides
* with other ticker node of higher composite priority
* @internal
*/
static u8_t ticker_resolve_collision(struct ticker_node *nodes,
struct ticker_node *ticker)
{
u8_t skipped = 0;
s32_t lazy_current = ticker->lazy_current;
if (ticker->lazy_periodic > lazy_current) {
/* Programmed latency must be respected */
skipped = 1;
} else if ((ticker->priority != TICKER_PRIORITY_CRITICAL) &&
(ticker->next != TICKER_NULL)) {
/* Check if this ticker node will starve next node which has
* latency or higher priority
*/
if (lazy_current >= ticker->lazy_periodic) {
lazy_current -= ticker->lazy_periodic;
}
u8_t id_head = ticker->next;
u32_t acc_ticks_to_expire = 0;
/* Age is time since last expiry */
u32_t current_age = ticker->ticks_periodic +
(lazy_current * ticker->ticks_periodic);
while (id_head != TICKER_NULL) {
struct ticker_node *ticker_next = &nodes[id_head];
/* We only care about nodes with slot reservation */
if (ticker_next->ticks_slot == 0) {
id_head = ticker_next->next;
continue;
}
/* Accumulate ticks_to_expire for each node */
acc_ticks_to_expire += ticker_next->ticks_to_expire;
s32_t lazy_next = ticker_next->lazy_current;
u8_t lazy_next_periodic_skip =
ticker_next->lazy_periodic > lazy_next;
if (!lazy_next_periodic_skip) {
lazy_next -= ticker_next->lazy_periodic;
}
/* Is the current and next node equal in priority? */
u8_t equal_priority = ticker->priority ==
ticker_next->priority;
/* Age is time since last expiry */
u32_t next_age = (ticker_next->ticks_periodic == 0U ?
0U :
(ticker_next->ticks_periodic -
ticker_next->ticks_to_expire)) +
(lazy_next *
ticker_next->ticks_periodic);
/* Was the current node scheduled earlier? */
u8_t current_is_older = current_age > next_age;
/* Was next node scheduled earlier (legacy priority)? */
u8_t next_is_older = next_age > current_age;
/* Is force requested for next node (e.g. update) -
* more so than for current node?
*/
u8_t next_force = (ticker_next->force > ticker->force);
/* Does next node have critical priority and should
* always be scheduled?
*/
u8_t next_is_critical = ticker_next->priority ==
TICKER_PRIORITY_CRITICAL;
/* Does next node have higher priority? */
u8_t next_has_priority =
(lazy_next - ticker_next->priority) >
(lazy_current - ticker->priority);
/* Check if next node is within this reservation slot
* and wins conflict resolution
*/
if (!lazy_next_periodic_skip &&
(acc_ticks_to_expire < ticker->ticks_slot) &&
(next_force ||
next_is_critical ||
(next_has_priority && !current_is_older) ||
(equal_priority && next_is_older))) {
skipped = 1;
break;
}
id_head = ticker_next->next;
}
}
return skipped;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Ticker worker
*
@ -535,11 +748,27 @@ void ticker_worker(void *param)
/* Auto variable containing the head of tickers expiring */
ticker_id_head = instance->ticker_id_head;
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/* Check if the previous ticker node which had air-time, is still
* active and has this time slot reserved
*/
u8_t slot_reserved = 0;
if (instance->ticker_id_slot_previous != TICKER_NULL) {
if (instance->ticks_slot_previous > ticks_elapsed) {
/* This node intersects reserved slot */
slot_reserved = 1;
}
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/* Expire all tickers within ticks_elapsed and collect ticks_expired */
node = &instance->nodes[0];
while (ticker_id_head != TICKER_NULL) {
struct ticker_node *ticker;
u32_t ticks_to_expire;
u8_t must_expire_skip;
ticker = &node[ticker_id_head];
@ -555,7 +784,23 @@ void ticker_worker(void *param)
/* Move to next ticker node */
ticker_id_head = ticker->next;
must_expire_skip = 0U;
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/* Check if node has slot reservation and resolve any collision
* with other ticker nodes
*/
if (ticker->ticks_slot != 0U &&
(slot_reserved || ticker_resolve_collision(node, ticker))) {
ticker->lazy_current++;
if (ticker->must_expire == 0U) {
/* Skip this ticker node */
continue;
}
/* Continue but perform shallow expiry */
must_expire_skip = 1U;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/* Skip if not scheduled to execute */
if (((ticker->req - ticker->ack) & 0xff) != 1U) {
continue;
@ -576,9 +821,23 @@ void ticker_worker(void *param)
/* Invoke the timeout callback */
ticker->timeout_func(ticks_at_expire,
ticker->remainder_current,
must_expire_skip ?
TICKER_LAZY_MUST_EXPIRE :
ticker->lazy_current,
ticker->context);
DEBUG_TICKER_TASK(0);
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
if (must_expire_skip == 0U) {
/* Reset latency to periodic offset */
ticker->lazy_current = 0U;
ticker->force = 0U;
if (ticker->ticks_slot != 0U) {
/* Any further nodes will be skipped */
slot_reserved = 1U;
}
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
}
}
@ -686,6 +945,7 @@ static u8_t ticker_remainder_inc(struct ticker_node *ticker)
#endif
}
#if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Decrement remainder
*
@ -710,12 +970,12 @@ static u8_t ticker_remainder_dec(struct ticker_node *ticker)
ticker->remainder_current += HAL_TICKER_REMAINDER_RANGE;
}
ticker->remainder_current -= ticker->remainder_periodic;
return decrement;
#else
return 0;
#endif
}
#endif /* CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Invoke user operation callback
@ -771,7 +1031,7 @@ static inline void ticker_job_node_update(struct ticker_node *ticker,
if ((ticker->ticks_periodic != 0U) &&
(user_op->params.update.lazy != 0U)) {
user_op->params.update.lazy--;
#if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
while ((ticks_to_expire > ticker->ticks_periodic) &&
(ticker->lazy_current > user_op->params.update.lazy)) {
ticks_to_expire -= ticker->ticks_periodic +
@ -784,7 +1044,7 @@ static inline void ticker_job_node_update(struct ticker_node *ticker,
ticker_remainder_inc(ticker);
ticker->lazy_current++;
}
#endif /* CONFIG_BT_TICKER_COMPATIBILITY_MODE */
ticker->lazy_periodic = user_op->params.update.lazy;
}
@ -1018,18 +1278,28 @@ static inline void ticker_job_worker_bh(struct ticker_instance *instance,
ticks_elapsed -= ticks_to_expire;
ticks_expired += ticks_to_expire;
/* decrement ticks_slot_previous */
if (instance->ticks_slot_previous > ticks_to_expire) {
instance->ticks_slot_previous -= ticks_to_expire;
} else {
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
if (ticker->lazy_current != 0U) {
instance->ticker_id_slot_previous = TICKER_NULL;
instance->ticks_slot_previous = 0U;
}
} else
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
{
/* decrement ticks_slot_previous */
if (instance->ticks_slot_previous > ticks_to_expire) {
instance->ticks_slot_previous -=
ticks_to_expire;
} else {
instance->ticker_id_slot_previous = TICKER_NULL;
instance->ticks_slot_previous = 0U;
}
/* save current ticks_slot_previous */
if (ticker->ticks_slot != 0U) {
instance->ticker_id_slot_previous = id_expired;
instance->ticks_slot_previous = ticker->ticks_slot;
/* save current ticks_slot_previous */
if (ticker->ticks_slot != 0U) {
instance->ticker_id_slot_previous = id_expired;
instance->ticks_slot_previous =
ticker->ticks_slot;
}
}
/* ticker expired, set ticks_to_expire zero */
@ -1040,6 +1310,14 @@ static inline void ticker_job_worker_bh(struct ticker_instance *instance,
/* ticker will be restarted if periodic */
if (ticker->ticks_periodic != 0U) {
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/* Reload ticks_to_expire with one period */
ticker->ticks_to_expire = ticker->ticks_periodic;
ticker->ticks_to_expire += ticker_remainder_inc(ticker);
ticks_to_expire_prep(ticker, instance->ticks_current,
(ticks_previous + ticks_expired));
#else /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
u32_t count;
/* Prepare for next interval */
@ -1057,7 +1335,7 @@ static inline void ticker_job_worker_bh(struct ticker_instance *instance,
/* Reset latency to periodic offset */
ticker->lazy_current = ticker->lazy_periodic;
ticker->force = 0U;
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/* Add to insert list */
ticker->next = *insert_head;
*insert_head = id_expired;
@ -1088,9 +1366,18 @@ static inline void ticker_job_op_start(struct ticker_node *ticker,
{
struct ticker_user_op_start *start = (void *)&user_op->params.start;
#if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/* Must expire is not supported in compatibility mode */
LL_ASSERT(start->lazy != TICKER_LAZY_MUST_EXPIRE);
#else
ticker->must_expire = (start->lazy == TICKER_LAZY_MUST_EXPIRE) ? 1U :
0U;
#endif /* CONFIG_BT_TICKER_COMPATIBILITY_MODE */
ticker->ticks_periodic = start->ticks_periodic;
ticker->remainder_periodic = start->remainder_periodic;
ticker->lazy_periodic = start->lazy;
ticker->lazy_periodic = (start->lazy == TICKER_LAZY_MUST_EXPIRE) ? 0U :
start->lazy;
ticker->ticks_slot = start->ticks_slot;
ticker->timeout_func = start->fp_timeout_func;
ticker->context = start->context;
@ -1102,6 +1389,42 @@ static inline void ticker_job_op_start(struct ticker_node *ticker,
ticker->force = 1U;
}
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Insert new ticker node
*
* @details Called by ticker_job to insert a new ticker node. If node collides
* with existing ticker nodes, either the new node is postponed, or colliding
* node is un-scheduled. Decision is based on latency and the force-state of
* individual nodes.
*
* @param instance Pointer to ticker instance
* @param id_insert Id of ticker to insert
* @param ticker Pointer to ticker node to insert
* @param insert_head Pointer to current head. Updated if colliding nodes
* are un-scheduled
* @internal
*/
static inline u32_t ticker_job_insert(struct ticker_instance *instance,
u8_t id_insert,
struct ticker_node *ticker,
u8_t *insert_head)
{
ARG_UNUSED(insert_head);
/* Prepare to insert */
ticker->next = TICKER_NULL;
/* Enqueue the ticker node */
(void)ticker_enqueue(instance, id_insert);
/* Inserted/Scheduled */
ticker->req = ticker->ack + 1;
return TICKER_STATUS_SUCCESS;
}
#else /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Insert new ticker node
*
@ -1205,6 +1528,7 @@ static inline u32_t ticker_job_insert(struct ticker_instance *instance,
return TICKER_STATUS_SUCCESS;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Insert and start ticker nodes for all users
@ -1325,7 +1649,20 @@ static inline void ticker_job_op_inquire(struct ticker_instance *instance,
uop->status = TICKER_STATUS_SUCCESS;
fp_op_func = uop->fp_op_func;
break;
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
case TICKER_USER_OP_TYPE_PRIORITY_SET:
if (uop->id < instance->count_node) {
struct ticker_node *node = instance->nodes;
node[uop->id].priority =
uop->params.priority_set.priority;
uop->status = TICKER_STATUS_SUCCESS;
} else {
uop->status = TICKER_STATUS_FAILURE;
}
fp_op_func = uop->fp_op_func;
break;
#endif
default:
/* do nothing for other ops */
break;
@ -1341,8 +1678,9 @@ static inline void ticker_job_op_inquire(struct ticker_instance *instance,
*
* @details Run through all user operation lists, checking for pending
* inquiries. Currently only two types of inquiries are supported:
* TICKER_USER_OP_TYPE_SLOT_GET and TICKER_USER_OP_TYPE_IDLE_GET. This
* operation modifies the user->first index, indicating user operations
* TICKER_USER_OP_TYPE_SLOT_GET and TICKER_USER_OP_TYPE_IDLE_GET. The
* function also supports user operation TICKER_USER_OP_TYPE_PRIORITY_SET.
* This operation modifies the user->first index, indicating user operations
* are complete.
*
* @param instance Pointer to ticker instance
@ -1451,7 +1789,7 @@ static inline void ticker_job_compare_update(struct ticker_instance *instance,
/**
* @brief Ticker job
*
* @details Runs the lower half of the ticker, after ticker nodes have elapsed
* @details Runs the bottom half of the ticker, after ticker nodes have elapsed
* or user operations requested. The ticker_job is responsible for removing and
* re-inserting ticker nodes, based on next elapsing and periodicity of the
* nodes. The ticker_job is also responsible for processing user operations,
@ -1540,7 +1878,7 @@ void ticker_job(void *param)
flag_compare_update = 1U;
}
/* Processing any list inquiries */
/* Process any list inquiries */
if (!pending) {
/* Handle inquiries */
ticker_job_list_inquire(instance);
@ -1606,6 +1944,12 @@ u32_t ticker_init(u8_t instance_index, u8_t count_node, void *node,
instance->count_node = count_node;
instance->nodes = node;
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
while (count_node--) {
instance->nodes[count_node].priority = 0;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
instance->count_user = count_user;
instance->users = user;
@ -1983,6 +2327,65 @@ u32_t ticker_job_idle_get(u8_t instance_index, u8_t user_id,
return user_op->status;
}
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
/**
* @brief Set ticker node priority
*
* @param instance_index Index of ticker instance
* @param user_id Ticker user id. Used for indexing user operations
* and mapping to mayfly caller id
* @param ticker_id Id of ticker node to set priority on
* @param priority Priority to set. Range [-128..127], default is 0.
* Lover value equals higher priority. Setting
* priority to -128 (TICKER_PRIORITY_CRITICAL) makes
* the node win all collision challenges. Only one
* node can have this priority assigned.
* @param fp_op_func Function pointer of user operation completion
* function
* @param op_context Context passed in operation completion call
*
* @return TICKER_STATUS_BUSY if request was successful but not yet completed.
* TICKER_STATUS_FAILURE is returned if there are no more user operations
* available, and TICKER_STATUS_SUCCESS is returned if ticker_job gets to run
* before exiting ticker_priority_set
*/
u32_t ticker_priority_set(u8_t instance_index, u8_t user_id, u8_t ticker_id,
s8_t priority, ticker_op_func fp_op_func,
void *op_context)
{
struct ticker_instance *instance = &_instance[instance_index];
struct ticker_user_op *user_op;
struct ticker_user *user;
u8_t last;
user = &instance->users[user_id];
last = user->last + 1;
if (last >= user->count_user_op) {
last = 0U;
}
if (last == user->first) {
return TICKER_STATUS_FAILURE;
}
user_op = &user->user_op[user->last];
user_op->op = TICKER_USER_OP_TYPE_PRIORITY_SET;
user_op->id = ticker_id;
user_op->params.priority_set.priority = priority;
user_op->status = TICKER_STATUS_BUSY;
user_op->fp_op_func = fp_op_func;
user_op->op_context = op_context;
user->last = last;
instance->sched_cb(instance->caller_id_get_cb(user_id),
TICKER_CALL_ID_JOB, 0, instance);
return user_op->status;
}
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */
/**
* @brief Schedule ticker job
*

View file

@ -29,13 +29,18 @@
#define TICKER_NULL_PERIOD 0
#define TICKER_NULL_SLOT 0
#define TICKER_NULL_LAZY 0
#define TICKER_NULL_MUST_EXPIRE 0
/**
* @}
*/
/** \brief Timer node type size.
*/
#if defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
#define TICKER_NODE_T_SIZE 40
#else
#define TICKER_NODE_T_SIZE 44
#endif
/** \brief Timer user type size.
*/
@ -52,6 +57,16 @@
#define TICKER_CALL_ID_JOB 4
#define TICKER_CALL_ID_PROGRAM 5
/* Use to ensure callback is invoked in all intervals, even when latencies
* occur
*/
#define TICKER_LAZY_MUST_EXPIRE 0xFFFF
/* Set this priority to ensure ticker node is always scheduled. Only one
* ticker node can have priority TICKER_PRIORITY_CRITICAL at a time
*/
#define TICKER_PRIORITY_CRITICAL -128
typedef u8_t (*ticker_caller_id_get_cb_t)(u8_t user_id);
typedef void (*ticker_sched_cb_t)(u8_t caller_id, u8_t callee_id, u8_t chain,
void *instance);
@ -106,3 +121,8 @@ u32_t ticker_job_idle_get(u8_t instance_index, u8_t user_id,
void ticker_job_sched(u8_t instance_index, u8_t user_id);
u32_t ticker_ticks_now_get(void);
u32_t ticker_ticks_diff_get(u32_t ticks_now, u32_t ticks_old);
#if !defined(CONFIG_BT_TICKER_COMPATIBILITY_MODE)
u32_t ticker_priority_set(u8_t instance_index, u8_t user_id, u8_t ticker_id,
s8_t priority, ticker_op_func fp_op_func,
void *op_context);
#endif /* !CONFIG_BT_TICKER_COMPATIBILITY_MODE */