1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_run_loop.c" 39 40 /* 41 * run_loop.c 42 * 43 * Created by Matthias Ringwald on 6/6/09. 44 */ 45 46 #include "btstack_run_loop.h" 47 48 #include "btstack_debug.h" 49 #include "btstack_config.h" 50 #include "btstack_util.h" 51 52 static const btstack_run_loop_t * the_run_loop = NULL; 53 54 extern const btstack_run_loop_t btstack_run_loop_embedded; 55 56 /* 57 * Portable implementation of timer and data source management as base for platform specific implementations 58 */ 59 60 // private data (access only by run loop implementations) 61 btstack_linked_list_t btstack_run_loop_base_timers; 62 btstack_linked_list_t btstack_run_loop_base_data_sources; 63 64 void btstack_run_loop_base_init(void){ 65 btstack_run_loop_base_timers = NULL; 66 btstack_run_loop_base_data_sources = NULL; 67 } 68 69 void btstack_run_loop_base_add_data_source(btstack_data_source_t *ds){ 70 btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 71 } 72 73 bool btstack_run_loop_base_remove_data_source(btstack_data_source_t *ds){ 74 return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 75 } 76 77 void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 78 ds->flags |= callback_types; 79 } 80 81 void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 82 ds->flags &= ~callback_types; 83 } 84 85 bool btstack_run_loop_base_remove_timer(btstack_timer_source_t *ts){ 86 return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) ts); 87 } 88 89 void btstack_run_loop_base_add_timer(btstack_timer_source_t *ts){ 90 btstack_linked_item_t *it; 91 for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){ 92 btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 93 btstack_assert(next != ts); 94 int32_t delta = btstack_time_delta(ts->timeout, next->timeout); 95 if (delta < 0) break; 96 } 97 ts->item.next = it->next; 98 it->next = (btstack_linked_item_t *) ts; 99 } 100 101 void btstack_run_loop_base_process_timers(uint32_t now){ 102 // process timers, exit when timeout is in the future 103 while (btstack_run_loop_base_timers) { 104 btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 105 int32_t delta = btstack_time_delta(ts->timeout, now); 106 if (delta > 0) break; 107 btstack_run_loop_base_remove_timer(ts); 108 ts->process(ts); 109 } 110 } 111 112 void btstack_run_loop_base_dump_timer(void){ 113 #ifdef ENABLE_LOG_INFO 114 btstack_linked_item_t *it; 115 uint16_t i = 0; 116 for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){ 117 btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 118 log_info("timer %u (%p): timeout %u\n", i, ts, ts->timeout); 119 } 120 #endif 121 122 } 123 /** 124 * @brief Get time until first timer fires 125 * @returns -1 if no timers, time until next timeout otherwise 126 */ 127 int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){ 128 if (btstack_run_loop_base_timers == NULL) return -1; 129 btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 130 uint32_t list_timeout = ts->timeout; 131 int32_t delta = btstack_time_delta(list_timeout, now); 132 if (delta < 0){ 133 delta = 0; 134 } 135 return delta; 136 } 137 138 void btstack_run_loop_base_poll_data_sources(void){ 139 // poll data sources 140 btstack_data_source_t *ds; 141 btstack_data_source_t *next; 142 for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){ 143 next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself 144 if (ds->flags & DATA_SOURCE_CALLBACK_POLL){ 145 ds->process(ds, DATA_SOURCE_CALLBACK_POLL); 146 } 147 } 148 } 149 150 /** 151 * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation 152 */ 153 154 // main implementation 155 156 void btstack_run_loop_set_timer_handler(btstack_timer_source_t *ts, void (*process)(btstack_timer_source_t *_ts)){ 157 ts->process = process; 158 }; 159 160 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)){ 161 ds->process = process; 162 }; 163 164 void btstack_run_loop_set_data_source_fd(btstack_data_source_t *ds, int fd){ 165 ds->source.fd = fd; 166 } 167 168 int btstack_run_loop_get_data_source_fd(btstack_data_source_t *ds){ 169 return ds->source.fd; 170 } 171 172 void btstack_run_loop_set_data_source_handle(btstack_data_source_t *ds, void * handle){ 173 ds->source.handle = handle; 174 } 175 176 void * btstack_run_loop_get_data_source_handle(btstack_data_source_t *ds){ 177 return ds->source.handle; 178 } 179 180 void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 181 btstack_assert(the_run_loop != NULL); 182 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 183 the_run_loop->enable_data_source_callbacks(ds, callbacks); 184 } 185 186 void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 187 btstack_assert(the_run_loop != NULL); 188 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 189 the_run_loop->disable_data_source_callbacks(ds, callbacks); 190 } 191 192 /** 193 * Add data_source to run_loop 194 */ 195 void btstack_run_loop_add_data_source(btstack_data_source_t *ds){ 196 btstack_assert(the_run_loop != NULL); 197 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 198 btstack_assert(ds->process != NULL); 199 the_run_loop->add_data_source(ds); 200 } 201 202 /** 203 * Remove data_source from run loop 204 */ 205 int btstack_run_loop_remove_data_source(btstack_data_source_t *ds){ 206 btstack_assert(the_run_loop != NULL); 207 btstack_assert(the_run_loop->disable_data_source_callbacks != NULL); 208 btstack_assert(ds->process != NULL); 209 return the_run_loop->remove_data_source(ds); 210 } 211 212 void btstack_run_loop_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){ 213 btstack_assert(the_run_loop != NULL); 214 the_run_loop->set_timer(a, timeout_in_ms); 215 } 216 217 /** 218 * @brief Set context for this timer 219 */ 220 void btstack_run_loop_set_timer_context(btstack_timer_source_t *ts, void * context){ 221 ts->context = context; 222 } 223 224 /** 225 * @brief Get context for this timer 226 */ 227 void * btstack_run_loop_get_timer_context(btstack_timer_source_t *ts){ 228 return ts->context; 229 } 230 231 /** 232 * Add timer to run_loop (keep list sorted) 233 */ 234 void btstack_run_loop_add_timer(btstack_timer_source_t *ts){ 235 btstack_assert(the_run_loop != NULL); 236 btstack_assert(ts->process != NULL); 237 the_run_loop->add_timer(ts); 238 } 239 240 /** 241 * Remove timer from run loop 242 */ 243 int btstack_run_loop_remove_timer(btstack_timer_source_t *ts){ 244 btstack_assert(the_run_loop != NULL); 245 return the_run_loop->remove_timer(ts); 246 } 247 248 /** 249 * @brief Get current time in ms 250 */ 251 uint32_t btstack_run_loop_get_time_ms(void){ 252 btstack_assert(the_run_loop != NULL); 253 return the_run_loop->get_time_ms(); 254 } 255 256 257 void btstack_run_loop_timer_dump(void){ 258 btstack_assert(the_run_loop != NULL); 259 the_run_loop->dump_timer(); 260 } 261 262 /** 263 * Execute run_loop 264 */ 265 void btstack_run_loop_execute(void){ 266 btstack_assert(the_run_loop != NULL); 267 the_run_loop->execute(); 268 } 269 270 // init must be called before any other run_loop call 271 void btstack_run_loop_init(const btstack_run_loop_t * run_loop){ 272 btstack_assert(the_run_loop == NULL); 273 the_run_loop = run_loop; 274 the_run_loop->init(); 275 } 276 277 void btstack_run_loop_deinit(void){ 278 the_run_loop = NULL; 279 } 280 281