timer.h
Go to the documentation of this file.
00001 00056 #ifndef DRV_TIMER_H 00057 #define DRV_TIMER_H 00058 00059 #include <cfg/os.h> 00060 #include <cfg/macros.h> 00061 00062 #include <cpu/attr.h> 00063 #include <cpu/irq.h> 00064 00065 #include <string.h> 00066 00067 /* 00068 * Include platform-specific binding header if we're hosted. 00069 * Try the CPU specific one for bare-metal environments. 00070 */ 00071 #if OS_HOSTED 00072 //#include OS_HEADER(timer) 00073 #include <emul/timer_posix.h> 00074 #else 00075 #include CPU_HEADER(timer) 00076 #endif 00077 00078 STATIC_ASSERT(sizeof(hptime_t) == SIZEOF_HPTIME_T); 00079 00080 #include "cfg/cfg_timer.h" 00081 #include <cfg/debug.h> 00082 #include <cfg/compiler.h> 00083 00084 #include <struct/list.h> 00085 00086 /* 00087 * Sanity check for config parameters required by this module. 00088 */ 00089 #if !defined(CONFIG_TIMER_EVENTS) || ((CONFIG_TIMER_EVENTS != 0) && CONFIG_TIMER_EVENTS != 1) 00090 #error CONFIG_TIMER_EVENTS must be set to either 0 or 1 in cfg_timer.h 00091 #endif 00092 #if !defined(CONFIG_TIMER_UDELAY) || ((CONFIG_TIMER_UDELAY != 0) && CONFIG_TIMER_EVENTS != 1) 00093 #error CONFIG_TIMER_UDELAY must be set to either 0 or 1 in cfg_timer.h 00094 #endif 00095 #if defined(CONFIG_TIMER_DISABLE_UDELAY) 00096 #error Obosolete config option CONFIG_TIMER_DISABLE_UDELAY. Use CONFIG_TIMER_UDELAY 00097 #endif 00098 #if defined(CONFIG_TIMER_DISABLE_EVENTS) 00099 #error Obosolete config option CONFIG_TIMER_DISABLE_EVENTS. Use CONFIG_TIMER_EVENTS 00100 #endif 00101 00102 extern volatile ticks_t _clock; 00103 00104 #define TIMER_AFTER(x, y) ((long)(y) - (long)(x) < 0) 00105 #define TIMER_BEFORE(x, y) TIMER_AFTER(y, x) 00106 00135 INLINE ticks_t timer_clock(void) 00136 { 00137 ticks_t result; 00138 00139 ATOMIC(result = _clock); 00140 00141 return result; 00142 } 00143 00151 INLINE ticks_t timer_clock_unlocked(void) 00152 { 00153 return _clock; 00154 } 00155 00156 00158 INLINE ticks_t ms_to_ticks(mtime_t ms) 00159 { 00160 #if TIMER_TICKS_PER_SEC < 1000 00161 /* Slow timer: avoid rounding down too much. */ 00162 return (ms * TIMER_TICKS_PER_SEC) / 1000; 00163 #else 00164 /* Fast timer: don't overflow ticks_t. */ 00165 return ms * DIV_ROUND(TIMER_TICKS_PER_SEC, 1000); 00166 #endif 00167 } 00168 00170 INLINE ticks_t us_to_ticks(utime_t us) 00171 { 00172 #if TIMER_TICKS_PER_SEC < 1000 00173 /* Slow timer: avoid rounding down too much. */ 00174 return ((us / 1000) * TIMER_TICKS_PER_SEC) / 1000; 00175 #else 00176 /* Fast timer: don't overflow ticks_t. */ 00177 return (us * DIV_ROUND(TIMER_TICKS_PER_SEC, 1000)) / 1000; 00178 #endif 00179 } 00180 00182 INLINE mtime_t ticks_to_ms(ticks_t ticks) 00183 { 00184 #if TIMER_TICKS_PER_SEC < 1000 00185 /* Slow timer: avoid rounding down too much. */ 00186 return (ticks * 1000) / TIMER_TICKS_PER_SEC; 00187 #else 00188 /* Fast timer: avoid overflowing ticks_t. */ 00189 return ticks / (TIMER_TICKS_PER_SEC / 1000); 00190 #endif 00191 } 00192 00194 INLINE utime_t ticks_to_us(ticks_t ticks) 00195 { 00196 #if TIMER_TICKS_PER_SEC < 1000 00197 /* Slow timer: avoid rounding down too much. */ 00198 return ((ticks * 1000) / TIMER_TICKS_PER_SEC) * 1000; 00199 #else 00200 /* Fast timer: avoid overflowing ticks_t. */ 00201 return (ticks / (TIMER_TICKS_PER_SEC / 1000)) * 1000; 00202 #endif 00203 } 00204 00206 INLINE hptime_t us_to_hptime(utime_t us) 00207 { 00208 #if TIMER_HW_HPTICKS_PER_SEC > 10000000UL 00209 return us * DIV_ROUND(TIMER_HW_HPTICKS_PER_SEC, 1000000UL); 00210 #else 00211 return (us * ((TIMER_HW_HPTICKS_PER_SEC + 500) / 1000UL) + 500) / 1000UL; 00212 #endif 00213 } 00214 00216 INLINE utime_t hptime_to_us(hptime_t hpticks) 00217 { 00218 #if TIMER_HW_HPTICKS_PER_SEC < 100000UL 00219 return hpticks * DIV_ROUND(1000000UL, TIMER_HW_HPTICKS_PER_SEC); 00220 #else 00221 return (hpticks * 1000UL) / DIV_ROUND(TIMER_HW_HPTICKS_PER_SEC, 1000UL); 00222 #endif /* TIMER_HW_HPTICKS_PER_SEC < 100000UL */ 00223 } 00224 00225 void timer_delayTicks(ticks_t delay); 00232 INLINE void timer_delay(mtime_t delay) 00233 { 00234 timer_delayTicks(ms_to_ticks(delay)); 00235 } 00236 00237 void timer_init(void); 00238 void timer_cleanup(void); 00239 00240 int timer_testSetup(void); 00241 int timer_testRun(void); 00242 int timer_testTearDown(void); 00243 00244 #if CONFIG_TIMER_UDELAY 00245 void timer_busyWait(hptime_t delay); 00246 void timer_delayHp(hptime_t delay); 00247 INLINE void timer_udelay(utime_t delay) 00248 { 00249 timer_delayHp(us_to_hptime(delay)); 00250 } 00251 #endif 00252 00253 #if CONFIG_TIMER_EVENTS 00254 00255 #include <mware/event.h> 00256 00264 typedef struct Timer 00265 { 00266 Node link; 00267 ticks_t _delay; 00268 ticks_t tick; 00269 Event expire; 00270 DB(uint16_t magic;) 00271 } Timer; 00272 00273 /* Timer is active when Timer.magic contains this value (for debugging purposes). */ 00274 #define TIMER_MAGIC_ACTIVE 0xABBA 00275 #define TIMER_MAGIC_INACTIVE 0xBAAB 00276 00277 void timer_add(Timer *timer); 00278 Timer *timer_abort(Timer *timer); 00279 00290 INLINE void timer_setSoftint(Timer *timer, Hook func, iptr_t user_data) 00291 { 00292 event_initSoftint(&timer->expire, func, user_data); 00293 } 00294 00301 INLINE void timer_setDelay(Timer *timer, ticks_t delay) 00302 { 00303 timer->_delay = delay; 00304 } 00305 00306 00307 void synctimer_add(Timer *timer, List* q); 00308 00310 #define synctimer_abort(t) timer_abort(t) 00311 00312 void synctimer_poll(List* q); 00313 00319 INLINE ticks_t synctimer_nextTimeout(List *q) 00320 { 00321 ticks_t timeout = -1; 00322 00323 if (!LIST_EMPTY(q)) 00324 { 00325 Timer *expiring_timer = (Timer *)LIST_HEAD(q); 00326 timeout = MAX(expiring_timer->tick - timer_clock(), (ticks_t)0); 00327 } 00328 return timeout; 00329 } 00330 00331 /* 00332 * Explicitly mark a timer as executed. 00333 * 00334 * When a timer is marked as executed, it is inactive until the next 00335 * call to synctimer_add(). 00336 * Normally you shouldn't need to call this function explicitly, as all 00337 * timers in this module are designed to stop themselves after a while 00338 * (eg. retransmission timer will stop after a few retransmissions). 00339 * The only exception is at startup, where you should mark all timers 00340 * as executed to avoid spurious events. 00341 * 00342 * \note We can't rely on REMOVE() of synctimer_poll() since in release mode 00343 * it is empty. 00344 */ 00345 INLINE void synctimer_executed(Timer *t) 00346 { 00347 memset(&t->link, 0, sizeof(Node)); 00348 } 00349 00350 /* 00351 * Test if a timer is active. 00352 * 00353 * In the general case it should be ATOMIC() and timer.link should always 00354 * be memset() to 0. 00355 */ 00356 INLINE bool synctimer_active(Timer *t) 00357 { 00358 return !(t->link.pred == NULL && t->link.succ == NULL); 00359 } 00360 00361 00362 INLINE void synctimer_stop(Timer *timer) 00363 { 00364 if (synctimer_active(timer)) 00365 { 00366 timer_abort(timer); 00367 synctimer_executed(timer); 00368 } 00369 } 00370 00371 INLINE void synctimer_restart(Timer *timer, List *list, mtime_t timeout) 00372 { 00373 synctimer_stop(timer); 00374 00375 timer_setDelay(timer, ms_to_ticks(timeout)); 00376 synctimer_add(timer, list); 00377 } 00378 00379 void synctimer_readd(Timer *timer, List *queue); 00380 00381 #endif /* CONFIG_TIMER_EVENTS */ 00382 00383 #if defined(CONFIG_KERN_SIGNALS) && CONFIG_KERN_SIGNALS 00384 00386 INLINE void timer_setSignal(Timer *timer, struct Process *proc, sigmask_t sigs) 00387 { 00388 event_initSignal(&timer->expire, proc, sigs); 00389 } 00390 00391 #define timer_set_event_signal timer_setSignal 00392 00393 #endif /* CONFIG_KERN_SIGNALS */ 00394 //defgroup drv_timers 00396 00397 #endif /* DRV_TIMER_H */
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)