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 BLUEKITCHEN 24 * GMBH 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 #include <inttypes.h> 53 54 static const btstack_run_loop_t * the_run_loop = NULL; 55 56 extern const btstack_run_loop_t btstack_run_loop_embedded; 57 58 /* 59 * Portable implementation of timer and data source management as base for platform specific implementations 60 */ 61 62 // private data (access only by run loop implementations) 63 btstack_linked_list_t btstack_run_loop_base_timers; 64 btstack_linked_list_t btstack_run_loop_base_data_sources; 65 btstack_linked_list_t btstack_run_loop_base_callbacks; 66 67 void btstack_run_loop_base_init(void){ 68 btstack_run_loop_base_timers = NULL; 69 btstack_run_loop_base_data_sources = NULL; 70 btstack_run_loop_base_callbacks = NULL; 71 } 72 73 void btstack_run_loop_base_add_data_source(btstack_data_source_t * data_source){ 74 btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source); 75 } 76 77 bool btstack_run_loop_base_remove_data_source(btstack_data_source_t * data_source){ 78 return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source); 79 } 80 81 void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){ 82 data_source->flags |= callback_types; 83 } 84 85 void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){ 86 data_source->flags &= ~callback_types; 87 } 88 89 bool btstack_run_loop_base_remove_timer(btstack_timer_source_t * timer){ 90 return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) timer); 91 } 92 93 void btstack_run_loop_base_add_timer(btstack_timer_source_t * timer){ 94 btstack_linked_item_t *it; 95 for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){ 96 btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 97 98 if (next == timer){ 99 log_error("Timer %p already registered! Please read source code comment.", (void*)timer); 100 // 101 // Dear BTstack User! 102 // 103 // If you hit the assert below, your application code tried to add a timer to the list of 104 // timers that's already in the timer list, i.e., it's already registered. 105 // 106 // As you've probably already modified the timer, just ignoring this might lead to unexpected 107 // and hard to debug issues. Instead, we decided to raise an assert in this case to help. 108 // 109 // Please do a backtrace and check where you register this timer. 110 // If you just want to restart it you can call btstack_run_loop_timer_remove(..) before restarting the timer. 111 // 112 btstack_assert(false); 113 } 114 115 int32_t delta = btstack_time_delta(timer->timeout, next->timeout); 116 if (delta < 0) break; 117 } 118 timer->item.next = it->next; 119 it->next = (btstack_linked_item_t *) timer; 120 } 121 122 void btstack_run_loop_base_process_timers(uint32_t now){ 123 // process timers, exit when timeout is in the future 124 while (btstack_run_loop_base_timers) { 125 btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers; 126 int32_t delta = btstack_time_delta(timer->timeout, now); 127 if (delta > 0) break; 128 btstack_run_loop_base_remove_timer(timer); 129 timer->process(timer); 130 } 131 } 132 133 void btstack_run_loop_base_dump_timer(void){ 134 #ifdef ENABLE_LOG_INFO 135 btstack_linked_item_t *it; 136 uint16_t i = 0; 137 for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){ 138 btstack_timer_source_t * timer = (btstack_timer_source_t*) it; 139 log_info("timer %u (%p): timeout %" PRIbtstack_time_t "\n", i, (void *) timer, timer->timeout); 140 } 141 #endif 142 143 } 144 /** 145 * @brief Get time until first timer fires 146 * @return -1 if no timers, time until next timeout otherwise 147 */ 148 int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){ 149 if (btstack_run_loop_base_timers == NULL) return -1; 150 btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers; 151 uint32_t list_timeout = timer->timeout; 152 int32_t delta = btstack_time_delta(list_timeout, now); 153 if (delta < 0){ 154 delta = 0; 155 } 156 return delta; 157 } 158 159 void btstack_run_loop_base_poll_data_sources(void){ 160 // poll data sources 161 btstack_data_source_t *ds; 162 btstack_data_source_t *next; 163 for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){ 164 next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself 165 if (ds->flags & DATA_SOURCE_CALLBACK_POLL){ 166 ds->process(ds, DATA_SOURCE_CALLBACK_POLL); 167 } 168 } 169 } 170 171 void btstack_run_loop_base_add_callback(btstack_context_callback_registration_t * callback_registration){ 172 btstack_linked_list_add_tail(&btstack_run_loop_base_callbacks, (btstack_linked_item_t *) callback_registration); 173 } 174 175 176 void btstack_run_loop_base_execute_callbacks(void){ 177 while (1){ 178 btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks); 179 if (callback_registration == NULL){ 180 break; 181 } 182 (*callback_registration->callback)(callback_registration->context); 183 } 184 } 185 186 187 /** 188 * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation 189 */ 190 191 // main implementation 192 193 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){ 194 timer->process = process; 195 } 196 197 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)){ 198 data_source->process = process; 199 } 200 201 void btstack_run_loop_set_data_source_fd(btstack_data_source_t * data_source, int fd){ 202 data_source->source.fd = fd; 203 } 204 205 int btstack_run_loop_get_data_source_fd(btstack_data_source_t * data_source){ 206 return data_source->source.fd; 207 } 208 209 void btstack_run_loop_set_data_source_handle(btstack_data_source_t * data_source, void * handle){ 210 data_source->source.handle = handle; 211 } 212 213 void * btstack_run_loop_get_data_source_handle(btstack_data_source_t * data_source){ 214 return data_source->source.handle; 215 } 216 217 void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){ 218 btstack_assert(the_run_loop != NULL); 219 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 220 the_run_loop->enable_data_source_callbacks(data_source, callbacks); 221 } 222 223 void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){ 224 btstack_assert(the_run_loop != NULL); 225 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 226 the_run_loop->disable_data_source_callbacks(data_source, callbacks); 227 } 228 229 /** 230 * Add data_source to run_loop 231 */ 232 void btstack_run_loop_add_data_source(btstack_data_source_t * data_source){ 233 btstack_assert(the_run_loop != NULL); 234 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 235 btstack_assert(data_source->process != NULL); 236 the_run_loop->add_data_source(data_source); 237 } 238 239 /** 240 * Remove data_source from run loop 241 */ 242 int btstack_run_loop_remove_data_source(btstack_data_source_t * data_source){ 243 btstack_assert(the_run_loop != NULL); 244 btstack_assert(the_run_loop->disable_data_source_callbacks != NULL); 245 btstack_assert(data_source->process != NULL); 246 return the_run_loop->remove_data_source(data_source); 247 } 248 249 void btstack_run_loop_poll_data_sources_from_irq(void){ 250 btstack_assert(the_run_loop != NULL); 251 btstack_assert(the_run_loop->poll_data_sources_from_irq != NULL); 252 the_run_loop->poll_data_sources_from_irq(); 253 } 254 255 void btstack_run_loop_set_timer(btstack_timer_source_t *timer, uint32_t timeout_in_ms){ 256 btstack_assert(the_run_loop != NULL); 257 the_run_loop->set_timer(timer, timeout_in_ms); 258 } 259 260 /** 261 * @brief Set context for this timer 262 */ 263 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){ 264 timer->context = context; 265 } 266 267 /** 268 * @brief Get context for this timer 269 */ 270 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){ 271 return timer->context; 272 } 273 274 /** 275 * Add timer to run_loop (keep list sorted) 276 */ 277 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){ 278 btstack_assert(the_run_loop != NULL); 279 btstack_assert(timer->process != NULL); 280 the_run_loop->add_timer(timer); 281 } 282 283 /** 284 * Remove timer from run loop 285 */ 286 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){ 287 btstack_assert(the_run_loop != NULL); 288 return the_run_loop->remove_timer(timer); 289 } 290 291 /** 292 * @brief Get current time in ms 293 */ 294 uint32_t btstack_run_loop_get_time_ms(void){ 295 btstack_assert(the_run_loop != NULL); 296 return the_run_loop->get_time_ms(); 297 } 298 299 300 void btstack_run_loop_timer_dump(void){ 301 btstack_assert(the_run_loop != NULL); 302 the_run_loop->dump_timer(); 303 } 304 305 /** 306 * Execute run_loop 307 */ 308 void btstack_run_loop_execute(void){ 309 btstack_assert(the_run_loop != NULL); 310 the_run_loop->execute(); 311 } 312 313 void btstack_run_loop_trigger_exit(void){ 314 btstack_assert(the_run_loop != NULL); 315 btstack_assert(the_run_loop->trigger_exit != NULL); 316 the_run_loop->trigger_exit(); 317 } 318 319 void btstack_run_loop_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){ 320 btstack_assert(the_run_loop != NULL); 321 btstack_assert(the_run_loop->execute_on_main_thread != NULL); 322 the_run_loop->execute_on_main_thread(callback_registration); 323 } 324 325 // init must be called before any other run_loop call 326 void btstack_run_loop_init(const btstack_run_loop_t * run_loop){ 327 btstack_assert(the_run_loop == NULL); 328 the_run_loop = run_loop; 329 the_run_loop->init(); 330 } 331 332 void btstack_run_loop_deinit(void){ 333 the_run_loop = NULL; 334 } 335 336