diff --git a/cpu/native/hwtimer_cpu.c b/cpu/native/hwtimer_cpu.c index c59a4f9e98..608304d90a 100644 --- a/cpu/native/hwtimer_cpu.c +++ b/cpu/native/hwtimer_cpu.c @@ -1,8 +1,11 @@ /** * Native CPU hwtimer_arch.h implementation * - * Uses POSIX real-time extension timers to mimic hardware timers. - * XXX: see hwtimer_isr_timer() + * Uses POSIX realtime clock and POSIX itimer to mimic hardware. + * Since there is only 1 itmer per process and RIOT needs several + * hardware timers, hwtimers are being multiplexed onto the itimer. + * + * XXX: does not scale well with number of timers (overhead: O(N)). * * Copyright (C) 2013 Ludwig Ortmann * @@ -18,6 +21,7 @@ */ #include +#include #include #include #include @@ -31,17 +35,30 @@ #include "debug.h" static unsigned long native_hwtimer_now; + static int native_hwtimer_irq[ARCH_MAXTIMERS]; -static timer_t native_hwtimer_timer[ARCH_MAXTIMERS]; +static struct itimerval native_hwtimer[ARCH_MAXTIMERS]; +static int native_hwtimer_isset[ARCH_MAXTIMERS]; + +static int next_timer; static void (*int_handler)(int); /** - * sets timespec to given ticks + * sets timeval to given ticks */ -void ticks2ts(unsigned long ticks, struct timespec *tp) +void ticks2tv(unsigned long ticks, struct timeval *tp) { tp->tv_sec = ticks / HWTIMER_SPEED; - tp->tv_nsec = (ticks % HWTIMER_SPEED)*1000 ; + tp->tv_usec = (ticks % HWTIMER_SPEED) ; +} + +/** + * returns ticks for give timeval + */ +unsigned long tv2ticks(struct timeval *tp) +{ + /* TODO: check for overflow */ + return((tp->tv_sec * HWTIMER_SPEED) + (tp->tv_usec)); } /** @@ -54,22 +71,72 @@ unsigned long ts2ticks(struct timespec *tp) } /** - * native timer signal handler, + * set next_timer to the next lowest enabled timer index + */ +void schedule_timer(void) +{ + int l = next_timer; + for ( + int i = ((next_timer +1) % ARCH_MAXTIMERS); + i != next_timer; + i = ((i+1) % ARCH_MAXTIMERS) + ) + { + + if ( native_hwtimer_isset[l] != 1 ) { + /* make sure we dont compare to garbage in the following + * if condition */ + l = i; + } + + if ( + ( native_hwtimer_isset[i] == 1 ) && + ( tv2ticks(&(native_hwtimer[i].it_value)) < tv2ticks(&(native_hwtimer[l].it_value)) ) + ) + { + /* set l to the lowest active time */ + l = i; + } + + } + next_timer = l; + /* l could still point to some unused (garbage) timer if no timers + * are set at all */ + if (native_hwtimer_isset[next_timer] == 1) { + if (setitimer(ITIMER_REAL, &native_hwtimer[next_timer], NULL) == -1) { + err(1, "schedule_timer"); + } + else { + DEBUG("schedule_timer(): set next timer.\n"); + } + } + else { + DEBUG("schedule_timer(): no next timer!? This looks suspicous.\n"); + // TODO: unset timer. + } +} + +/** + * native timer signal handler * - * XXX: Calls callback for all timers whenever any timer finishes. + * set new system timer, call timer interrupt handler */ void hwtimer_isr_timer() { + int i; + DEBUG("hwtimer_isr_timer()\n"); - for (int i = 0; i 0 ) { - errx(1, "XXX: unhandled hwtimer situation"); - } + i = next_timer; + native_hwtimer_isset[next_timer] = 0; + schedule_timer(); + + if (native_hwtimer_irq[i] == 1) { + DEBUG("hwtimer_isr_timer(): calling hwtimer.int_handler(%i)\n", i); + int_handler(i); + } + else { + DEBUG("hwtimer_isr_timer(): this should not have happened"); } } @@ -93,39 +160,27 @@ void hwtimer_arch_disable_interrupt(void) void hwtimer_arch_unset(short timer) { - struct itimerspec its; - DEBUG("hwtimer_arch_unset(%d)\n", timer); native_hwtimer_irq[timer] = 0; - - its.it_interval.tv_nsec = 0; - its.it_interval.tv_sec = 0; - its.it_value.tv_nsec = 0; - its.it_value.tv_sec = 0; - - if( (timer_settime(native_hwtimer_timer[timer], 0, &its, NULL)) == -1) { - err(1, "hwtimer_arch_unset: timer_settime"); - } + native_hwtimer_isset[timer] = 0; + schedule_timer(); return; } void hwtimer_arch_set(unsigned long offset, short timer) { - struct itimerspec its; - DEBUG("hwtimer_arch_set(%li, %i)\n", offset, timer); native_hwtimer_irq[timer] = 1; + native_hwtimer_isset[timer] = 1; - ticks2ts(offset, &its.it_value); - DEBUG("hwtimer_arch_set(): that is %lis %lins from now\n", its.it_value.tv_sec, its.it_value.tv_nsec); + ticks2tv(offset, &(native_hwtimer[timer].it_value)); + DEBUG("hwtimer_arch_set(): that is %lis %lius from now\n", + native_hwtimer[timer].it_value.tv_sec, + native_hwtimer[timer].it_value.tv_usec); - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - if (timer_settime(native_hwtimer_timer[timer], 0, &its, NULL) == -1) { - err(1, "hwtimer_arch_unset: timer_settime"); - } + schedule_timer(); return; } @@ -155,24 +210,18 @@ unsigned long hwtimer_arch_now(void) void hwtimer_arch_init(void (*handler)(int), uint32_t fcpu) { - struct sigevent sev; - DEBUG("hwtimer_arch_init()\n"); hwtimer_arch_disable_interrupt(); - int_handler = handler; - sev.sigev_notify = SIGEV_SIGNAL; for (int i = 0; i