2013-11-22 20:41:09 +01:00
|
|
|
/**
|
|
|
|
* virtual timer
|
|
|
|
*
|
2014-07-13 06:39:19 +02:00
|
|
|
* Copyright (C) 2013, 2014 Freie Universität Berlin
|
2013-11-22 20:41:09 +01:00
|
|
|
*
|
2014-07-31 19:45:27 +02:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
2013-11-22 20:41:09 +01:00
|
|
|
*
|
|
|
|
* @ingroup vtimer
|
|
|
|
* @{
|
|
|
|
* @file
|
2014-01-28 11:50:12 +01:00
|
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de> (author)
|
2013-11-22 20:41:09 +01:00
|
|
|
* @author Oliver Hahm <oliver.hahm@inria.fr> (modifications)
|
|
|
|
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> (cleaning up the mess)
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2010-12-06 16:02:40 +01:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
2013-06-13 10:22:55 +02:00
|
|
|
#include <string.h>
|
2013-06-24 14:08:40 +02:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "irq.h"
|
2014-07-29 09:21:11 +02:00
|
|
|
#include "priority_queue.h"
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "timex.h"
|
|
|
|
#include "hwtimer.h"
|
|
|
|
#include "msg.h"
|
2014-01-23 15:20:43 +01:00
|
|
|
#include "mutex.h"
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "thread.h"
|
2014-09-07 22:06:05 +02:00
|
|
|
#include "kernel_macros.h"
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "vtimer.h"
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2013-07-24 00:36:06 +02:00
|
|
|
#define ENABLE_DEBUG (0)
|
2013-12-16 17:54:58 +01:00
|
|
|
#include "debug.h"
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2013-05-24 02:20:54 +02:00
|
|
|
#define VTIMER_THRESHOLD 20UL
|
|
|
|
#define VTIMER_BACKOFF 10UL
|
2010-12-06 16:02:40 +01:00
|
|
|
|
|
|
|
#define SECONDS_PER_TICK (4096U)
|
2013-05-24 02:20:54 +02:00
|
|
|
#define MICROSECONDS_PER_TICK (4096UL * 1000000)
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
static void vtimer_callback(void *ptr);
|
|
|
|
static void vtimer_callback_tick(vtimer_t *timer);
|
|
|
|
static void vtimer_callback_msg(vtimer_t *timer);
|
|
|
|
static void vtimer_callback_wakeup(vtimer_t *timer);
|
|
|
|
|
2010-12-10 17:16:18 +01:00
|
|
|
static int vtimer_set(vtimer_t *timer);
|
2010-12-06 16:02:40 +01:00
|
|
|
static int set_longterm(vtimer_t *timer);
|
|
|
|
static int set_shortterm(vtimer_t *timer);
|
|
|
|
|
2014-07-29 09:52:33 +02:00
|
|
|
static priority_queue_t longterm_priority_queue_root = PRIORITY_QUEUE_INIT;
|
|
|
|
static priority_queue_t shortterm_priority_queue_root = PRIORITY_QUEUE_INIT;
|
2010-12-06 16:02:40 +01:00
|
|
|
|
|
|
|
static vtimer_t longterm_tick_timer;
|
|
|
|
static uint32_t longterm_tick_start;
|
|
|
|
static volatile int in_callback = false;
|
|
|
|
|
|
|
|
static int hwtimer_id = -1;
|
|
|
|
static uint32_t hwtimer_next_absolute;
|
|
|
|
|
|
|
|
static uint32_t seconds = 0;
|
|
|
|
|
2014-09-07 22:06:05 +02:00
|
|
|
static inline priority_queue_node_t *timer_get_node(vtimer_t *timer)
|
|
|
|
{
|
|
|
|
if (!timer) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return &timer->priority_queue_entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline vtimer_t *node_get_timer(priority_queue_node_t *node)
|
|
|
|
{
|
|
|
|
if (!node) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return container_of(node, vtimer_t, priority_queue_entry);
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
static int set_longterm(vtimer_t *timer)
|
|
|
|
{
|
2014-07-29 09:21:11 +02:00
|
|
|
timer->priority_queue_entry.priority = timer->absolute.seconds;
|
2014-09-07 22:06:05 +02:00
|
|
|
priority_queue_add(&longterm_priority_queue_root, timer_get_node(timer));
|
2010-12-06 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
static int update_shortterm(void)
|
|
|
|
{
|
2014-07-29 09:21:11 +02:00
|
|
|
if (shortterm_priority_queue_root.first == NULL) {
|
2013-12-16 11:28:04 +01:00
|
|
|
/* there is no vtimer to schedule, queue is empty */
|
2014-07-29 09:21:11 +02:00
|
|
|
DEBUG("update_shortterm: shortterm_priority_queue_root.next == NULL - dont know what to do here\n");
|
2013-11-22 19:54:53 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2013-06-24 22:37:35 +02:00
|
|
|
if (hwtimer_id != -1) {
|
2013-12-16 11:28:04 +01:00
|
|
|
/* there is a running hwtimer for us */
|
2014-07-29 09:21:11 +02:00
|
|
|
if (hwtimer_next_absolute != shortterm_priority_queue_root.first->priority) {
|
2013-12-16 11:28:04 +01:00
|
|
|
/* the next timer in the vtimer queue is not the next hwtimer */
|
|
|
|
/* we have to remove the running hwtimer (and schedule a new one) */
|
2010-12-06 16:02:40 +01:00
|
|
|
hwtimer_remove(hwtimer_id);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-12-16 11:28:04 +01:00
|
|
|
/* the next vtimer is the next hwtimer, nothing to do */
|
2010-12-06 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 11:28:04 +01:00
|
|
|
/* short term part of the next vtimer */
|
2014-07-29 09:21:11 +02:00
|
|
|
hwtimer_next_absolute = shortterm_priority_queue_root.first->priority;
|
2010-12-10 16:52:06 +01:00
|
|
|
|
2013-11-22 19:54:53 +01:00
|
|
|
uint32_t next = hwtimer_next_absolute;
|
2013-12-16 11:28:04 +01:00
|
|
|
|
|
|
|
/* current short term time */
|
2013-05-24 02:20:54 +02:00
|
|
|
uint32_t now = HWTIMER_TICKS_TO_US(hwtimer_now());
|
2010-12-10 16:52:06 +01:00
|
|
|
|
2013-11-22 19:54:53 +01:00
|
|
|
/* make sure the longterm_tick_timer does not get truncated */
|
2014-09-07 22:06:05 +02:00
|
|
|
if (node_get_timer(shortterm_priority_queue_root.first)->action != vtimer_callback_tick) {
|
2013-12-16 11:28:04 +01:00
|
|
|
/* the next vtimer to schedule is the long term tick */
|
|
|
|
/* it has a shortterm offset of longterm_tick_start */
|
2013-11-22 19:54:53 +01:00
|
|
|
next += longterm_tick_start;
|
|
|
|
}
|
|
|
|
|
2013-05-24 02:20:54 +02:00
|
|
|
if((next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now) > MICROSECONDS_PER_TICK ) {
|
2013-12-13 21:42:08 +01:00
|
|
|
DEBUG("truncating next (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now): %lu\n", (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now));
|
2013-05-24 02:20:54 +02:00
|
|
|
next = now + HWTIMER_TICKS_TO_US(VTIMER_BACKOFF);
|
2010-12-06 16:02:40 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("update_shortterm: Set hwtimer to %" PRIu32 " (now=%lu)\n", next, HWTIMER_TICKS_TO_US(hwtimer_now()));
|
2013-12-16 11:30:22 +01:00
|
|
|
hwtimer_id = hwtimer_set_absolute(HWTIMER_TICKS(next), vtimer_callback, NULL);
|
|
|
|
|
2010-12-06 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
void vtimer_callback_tick(vtimer_t *timer)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-04-18 21:43:43 +02:00
|
|
|
(void) timer;
|
|
|
|
|
|
|
|
DEBUG("vtimer_callback_tick().\n");
|
2010-12-06 16:02:40 +01:00
|
|
|
seconds += SECONDS_PER_TICK;
|
|
|
|
|
2011-12-01 13:01:36 +01:00
|
|
|
longterm_tick_start = longterm_tick_timer.absolute.microseconds;
|
2013-11-22 19:54:53 +01:00
|
|
|
longterm_tick_timer.absolute.microseconds += MICROSECONDS_PER_TICK;
|
2010-12-06 16:02:40 +01:00
|
|
|
set_shortterm(&longterm_tick_timer);
|
|
|
|
|
2014-07-29 09:21:11 +02:00
|
|
|
while (longterm_priority_queue_root.first) {
|
2014-09-07 22:06:05 +02:00
|
|
|
vtimer_t *timer = node_get_timer(longterm_priority_queue_root.first);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (timer->absolute.seconds == seconds) {
|
2014-07-29 09:21:11 +02:00
|
|
|
priority_queue_remove_head(&longterm_priority_queue_root);
|
2010-12-06 16:02:40 +01:00
|
|
|
set_shortterm(timer);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-12-06 16:02:40 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
static void vtimer_callback_msg(vtimer_t *timer)
|
|
|
|
{
|
|
|
|
msg_t msg;
|
|
|
|
msg.type = MSG_TIMER;
|
|
|
|
msg.content.value = (unsigned int) timer->arg;
|
|
|
|
msg_send_int(&msg, timer->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vtimer_callback_wakeup(vtimer_t *timer)
|
|
|
|
{
|
|
|
|
thread_wakeup(timer->pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vtimer_callback_unlock(vtimer_t *timer)
|
|
|
|
{
|
|
|
|
mutex_t *mutex = (mutex_t *) timer->arg;
|
|
|
|
mutex_unlock(mutex);
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
static int set_shortterm(vtimer_t *timer)
|
|
|
|
{
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("set_shortterm(): Absolute: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
|
2014-07-29 09:21:11 +02:00
|
|
|
timer->priority_queue_entry.priority = timer->absolute.microseconds;
|
2014-09-07 22:06:05 +02:00
|
|
|
priority_queue_add(&shortterm_priority_queue_root, timer_get_node(timer));
|
2010-12-06 16:02:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void vtimer_callback(void *ptr)
|
|
|
|
{
|
2013-12-16 11:28:04 +01:00
|
|
|
DEBUG("vtimer_callback ptr=%p\n", ptr);
|
2013-08-04 04:06:31 +02:00
|
|
|
(void) ptr;
|
2014-04-18 21:43:43 +02:00
|
|
|
|
2010-12-06 16:02:40 +01:00
|
|
|
in_callback = true;
|
2010-12-10 16:52:06 +01:00
|
|
|
hwtimer_id = -1;
|
|
|
|
|
2013-12-16 11:28:04 +01:00
|
|
|
/* get the vtimer that fired */
|
2014-09-07 22:06:05 +02:00
|
|
|
vtimer_t *timer = node_get_timer(priority_queue_remove_head(&shortterm_priority_queue_root));
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2014-07-18 14:42:52 +02:00
|
|
|
if (timer) {
|
2013-07-24 00:36:06 +02:00
|
|
|
#if ENABLE_DEBUG
|
2014-07-18 14:42:52 +02:00
|
|
|
vtimer_print(timer);
|
2011-11-30 15:50:36 +01:00
|
|
|
#endif
|
2014-07-18 14:42:52 +02:00
|
|
|
DEBUG("vtimer_callback(): Shooting %" PRIu32 ".\n", timer->absolute.microseconds);
|
2010-12-10 16:52:06 +01:00
|
|
|
|
2014-07-18 14:42:52 +02:00
|
|
|
/* shoot timer */
|
|
|
|
timer->action(timer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUG("vtimer_callback(): spurious call.\n");
|
|
|
|
}
|
2010-12-06 16:02:40 +01:00
|
|
|
|
|
|
|
in_callback = false;
|
|
|
|
update_shortterm();
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void normalize_to_tick(timex_t *time)
|
|
|
|
{
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("Normalizing: %" PRIu32 " %" PRIu32 "\n", time->seconds, time->microseconds);
|
2010-12-06 16:02:40 +01:00
|
|
|
uint32_t seconds_tmp = time->seconds % SECONDS_PER_TICK;
|
|
|
|
time->seconds -= seconds_tmp;
|
2011-12-01 13:01:36 +01:00
|
|
|
uint32_t usecs_tmp = time->microseconds + (seconds_tmp * 1000000);
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("Normalizin2: %" PRIu32 " %" PRIu32 "\n", time->seconds, usecs_tmp);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (usecs_tmp < time->microseconds) {
|
2011-12-01 13:01:36 +01:00
|
|
|
usecs_tmp -= MICROSECONDS_PER_TICK;
|
2010-12-06 16:02:40 +01:00
|
|
|
time->seconds += SECONDS_PER_TICK;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (usecs_tmp > MICROSECONDS_PER_TICK) {
|
2011-12-01 13:01:36 +01:00
|
|
|
usecs_tmp -= MICROSECONDS_PER_TICK;
|
2010-12-06 16:02:40 +01:00
|
|
|
time->seconds += SECONDS_PER_TICK;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-12-01 13:01:36 +01:00
|
|
|
time->microseconds = usecs_tmp;
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG(" Result: %" PRIu32 " %" PRIu32 "\n", time->seconds, time->microseconds);
|
2010-12-06 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
static int vtimer_set(vtimer_t *timer)
|
|
|
|
{
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("vtimer_set(): New timer. Offset: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2013-06-13 10:22:55 +02:00
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
|
|
|
timer->absolute = timex_add(now, timer->absolute);
|
2010-12-06 16:02:40 +01:00
|
|
|
normalize_to_tick(&(timer->absolute));
|
|
|
|
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("vtimer_set(): Absolute: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
|
|
|
|
DEBUG("vtimer_set(): NOW: %" PRIu32 " %" PRIu32 "\n", now.seconds, now.microseconds);
|
2010-12-06 16:02:40 +01:00
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (timer->absolute.seconds == 0) {
|
|
|
|
if (timer->absolute.microseconds > 10) {
|
2011-12-01 13:01:36 +01:00
|
|
|
timer->absolute.microseconds -= 10;
|
2010-12-10 16:52:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
unsigned state = disableIRQ();
|
2013-06-24 22:37:35 +02:00
|
|
|
if (timer->absolute.seconds != seconds) {
|
2010-12-06 16:02:40 +01:00
|
|
|
/* we're long-term */
|
|
|
|
DEBUG("vtimer_set(): setting long_term\n");
|
|
|
|
result = set_longterm(timer);
|
2012-01-11 17:02:43 +01:00
|
|
|
}
|
|
|
|
else {
|
2010-12-06 16:02:40 +01:00
|
|
|
DEBUG("vtimer_set(): setting short_term\n");
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (set_shortterm(timer)) {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* delay update of next shortterm timer if we
|
2012-01-11 17:02:43 +01:00
|
|
|
* are called from within vtimer_callback. */
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (!in_callback) {
|
2010-12-06 16:02:40 +01:00
|
|
|
result = update_shortterm();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
restoreIRQ(state);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void vtimer_now(timex_t *out)
|
|
|
|
{
|
2013-12-16 11:47:02 +01:00
|
|
|
uint32_t us = HWTIMER_TICKS_TO_US(hwtimer_now() - longterm_tick_start);
|
2014-04-17 14:46:21 +02:00
|
|
|
uint32_t us_per_s = 1000ul * 1000ul;
|
2013-12-16 11:47:02 +01:00
|
|
|
|
2014-04-17 14:46:21 +02:00
|
|
|
out->seconds = seconds + us / us_per_s;
|
|
|
|
out->microseconds = us % us_per_s;
|
2010-12-06 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
2014-02-25 12:13:34 +01:00
|
|
|
void vtimer_gettimeofday(struct timeval *tp) {
|
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
|
|
|
|
|
|
|
tp->tv_sec = now.seconds;
|
|
|
|
tp->tv_usec = now.microseconds;
|
|
|
|
}
|
|
|
|
|
2013-12-18 20:47:33 +01:00
|
|
|
void vtimer_get_localtime(struct tm *localt)
|
|
|
|
{
|
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
|
|
|
|
|
|
|
localt->tm_sec = now.seconds % 60;
|
|
|
|
localt->tm_min = (now.seconds / 60) % 60;
|
|
|
|
localt->tm_hour = (now.seconds / 60 / 60) % 24;
|
|
|
|
|
|
|
|
// TODO: fill the other fields
|
|
|
|
}
|
|
|
|
|
2014-05-07 12:36:32 +02:00
|
|
|
int vtimer_init(void)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2010-12-06 16:02:40 +01:00
|
|
|
DEBUG("vtimer_init().\n");
|
2014-10-27 16:18:40 +01:00
|
|
|
unsigned state = disableIRQ();
|
2010-12-06 16:02:40 +01:00
|
|
|
seconds = 0;
|
|
|
|
|
2013-05-24 02:20:54 +02:00
|
|
|
longterm_tick_start = 0;
|
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
longterm_tick_timer.action = vtimer_callback_tick;
|
2010-12-06 16:02:40 +01:00
|
|
|
longterm_tick_timer.arg = NULL;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2010-12-06 16:02:40 +01:00
|
|
|
longterm_tick_timer.absolute.seconds = 0;
|
2011-12-01 13:01:36 +01:00
|
|
|
longterm_tick_timer.absolute.microseconds = MICROSECONDS_PER_TICK;
|
2010-12-06 16:02:40 +01:00
|
|
|
|
2013-07-16 15:25:23 +02:00
|
|
|
DEBUG("vtimer_init(): Setting longterm tick to %" PRIu32 "\n", longterm_tick_timer.absolute.microseconds);
|
2010-12-06 16:02:40 +01:00
|
|
|
|
|
|
|
set_shortterm(&longterm_tick_timer);
|
|
|
|
update_shortterm();
|
|
|
|
|
2010-12-10 16:52:06 +01:00
|
|
|
restoreIRQ(state);
|
2010-12-06 16:02:40 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-06 22:57:56 +02:00
|
|
|
int vtimer_set_wakeup(vtimer_t *t, timex_t interval, kernel_pid_t pid)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-04-18 21:43:43 +02:00
|
|
|
t->action = vtimer_callback_wakeup;
|
|
|
|
t->arg = NULL;
|
2010-12-10 17:16:18 +01:00
|
|
|
t->absolute = interval;
|
2014-04-18 21:43:43 +02:00
|
|
|
t->pid = pid;
|
|
|
|
return vtimer_set(t);
|
2010-12-10 17:16:18 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
int vtimer_usleep(uint32_t usecs)
|
|
|
|
{
|
2010-12-06 16:02:40 +01:00
|
|
|
timex_t offset = timex_set(0, usecs);
|
2010-12-10 17:16:18 +01:00
|
|
|
return vtimer_sleep(offset);
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
int vtimer_sleep(timex_t time)
|
|
|
|
{
|
2014-07-13 06:39:19 +02:00
|
|
|
/**
|
|
|
|
* Use spin lock for short periods.
|
|
|
|
* Assumes that hardware timer ticks are shorter than a second.
|
|
|
|
*/
|
|
|
|
if (time.seconds == 0) {
|
|
|
|
unsigned long ticks = HWTIMER_TICKS(time.microseconds);
|
2014-07-13 07:11:55 +02:00
|
|
|
if (ticks <= HWTIMER_SPIN_BARRIER) {
|
2014-07-13 06:39:19 +02:00
|
|
|
hwtimer_spin(ticks);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 14:07:48 +01:00
|
|
|
int ret;
|
2010-12-10 17:16:18 +01:00
|
|
|
vtimer_t t;
|
2014-07-17 12:27:29 +02:00
|
|
|
mutex_t mutex = MUTEX_INIT;
|
2014-01-23 15:20:43 +01:00
|
|
|
mutex_lock(&mutex);
|
|
|
|
|
2014-04-18 21:43:43 +02:00
|
|
|
t.action = vtimer_callback_unlock;
|
|
|
|
t.arg = &mutex;
|
2014-01-23 15:20:43 +01:00
|
|
|
t.absolute = time;
|
2014-02-11 18:15:43 +01:00
|
|
|
|
2014-01-23 15:20:43 +01:00
|
|
|
ret = vtimer_set(&t);
|
2014-02-11 18:15:43 +01:00
|
|
|
mutex_lock(&mutex);
|
2012-02-17 14:07:48 +01:00
|
|
|
return ret;
|
2010-12-06 16:02:40 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
int vtimer_remove(vtimer_t *t)
|
|
|
|
{
|
2014-10-27 16:18:40 +01:00
|
|
|
unsigned irq_state = disableIRQ();
|
2014-03-26 19:25:07 +01:00
|
|
|
|
2014-09-07 22:06:05 +02:00
|
|
|
priority_queue_remove(&shortterm_priority_queue_root, timer_get_node(t));
|
|
|
|
priority_queue_remove(&longterm_priority_queue_root, timer_get_node(t));
|
2011-06-24 18:54:20 +02:00
|
|
|
update_shortterm();
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2014-03-26 19:25:07 +01:00
|
|
|
restoreIRQ(irq_state);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
return 0;
|
2011-06-24 18:54:20 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 22:57:56 +02:00
|
|
|
int vtimer_set_msg(vtimer_t *t, timex_t interval, kernel_pid_t pid, void *ptr)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-04-18 21:43:43 +02:00
|
|
|
t->action = vtimer_callback_msg;
|
2011-11-30 15:50:36 +01:00
|
|
|
t->arg = ptr;
|
2011-06-24 18:54:20 +02:00
|
|
|
t->absolute = interval;
|
2013-06-22 05:11:53 +02:00
|
|
|
t->pid = pid;
|
2011-06-24 18:54:20 +02:00
|
|
|
vtimer_set(t);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-30 15:50:36 +01:00
|
|
|
|
2013-12-03 12:27:49 +01:00
|
|
|
int vtimer_msg_receive_timeout(msg_t *m, timex_t timeout) {
|
|
|
|
msg_t timeout_message;
|
|
|
|
timeout_message.type = MSG_TIMER;
|
|
|
|
timeout_message.content.ptr = (char *) &timeout_message;
|
|
|
|
|
|
|
|
vtimer_t t;
|
2014-04-10 22:28:35 +02:00
|
|
|
vtimer_set_msg(&t, timeout, sched_active_pid, &timeout_message);
|
2013-12-03 12:27:49 +01:00
|
|
|
msg_receive(m);
|
|
|
|
if (m->type == MSG_TIMER && m->content.ptr == (char *) &timeout_message) {
|
|
|
|
/* we hit the timeout */
|
|
|
|
return -1;
|
2014-02-16 20:50:48 +01:00
|
|
|
}
|
|
|
|
else {
|
2013-12-03 12:27:49 +01:00
|
|
|
vtimer_remove(&t);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-10 17:06:41 +02:00
|
|
|
#if ENABLE_DEBUG
|
|
|
|
|
2013-03-15 17:48:13 +01:00
|
|
|
void vtimer_print_short_queue(){
|
2014-07-29 09:21:11 +02:00
|
|
|
priority_queue_print(&shortterm_priority_queue_root);
|
2013-03-15 17:48:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void vtimer_print_long_queue(){
|
2014-07-29 09:21:11 +02:00
|
|
|
priority_queue_print(&longterm_priority_queue_root);
|
2013-03-15 17:48:13 +01:00
|
|
|
}
|
|
|
|
|
2013-06-30 01:53:53 +02:00
|
|
|
void vtimer_print(vtimer_t *t)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2014-02-18 16:54:42 +01:00
|
|
|
printf("Seconds: %" PRIu32 " - Microseconds: %" PRIu32 "\n \
|
2011-11-30 15:50:36 +01:00
|
|
|
action: %p\n \
|
2013-11-21 21:35:25 +01:00
|
|
|
arg: %p\n \
|
2014-07-06 22:57:56 +02:00
|
|
|
pid: %" PRIkernel_pid "\n",
|
2013-06-22 05:11:53 +02:00
|
|
|
t->absolute.seconds, t->absolute.microseconds,
|
|
|
|
t->action,
|
|
|
|
t->arg,
|
|
|
|
t->pid);
|
2011-11-30 15:50:36 +01:00
|
|
|
}
|
2013-10-10 17:06:41 +02:00
|
|
|
|
|
|
|
#endif
|