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" 50*796f7837SMatthias Ringwald #include "btstack_util.h" 5115d50271SMatthias Ringwald 52528a4a3bSMatthias Ringwald static const btstack_run_loop_t * the_run_loop = NULL; 5315d50271SMatthias Ringwald 54528a4a3bSMatthias Ringwald extern const btstack_run_loop_t btstack_run_loop_embedded; 5515d50271SMatthias Ringwald 56*796f7837SMatthias Ringwald /* 57*796f7837SMatthias Ringwald * Portable implementation of timer and data source management as base for platform specific implementations 58*796f7837SMatthias Ringwald */ 59*796f7837SMatthias Ringwald 60*796f7837SMatthias Ringwald // private data (access only by run loop implementations) 61*796f7837SMatthias Ringwald btstack_linked_list_t btstack_run_loop_base_timers; 62*796f7837SMatthias Ringwald btstack_linked_list_t btstack_run_loop_base_data_sources; 63*796f7837SMatthias Ringwald 64*796f7837SMatthias Ringwald void btstack_run_loop_base_init(void){ 65*796f7837SMatthias Ringwald btstack_run_loop_base_timers = NULL; 66*796f7837SMatthias Ringwald btstack_run_loop_base_data_sources = NULL; 67*796f7837SMatthias Ringwald } 68*796f7837SMatthias Ringwald 69*796f7837SMatthias Ringwald void btstack_run_loop_base_add_data_source(btstack_data_source_t *ds){ 70*796f7837SMatthias Ringwald btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 71*796f7837SMatthias Ringwald } 72*796f7837SMatthias Ringwald 73*796f7837SMatthias Ringwald bool btstack_run_loop_base_remove_data_source(btstack_data_source_t *ds){ 74*796f7837SMatthias Ringwald return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 75*796f7837SMatthias Ringwald } 76*796f7837SMatthias Ringwald 77*796f7837SMatthias Ringwald void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 78*796f7837SMatthias Ringwald ds->flags |= callback_types; 79*796f7837SMatthias Ringwald } 80*796f7837SMatthias Ringwald 81*796f7837SMatthias Ringwald void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 82*796f7837SMatthias Ringwald ds->flags &= ~callback_types; 83*796f7837SMatthias Ringwald } 84*796f7837SMatthias Ringwald 85*796f7837SMatthias Ringwald bool btstack_run_loop_base_remove_timer(btstack_timer_source_t *ts){ 86*796f7837SMatthias Ringwald return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) ts); 87*796f7837SMatthias Ringwald } 88*796f7837SMatthias Ringwald 89*796f7837SMatthias Ringwald void btstack_run_loop_base_add_timer(btstack_timer_source_t *ts){ 90*796f7837SMatthias Ringwald btstack_linked_item_t *it; 91*796f7837SMatthias Ringwald for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){ 92*796f7837SMatthias Ringwald btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 93*796f7837SMatthias Ringwald btstack_assert(next != ts); 94*796f7837SMatthias Ringwald int32_t delta = btstack_time_delta(ts->timeout, next->timeout); 95*796f7837SMatthias Ringwald if (delta < 0) break; 96*796f7837SMatthias Ringwald } 97*796f7837SMatthias Ringwald ts->item.next = it->next; 98*796f7837SMatthias Ringwald it->next = (btstack_linked_item_t *) ts; 99*796f7837SMatthias Ringwald } 100*796f7837SMatthias Ringwald 101*796f7837SMatthias Ringwald void btstack_run_loop_base_process_timers(uint32_t now){ 102*796f7837SMatthias Ringwald // process timers, exit when timeout is in the future 103*796f7837SMatthias Ringwald while (btstack_run_loop_base_timers) { 104*796f7837SMatthias Ringwald btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 105*796f7837SMatthias Ringwald int32_t delta = btstack_time_delta(ts->timeout, now); 106*796f7837SMatthias Ringwald if (delta > 0) break; 107*796f7837SMatthias Ringwald btstack_run_loop_base_remove_timer(ts); 108*796f7837SMatthias Ringwald ts->process(ts); 109*796f7837SMatthias Ringwald } 110*796f7837SMatthias Ringwald } 111*796f7837SMatthias Ringwald 112*796f7837SMatthias Ringwald void btstack_run_loop_base_dump_timer(void){ 113*796f7837SMatthias Ringwald #ifdef ENABLE_LOG_INFO 114*796f7837SMatthias Ringwald btstack_linked_item_t *it; 115*796f7837SMatthias Ringwald uint16_t i = 0; 116*796f7837SMatthias Ringwald for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){ 117*796f7837SMatthias Ringwald btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 118*796f7837SMatthias Ringwald log_info("timer %u (%p): timeout %u\n", i, ts, ts->timeout); 119*796f7837SMatthias Ringwald } 120*796f7837SMatthias Ringwald #endif 121*796f7837SMatthias Ringwald 122*796f7837SMatthias Ringwald } 123*796f7837SMatthias Ringwald /** 124*796f7837SMatthias Ringwald * @brief Get time until first timer fires 125*796f7837SMatthias Ringwald * @returns -1 if no timers, time until next timeout otherwise 126*796f7837SMatthias Ringwald */ 127*796f7837SMatthias Ringwald int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){ 128*796f7837SMatthias Ringwald if (btstack_run_loop_base_timers == NULL) return -1; 129*796f7837SMatthias Ringwald btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 130*796f7837SMatthias Ringwald uint32_t list_timeout = ts->timeout; 131*796f7837SMatthias Ringwald int32_t delta = btstack_time_delta(list_timeout, now); 132*796f7837SMatthias Ringwald if (delta < 0){ 133*796f7837SMatthias Ringwald delta = 0; 134*796f7837SMatthias Ringwald } 135*796f7837SMatthias Ringwald return delta; 136*796f7837SMatthias Ringwald } 137*796f7837SMatthias Ringwald 138*796f7837SMatthias Ringwald void btstack_run_loop_base_poll_data_sources(void){ 139*796f7837SMatthias Ringwald // poll data sources 140*796f7837SMatthias Ringwald btstack_data_source_t *ds; 141*796f7837SMatthias Ringwald btstack_data_source_t *next; 142*796f7837SMatthias Ringwald for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){ 143*796f7837SMatthias Ringwald next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself 144*796f7837SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_POLL){ 145*796f7837SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_POLL); 146*796f7837SMatthias Ringwald } 147*796f7837SMatthias Ringwald } 148*796f7837SMatthias Ringwald } 149*796f7837SMatthias Ringwald 150*796f7837SMatthias Ringwald /** 151*796f7837SMatthias Ringwald * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation 152*796f7837SMatthias Ringwald */ 153*796f7837SMatthias Ringwald 154*796f7837SMatthias Ringwald // main implementation 155*796f7837SMatthias Ringwald 156ec820d77SMatthias Ringwald void btstack_run_loop_set_timer_handler(btstack_timer_source_t *ts, void (*process)(btstack_timer_source_t *_ts)){ 15715d50271SMatthias Ringwald ts->process = process; 15815d50271SMatthias Ringwald }; 15915d50271SMatthias Ringwald 160896424b7SMatthias Ringwald void btstack_run_loop_set_data_source_handler(btstack_data_source_t *ds, void (*process)(btstack_data_source_t *_ds, btstack_data_source_callback_type_t callback_type)){ 16115d50271SMatthias Ringwald ds->process = process; 16215d50271SMatthias Ringwald }; 16315d50271SMatthias Ringwald 1643a5c43eeSMatthias Ringwald void btstack_run_loop_set_data_source_fd(btstack_data_source_t *ds, int fd){ 165398a95ecSMatthias Ringwald ds->source.fd = fd; 1663a5c43eeSMatthias Ringwald } 1673a5c43eeSMatthias Ringwald 1683a5c43eeSMatthias Ringwald int btstack_run_loop_get_data_source_fd(btstack_data_source_t *ds){ 169398a95ecSMatthias Ringwald return ds->source.fd; 1703a5c43eeSMatthias Ringwald } 1713a5c43eeSMatthias Ringwald 172f04a41aeSMatthias Ringwald void btstack_run_loop_set_data_source_handle(btstack_data_source_t *ds, void * handle){ 173398a95ecSMatthias Ringwald ds->source.handle = handle; 174f04a41aeSMatthias Ringwald } 175f04a41aeSMatthias Ringwald 176f04a41aeSMatthias Ringwald void * btstack_run_loop_get_data_source_handle(btstack_data_source_t *ds){ 177398a95ecSMatthias Ringwald return ds->source.handle; 178f04a41aeSMatthias Ringwald } 179f04a41aeSMatthias Ringwald 1800d70dd62SMatthias Ringwald void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 18127e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 182141177f8SMatthias Ringwald btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 1834ea196a4SMatthias Ringwald the_run_loop->enable_data_source_callbacks(ds, callbacks); 184896424b7SMatthias Ringwald } 185896424b7SMatthias Ringwald 1860d70dd62SMatthias Ringwald void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 18727e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 188141177f8SMatthias Ringwald btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 1894ea196a4SMatthias Ringwald the_run_loop->disable_data_source_callbacks(ds, callbacks); 190896424b7SMatthias Ringwald } 19115d50271SMatthias Ringwald 19215d50271SMatthias Ringwald /** 19315d50271SMatthias Ringwald * Add data_source to run_loop 19415d50271SMatthias Ringwald */ 195ec820d77SMatthias Ringwald void btstack_run_loop_add_data_source(btstack_data_source_t *ds){ 19627e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 197141177f8SMatthias Ringwald btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 1980ad702f3SMatthias Ringwald btstack_assert(ds->process != NULL); 19915d50271SMatthias Ringwald the_run_loop->add_data_source(ds); 20015d50271SMatthias Ringwald } 20115d50271SMatthias Ringwald 20215d50271SMatthias Ringwald /** 20315d50271SMatthias Ringwald * Remove data_source from run loop 20415d50271SMatthias Ringwald */ 205ec820d77SMatthias Ringwald int btstack_run_loop_remove_data_source(btstack_data_source_t *ds){ 20627e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 2070ad702f3SMatthias Ringwald btstack_assert(the_run_loop->disable_data_source_callbacks != NULL); 2080ad702f3SMatthias Ringwald btstack_assert(ds->process != NULL); 20915d50271SMatthias Ringwald return the_run_loop->remove_data_source(ds); 21015d50271SMatthias Ringwald } 21115d50271SMatthias Ringwald 212ec820d77SMatthias Ringwald void btstack_run_loop_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){ 21327e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 21415d50271SMatthias Ringwald the_run_loop->set_timer(a, timeout_in_ms); 21515d50271SMatthias Ringwald } 21615d50271SMatthias Ringwald 21715d50271SMatthias Ringwald /** 218fd939756SMatthias Ringwald * @brief Set context for this timer 219fd939756SMatthias Ringwald */ 220fd939756SMatthias Ringwald void btstack_run_loop_set_timer_context(btstack_timer_source_t *ts, void * context){ 221fd939756SMatthias Ringwald ts->context = context; 222fd939756SMatthias Ringwald } 223fd939756SMatthias Ringwald 224fd939756SMatthias Ringwald /** 225fd939756SMatthias Ringwald * @brief Get context for this timer 226fd939756SMatthias Ringwald */ 227fd939756SMatthias Ringwald void * btstack_run_loop_get_timer_context(btstack_timer_source_t *ts){ 228fd939756SMatthias Ringwald return ts->context; 229fd939756SMatthias Ringwald } 230fd939756SMatthias Ringwald 231fd939756SMatthias Ringwald /** 23215d50271SMatthias Ringwald * Add timer to run_loop (keep list sorted) 23315d50271SMatthias Ringwald */ 234ec820d77SMatthias Ringwald void btstack_run_loop_add_timer(btstack_timer_source_t *ts){ 23527e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 2360ad702f3SMatthias Ringwald btstack_assert(ts->process != NULL); 23715d50271SMatthias Ringwald the_run_loop->add_timer(ts); 23815d50271SMatthias Ringwald } 23915d50271SMatthias Ringwald 24015d50271SMatthias Ringwald /** 24115d50271SMatthias Ringwald * Remove timer from run loop 24215d50271SMatthias Ringwald */ 243ec820d77SMatthias Ringwald int btstack_run_loop_remove_timer(btstack_timer_source_t *ts){ 24427e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 24515d50271SMatthias Ringwald return the_run_loop->remove_timer(ts); 24615d50271SMatthias Ringwald } 24715d50271SMatthias Ringwald 24815d50271SMatthias Ringwald /** 24915d50271SMatthias Ringwald * @brief Get current time in ms 25015d50271SMatthias Ringwald */ 251528a4a3bSMatthias Ringwald uint32_t btstack_run_loop_get_time_ms(void){ 25227e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 25315d50271SMatthias Ringwald return the_run_loop->get_time_ms(); 25415d50271SMatthias Ringwald } 25515d50271SMatthias Ringwald 25615d50271SMatthias Ringwald 257528a4a3bSMatthias Ringwald void btstack_run_loop_timer_dump(void){ 25827e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 25915d50271SMatthias Ringwald the_run_loop->dump_timer(); 26015d50271SMatthias Ringwald } 26115d50271SMatthias Ringwald 26215d50271SMatthias Ringwald /** 26315d50271SMatthias Ringwald * Execute run_loop 26415d50271SMatthias Ringwald */ 265528a4a3bSMatthias Ringwald void btstack_run_loop_execute(void){ 26627e05778SMatthias Ringwald btstack_assert(the_run_loop != NULL); 26715d50271SMatthias Ringwald the_run_loop->execute(); 26815d50271SMatthias Ringwald } 26915d50271SMatthias Ringwald 27015d50271SMatthias Ringwald // init must be called before any other run_loop call 271528a4a3bSMatthias Ringwald void btstack_run_loop_init(const btstack_run_loop_t * run_loop){ 27227e05778SMatthias Ringwald btstack_assert(the_run_loop == NULL); 27315d50271SMatthias Ringwald the_run_loop = run_loop; 27415d50271SMatthias Ringwald the_run_loop->init(); 27515d50271SMatthias Ringwald } 27615d50271SMatthias Ringwald 2773a2e2107SMatthias Ringwald void btstack_run_loop_deinit(void){ 2783a2e2107SMatthias Ringwald the_run_loop = NULL; 2793a2e2107SMatthias Ringwald } 2803a2e2107SMatthias Ringwald 281