1 /*
2 * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "pico/btstack_run_loop_async_context.h"
8 #include "hardware/sync.h"
9
10 static async_context_t *btstack_async_context;
11 static async_at_time_worker_t btstack_timeout_worker;
12 static async_when_pending_worker_t btstack_processing_worker;
13 static void btstack_timeout_reached(async_context_t *context, async_at_time_worker_t *worker);
14 static void btstack_work_pending(async_context_t *context, async_when_pending_worker_t *worker);
15 static volatile bool run_loop_exit;
16
btstack_run_loop_async_context_init(void)17 static void btstack_run_loop_async_context_init(void) {
18 btstack_run_loop_base_init();
19 btstack_timeout_worker.do_work = btstack_timeout_reached;
20 btstack_processing_worker.do_work = btstack_work_pending;
21 async_context_add_when_pending_worker(btstack_async_context, &btstack_processing_worker);
22 }
23
btstack_run_loop_async_context_add_data_source(btstack_data_source_t * data_source)24 static void btstack_run_loop_async_context_add_data_source(btstack_data_source_t * data_source) {
25 async_context_acquire_lock_blocking(btstack_async_context);
26 btstack_run_loop_base_add_data_source(data_source);
27 async_context_release_lock(btstack_async_context);
28 }
29
btstack_run_loop_async_context_remove_data_source(btstack_data_source_t * data_source)30 static bool btstack_run_loop_async_context_remove_data_source(btstack_data_source_t * data_source) {
31 async_context_acquire_lock_blocking(btstack_async_context);
32 bool rc = btstack_run_loop_base_remove_data_source(data_source);
33 async_context_release_lock(btstack_async_context);
34 return rc;
35 }
36
btstack_run_loop_async_context_enable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callbacks)37 static void btstack_run_loop_async_context_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
38 async_context_acquire_lock_blocking(btstack_async_context);
39 btstack_run_loop_base_enable_data_source_callbacks(data_source, callbacks);
40 async_context_release_lock(btstack_async_context);
41 }
42
btstack_run_loop_async_context_disable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callbacks)43 static void btstack_run_loop_async_context_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
44 async_context_acquire_lock_blocking(btstack_async_context);
45 btstack_run_loop_base_disable_data_source_callbacks(data_source, callbacks);
46 async_context_release_lock(btstack_async_context);
47 }
48
btstack_run_loop_async_context_set_timer(btstack_timer_source_t * ts,uint32_t timeout_in_ms)49 static void btstack_run_loop_async_context_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms){
50 async_context_acquire_lock_blocking(btstack_async_context);
51 ts->timeout = to_ms_since_boot(get_absolute_time()) + timeout_in_ms + 1;
52 async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
53 async_context_release_lock(btstack_async_context);
54 }
55
btstack_run_loop_async_context_add_timer(btstack_timer_source_t * timer)56 static void btstack_run_loop_async_context_add_timer(btstack_timer_source_t *timer) {
57 async_context_acquire_lock_blocking(btstack_async_context);
58 btstack_run_loop_base_add_timer(timer);
59 async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
60 async_context_release_lock(btstack_async_context);
61 }
62
btstack_run_loop_async_context_remove_timer(btstack_timer_source_t * timer)63 static bool btstack_run_loop_async_context_remove_timer(btstack_timer_source_t *timer) {
64 async_context_acquire_lock_blocking(btstack_async_context);
65 bool rc = btstack_run_loop_base_remove_timer(timer);
66 async_context_release_lock(btstack_async_context);
67 return rc;
68 }
69
btstack_run_loop_async_context_dump_timer(void)70 static void btstack_run_loop_async_context_dump_timer(void){
71 async_context_acquire_lock_blocking(btstack_async_context);
72 btstack_run_loop_base_dump_timer();
73 async_context_release_lock(btstack_async_context);
74 }
75
btstack_run_loop_async_context_get_time_ms(void)76 static uint32_t btstack_run_loop_async_context_get_time_ms(void)
77 {
78 return to_ms_since_boot(get_absolute_time());
79 }
80
btstack_run_loop_async_context_execute(void)81 static void btstack_run_loop_async_context_execute(void)
82 {
83 run_loop_exit = false;
84 while (!run_loop_exit) {
85 async_context_poll(btstack_async_context);
86 async_context_wait_for_work_until(btstack_async_context, at_the_end_of_time);
87 }
88 }
89
btstack_run_loop_async_context_trigger_exit(void)90 static void btstack_run_loop_async_context_trigger_exit(void)
91 {
92 run_loop_exit = true;
93 }
94
btstack_run_loop_async_context_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration)95 static void btstack_run_loop_async_context_execute_on_main_thread(btstack_context_callback_registration_t *callback_registration)
96 {
97 async_context_acquire_lock_blocking(btstack_async_context);
98 btstack_run_loop_base_add_callback(callback_registration);
99 async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
100 async_context_release_lock(btstack_async_context);
101 }
102
btstack_run_loop_async_context_poll_data_sources_from_irq(void)103 static void btstack_run_loop_async_context_poll_data_sources_from_irq(void)
104 {
105 async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
106 }
107
108 static const btstack_run_loop_t btstack_run_loop_async_context = {
109 &btstack_run_loop_async_context_init,
110 &btstack_run_loop_async_context_add_data_source,
111 &btstack_run_loop_async_context_remove_data_source,
112 &btstack_run_loop_async_context_enable_data_source_callbacks,
113 &btstack_run_loop_async_context_disable_data_source_callbacks,
114 &btstack_run_loop_async_context_set_timer,
115 &btstack_run_loop_async_context_add_timer,
116 &btstack_run_loop_async_context_remove_timer,
117 &btstack_run_loop_async_context_execute,
118 &btstack_run_loop_async_context_dump_timer,
119 &btstack_run_loop_async_context_get_time_ms,
120 &btstack_run_loop_async_context_poll_data_sources_from_irq,
121 &btstack_run_loop_async_context_execute_on_main_thread,
122 &btstack_run_loop_async_context_trigger_exit,
123 };
124
btstack_run_loop_async_context_get_instance(async_context_t * async_context)125 const btstack_run_loop_t *btstack_run_loop_async_context_get_instance(async_context_t *async_context)
126 {
127 assert(!btstack_async_context || btstack_async_context == async_context);
128 btstack_async_context = async_context;
129 return &btstack_run_loop_async_context;
130 }
131
btstack_timeout_reached(__unused async_context_t * context,__unused async_at_time_worker_t * worker)132 static void btstack_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) {
133 // simply wakeup worker
134 async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
135 }
136
btstack_work_pending(__unused async_context_t * context,__unused async_when_pending_worker_t * worker)137 static void btstack_work_pending(__unused async_context_t *context, __unused async_when_pending_worker_t *worker) {
138 // poll data sources
139 btstack_run_loop_base_poll_data_sources();
140
141 // execute callbacks
142 btstack_run_loop_base_execute_callbacks();
143
144 uint32_t now = to_ms_since_boot(get_absolute_time());
145
146 // process timers
147 btstack_run_loop_base_process_timers(now);
148 now = to_ms_since_boot(get_absolute_time());
149 int ms = btstack_run_loop_base_get_time_until_timeout(now);
150 if (ms == -1) {
151 async_context_remove_at_time_worker(btstack_async_context, &btstack_timeout_worker);
152 } else {
153 async_context_add_at_time_worker_in_ms(btstack_async_context, &btstack_timeout_worker, ms);
154 }
155 }
156