int _xtimer_set_absolute(xtimer_t *timer, uint32_t target) { uint32_t now = xtimer_now(); int res = 0; DEBUG("timer_set_absolute(): now=%" PRIu32 " target=%" PRIu32 "\n", now, target); timer->next = NULL; if ((target >= now) && ((target - XTIMER_BACKOFF) < now)) { /* backoff */ xtimer_spin_until(target + XTIMER_BACKOFF); _shoot(timer); return 0; } unsigned state = irq_disable(); if (_is_set(timer)) { _remove(timer); } timer->target = target; timer->long_target = _long_cnt; if (target < now) { timer->long_target++; } if ( (timer->long_target > _long_cnt) || !_this_high_period(target) ) { DEBUG("xtimer_set_absolute(): the timer doesn't fit into the low-level timer's mask.\n"); _add_timer_to_long_list(&long_list_head, timer); } else { if (_xtimer_lltimer_mask(now) >= target) { DEBUG("xtimer_set_absolute(): the timer will expire in the next timer period\n"); _add_timer_to_list(&overflow_list_head, timer); } else { DEBUG("timer_set_absolute(): timer will expire in this timer period.\n"); _add_timer_to_list(&timer_list_head, timer); if (timer_list_head == timer) { DEBUG("timer_set_absolute(): timer is new list head. updating lltimer.\n"); _lltimer_set(target - XTIMER_OVERHEAD); } } } irq_restore(state); return res; }
void xtimer_set(xtimer_t *timer, uint32_t offset) { DEBUG("timer_set(): offset=%" PRIu32 " now=%" PRIu32 " (%" PRIu32 ")\n", offset, xtimer_now(), _xtimer_now()); if (!timer->callback) { DEBUG("timer_set(): timer has no callback.\n"); return; } xtimer_remove(timer); uint32_t target = xtimer_now() + offset; if (offset < XTIMER_BACKOFF) { xtimer_spin(offset); _shoot(timer); } else { _xtimer_set_absolute(timer, target); } }
/** * @brief main xtimer callback function */ static void _timer_callback(void) { uint32_t next_target; uint32_t reference; _in_handler = 1; DEBUG("_timer_callback() now=%" PRIu32 " (%" PRIu32 ")pleft=%" PRIu32 "\n", xtimer_now(), _mask(xtimer_now()), _mask(0xffffffff-xtimer_now())); if (!timer_list_head) { DEBUG("_timer_callback(): tick\n"); /* there's no timer for this timer period, * so this was a timer overflow callback. * * In this case, we advance to the next timer period. */ _next_period(); reference = 0; /* make sure the timer counter also arrived * in the next timer period */ while (_xtimer_now() == _mask(0xFFFFFFFF)); } else { /* we ended up in _timer_callback and there is * a timer waiting. */ /* set our period reference to that timer's target time. */ reference = _mask(timer_list_head->target); } overflow: /* check if next timers are close to expiring */ while (timer_list_head && (_time_left(_mask(timer_list_head->target), reference) < XTIMER_ISR_BACKOFF)) { /* make sure we don't fire too early */ while (_time_left(_mask(timer_list_head->target), reference)); /* pick first timer in list */ xtimer_t *timer = timer_list_head; /* advance list */ timer_list_head = timer->next; /* make sure timer is recognized as being already fired */ timer->target = 0; timer->long_target = 0; /* fire timer */ _shoot(timer); } /* possibly executing all callbacks took enough * time to overflow. In that case we advance to * next timer period and check again for expired * timers.*/ if (reference > _xtimer_now()) { DEBUG("_timer_callback: overflowed while executing callbacks. %i\n", timer_list_head != 0); _next_period(); reference = 0; goto overflow; } if (timer_list_head) { /* schedule callback on next timer target time */ next_target = timer_list_head->target - XTIMER_OVERHEAD; } else { /* there's no timer planned for this timer period */ /* schedule callback on next overflow */ next_target = _mask(0xFFFFFFFF); uint32_t now = _xtimer_now(); /* check for overflow again */ if (now < reference) { _next_period(); reference = 0; goto overflow; } else { /* check if the end of this period is very soon */ if (_mask(now + XTIMER_ISR_BACKOFF) < now) { /* spin until next period, then advance */ while (_xtimer_now() > now); _next_period(); reference = 0; goto overflow; } } } _in_handler = 0; /* set low level timer */ _lltimer_set(next_target); }