timer.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2006 by egnite Software GmbH. All rights reserved.
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  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00187 #include <cfg/os.h>
00188 #include <dev/irqreg.h>
00189 
00190 #include <sys/types.h>
00191 #include <sys/atom.h>
00192 #include <sys/heap.h>
00193 #include <sys/thread.h>
00194 #include <sys/timer.h>
00195 
00196 #ifdef NUTDEBUG
00197 #include <sys/osdebug.h>
00198 #endif
00199 
00200 #ifdef NUTTRACER
00201 #include <sys/tracer.h>
00202 #endif
00203 
00204 #if defined (__linux__) || defined(__APPLE__) || defined(__CYGWIN__)
00205 #include <sys/time.h>
00206 
00207 static struct timeval   timeStart;
00208 #endif
00209 
00214 
00218 NUTTIMERINFO *nutTimerList;
00219 
00220 /*
00221  * Last processing time of elapsed timers. 
00222  */
00223 static u_long nut_ticks_resume; 
00224 
00228 volatile u_long nut_ticks;
00229 
00230 // volatile u_long nut_tick_dist[32];
00231 
00235 #if !(defined (__linux__) || defined(__APPLE__) || defined(__CYGWIN__))
00236 #ifdef USE_TIMER
00237 SIGNAL( SIG_TIMER ) 
00238 #else
00239 static void NutTimerIntr(void *arg)
00240 #endif
00241 {
00242     nut_ticks++;
00243     // nut_tick_dist[TCNT0]++;
00244 }
00245 #endif
00246 
00247 
00255 void NutTimerInit(void)
00256 {
00257 #if defined (__linux__) || defined(__APPLE__) || defined(__CYGWIN__)
00258     gettimeofday( &timeStart, NULL );
00259 #else
00260     NutRegisterTimer(NutTimerIntr);
00261     NutEnableTimerIrq();
00262 #endif
00263 }
00264 
00265 
00275 void NutTimerInsert(NUTTIMERINFO * tn)
00276 {
00277     NUTTIMERINFO *tnp;
00278 
00279     tn->tn_prev = NULL;
00280     for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) {
00281         if (tn->tn_ticks_left < tnp->tn_ticks_left) {
00282             tnp->tn_ticks_left -= tn->tn_ticks_left;
00283             break;
00284         }
00285         tn->tn_ticks_left -= tnp->tn_ticks_left;
00286         tn->tn_prev = tnp;
00287     }
00288     tn->tn_next = tnp;
00289     if (tn->tn_next) {
00290         tn->tn_next->tn_prev = tn;
00291     }
00292     if (tn->tn_prev) {
00293         tn->tn_prev->tn_next = tn;
00294     }
00295     else {
00296         nutTimerList = tn;
00297     }
00298 }
00299 
00306 void NutTimerProcessElapsed(void)
00307 {
00308     NUTTIMERINFO *tn;
00309     u_long ticks;
00310     u_long ticks_new;
00311 
00312     // calculate ticks since last call
00313     ticks = NutGetTickCount();
00314     ticks_new = ticks - nut_ticks_resume;
00315     nut_ticks_resume = ticks;
00316     
00317     // process timers
00318     while (nutTimerList && ticks_new){
00319         
00320         tn = nutTimerList;
00321 
00322         // subtract time
00323         if (ticks_new < tn->tn_ticks_left) {
00324             tn->tn_ticks_left -= ticks_new;
00325             ticks_new = 0;
00326         } else {
00327             ticks_new -= tn->tn_ticks_left;
00328             tn->tn_ticks_left = 0;
00329         }
00330         
00331         // elapsed
00332         if (tn->tn_ticks_left == 0){
00333 
00334             // callback
00335             if (tn->tn_callback) {
00336                 (*tn->tn_callback) (tn, (void *) tn->tn_arg);
00337             }
00338             if ((tn->tn_ticks_left = tn->tn_ticks) == 0) {
00339                 NutTimerStop(tn);
00340             }
00341             else {
00342                 // remove from list
00343                 nutTimerList = nutTimerList->tn_next;
00344                 if (nutTimerList) {
00345                     nutTimerList->tn_prev = 0;
00346                 }
00347                 // re-insert
00348                 NutTimerInsert(tn);
00349             }
00350         }
00351     }
00352 }
00353 
00373 NUTTIMERINFO * NutTimerCreate(u_long ticks, void (*callback) (HANDLE, void *), void *arg, u_char flags)
00374 {
00375     NUTTIMERINFO *tn;
00376     
00377     tn = NutHeapAlloc(sizeof(NUTTIMERINFO));
00378     if (tn) {
00379         tn->tn_ticks_left = ticks + NutGetTickCount() - nut_ticks_resume;
00380         
00381         /*
00382          * Periodic timers will reload the tick counter on each timer 
00383          * intervall.
00384          */
00385         if (flags & TM_ONESHOT) {
00386             tn->tn_ticks = 0;
00387         } else {
00388             tn->tn_ticks = ticks;
00389         }
00390         
00391         /* Set callback and callback argument. */
00392         tn->tn_callback = callback;
00393         tn->tn_arg = arg;
00394     }
00395     return tn;    
00396 }
00397 
00424 HANDLE NutTimerStartTicks(u_long ticks, void (*callback) (HANDLE, void *), void *arg, u_char flags)
00425 {
00426     NUTTIMERINFO *tn;
00427 
00428     tn = NutTimerCreate( ticks, callback, arg, flags);
00429     if (tn) {
00430         /* Add the timer to the list. */
00431         NutTimerInsert(tn);
00432     }
00433     return tn;
00434 }
00435 
00464 HANDLE NutTimerStart(u_long ms, void (*callback) (HANDLE, void *), void *arg, u_char flags)
00465 {
00466         return NutTimerStartTicks(NutTimerMillisToTicks(ms), callback, arg, flags);
00467 }
00468 
00490 void NutSleep(u_long ms)
00491 {
00492     if (ms) {
00493 
00494         /* remove running thread from runQueue */
00495         NutThreadRemoveQueue(runningThread, &runQueue);
00496         runningThread->td_state = TDS_SLEEP;
00497 
00498         if ((runningThread->td_timer = NutTimerStart(ms, NutThreadWake, runningThread, TM_ONESHOT)) != 0) {
00499 #ifdef NUTTRACER
00500             TRACE_ADD_ITEM(TRACE_TAG_THREAD_SLEEP,(int)runningThread);
00501 #endif
00502             NutThreadResume();
00503         } else
00504         {
00505             /* timer creation failed, restore queues */
00506             runningThread->td_queue = &runQueue;
00507             runningThread->td_qnxt  = runQueue;
00508             runningThread->td_state = TDS_RUNNING;
00509             runQueue = runningThread;
00510         }
00511     } else
00512         NutThreadYield();
00513 }
00514 
00527 void NutTimerStop(HANDLE handle)
00528 {
00529     NUTTIMERINFO *tn = (NUTTIMERINFO *)handle;
00530 
00531     if (tn->tn_prev) {
00532         tn->tn_prev->tn_next = tn->tn_next;
00533     }
00534     else {
00535         nutTimerList = tn->tn_next;
00536     }
00537     if (tn->tn_next) {
00538         tn->tn_next->tn_prev = tn->tn_prev;
00539         tn->tn_next->tn_ticks_left += tn->tn_ticks_left;
00540     }
00541     NutHeapFree(tn);
00542 }
00543 
00552 u_long NutGetTickCount(void)
00553 {
00554     u_long rc;
00555 
00556 #if defined (__linux__) || defined(__APPLE__) || defined(__CYGWIN__)
00557     struct timeval   timeNow;
00558 
00559     gettimeofday( &timeNow, NULL );
00560     rc = (timeNow.tv_sec - timeStart.tv_sec) * 1000;
00561     rc += (timeNow.tv_usec - timeStart.tv_usec) / 1000;
00562 #else
00563     NutEnterCritical();
00564     rc = nut_ticks;
00565     NutExitCritical();
00566 #endif
00567 
00568     return rc;
00569 }
00570 
00585 u_long NutGetSeconds(void)
00586 {
00587     return NutGetTickCount() / NutGetTickClock();
00588 }
00589 
00606 u_long NutGetMillis(void)
00607 {
00608     // carefully stay within 32 bit values
00609     u_long ticks   = NutGetTickCount();
00610     u_long seconds = ticks / NutGetTickClock();
00611     ticks         -= seconds * NutGetTickClock();
00612     return seconds * 1000 + (ticks * 1000 ) / NutGetTickClock();
00613 }
00614 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/