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 #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 66 void btstack_run_loop_base_init(void){ 67 btstack_run_loop_base_timers = NULL; 68 btstack_run_loop_base_data_sources = NULL; 69 } 70 71 void btstack_run_loop_base_add_data_source(btstack_data_source_t *ds){ 72 btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 73 } 74 75 bool btstack_run_loop_base_remove_data_source(btstack_data_source_t *ds){ 76 return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) ds); 77 } 78 79 void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 80 ds->flags |= callback_types; 81 } 82 83 void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 84 ds->flags &= ~callback_types; 85 } 86 87 bool btstack_run_loop_base_remove_timer(btstack_timer_source_t *ts){ 88 return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) ts); 89 } 90 91 void btstack_run_loop_base_add_timer(btstack_timer_source_t *ts){ 92 btstack_linked_item_t *it; 93 for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){ 94 btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 95 btstack_assert(next != ts); 96 int32_t delta = btstack_time_delta(ts->timeout, next->timeout); 97 if (delta < 0) break; 98 } 99 ts->item.next = it->next; 100 it->next = (btstack_linked_item_t *) ts; 101 } 102 103 void btstack_run_loop_base_process_timers(uint32_t now){ 104 // process timers, exit when timeout is in the future 105 while (btstack_run_loop_base_timers) { 106 btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 107 int32_t delta = btstack_time_delta(ts->timeout, now); 108 if (delta > 0) break; 109 btstack_run_loop_base_remove_timer(ts); 110 ts->process(ts); 111 } 112 } 113 114 void btstack_run_loop_base_dump_timer(void){ 115 #ifdef ENABLE_LOG_INFO 116 btstack_linked_item_t *it; 117 uint16_t i = 0; 118 for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){ 119 btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 120 log_info("timer %u (%p): timeout %" PRIu32 "u\n", i, ts, ts->timeout); 121 } 122 #endif 123 124 } 125 /** 126 * @brief Get time until first timer fires 127 * @returns -1 if no timers, time until next timeout otherwise 128 */ 129 int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){ 130 if (btstack_run_loop_base_timers == NULL) return -1; 131 btstack_timer_source_t * ts = (btstack_timer_source_t *) btstack_run_loop_base_timers; 132 uint32_t list_timeout = ts->timeout; 133 int32_t delta = btstack_time_delta(list_timeout, now); 134 if (delta < 0){ 135 delta = 0; 136 } 137 return delta; 138 } 139 140 void btstack_run_loop_base_poll_data_sources(void){ 141 // poll data sources 142 btstack_data_source_t *ds; 143 btstack_data_source_t *next; 144 for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){ 145 next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself 146 if (ds->flags & DATA_SOURCE_CALLBACK_POLL){ 147 ds->process(ds, DATA_SOURCE_CALLBACK_POLL); 148 } 149 } 150 } 151 152 /** 153 * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation 154 */ 155 156 // main implementation 157 158 void btstack_run_loop_set_timer_handler(btstack_timer_source_t *ts, void (*process)(btstack_timer_source_t *_ts)){ 159 ts->process = process; 160 }; 161 162 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)){ 163 ds->process = process; 164 }; 165 166 void btstack_run_loop_set_data_source_fd(btstack_data_source_t *ds, int fd){ 167 ds->source.fd = fd; 168 } 169 170 int btstack_run_loop_get_data_source_fd(btstack_data_source_t *ds){ 171 return ds->source.fd; 172 } 173 174 void btstack_run_loop_set_data_source_handle(btstack_data_source_t *ds, void * handle){ 175 ds->source.handle = handle; 176 } 177 178 void * btstack_run_loop_get_data_source_handle(btstack_data_source_t *ds){ 179 return ds->source.handle; 180 } 181 182 void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 183 btstack_assert(the_run_loop != NULL); 184 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 185 the_run_loop->enable_data_source_callbacks(ds, callbacks); 186 } 187 188 void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t *ds, uint16_t callbacks){ 189 btstack_assert(the_run_loop != NULL); 190 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 191 the_run_loop->disable_data_source_callbacks(ds, callbacks); 192 } 193 194 /** 195 * Add data_source to run_loop 196 */ 197 void btstack_run_loop_add_data_source(btstack_data_source_t *ds){ 198 btstack_assert(the_run_loop != NULL); 199 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL); 200 btstack_assert(ds->process != NULL); 201 the_run_loop->add_data_source(ds); 202 } 203 204 /** 205 * Remove data_source from run loop 206 */ 207 int btstack_run_loop_remove_data_source(btstack_data_source_t *ds){ 208 btstack_assert(the_run_loop != NULL); 209 btstack_assert(the_run_loop->disable_data_source_callbacks != NULL); 210 btstack_assert(ds->process != NULL); 211 return the_run_loop->remove_data_source(ds); 212 } 213 214 void btstack_run_loop_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){ 215 btstack_assert(the_run_loop != NULL); 216 the_run_loop->set_timer(a, timeout_in_ms); 217 } 218 219 /** 220 * @brief Set context for this timer 221 */ 222 void btstack_run_loop_set_timer_context(btstack_timer_source_t *ts, void * context){ 223 ts->context = context; 224 } 225 226 /** 227 * @brief Get context for this timer 228 */ 229 void * btstack_run_loop_get_timer_context(btstack_timer_source_t *ts){ 230 return ts->context; 231 } 232 233 /** 234 * Add timer to run_loop (keep list sorted) 235 */ 236 void btstack_run_loop_add_timer(btstack_timer_source_t *ts){ 237 btstack_assert(the_run_loop != NULL); 238 btstack_assert(ts->process != NULL); 239 the_run_loop->add_timer(ts); 240 } 241 242 /** 243 * Remove timer from run loop 244 */ 245 int btstack_run_loop_remove_timer(btstack_timer_source_t *ts){ 246 btstack_assert(the_run_loop != NULL); 247 return the_run_loop->remove_timer(ts); 248 } 249 250 /** 251 * @brief Get current time in ms 252 */ 253 uint32_t btstack_run_loop_get_time_ms(void){ 254 btstack_assert(the_run_loop != NULL); 255 return the_run_loop->get_time_ms(); 256 } 257 258 259 void btstack_run_loop_timer_dump(void){ 260 btstack_assert(the_run_loop != NULL); 261 the_run_loop->dump_timer(); 262 } 263 264 /** 265 * Execute run_loop 266 */ 267 void btstack_run_loop_execute(void){ 268 btstack_assert(the_run_loop != NULL); 269 the_run_loop->execute(); 270 } 271 272 // init must be called before any other run_loop call 273 void btstack_run_loop_init(const btstack_run_loop_t * run_loop){ 274 btstack_assert(the_run_loop == NULL); 275 the_run_loop = run_loop; 276 the_run_loop->init(); 277 } 278 279 void btstack_run_loop_deinit(void){ 280 the_run_loop = NULL; 281 } 282 283