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.
timers.c
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 */
Generated on Tue Jul 12 2022 21:10:26 by 1.7.2