BTstack Bluetooth stack

Dependencies:   mbed USBHost

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers run_loop_embedded.c Source File

run_loop_embedded.c

00001 /*
00002  * Copyright (C) 2009-2012 by Matthias Ringwald
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  * 4. Any redistribution, use, or modification is done solely for
00017  *    personal benefit and not for any commercial purpose or for
00018  *    monetary gain.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
00024  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * Please inquire about commercial licensing options at btstack@ringwald.ch
00034  *
00035  */
00036 
00037 /*
00038  *  run_loop_embedded.c
00039  *
00040  *  For this run loop, we assume that there's no global way to wait for a list
00041  *  of data sources to get ready. Instead, each data source has to queried
00042  *  individually. Calling ds->isReady() before calling ds->process() doesn't 
00043  *  make sense, so we just poll each data source round robin.
00044  *
00045  *  To support an idle state, where an MCU could go to sleep, the process function
00046  *  has to return if it has to called again as soon as possible
00047  *
00048  *  After calling process() on every data source and evaluating the pending timers,
00049  *  the idle hook gets called if no data source did indicate that it needs to be
00050  *  called right away.
00051  *
00052  */
00053 
00054 
00055 #include <btstack/run_loop.h>
00056 #include <btstack/linked_list.h>
00057 #include <btstack/hal_tick.h>
00058 #include <btstack/hal_cpu.h>
00059 
00060 #include "run_loop_private.h"
00061 #include "debug.h"
00062 
00063 #include <stddef.h> // NULL
00064 
00065 // the run loop
00066 static linked_list_t data_sources;
00067 
00068 static linked_list_t timers;
00069 
00070 #ifdef HAVE_TICK
00071 static uint32_t system_ticks;
00072 #endif
00073 
00074 static int trigger_event_received = 0;
00075 
00076 /**
00077  * trigger run loop iteration
00078  */
00079 void embedded_trigger(void){
00080     trigger_event_received = 1;
00081 }
00082 
00083 /**
00084  * Add data_source to run_loop
00085  */
00086 void embedded_add_data_source(data_source_t *ds){
00087     linked_list_add(&data_sources, (linked_item_t *) ds);
00088 }
00089 
00090 /**
00091  * Remove data_source from run loop
00092  */
00093 int embedded_remove_data_source(data_source_t *ds){
00094     return linked_list_remove(&data_sources, (linked_item_t *) ds);
00095 }
00096 
00097 /**
00098  * Add timer to run_loop (keep list sorted)
00099  */
00100 void embedded_add_timer(timer_source_t *ts){
00101 #ifdef HAVE_TICK
00102     linked_item_t *it;
00103     for (it = (linked_item_t *) &timers; it->next ; it = it->next){
00104         if (ts->timeout < ((timer_source_t *) it->next)->timeout) {
00105             break;
00106         }
00107     }
00108     ts->item.next = it->next;
00109     it->next = (linked_item_t *) ts;
00110     // log_info("Added timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
00111     // embedded_dump_timer();
00112 #endif
00113 }
00114 
00115 /**
00116  * Remove timer from run loop
00117  */
00118 int embedded_remove_timer(timer_source_t *ts){
00119 #ifdef HAVE_TICK    
00120     // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
00121     return linked_list_remove(&timers, (linked_item_t *) ts);
00122 #else
00123     return 0;
00124 #endif
00125 }
00126 
00127 void embedded_dump_timer(void){
00128 #ifdef HAVE_TICK
00129 #ifdef ENABLE_LOG_INFO 
00130     linked_item_t *it;
00131     int i = 0;
00132     for (it = (linked_item_t *) timers; it ; it = it->next){
00133         timer_source_t *ts = (timer_source_t*) it;
00134         log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout);
00135     }
00136 #endif
00137 #endif
00138 }
00139 
00140 /**
00141  * Execute run_loop
00142  */
00143 void embedded_execute(void) {
00144     data_source_t *ds;
00145 
00146     while (1) {
00147 
00148         // process data sources
00149         data_source_t *next;
00150         for (ds = (data_source_t *) data_sources; ds != NULL ; ds = next){
00151             next = (data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
00152             ds->process(ds);
00153         }
00154         
00155 #ifdef HAVE_TICK
00156         // process timers
00157         while (timers) {
00158             timer_source_t *ts = (timer_source_t *) timers;
00159             if (ts->timeout > system_ticks) break;
00160             run_loop_remove_timer(ts);
00161             ts->process(ts);
00162         }
00163 #endif
00164         
00165         // disable IRQs and check if run loop iteration has been requested. if not, go to sleep
00166         hal_cpu_disable_irqs();
00167         if (trigger_event_received){
00168             hal_cpu_enable_irqs_and_sleep();
00169             continue;
00170         }
00171         hal_cpu_enable_irqs();
00172     }
00173 }
00174 
00175 #ifdef HAVE_TICK
00176 static void embedded_tick_handler(void){
00177     system_ticks++;
00178     trigger_event_received = 1;
00179 }
00180 
00181 uint32_t embedded_get_ticks(void){
00182     return system_ticks;
00183 }
00184 
00185 uint32_t embedded_ticks_for_ms(uint32_t time_in_ms){
00186     return time_in_ms / hal_tick_get_tick_period_in_ms();
00187 }
00188 
00189 // set timer
00190 void run_loop_set_timer(timer_source_t *ts, uint32_t timeout_in_ms){
00191     uint32_t ticks = embedded_ticks_for_ms(timeout_in_ms);
00192     if (ticks == 0) ticks++;
00193     ts->timeout = system_ticks + ticks; 
00194 }
00195 #endif
00196 
00197 void embedded_init(void){
00198 
00199     data_sources = NULL;
00200 
00201 #ifdef HAVE_TICK
00202     timers = NULL;
00203     system_ticks = 0;
00204     hal_tick_init();
00205     hal_tick_set_handler(&embedded_tick_handler);
00206 #endif
00207 }
00208 
00209 extern const run_loop_t run_loop_embedded;
00210 const run_loop_t run_loop_embedded = {
00211     &embedded_init,
00212     &embedded_add_data_source,
00213     &embedded_remove_data_source,
00214     &embedded_add_timer,
00215     &embedded_remove_timer,
00216     &embedded_execute,
00217     &embedded_dump_timer
00218 };