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