Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers timers.c Source File

timers.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Stack-internal timers implementation.
00004  * This file includes timer callbacks for stack-internal timers as well as
00005  * functions to set up or stop timers and check for expired timers.
00006  *
00007  */
00008 
00009 /*
00010  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00011  * All rights reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  * 3. The name of the author may not be used to endorse or promote products
00022  *    derived from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00025  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00027  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00033  * OF SUCH DAMAGE.
00034  *
00035  * This file is part of the lwIP TCP/IP stack.
00036  *
00037  * Author: Adam Dunkels <adam@sics.se>
00038  *         Simon Goldschmidt
00039  *
00040  */
00041 
00042 #include "lwip/opt.h"
00043 
00044 #include "lwip/timers.h"
00045 #include "lwip/def.h"
00046 #include "lwip/memp.h"
00047 #include "lwip/tcpip.h"
00048 
00049 #include "lwip/tcp_impl.h"
00050 #include "lwip/ip_frag.h"
00051 #include "netif/etharp.h"
00052 #include "lwip/dhcp.h "
00053 #include "lwip/autoip.h"
00054 #include "lwip/igmp.h"
00055 #include "lwip/dns.h"
00056 
00057 
00058 /** The one and only timeout list */
00059 static struct sys_timeo *next_timeout;
00060 #if NO_SYS
00061 static u32_t timeouts_last_time;
00062 #endif /* NO_SYS */
00063 
00064 #if LWIP_TCP
00065 /** global variable that shows if the tcp timer is currently scheduled or not */
00066 static int tcpip_tcp_timer_active;
00067 
00068 /**
00069  * Timer callback function that calls tcp_tmr() and reschedules itself.
00070  *
00071  * @param arg unused argument
00072  */
00073 static void
00074 tcpip_tcp_timer(void *arg)
00075 {
00076   LWIP_UNUSED_ARG(arg);
00077 
00078   /* call TCP timer handler */
00079   tcp_tmr();
00080   /* timer still needed? */
00081   if (tcp_active_pcbs || tcp_tw_pcbs) {
00082     /* restart timer */
00083     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
00084   } else {
00085     /* disable timer */
00086     tcpip_tcp_timer_active = 0;
00087   }
00088 }
00089 
00090 /**
00091  * Called from TCP_REG when registering a new PCB:
00092  * the reason is to have the TCP timer only running when
00093  * there are active (or time-wait) PCBs.
00094  */
00095 void
00096 tcp_timer_needed(void)
00097 {
00098   /* timer is off but needed again? */
00099   if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
00100     /* enable and start timer */
00101     tcpip_tcp_timer_active = 1;
00102     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
00103   }
00104 }
00105 #endif /* LWIP_TCP */
00106 
00107 #if IP_REASSEMBLY
00108 /**
00109  * Timer callback function that calls ip_reass_tmr() and reschedules itself.
00110  *
00111  * @param arg unused argument
00112  */
00113 static void
00114 ip_reass_timer(void *arg)
00115 {
00116   LWIP_UNUSED_ARG(arg);
00117   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
00118   ip_reass_tmr();
00119   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
00120 }
00121 #endif /* IP_REASSEMBLY */
00122 
00123 #if LWIP_ARP
00124 /**
00125  * Timer callback function that calls etharp_tmr() and reschedules itself.
00126  *
00127  * @param arg unused argument
00128  */
00129 static void
00130 arp_timer(void *arg)
00131 {
00132   LWIP_UNUSED_ARG(arg);
00133   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
00134   etharp_tmr();
00135   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
00136 }
00137 #endif /* LWIP_ARP */
00138 
00139 #if LWIP_DHCP
00140 /**
00141  * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
00142  *
00143  * @param arg unused argument
00144  */
00145 static void
00146 dhcp_timer_coarse(void *arg)
00147 {
00148   LWIP_UNUSED_ARG(arg);
00149   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
00150   dhcp_coarse_tmr();
00151   sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
00152 }
00153 
00154 /**
00155  * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
00156  *
00157  * @param arg unused argument
00158  */
00159 static void
00160 dhcp_timer_fine(void *arg)
00161 {
00162   LWIP_UNUSED_ARG(arg);
00163   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
00164   dhcp_fine_tmr();
00165   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
00166 }
00167 #endif /* LWIP_DHCP */
00168 
00169 #if LWIP_AUTOIP
00170 /**
00171  * Timer callback function that calls autoip_tmr() and reschedules itself.
00172  *
00173  * @param arg unused argument
00174  */
00175 static void
00176 autoip_timer(void *arg)
00177 {
00178   LWIP_UNUSED_ARG(arg);
00179   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
00180   autoip_tmr();
00181   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
00182 }
00183 #endif /* LWIP_AUTOIP */
00184 
00185 #if LWIP_IGMP
00186 /**
00187  * Timer callback function that calls igmp_tmr() and reschedules itself.
00188  *
00189  * @param arg unused argument
00190  */
00191 static void
00192 igmp_timer(void *arg)
00193 {
00194   LWIP_UNUSED_ARG(arg);
00195   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
00196   igmp_tmr();
00197   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
00198 }
00199 #endif /* LWIP_IGMP */
00200 
00201 #if LWIP_DNS
00202 /**
00203  * Timer callback function that calls dns_tmr() and reschedules itself.
00204  *
00205  * @param arg unused argument
00206  */
00207 static void
00208 dns_timer(void *arg)
00209 {
00210   LWIP_UNUSED_ARG(arg);
00211   LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
00212   dns_tmr();
00213   sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
00214 }
00215 #endif /* LWIP_DNS */
00216 
00217 /** Initialize this module */
00218 void sys_timeouts_init(void)
00219 {
00220 #if IP_REASSEMBLY
00221   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
00222 #endif /* IP_REASSEMBLY */
00223 #if LWIP_ARP
00224   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
00225 #endif /* LWIP_ARP */
00226 #if LWIP_DHCP
00227   sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
00228   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
00229 #endif /* LWIP_DHCP */
00230 #if LWIP_AUTOIP
00231   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
00232 #endif /* LWIP_AUTOIP */
00233 #if LWIP_IGMP
00234   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
00235 #endif /* LWIP_IGMP */
00236 #if LWIP_DNS
00237   sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
00238 #endif /* LWIP_DNS */
00239 
00240 #if NO_SYS
00241   /* Initialise timestamp for sys_check_timeouts */
00242   timeouts_last_time = sys_now();
00243 #endif
00244 }
00245 
00246 /**
00247  * Create a one-shot timer (aka timeout). Timeouts are processed in the
00248  * following cases:
00249  * - while waiting for a message using sys_timeouts_mbox_fetch()
00250  * - by calling sys_check_timeouts() (NO_SYS==1 only)
00251  *
00252  * @param msecs time in milliseconds after that the timer should expire
00253  * @param h callback function to call when msecs have elapsed
00254  * @param arg argument to pass to the callback function
00255  */
00256 #if LWIP_DEBUG_TIMERNAMES
00257 void
00258 sys_timeout_debug(u32_t msecs, sys_timeout_handler h, void *arg, const char* handler_name)
00259 #else /* LWIP_DEBUG_TIMERNAMES */
00260 void
00261 sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
00262 #endif /* LWIP_DEBUG_TIMERNAMES */
00263 {
00264   struct sys_timeo *timeout, *t;
00265 
00266   timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
00267   if (timeout == NULL) {
00268     LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
00269     return;
00270   }
00271   timeout->next = NULL;
00272   timeout->h = h;
00273   timeout->arg = arg;
00274   timeout->time = msecs;
00275 #if LWIP_DEBUG_TIMERNAMES
00276   timeout->handler_name = handler_name;
00277 #endif /* LWIP_DEBUG_TIMERNAMES */
00278 
00279 #if LWIP_DEBUG_TIMERNAMES
00280   LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p name=%s\n",
00281     (void *)timeout, msecs, *(void**)&h, (void *)arg, handler_name));
00282 #else /* LWIP_DEBUG_TIMERNAMES */
00283   LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
00284     (void *)timeout, msecs, *(void**)&h, (void *)arg));
00285 #endif /* LWIP_DEBUG_TIMERNAMES */
00286 
00287   if (next_timeout == NULL) {
00288     next_timeout = timeout;
00289     return;
00290   }
00291 
00292   if (next_timeout->time > msecs) {
00293     next_timeout->time -= msecs;
00294     timeout->next = next_timeout;
00295     next_timeout = timeout;
00296   } else {
00297     for(t = next_timeout; t != NULL; t = t->next) {
00298       timeout->time -= t->time;
00299       if (t->next == NULL || t->next->time > timeout->time) {
00300         if (t->next != NULL) {
00301           t->next->time -= timeout->time;
00302         }
00303         timeout->next = t->next;
00304         t->next = timeout;
00305         break;
00306       }
00307     }
00308   }
00309 }
00310 
00311 /**
00312  * Go through timeout list (for this task only) and remove the first matching
00313  * entry, even though the timeout has not triggered yet.
00314  *
00315  * @note This function only works as expected if there is only one timeout
00316  * calling 'h' in the list of timeouts.
00317  *
00318  * @param h callback function that would be called by the timeout
00319  * @param arg callback argument that would be passed to h
00320 */
00321 void
00322 sys_untimeout(sys_timeout_handler h, void *arg)
00323 {
00324   struct sys_timeo *prev_t, *t;
00325 
00326   if (next_timeout == NULL) {
00327     return;
00328   }
00329 
00330   for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
00331     if ((t->h == h) && (t->arg == arg)) {
00332       /* We have a match */
00333       /* Unlink from previous in list */
00334       if (prev_t == NULL) {
00335         next_timeout = t->next;
00336       } else {
00337         prev_t->next = t->next;
00338       }
00339       /* If not the last one, add time of this one back to next */
00340       if (t->next != NULL) {
00341         t->next->time += t->time;
00342       }
00343       memp_free(MEMP_SYS_TIMEOUT, t);
00344       return;
00345     }
00346   }
00347   return;
00348 }
00349 
00350 #if NO_SYS
00351 
00352 /** Handle timeouts for NO_SYS==1 (i.e. without using
00353  * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
00354  * handler functions when timeouts expire.
00355  *
00356  * Must be called periodically from your main loop.
00357  */
00358 void
00359 sys_check_timeouts(void)
00360 {
00361   struct sys_timeo *tmptimeout;
00362   u32_t diff;
00363   sys_timeout_handler h;
00364   void *arg;
00365   int had_one;
00366   u32_t now;
00367 #if LWIP_DEBUG_TIMERNAMES
00368   const char *handler_name;
00369 #endif /* LWIP_DEBUG_TIMERNAMES */
00370 
00371   now = sys_now();
00372   if (next_timeout) {
00373     /* @todo: wrap around? */
00374     diff = now - timeouts_last_time;
00375     do
00376     {
00377       had_one = 0;
00378       tmptimeout = next_timeout;
00379       if (tmptimeout->time <= diff) {
00380         /* timeout has expired */
00381         had_one = 1;
00382         timeouts_last_time = now;
00383         diff -= tmptimeout->time;
00384         next_timeout = tmptimeout->next;
00385         h   = tmptimeout->h;
00386         arg = tmptimeout->arg;
00387 #if LWIP_DEBUG_TIMERNAMES
00388         handler_name = tmptimeout->handler_name;
00389 #endif /* LWIP_DEBUG_TIMERNAMES */
00390         memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
00391         if (h != NULL) {
00392 #if LWIP_DEBUG_TIMERNAMES
00393           LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%p(%p) (%s)\n", *(void**)&h, arg, handler_name));
00394 #else /* LWIP_DEBUG_TIMERNAMES */
00395           LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%p(%p)\n", *(void**)&h, arg));
00396 #endif /* LWIP_DEBUG_TIMERNAMES */
00397           h(arg);
00398         }
00399       }
00400     /* repeat until all expired timers have been called */
00401     }while(had_one);
00402   }
00403 }
00404 
00405 /** Set back the timestamp of the last call to sys_check_timeouts()
00406  * This is necessary if sys_check_timeouts() hasn't been called for a long
00407  * time (e.g. while saving energy) to prevent all timer functions of that
00408  * period being called.
00409  */
00410 void
00411 sys_restart_timeouts(void)
00412 {
00413   timeouts_last_time = sys_now();
00414 }
00415 
00416 #else /* NO_SYS */
00417 
00418 /**
00419  * Wait (forever) for a message to arrive in an mbox.
00420  * While waiting, timeouts are processed.
00421  *
00422  * @param mbox the mbox to fetch the message from
00423  * @param msg the place to store the message
00424  */
00425 void
00426 sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
00427 {
00428   u32_t time_needed;
00429   struct sys_timeo *tmptimeout;
00430   sys_timeout_handler h;
00431   void *arg;
00432 #if LWIP_DEBUG_TIMERNAMES
00433   const char *handler_name;
00434 #endif /* LWIP_DEBUG_TIMERNAMES */
00435 
00436  again:
00437   if (!next_timeout) {
00438     time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
00439   } else {
00440     if (next_timeout->time > 0) {
00441       time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
00442     } else {
00443       time_needed = SYS_ARCH_TIMEOUT;
00444     }
00445 
00446     if (time_needed == SYS_ARCH_TIMEOUT) {
00447       /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
00448          could be fetched. We should now call the timeout handler and
00449          deallocate the memory allocated for the timeout. */
00450       tmptimeout = next_timeout;
00451       next_timeout = tmptimeout->next;
00452       h   = tmptimeout->h;
00453       arg = tmptimeout->arg;
00454 #if LWIP_DEBUG_TIMERNAMES
00455       handler_name = tmptimeout->handler_name;
00456 #endif /* LWIP_DEBUG_TIMERNAMES */
00457       memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
00458       if (h != NULL) {
00459 #if LWIP_DEBUG_TIMERNAMES
00460         LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%p(%p) (%s)\n", *(void**)&h, arg, handler_name));
00461 #else /* LWIP_DEBUG_TIMERNAMES */
00462         LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%p(%p)\n", *(void**)&h, arg));
00463 #endif /* LWIP_DEBUG_TIMERNAMES */
00464         /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
00465            timeout handler function. */
00466         LOCK_TCPIP_CORE();
00467         h(arg);
00468         UNLOCK_TCPIP_CORE();
00469       }
00470 
00471       /* We try again to fetch a message from the mbox. */
00472       goto again;
00473     } else {
00474       /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
00475          occured. The time variable is set to the number of
00476          milliseconds we waited for the message. */
00477       if (time_needed < next_timeout->time) {
00478         next_timeout->time -= time_needed;
00479       } else {
00480         next_timeout->time = 0;
00481       }
00482     }
00483   }
00484 }
00485 
00486 #endif /* NO_SYS */