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 23*2fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24*2fca4dadSMilanka Ringwald * GMBH 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; 657eaf37e0SMatthias 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; 707eaf37e0SMatthias 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 1296b65794dSMilanka Ringwald * @return -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 1547eaf37e0SMatthias Ringwald void btstack_run_loop_base_add_callback(btstack_context_callback_registration_t * callback_registration){ 1557eaf37e0SMatthias Ringwald btstack_linked_list_add_tail(&btstack_run_loop_base_callbacks, (btstack_linked_item_t *) callback_registration); 1567eaf37e0SMatthias Ringwald } 1577eaf37e0SMatthias Ringwald 1587eaf37e0SMatthias Ringwald 1597eaf37e0SMatthias Ringwald void btstack_run_loop_base_execute_callbacks(void){ 1607eaf37e0SMatthias Ringwald while (1){ 1617eaf37e0SMatthias Ringwald btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks); 1627eaf37e0SMatthias Ringwald if (callback_registration == NULL){ 1637eaf37e0SMatthias Ringwald break; 1647eaf37e0SMatthias Ringwald } 1657eaf37e0SMatthias Ringwald (*callback_registration->callback)(callback_registration->context); 1667eaf37e0SMatthias Ringwald } 1677eaf37e0SMatthias Ringwald } 1687eaf37e0SMatthias Ringwald 1697eaf37e0SMatthias 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