1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <string.h>
8 #include "pico/async_context_poll.h"
9 #include "pico/async_context_base.h"
10 #include "pico/sync.h"
11 
noop(__unused async_context_t * context)12 static void noop(__unused async_context_t *context) { }
13 
14 static const async_context_type_t template;
15 
async_context_poll_init_with_defaults(async_context_poll_t * self)16 bool async_context_poll_init_with_defaults(async_context_poll_t *self) {
17     memset(self, 0, sizeof(*self));
18     self->core.core_num = get_core_num();
19     self->core.type = &template;
20     self->core.flags = ASYNC_CONTEXT_FLAG_POLLED | ASYNC_CONTEXT_FLAG_CALLBACK_FROM_NON_IRQ;
21     sem_init(&self->sem, 1, 1);
22     return true;
23 }
24 
async_context_poll_wake_up(async_context_t * self_base)25 static void async_context_poll_wake_up(async_context_t *self_base) {
26     sem_release(&((async_context_poll_t *)self_base)->sem);
27 }
28 
async_context_poll_requires_update(async_context_t * self_base,async_when_pending_worker_t * worker)29 static void async_context_poll_requires_update(async_context_t *self_base, async_when_pending_worker_t *worker) {
30     worker->work_pending = true;
31     async_context_poll_wake_up(self_base);
32 }
33 
async_context_poll_poll(async_context_t * self_base)34 static void async_context_poll_poll(async_context_t *self_base) {
35     async_context_base_execute_once(self_base);
36 }
37 
async_context_poll_wait_until(__unused async_context_t * self_base,absolute_time_t until)38 static void async_context_poll_wait_until(__unused async_context_t *self_base, absolute_time_t until) {
39     sleep_until(until);
40 }
41 
async_context_poll_wait_for_work_until(async_context_t * self_base,absolute_time_t until)42 static void async_context_poll_wait_for_work_until(async_context_t *self_base, absolute_time_t until) {
43     absolute_time_t next_time = self_base->next_time;
44     async_context_poll_t *self = (async_context_poll_t *)self_base;
45     sem_acquire_block_until(&self->sem, absolute_time_min(next_time, until));
46 }
47 
async_context_poll_lock_check(async_context_t * self_base)48 static void async_context_poll_lock_check(async_context_t *self_base) {
49     if (__get_current_exception() || get_core_num() != self_base->core_num) {
50         panic("async_context_poll context check failed (IRQ or wrong core)");
51     }
52 }
53 
async_context_poll_execute_sync(__unused async_context_t * context,uint32_t (* func)(void * param),void * param)54 uint32_t async_context_poll_execute_sync(__unused async_context_t *context, uint32_t (*func)(void *param), void *param) {
55     return func(param);
56 }
57 
58 static const async_context_type_t template = {
59         .type = ASYNC_CONTEXT_POLL,
60         .acquire_lock_blocking = noop,
61         .release_lock = noop,
62         .lock_check = async_context_poll_lock_check,
63         .execute_sync = async_context_poll_execute_sync,
64         .add_at_time_worker = async_context_base_add_at_time_worker,
65         .remove_at_time_worker = async_context_base_remove_at_time_worker,
66         .add_when_pending_worker = async_context_base_add_when_pending_worker,
67         .remove_when_pending_worker = async_context_base_remove_when_pending_worker,
68         .set_work_pending = async_context_poll_requires_update,
69         .poll = async_context_poll_poll,
70         .wait_until = async_context_poll_wait_until,
71         .wait_for_work_until = async_context_poll_wait_for_work_until,
72         .deinit = noop,
73 };
74