xref: /btstack/src/btstack_run_loop.c (revision 7eaf37e0f99efbbb9c9194b05a4ce9d62161d3c5)
115d50271SMatthias Ringwald /*
215d50271SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
315d50271SMatthias Ringwald  *
415d50271SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
515d50271SMatthias Ringwald  * modification, are permitted provided that the following conditions
615d50271SMatthias Ringwald  * are met:
715d50271SMatthias Ringwald  *
815d50271SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
915d50271SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
1015d50271SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
1115d50271SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
1215d50271SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
1315d50271SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
1415d50271SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
1515d50271SMatthias Ringwald  *    from this software without specific prior written permission.
1615d50271SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
1715d50271SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
1815d50271SMatthias Ringwald  *    monetary gain.
1915d50271SMatthias Ringwald  *
2015d50271SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2115d50271SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2215d50271SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2315d50271SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
2415d50271SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2515d50271SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2615d50271SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2715d50271SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2815d50271SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2915d50271SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3015d50271SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3115d50271SMatthias Ringwald  * SUCH DAMAGE.
3215d50271SMatthias Ringwald  *
3315d50271SMatthias Ringwald  * Please inquire about commercial licensing options at
3415d50271SMatthias Ringwald  * [email protected]
3515d50271SMatthias Ringwald  *
3615d50271SMatthias Ringwald  */
3715d50271SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_run_loop.c"
39ab2c6ae4SMatthias Ringwald 
4015d50271SMatthias Ringwald /*
4115d50271SMatthias Ringwald  *  run_loop.c
4215d50271SMatthias Ringwald  *
4315d50271SMatthias Ringwald  *  Created by Matthias Ringwald on 6/6/09.
4415d50271SMatthias Ringwald  */
4515d50271SMatthias Ringwald 
4615d50271SMatthias Ringwald #include "btstack_run_loop.h"
4715d50271SMatthias Ringwald 
4815d50271SMatthias Ringwald #include "btstack_debug.h"
497907f069SMatthias Ringwald #include "btstack_config.h"
50796f7837SMatthias Ringwald #include "btstack_util.h"
5115d50271SMatthias Ringwald 
52016e9464SMatthias Ringwald #include <inttypes.h>
53016e9464SMatthias Ringwald 
54528a4a3bSMatthias Ringwald static const btstack_run_loop_t * the_run_loop = NULL;
5515d50271SMatthias Ringwald 
56528a4a3bSMatthias Ringwald extern const btstack_run_loop_t btstack_run_loop_embedded;
5715d50271SMatthias Ringwald 
58796f7837SMatthias Ringwald /*
59796f7837SMatthias Ringwald  *  Portable implementation of timer and data source management as base for platform specific implementations
60796f7837SMatthias Ringwald  */
61796f7837SMatthias Ringwald 
62796f7837SMatthias Ringwald // private data (access only by run loop implementations)
63796f7837SMatthias Ringwald btstack_linked_list_t  btstack_run_loop_base_timers;
64796f7837SMatthias Ringwald btstack_linked_list_t  btstack_run_loop_base_data_sources;
65*7eaf37e0SMatthias Ringwald btstack_linked_list_t  btstack_run_loop_base_callbacks;
66796f7837SMatthias Ringwald 
67796f7837SMatthias Ringwald void btstack_run_loop_base_init(void){
68796f7837SMatthias Ringwald     btstack_run_loop_base_timers = NULL;
69796f7837SMatthias Ringwald     btstack_run_loop_base_data_sources = NULL;
70*7eaf37e0SMatthias Ringwald     btstack_run_loop_base_callbacks = NULL;
71796f7837SMatthias Ringwald }
72796f7837SMatthias Ringwald 
73b45b7749SMilanka Ringwald void btstack_run_loop_base_add_data_source(btstack_data_source_t * data_source){
74b45b7749SMilanka Ringwald     btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source);
75796f7837SMatthias Ringwald }
76796f7837SMatthias Ringwald 
77b45b7749SMilanka Ringwald bool btstack_run_loop_base_remove_data_source(btstack_data_source_t * data_source){
78b45b7749SMilanka Ringwald     return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source);
79796f7837SMatthias Ringwald }
80796f7837SMatthias Ringwald 
81b45b7749SMilanka Ringwald void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){
82b45b7749SMilanka Ringwald     data_source->flags |= callback_types;
83796f7837SMatthias Ringwald }
84796f7837SMatthias Ringwald 
85b45b7749SMilanka Ringwald void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){
86b45b7749SMilanka Ringwald     data_source->flags &= ~callback_types;
87796f7837SMatthias Ringwald }
88796f7837SMatthias Ringwald 
89b45b7749SMilanka Ringwald bool btstack_run_loop_base_remove_timer(btstack_timer_source_t * timer){
90b45b7749SMilanka Ringwald     return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) timer);
91796f7837SMatthias Ringwald }
92796f7837SMatthias Ringwald 
93b45b7749SMilanka Ringwald void btstack_run_loop_base_add_timer(btstack_timer_source_t * timer){
94796f7837SMatthias Ringwald     btstack_linked_item_t *it;
95796f7837SMatthias Ringwald     for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){
96796f7837SMatthias Ringwald         btstack_timer_source_t * next = (btstack_timer_source_t *) it->next;
97b45b7749SMilanka Ringwald         btstack_assert(next != timer);
98b45b7749SMilanka Ringwald         int32_t delta = btstack_time_delta(timer->timeout, next->timeout);
99796f7837SMatthias Ringwald         if (delta < 0) break;
100796f7837SMatthias Ringwald     }
101b45b7749SMilanka Ringwald     timer->item.next = it->next;
102b45b7749SMilanka Ringwald     it->next = (btstack_linked_item_t *) timer;
103796f7837SMatthias Ringwald }
104796f7837SMatthias Ringwald 
105796f7837SMatthias Ringwald void btstack_run_loop_base_process_timers(uint32_t now){
106796f7837SMatthias Ringwald     // process timers, exit when timeout is in the future
107796f7837SMatthias Ringwald     while (btstack_run_loop_base_timers) {
108b45b7749SMilanka Ringwald         btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers;
109b45b7749SMilanka Ringwald         int32_t delta = btstack_time_delta(timer->timeout, now);
110796f7837SMatthias Ringwald         if (delta > 0) break;
111b45b7749SMilanka Ringwald         btstack_run_loop_base_remove_timer(timer);
112b45b7749SMilanka Ringwald         timer->process(timer);
113796f7837SMatthias Ringwald     }
114796f7837SMatthias Ringwald }
115796f7837SMatthias Ringwald 
116796f7837SMatthias Ringwald void btstack_run_loop_base_dump_timer(void){
117796f7837SMatthias Ringwald #ifdef ENABLE_LOG_INFO
118796f7837SMatthias Ringwald     btstack_linked_item_t *it;
119796f7837SMatthias Ringwald     uint16_t i = 0;
120796f7837SMatthias Ringwald     for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){
121b45b7749SMilanka Ringwald         btstack_timer_source_t * timer = (btstack_timer_source_t*) it;
122aadd60a1SMatthias Ringwald         log_info("timer %u (%p): timeout %" PRIu32 "u\n", i, (void *) timer, timer->timeout);
123796f7837SMatthias Ringwald     }
124796f7837SMatthias Ringwald #endif
125796f7837SMatthias Ringwald 
126796f7837SMatthias Ringwald }
127796f7837SMatthias Ringwald /**
128796f7837SMatthias Ringwald  * @brief Get time until first timer fires
129796f7837SMatthias Ringwald  * @returns -1 if no timers, time until next timeout otherwise
130796f7837SMatthias Ringwald  */
131796f7837SMatthias Ringwald int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){
132796f7837SMatthias Ringwald     if (btstack_run_loop_base_timers == NULL) return -1;
133b45b7749SMilanka Ringwald     btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers;
134b45b7749SMilanka Ringwald     uint32_t list_timeout  = timer->timeout;
135796f7837SMatthias Ringwald     int32_t delta = btstack_time_delta(list_timeout, now);
136796f7837SMatthias Ringwald     if (delta < 0){
137796f7837SMatthias Ringwald         delta = 0;
138796f7837SMatthias Ringwald     }
139796f7837SMatthias Ringwald     return delta;
140796f7837SMatthias Ringwald }
141796f7837SMatthias Ringwald 
142796f7837SMatthias Ringwald void btstack_run_loop_base_poll_data_sources(void){
143796f7837SMatthias Ringwald     // poll data sources
144796f7837SMatthias Ringwald     btstack_data_source_t *ds;
145796f7837SMatthias Ringwald     btstack_data_source_t *next;
146796f7837SMatthias Ringwald     for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){
147796f7837SMatthias Ringwald         next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
148796f7837SMatthias Ringwald         if (ds->flags & DATA_SOURCE_CALLBACK_POLL){
149796f7837SMatthias Ringwald             ds->process(ds, DATA_SOURCE_CALLBACK_POLL);
150796f7837SMatthias Ringwald         }
151796f7837SMatthias Ringwald     }
152796f7837SMatthias Ringwald }
153796f7837SMatthias Ringwald 
154*7eaf37e0SMatthias Ringwald void btstack_run_loop_base_add_callback(btstack_context_callback_registration_t * callback_registration){
155*7eaf37e0SMatthias Ringwald     btstack_linked_list_add_tail(&btstack_run_loop_base_callbacks, (btstack_linked_item_t *) callback_registration);
156*7eaf37e0SMatthias Ringwald }
157*7eaf37e0SMatthias Ringwald 
158*7eaf37e0SMatthias Ringwald 
159*7eaf37e0SMatthias Ringwald void btstack_run_loop_base_execute_callbacks(void){
160*7eaf37e0SMatthias Ringwald     while (1){
161*7eaf37e0SMatthias Ringwald         btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks);
162*7eaf37e0SMatthias Ringwald         if (callback_registration == NULL){
163*7eaf37e0SMatthias Ringwald             break;
164*7eaf37e0SMatthias Ringwald         }
165*7eaf37e0SMatthias Ringwald         (*callback_registration->callback)(callback_registration->context);
166*7eaf37e0SMatthias Ringwald     }
167*7eaf37e0SMatthias Ringwald }
168*7eaf37e0SMatthias Ringwald 
169*7eaf37e0SMatthias Ringwald 
170796f7837SMatthias Ringwald /**
171796f7837SMatthias Ringwald  * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation
172796f7837SMatthias Ringwald  */
173796f7837SMatthias Ringwald 
174796f7837SMatthias Ringwald // main implementation
175796f7837SMatthias Ringwald 
176b45b7749SMilanka Ringwald void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
177b45b7749SMilanka Ringwald     timer->process = process;
178aadd60a1SMatthias Ringwald }
17915d50271SMatthias Ringwald 
180b45b7749SMilanka Ringwald void btstack_run_loop_set_data_source_handler(btstack_data_source_t * data_source, void (*process)(btstack_data_source_t *_data_source,  btstack_data_source_callback_type_t callback_type)){
181b45b7749SMilanka Ringwald     data_source->process = process;
182aadd60a1SMatthias Ringwald }
18315d50271SMatthias Ringwald 
184b45b7749SMilanka Ringwald void btstack_run_loop_set_data_source_fd(btstack_data_source_t * data_source, int fd){
185b45b7749SMilanka Ringwald     data_source->source.fd = fd;
1863a5c43eeSMatthias Ringwald }
1873a5c43eeSMatthias Ringwald 
188b45b7749SMilanka Ringwald int btstack_run_loop_get_data_source_fd(btstack_data_source_t * data_source){
189b45b7749SMilanka Ringwald     return data_source->source.fd;
1903a5c43eeSMatthias Ringwald }
1913a5c43eeSMatthias Ringwald 
192b45b7749SMilanka Ringwald void btstack_run_loop_set_data_source_handle(btstack_data_source_t * data_source, void * handle){
193b45b7749SMilanka Ringwald     data_source->source.handle = handle;
194f04a41aeSMatthias Ringwald }
195f04a41aeSMatthias Ringwald 
196b45b7749SMilanka Ringwald void * btstack_run_loop_get_data_source_handle(btstack_data_source_t * data_source){
197b45b7749SMilanka Ringwald     return data_source->source.handle;
198f04a41aeSMatthias Ringwald }
199f04a41aeSMatthias Ringwald 
200b45b7749SMilanka Ringwald void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){
20127e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
202141177f8SMatthias Ringwald     btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
203b45b7749SMilanka Ringwald     the_run_loop->enable_data_source_callbacks(data_source, callbacks);
204896424b7SMatthias Ringwald }
205896424b7SMatthias Ringwald 
206b45b7749SMilanka Ringwald void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){
20727e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
208141177f8SMatthias Ringwald     btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
209b45b7749SMilanka Ringwald     the_run_loop->disable_data_source_callbacks(data_source, callbacks);
210896424b7SMatthias Ringwald }
21115d50271SMatthias Ringwald 
21215d50271SMatthias Ringwald /**
21315d50271SMatthias Ringwald  * Add data_source to run_loop
21415d50271SMatthias Ringwald  */
215b45b7749SMilanka Ringwald void btstack_run_loop_add_data_source(btstack_data_source_t * data_source){
21627e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
217141177f8SMatthias Ringwald     btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
218b45b7749SMilanka Ringwald     btstack_assert(data_source->process != NULL);
219b45b7749SMilanka Ringwald     the_run_loop->add_data_source(data_source);
22015d50271SMatthias Ringwald }
22115d50271SMatthias Ringwald 
22215d50271SMatthias Ringwald /**
22315d50271SMatthias Ringwald  * Remove data_source from run loop
22415d50271SMatthias Ringwald  */
225b45b7749SMilanka Ringwald int btstack_run_loop_remove_data_source(btstack_data_source_t * data_source){
22627e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
2270ad702f3SMatthias Ringwald     btstack_assert(the_run_loop->disable_data_source_callbacks != NULL);
228b45b7749SMilanka Ringwald     btstack_assert(data_source->process != NULL);
229b45b7749SMilanka Ringwald     return the_run_loop->remove_data_source(data_source);
23015d50271SMatthias Ringwald }
23115d50271SMatthias Ringwald 
2329fb44c6dSMatthias Ringwald void btstack_run_loop_poll_data_sources_from_irq(void){
2339fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop != NULL);
2349fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop->poll_data_sources_from_irq != NULL);
2359fb44c6dSMatthias Ringwald     the_run_loop->poll_data_sources_from_irq();
2369fb44c6dSMatthias Ringwald }
2379fb44c6dSMatthias Ringwald 
238b45b7749SMilanka Ringwald void btstack_run_loop_set_timer(btstack_timer_source_t *timer, uint32_t timeout_in_ms){
23927e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
240b45b7749SMilanka Ringwald     the_run_loop->set_timer(timer, timeout_in_ms);
24115d50271SMatthias Ringwald }
24215d50271SMatthias Ringwald 
24315d50271SMatthias Ringwald /**
244fd939756SMatthias Ringwald  * @brief Set context for this timer
245fd939756SMatthias Ringwald  */
246b45b7749SMilanka Ringwald void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
247b45b7749SMilanka Ringwald     timer->context = context;
248fd939756SMatthias Ringwald }
249fd939756SMatthias Ringwald 
250fd939756SMatthias Ringwald /**
251fd939756SMatthias Ringwald  * @brief Get context for this timer
252fd939756SMatthias Ringwald  */
253b45b7749SMilanka Ringwald void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
254b45b7749SMilanka Ringwald     return timer->context;
255fd939756SMatthias Ringwald }
256fd939756SMatthias Ringwald 
257fd939756SMatthias Ringwald /**
25815d50271SMatthias Ringwald  * Add timer to run_loop (keep list sorted)
25915d50271SMatthias Ringwald  */
260b45b7749SMilanka Ringwald void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
26127e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
262b45b7749SMilanka Ringwald     btstack_assert(timer->process != NULL);
263b45b7749SMilanka Ringwald     the_run_loop->add_timer(timer);
26415d50271SMatthias Ringwald }
26515d50271SMatthias Ringwald 
26615d50271SMatthias Ringwald /**
26715d50271SMatthias Ringwald  * Remove timer from run loop
26815d50271SMatthias Ringwald  */
269b45b7749SMilanka Ringwald int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
27027e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
271b45b7749SMilanka Ringwald     return the_run_loop->remove_timer(timer);
27215d50271SMatthias Ringwald }
27315d50271SMatthias Ringwald 
27415d50271SMatthias Ringwald /**
27515d50271SMatthias Ringwald  * @brief Get current time in ms
27615d50271SMatthias Ringwald  */
277528a4a3bSMatthias Ringwald uint32_t btstack_run_loop_get_time_ms(void){
27827e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
27915d50271SMatthias Ringwald     return the_run_loop->get_time_ms();
28015d50271SMatthias Ringwald }
28115d50271SMatthias Ringwald 
28215d50271SMatthias Ringwald 
283528a4a3bSMatthias Ringwald void btstack_run_loop_timer_dump(void){
28427e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
28515d50271SMatthias Ringwald     the_run_loop->dump_timer();
28615d50271SMatthias Ringwald }
28715d50271SMatthias Ringwald 
28815d50271SMatthias Ringwald /**
28915d50271SMatthias Ringwald  * Execute run_loop
29015d50271SMatthias Ringwald  */
291528a4a3bSMatthias Ringwald void btstack_run_loop_execute(void){
29227e05778SMatthias Ringwald     btstack_assert(the_run_loop != NULL);
29315d50271SMatthias Ringwald     the_run_loop->execute();
29415d50271SMatthias Ringwald }
29515d50271SMatthias Ringwald 
2969fb44c6dSMatthias Ringwald void btstack_run_loop_trigger_exit(void){
2979fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop != NULL);
2989fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop->trigger_exit != NULL);
2999fb44c6dSMatthias Ringwald     the_run_loop->trigger_exit();
3009fb44c6dSMatthias Ringwald }
3019fb44c6dSMatthias Ringwald 
3029fb44c6dSMatthias Ringwald void btstack_run_loop_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){
3039fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop != NULL);
3049fb44c6dSMatthias Ringwald     btstack_assert(the_run_loop->execute_on_main_thread != NULL);
3059fb44c6dSMatthias Ringwald     the_run_loop->execute_on_main_thread(callback_registration);
3069fb44c6dSMatthias Ringwald }
3079fb44c6dSMatthias Ringwald 
30815d50271SMatthias Ringwald // init must be called before any other run_loop call
309528a4a3bSMatthias Ringwald void btstack_run_loop_init(const btstack_run_loop_t * run_loop){
31027e05778SMatthias Ringwald     btstack_assert(the_run_loop == NULL);
31115d50271SMatthias Ringwald     the_run_loop = run_loop;
31215d50271SMatthias Ringwald     the_run_loop->init();
31315d50271SMatthias Ringwald }
31415d50271SMatthias Ringwald 
3153a2e2107SMatthias Ringwald void btstack_run_loop_deinit(void){
3163a2e2107SMatthias Ringwald     the_run_loop = NULL;
3173a2e2107SMatthias Ringwald }
3183a2e2107SMatthias Ringwald 
319