Pico GPS Teseo I2C
Loading...
Searching...
No Matches
time.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdlib.h>
8#include "pico.h"
9#include "pico/time.h"
10#include "pico/sync.h"
11#include "pico/runtime_init.h"
12
15
16typedef struct alarm_pool_entry {
17 // next entry link or -1
18 int16_t next;
19 // low 15 bits are a sequence number used in the low word of the alarm_id so that
20 // the alarm_id for this entry only repeats every 32767 adds (note this value is never zero)
21 // the top bit is a cancellation flag.
22 volatile uint16_t sequence;
23 int64_t target;
25 void *user_data;
27
28struct alarm_pool {
30 uint8_t core_num;
31 // this is protected by the lock (threads allocate from it, and the IRQ handler adds back to it)
32 int16_t free_head;
33 // this is protected by the lock (threads add to it, the IRQ handler removes from it)
34 volatile int16_t new_head;
36
37 // this is owned by the IRQ handler so doesn't need additional locking
38 int16_t ordered_head;
39 uint16_t num_entries;
43};
44
45#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
46// To avoid bringing in calloc, we statically allocate the arrays and the heap
47static alarm_pool_entry_t default_alarm_pool_entries[PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS];
48
49static alarm_pool_t default_alarm_pool = {
50 .entries = default_alarm_pool_entries,
51};
52
53static inline bool default_alarm_pool_initialized(void) {
54 return default_alarm_pool.lock != NULL;
55}
56
57static lock_core_t sleep_notifier;
58#endif
59
60#include "pico/time_adapter.h"
61
63
64static void alarm_pool_post_alloc_init(alarm_pool_t *pool, alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers);
65
66static inline int16_t alarm_index(alarm_id_t id) {
67 return (int16_t)(id >> 16);
68}
69
70static inline uint16_t alarm_sequence(alarm_id_t id) {
71 return (uint16_t)id;
72}
73
74static alarm_id_t make_alarm_id(int index, uint16_t counter) {
75 return index << 16 | counter;
76}
77
78#if !PICO_RUNTIME_NO_INIT_DEFAULT_ALARM_POOL
80#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
81 // allow multiple calls for ease of use from host tests
82 if (!default_alarm_pool_initialized()) {
85 alarm_pool_post_alloc_init(&default_alarm_pool,
86 timer,
89 }
90 lock_init(&sleep_notifier, PICO_SPINLOCK_ID_TIMER);
91#endif
92}
93#endif
94
98
99#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
101 assert(default_alarm_pool_initialized());
102 return &default_alarm_pool;
103}
104
105#if defined(PICO_RUNTIME_INIT_DEFAULT_ALARM_POOL) && !PICO_RUNTIME_SKIP_INIT_DEFAULT_ALARM_POOL
107#endif
108#endif
109
110// note the timer is created with IRQs on this core
112 alarm_pool_t *pool = (alarm_pool_t *) malloc(sizeof(alarm_pool_t));
113 if (pool) {
114 pool->entries = (alarm_pool_entry_t *) calloc(max_timers, sizeof(alarm_pool_entry_t));
115 ta_hardware_alarm_claim(timer, hardware_alarm_num);
116 alarm_pool_post_alloc_init(pool, timer, hardware_alarm_num, max_timers);
117 }
118 return pool;
119}
120
122 alarm_pool_t *pool = (alarm_pool_t *) malloc(sizeof(alarm_pool_t));
123 if (pool) {
124 pool->entries = (alarm_pool_entry_t *) calloc(max_timers, sizeof(alarm_pool_entry_t));
125 alarm_pool_post_alloc_init(pool, timer, (uint) ta_hardware_alarm_claim_unused(timer, true), max_timers);
126 }
127 return pool;
128}
129
130static void alarm_pool_irq_handler(void);
131
132// marker which we can use in place of handler function to indicate we are a repeating timer
133
134#define repeating_timer_marker ((alarm_callback_t)alarm_pool_irq_handler)
135#include "hardware/gpio.h"
136static void alarm_pool_irq_handler(void) {
137 // This IRQ handler does the main work, as it always (assuming the IRQ hasn't been enabled on both cores
138 // which is unsupported) run on the alarm pool's core, and can't be preempted by itself, meaning
139 // that it doesn't need locks except to protect against linked list, or other state access.
140 // This simplifies the code considerably, and makes it much faster in general, even though we are forced to take
141 // two IRQs per alarm.
142 uint timer_alarm_num;
143 alarm_pool_timer_t *timer = ta_from_current_irq(&timer_alarm_num);
144 uint timer_num = ta_timer_num(timer);
145 alarm_pool_t *pool = pools[timer_num][timer_alarm_num];
146 assert(pool->timer_alarm_num == timer_alarm_num);
147 int64_t earliest_target;
148 // 1. clear force bits if we were forced (do this outside the loop, as forcing is hopefully rare)
149 ta_clear_force_irq(timer, timer_alarm_num);
150 do {
151 // 2. clear the IRQ if it was fired
152 ta_clear_irq(timer, timer_alarm_num);
153 // 3. we look at the earliest existing alarm first; the reasoning here is that we
154 // don't want to delay an existing callback because a later one is added, and
155 // if both are due now, then we have a race anyway (but we prefer to fire existing
156 // timers before new ones anyway.
157 int16_t earliest_index = pool->ordered_head;
158 // by default, we loop if there was any event pending (we will mark it false
159 // later if there is no work to do)
160 if (earliest_index >= 0) {
161 alarm_pool_entry_t *earliest_entry = &pool->entries[earliest_index];
162 earliest_target = earliest_entry->target;
163 if (((int64_t)ta_time_us_64(timer) - earliest_target) >= 0) {
164 // time to call the callback now (or in the past)
165 // note that an entry->target of < 0 means the entry has been canceled (not this is set
166 // by this function, in response to the entry having been queued by the cancel_alarm API
167 // meaning that we don't need to worry about tearing of the 64 bit value)
168 int64_t delta;
169 if (earliest_target >= 0) {
170 // special case repeating timer without making another function call which adds overhead
171 if (earliest_entry->callback == repeating_timer_marker) {
172 repeating_timer_t *rpt = (repeating_timer_t *)earliest_entry->user_data;
173 delta = rpt->callback(rpt) ? rpt->delay_us : 0;
174 } else {
175 alarm_id_t id = make_alarm_id(pool->ordered_head, earliest_entry->sequence);
176 delta = earliest_entry->callback(id, earliest_entry->user_data);
177 }
178 } else {
179 // negative target means cancel alarm
180 delta = 0;
181 }
182 if (delta) {
183 int64_t next_time;
184 if (delta < 0) {
185 // delta is (positive) delta from last fire time
186 next_time = earliest_target - delta;
187 } else {
188 // delta is relative to now
189 next_time = (int64_t) ta_time_us_64(timer) + delta;
190 }
191 earliest_entry->target = next_time;
192 // need to re-add, unless we are the only entry or already at the front
193 if (earliest_entry->next >= 0 && next_time - pool->entries[earliest_entry->next].target >= 0) {
194 // unlink this item
195 pool->ordered_head = earliest_entry->next;
196 int16_t *prev = &pool->ordered_head;
197 // find insertion point; note >= as if we add a new item for the same time as another, then it follows
198 while (*prev >= 0 && (next_time - pool->entries[*prev].target) >= 0) {
199 prev = &pool->entries[*prev].next;
200 }
201 earliest_entry->next = *prev;
202 *prev = earliest_index;
203 }
204 } else {
205 // need to remove the item
206 pool->ordered_head = earliest_entry->next;
207 // and add it back to the free list (under lock)
208 uint32_t save = spin_lock_blocking(pool->lock);
209 earliest_entry->next = pool->free_head;
210 pool->free_head = earliest_index;
211 spin_unlock(pool->lock, save);
212 }
213 }
214 }
215 // if we have any new alarms, add them to the ordered list
216 if (pool->new_head >= 0) {
217 uint32_t save = spin_lock_blocking(pool->lock);
218 // must re-read new head under lock
219 int16_t new_index = pool->new_head;
220 // clear the list
221 pool->new_head = -1;
222 spin_unlock(pool->lock, save);
223 // insert each of the new items
224 while (new_index >= 0) {
225 alarm_pool_entry_t *new_entry = &pool->entries[new_index];
226 int64_t new_entry_time = new_entry->target;
227 int16_t *prev = &pool->ordered_head;
228 // find insertion point; note >= as if we add a new item for the same time as another, then it follows
229 while (*prev >= 0 && (new_entry_time - pool->entries[*prev].target) >= 0) {
230 prev = &pool->entries[*prev].next;
231 }
232 int16_t next = *prev;
233 *prev = new_index;
234 new_index = new_entry->next;
235 new_entry->next = next;
236 }
237 }
238 // if we have any canceled alarms, then mark them for removal by setting their due time to -1 (which will
239 // cause them to be handled the next time round and removed)
240 if (pool->has_pending_cancellations) {
241 pool->has_pending_cancellations = false;
242 __compiler_memory_barrier();
243 int16_t *prev = &pool->ordered_head;
244 // set target for canceled items to -1, and move to front of the list
245 for(int16_t index = pool->ordered_head; index != -1; ) {
246 alarm_pool_entry_t *entry = &pool->entries[index];
247 int16_t next = entry->next;
248 if ((int16_t)entry->sequence < 0) {
249 // mark for deletion
250 entry->target = -1;
251 if (index != pool->ordered_head) {
252 // move to start of queue
253 *prev = entry->next;
254 entry->next = pool->ordered_head;
255 pool->ordered_head = index;
256 }
257 } else {
258 prev = &entry->next;
259 }
260 index = next;
261 }
262 }
263 earliest_index = pool->ordered_head;
264 if (earliest_index < 0) break;
265 // need to wait
266 alarm_pool_entry_t *earliest_entry = &pool->entries[earliest_index];
267 earliest_target = earliest_entry->target;
268 // we are leaving a timeout every 2^32 microseconds anyway if there is no valid target, so we can choose any value.
269 // best_effort_wfe_or_timeout now relies on it being the last value set, and arguably this is the
270 // best value anyway, as it is the furthest away from the last fire.
271 if (earliest_target != -1) { // cancelled alarm has target of -1
272 ta_set_timeout(timer, timer_alarm_num, earliest_target);
273 }
274 // check we haven't now passed the target time; if not we don't want to loop again
275 } while ((earliest_target - (int64_t)ta_time_us_64(timer)) <= 0);
276 // We always want the timer IRQ to wake a WFE so that best_effort_wfe_or_timeout() will wake up. It will wake
277 // a WFE on its own core by nature of having taken an IRQ, but we do an explicit SEV so it wakes the other core
278 __sev();
279}
280
281void alarm_pool_post_alloc_init(alarm_pool_t *pool, alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers) {
282 pool->timer = timer;
284 pool->timer_alarm_num = (uint8_t) hardware_alarm_num;
285 invalid_params_if(PICO_TIME, max_timers > 65536);
286 pool->num_entries = (uint16_t)max_timers;
287 pool->core_num = (uint8_t) get_core_num();
288 pool->new_head = pool->ordered_head = -1;
289 pool->free_head = (int16_t)(max_timers - 1);
290 for(uint i=0;i<max_timers;i++) {
291 pool->entries[i].next = (int16_t)(i-1);
292 }
293 pools[ta_timer_num(timer)][hardware_alarm_num] = pool;
294
295 ta_enable_irq_handler(timer, hardware_alarm_num, alarm_pool_irq_handler);
296}
297
299#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
300 if (pool == &default_alarm_pool) {
301 assert(false); // attempt to delete default alarm pool
302 return;
303 }
304#endif
305 ta_disable_irq_handler(pool->timer, pool->timer_alarm_num, alarm_pool_irq_handler);
306 assert(pools[ta_timer_num(pool->timer)][pool->timer_alarm_num] == pool);
307 pools[ta_timer_num(pool->timer)][pool->timer_alarm_num] = NULL;
308 free(pool->entries);
309 free(pool);
310}
311
313 void *user_data, bool fire_if_past) {
314 if (!fire_if_past) {
315 absolute_time_t t = get_absolute_time();
316 if (absolute_time_diff_us(t, time) < 0) return 0;
317 }
318 return alarm_pool_add_alarm_at_force_in_context(pool, time, callback, user_data);
319}
320
322 void *user_data) {
323 // ---- take a free pool entry
324 uint32_t save = spin_lock_blocking(pool->lock);
325 int16_t index = pool->free_head;
326 alarm_pool_entry_t *entry = &pool->entries[index];
327 if (index >= 0) {
328 // remove from free list
329 pool->free_head = entry->next;
330 }
331 spin_unlock(pool->lock, save);
332 if (index < 0) return PICO_ERROR_GENERIC; // PICO_ERROR_INSUFFICIENT_RESOURCES - not using to preserve previous -1 return code
333
334 // ---- initialize the pool entry
335 entry->callback = callback;
336 entry->user_data = user_data;
337 entry->target = (int64_t)to_us_since_boot(time);
338 uint16_t next_sequence = (entry->sequence + 1) & 0x7fff;
339 if (!next_sequence) next_sequence = 1; // zero is not allowed
340 entry->sequence = next_sequence;
341 alarm_id_t id = make_alarm_id(index, next_sequence);
342
343 // ---- and add it to the new list
344 save = spin_lock_blocking(pool->lock);
345 entry->next = pool->new_head;
346 pool->new_head = index;
347 spin_unlock(pool->lock, save);
348
349 // force the IRQ
350 ta_force_irq(pool->timer, pool->timer_alarm_num);
351 return id;
352}
353
355 int16_t index = alarm_index(alarm_id);
356 if (index >= pool->num_entries) return false;
357 uint16_t sequence = alarm_sequence(alarm_id);
358 bool canceled = false;
359 alarm_pool_entry_t *entry = &pool->entries[index];
360 uint32_t save = spin_lock_blocking(pool->lock);
361 // note this will not be true if the entry is already canceled (as the entry->sequence
362 // will have the top bit set)
363 uint current_sequence = entry->sequence;
364 if (sequence == current_sequence) {
365 entry->sequence = (uint16_t)(current_sequence | 0x8000);
366 __compiler_memory_barrier();
367 pool->has_pending_cancellations = true;
368 canceled = true;
369 }
370 spin_unlock(pool->lock, save);
371 // force the IRQ if we need to clean up an alarm id
372 if (canceled) ta_force_irq(pool->timer, pool->timer_alarm_num);
373 return canceled;
374}
375
379
381 return pool->core_num;
382}
383
384#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
385static int64_t sleep_until_callback(__unused alarm_id_t id, __unused void *user_data) {
386 uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
387 lock_internal_spin_unlock_with_notify(&sleep_notifier, save);
388 return 0;
389}
390#endif
391
393#if PICO_ON_DEVICE && !defined(NDEBUG)
394 if (__get_current_exception()) {
395 panic("Attempted to sleep inside of an exception handler; use busy_wait if you must");
396 }
397#endif
398#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
399 uint64_t t_us = to_us_since_boot(t);
400 uint64_t t_before_us = t_us - PICO_TIME_SLEEP_OVERHEAD_ADJUST_US;
401 // needs to work in the first PICO_TIME_SLEEP_OVERHEAD_ADJUST_US of boot
402 if (t_before_us > t_us) t_before_us = 0;
403 absolute_time_t t_before;
404 update_us_since_boot(&t_before, t_before_us);
405 if (absolute_time_diff_us(get_absolute_time(), t_before) > 0) {
406 if (add_alarm_at(t_before, sleep_until_callback, NULL, false) >= 0) {
407 // able to add alarm for just before the time
408 while (!time_reached(t_before)) {
409 uint32_t save = spin_lock_blocking(sleep_notifier.spin_lock);
410 lock_internal_spin_unlock_with_wait(&sleep_notifier, save);
411 }
412 }
413 }
414#else
415 // hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
417#endif
418 // now wait until the exact time
420}
421
422void sleep_us(uint64_t us) {
423#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
424 sleep_until(make_timeout_time_us(us));
425#else
427 busy_wait_us(us);
428 } else {
429 // hook in case we're in RTOS; note we assume using the alarm pool is better always if available.
430 absolute_time_t t = make_timeout_time_us(us - PICO_TIME_SLEEP_OVERHEAD_ADJUST_US);
432
433 // then wait the rest of the way
435 }
436#endif
437}
438
440 sleep_us(ms * 1000ull);
441}
442
444#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
445 if (__get_current_exception()) {
447 return time_reached(timeout_timestamp);
448 } else {
450 // note that as of SDK 2.0.0 calling add_alarm_at always causes a SEV. What we really
451 // want to do is cause an IRQ at the specified time in the future if there is not
452 // an IRQ already happening before then. The problem is that the IRQ may be happening on the
453 // other core, so taking an IRQ is the only way to get the state protection.
454 //
455 // Therefore, we make a compromise; we will set the alarm, if we won't wake up before the right time
456 // already. This means that repeated calls to this function with the same timeout will work correctly
457 // after the first one! This is fine, because we ask callers to use a polling loop on another
458 // event variable when using this function.
459 //
460 // For this to work, we require that once we have set an alarm, an SEV happens no later than that, even
461 // if we cancel the alarm as we do below. Therefore, the IRQ handler (which is always enabled) will
462 // never set its wakeup time to a later value, but instead wake up once and then wake up again.
463 //
464 // This overhead when canceling alarms is a small price to pay for the much simpler/faster/cleaner
465 // implementation that relies on the IRQ handler (on a single core) being the only state accessor.
466 //
467 // Note also, that the use of software spin locks on RP2350 to access state would always cause a SEV
468 // due to use of LDREX etc., so actually using spin locks to protect the state would be worse.
470 (int64_t)to_us_since_boot(timeout_timestamp))) {
471 // we already are waking up at or before when we want to (possibly due to us having been called
472 // before in a loop), so we can do an actual WFE. Note we rely on the fact that the alarm pool IRQ
473 // handler always does an explicit SEV, since it may be on the other core.
474 __wfe();
475 return time_reached(timeout_timestamp);
476 } else {
477 id = add_alarm_at(timeout_timestamp, sleep_until_callback, NULL, false);
478 if (id <= 0) {
480 return time_reached(timeout_timestamp);
481 } else {
482 if (!time_reached(timeout_timestamp)) {
483 // ^ at the point above the timer hadn't fired, so it is safe
484 // to wait; the event will happen due to IRQ at some point between
485 // then and the correct wakeup time
486 __wfe();
487 }
488 // we need to clean up if it wasn't us that caused the wfe; if it was this will be a noop.
489 cancel_alarm(id);
490 return time_reached(timeout_timestamp);
491 }
492 }
493 }
494#else
496 return time_reached(timeout_timestamp);
497#endif
498}
499
501 if (!delay_us) delay_us = 1;
502 out->pool = pool;
503 out->callback = callback;
504 out->delay_us = delay_us;
505 out->user_data = user_data;
506 out->alarm_id = alarm_pool_add_alarm_at(pool, make_timeout_time_us((uint64_t)(delay_us >= 0 ? delay_us : -delay_us)),
508 return out->alarm_id > 0;
509}
510
512 bool rc = false;
513 if (timer->alarm_id) {
514 rc = alarm_pool_cancel_alarm(timer->pool, timer->alarm_id);
515 timer->alarm_id = 0;
516 }
517 return rc;
518}
519
523
527
529 // note there is no point distinguishing between invalid alarm_id and timer passed,
530 // since an alarm_id that has fired without being re-enabled becomes logically invalid after
531 // that point anyway
532 int64_t rc = -1;
533 int16_t index = alarm_index(alarm_id);
534 if ((uint16_t)index < pool->num_entries) {
535 uint16_t sequence = alarm_sequence(alarm_id);
536 alarm_pool_entry_t *entry = &pool->entries[index];
537 if (entry->sequence == sequence) {
538 uint32_t save = spin_lock_blocking(pool->lock);
539 int16_t search_index = pool->ordered_head;
540 while (search_index >= 0) {
541 entry = &pool->entries[search_index];
542 if (index == search_index) {
543 if (entry->sequence == sequence) {
544 rc = entry->target - (int64_t) ta_time_us_64(pool->timer);
545 }
546 break;
547 }
548 search_index = entry->next;
549 }
550 spin_unlock(pool->lock, save);
551 }
552 }
553 return rc;
554}
555
557 int64_t rc = alarm_pool_remaining_alarm_time_us(pool, alarm_id);
558 if (rc >= 0) rc /= 1000;
559 return rc >= INT32_MAX ? INT32_MAX : (int32_t) rc;
560}
561
562#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
566
570#endif
#define invalid_params_if(x, test)
Definition assert.h:34
void uint32_t
Definition bootrom.h:36
#define assert(expr)
Definition debug.h:68
int t
Definition ctypes.h:77
#define NULL
Definition oi_stddefs.h:55
bool alarm_pool_cancel_alarm(alarm_pool_t *pool, alarm_id_t alarm_id)
Cancel an alarm.
Definition time.c:354
int64_t alarm_pool_remaining_alarm_time_us(alarm_pool_t *pool, alarm_id_t alarm_id)
Return the time remaining before the next trigger of an alarm.
Definition time.c:528
int32_t alarm_pool_remaining_alarm_time_ms(alarm_pool_t *pool, alarm_id_t alarm_id)
Return the time remaining before the next trigger of an alarm.
Definition time.c:556
#define PICO_TIME_DEFAULT_ALARM_POOL_HARDWARE_ALARM_NUM
Selects which timer_alarm is used for the default alarm pool.
Definition time.h:337
uint alarm_pool_core_num(alarm_pool_t *pool)
Return the core number the alarm pool was initialized on (and hence callbacks are called on)
Definition time.c:380
#define PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS
Selects the maximum number of concurrent timers in the default alarm pool.
Definition time.h:350
alarm_pool_t * alarm_pool_get_default(void)
The default alarm pool used when alarms are added without specifying an alarm pool,...
Definition time.c:100
int64_t remaining_alarm_time_us(alarm_id_t alarm_id)
Return the time remaining before the next trigger of an alarm.
Definition time.c:563
int32_t remaining_alarm_time_ms(alarm_id_t alarm_id)
Return the time remaining before the next trigger of an alarm.
Definition time.c:567
alarm_id_t alarm_pool_add_alarm_at_force_in_context(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback, void *user_data)
Add an alarm callback to be called at or after a specific time.
Definition time.c:321
int32_t alarm_id_t
The identifier for an alarm.
Definition time.h:367
void alarm_pool_init_default(void)
Create the default alarm pool (if not already created or disabled)
Definition time.c:95
alarm_id_t alarm_pool_add_alarm_at(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback, void *user_data, bool fire_if_past)
Add an alarm callback to be called at a specific time.
Definition time.c:312
int64_t(* alarm_callback_t)(alarm_id_t id, void *user_data)
User alarm callback.
Definition time.h:378
void alarm_pool_destroy(alarm_pool_t *pool)
Destroy the alarm pool, cancelling all alarms and freeing up the underlying timer_alarm.
Definition time.c:298
uint alarm_pool_timer_alarm_num(alarm_pool_t *pool)
Return the timer alarm used by an alarm pool.
Definition time.c:376
#define delay_us(delay)
Delay in microseconds.
Definition delay.h:129
#define sync_internal_yield_until_before(until)
yield to other processing until some time before the requested time
Definition lock_core.h:196
#define lock_internal_spin_unlock_with_notify(lock, save)
Atomically unlock the lock's spin lock, and send a notification.
Definition lock_core.h:151
#define lock_internal_spin_unlock_with_wait(lock, save)
Atomically unlock the lock's spin lock, and wait for a notification.
Definition lock_core.h:128
void lock_init(lock_core_t *core, uint lock_num)
Initialise a lock structure.
Definition lock_core.c:9
@ PICO_ERROR_GENERIC
An unspecified error occurred.
Definition error.h:25
bool(* repeating_timer_callback_t)(repeating_timer_t *rt)
Callback for a repeating timer.
Definition time.h:729
bool alarm_pool_add_repeating_timer_us(alarm_pool_t *pool, int64_t delay_us, repeating_timer_callback_t callback, void *user_data, repeating_timer_t *out)
Add a repeating timer that is called repeatedly at the specified interval in microseconds.
Definition time.c:500
bool cancel_repeating_timer(repeating_timer_t *timer)
Cancel a repeating timer.
Definition time.c:511
void sleep_until(absolute_time_t t)
Wait until after the given timestamp to return.
Definition time.c:392
void sleep_ms(uint32_t ms)
Wait for the given number of milliseconds before returning.
Definition time.c:439
bool best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp)
Helper method for blocking on a timeout.
Definition time.c:443
void sleep_us(uint64_t us)
Wait for the given number of microseconds before returning.
Definition time.c:422
const absolute_time_t nil_time
The timestamp representing a null timestamp.
const absolute_time_t at_the_end_of_time
The timestamp representing the end of time; this is actually not the maximum possible timestamp,...
uint64_t absolute_time_t
An opaque 64 bit timestamp in microseconds.
Definition types.h:43
spin_lock_t * spin_lock_instance(uint lock_num)
void __wfe()
#define PICO_SPINLOCK_ID_TIMER
Definition sync.h:41
void __sev()
uint32_t spin_lock_blocking(spin_lock_t *lock)
struct _spin_lock_t spin_lock_t
Definition sync.h:88
uint next_striped_spin_lock_num()
void spin_unlock(spin_lock_t *lock, uint32_t saved_irq)
void busy_wait_until(absolute_time_t t)
Definition timer.c:68
bool time_reached(absolute_time_t t)
Definition timer.c:62
void busy_wait_us(uint64_t delay_us)
Definition timer.c:26
#define PICO_RUNTIME_INIT_FUNC_RUNTIME(func, priority_string1, priority_string2)
Definition runtime.h:29
void ta_enable_irq_handler(alarm_pool_timer_t *timer, uint hardware_alarm_num, void(*irq_handler)(void))
void ta_set_timeout(alarm_pool_timer_t *timer, uint hardware_alarm_num, int64_t target)
void ta_force_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num)
void ta_clear_force_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num)
int ta_hardware_alarm_claim_unused(alarm_pool_timer_t *timer, bool required)
uint ta_timer_num(alarm_pool_timer_t *timer)
alarm_pool_timer_t * ta_default_timer_instance(void)
void ta_hardware_alarm_claim(alarm_pool_timer_t *timer, uint hardware_alarm_num)
#define TA_NUM_TIMERS
void ta_clear_irq(alarm_pool_timer_t *timer, uint hardware_alarm_num)
alarm_pool_timer_t * ta_from_current_irq(uint *alarm_num)
void ta_disable_irq_handler(alarm_pool_timer_t *timer, uint hardware_alarm_num, void(*irq_handler)(void))
#define TA_NUM_TIMER_ALARMS
alarm_pool_timer_t * ta_timer_instance(uint instance_num)
bool ta_wakes_up_on_or_before(alarm_pool_timer_t *timer, uint alarm_num, int64_t target)
btstack_timer_source_t timer
uint8_t id
Definition otp.h:37
struct lock_core lock_core_t
Definition lock_core.h:61
void *REAL_FUNC malloc(size_t size)
Definition malloc.c:68
void *REAL_FUNC calloc(size_t count, size_t size)
Definition malloc.c:83
void REAL_FUNC free(void *mem)
Definition malloc.c:113
#define PICO_RUNTIME_INIT_DEFAULT_ALARM_POOL
int i
Definition sqrt_test.cpp:12
unsigned int uint
Definition types.h:18
#define ABSOLUTE_TIME_INITIALIZED_VAR(name, value)
Definition types.h:91
struct repeating_timer repeating_timer_t
Definition time.h:721
void runtime_init_default_alarm_pool(void)
Definition time.c:79
#define PICO_TIME_SLEEP_OVERHEAD_ADJUST_US
Definition time.h:43
void alarm_pool_timer_t
Definition time.h:381
struct alarm_pool alarm_pool_t
Definition time.h:380
struct alarm_pool_entry alarm_pool_entry_t
alarm_pool_t * alarm_pool_create_on_timer_with_unused_hardware_alarm(alarm_pool_timer_t *timer, uint max_timers)
Definition time.c:121
alarm_pool_timer_t * alarm_pool_timer_for_timer_num(uint timer_num)
Definition time.c:520
alarm_pool_t * alarm_pool_create_on_timer(alarm_pool_timer_t *timer, uint hardware_alarm_num, uint max_timers)
Definition time.c:111
alarm_pool_timer_t * alarm_pool_get_default_timer(void)
Definition time.c:524
#define repeating_timer_marker
Definition time.c:134
void __weak runtime_init_default_alarm_pool(void)
Definition time.c:79
#define __unused
Definition platform.h:56
void tight_loop_contents()
#define __weak
Definition platform.h:77
void __noreturn panic(const char *fmt,...)
uint get_core_num()
Definition time.c:16
int16_t next
Definition time.c:18
int64_t target
Definition time.c:23
void * user_data
Definition time.c:25
alarm_callback_t callback
Definition time.c:24
volatile uint16_t sequence
Definition time.c:22
volatile int16_t new_head
Definition time.c:34
alarm_pool_timer_t * timer
Definition time.c:40
int16_t ordered_head
Definition time.c:38
spin_lock_t * lock
Definition time.c:41
alarm_pool_entry_t * entries
Definition time.c:42
uint16_t num_entries
Definition time.c:39
uint8_t timer_alarm_num
Definition time.c:29
int16_t free_head
Definition time.c:32
volatile bool has_pending_cancellations
Definition time.c:35
uint8_t core_num
Definition time.c:30
int64_t delay_us
Definition time.h:737
repeating_timer_callback_t callback
Definition time.h:740
uint32_t * prev
Definition tl.h:67