macro has to be defined in configuration file.
+CONFIG_MODULE_CALLOUT
+ The 'callout' module is another timer manager that aims to replace the
+ scheduler module. The management of timers can be done either from an
+ asynchronous interruption or from the main program. This module is
+ able to handle priorities between timers and allow to reschedule
+ a timer later if its priority is too low.
+
+
CONFIG_TIME
This module can be used to get a human readable time. It uses the
scheduler module. Its goal is not to be very precise, but just
fi
+bool 'Callout' CONFIG_MODULE_CALLOUT
+
#### TIME
dep_bool 'Time' CONFIG_MODULE_TIME \
$CONFIG_MODULE_SCHEDULER
CONFIG_MODULE_CONTROL_SYSTEM_MANAGER,devices/control_system/control_system_manager
CONFIG_MODULE_TIME,base/time
CONFIG_MODULE_SCHEDULER,base/scheduler
+ CONFIG_MODULE_CALLOUT,base/callout
CONFIG_MODULE_SPI,comm/spi
CONFIG_MODULE_CC2420,devices/radio/cc2420
CONFIG_MODULE_XBEE,devices/radio/xbee
--- /dev/null
+TARGET = callout
+
+SRC := callout.c
+
+include $(AVERSIVE_DIR)/mk/aversive_module.mk
--- /dev/null
+/*
+ * Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Inspired from Intel DPDK rte_timer library */
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <aversive.h>
+#include <aversive/pgmspace.h>
+#include <aversive/queue.h>
+
+#include "callout.h"
+
+/* allow to browse a list while modifying the current element */
+#define LIST_FOREACH_SAFE(cur, next, head, field) \
+ for ((cur) = LIST_FIRST((head)), \
+ (next) = ((cur) ? LIST_NEXT((cur), field) : NULL); \
+ (cur); \
+ (cur) = (next), \
+ (next) = ((cur) ? LIST_NEXT((cur), field) : NULL))
+
+#ifdef CALLOUT_STATS
+/* called with irq locked */
+#define CALLOUT_STAT_ADD(cm, field, x) do { \
+ cm->stats.field += x; \
+ } while(0)
+#else
+#define CALLOUT_STAT_ADD(cm, field, x) do { } while(0)
+#endif
+
+#ifdef CALLOUT_DEBUG
+#define callout_dprintf_P(fmt, ...) printf_P(PSTR("%s(): " fmt), __FUNCTION__, \
+ __VA_ARGS__)
+#else
+#define callout_dprintf_P(...) do { } while (0)
+#endif
+
+/* Initialize a callout manager */
+void
+callout_mgr_init(struct callout_mgr *cm, get_time_t *get_time)
+{
+ memset(cm, 0, sizeof(*cm));
+ cm->get_time = get_time;
+ LIST_INIT(&cm->sched_list);
+}
+
+/* Initialize the timer handle tim for use */
+void
+callout_init(struct callout *tim, callout_cb_t f, void *arg, uint8_t priority)
+{
+ memset(tim, 0, sizeof(*tim));
+ tim->f = f;
+ tim->arg = arg;
+ tim->priority = priority;
+}
+
+/*
+ * Add a timer in the scheduled list (timer must not already be in a list). The
+ * timers are sorted in the list according the expire time (the closer timers
+ * first).
+ *
+ * called with irq locked
+ */
+static void
+callout_add_in_sched_list(struct callout_mgr *cm, struct callout *tim)
+{
+ struct callout *t, *prev_t;
+
+ callout_dprintf_P("cm=%p tim=%p\r\n", cm, tim);
+ tim->state = CALLOUT_STATE_SCHEDULED;
+
+ /* list is empty */
+ if (LIST_EMPTY(&cm->sched_list)) {
+ LIST_INSERT_HEAD(&cm->sched_list, tim, next);
+ return;
+ }
+
+ /* 'tim' expires before first entry */
+ t = LIST_FIRST(&cm->sched_list);
+ if ((int16_t)(tim->expire - t->expire) <= 0) {
+ LIST_INSERT_HEAD(&cm->sched_list, tim, next);
+ return;
+ }
+
+ /* find an element that will expire after 'tim' */
+ LIST_FOREACH(t, &cm->sched_list, next) {
+ if ((int16_t)(tim->expire - t->expire) <= 0) {
+ LIST_INSERT_BEFORE(t, tim, next);
+ return;
+ }
+ prev_t = t;
+ }
+
+ /* not found, insert at the end of the list */
+ LIST_INSERT_AFTER(prev_t, tim, next);
+}
+
+/*
+ * Add a timer in the local expired list (timer must not already be in a
+ * list). The timers are sorted in the list according to the priority (high
+ * priority first).
+ *
+ * called with irq locked
+ */
+static void
+callout_add_in_expired_list(struct callout_mgr *cm,
+ struct callout_list *expired_list, struct callout *tim)
+{
+ struct callout *t, *prev_t;
+
+ (void)cm; /* avoid warning if debug is disabled */
+
+ callout_dprintf_P("cm=%p tim=%p\r\n", cm, tim);
+ tim->state = CALLOUT_STATE_EXPIRED;
+
+ /* list is empty */
+ if (LIST_EMPTY(expired_list)) {
+ LIST_INSERT_HEAD(expired_list, tim, next);
+ return;
+ }
+
+ /* 'tim' has a higher prio */
+ t = LIST_FIRST(expired_list);
+ if (tim->priority >= t->priority) {
+ LIST_INSERT_HEAD(expired_list, tim, next);
+ return;
+ }
+
+ /* find an element that will expire after 'tim' */
+ LIST_FOREACH(t, expired_list, next) {
+ if (tim->priority >= t->priority) {
+ LIST_INSERT_BEFORE(t, tim, next);
+ return;
+ }
+ prev_t = t;
+ }
+
+ /* not found, insert at the end of the list */
+ LIST_INSERT_AFTER(prev_t, tim, next);
+}
+
+/*
+ * del from list (timer must be in a list)
+ */
+static void
+callout_del(struct callout_mgr *cm, struct callout *tim)
+{
+ (void)cm; /* avoid warning if debug is disabled */
+ callout_dprintf_P("cm=%p tim=%p\r\n", cm, tim);
+ LIST_REMOVE(tim, next);
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+static int
+__callout_schedule(struct callout_mgr *cm, struct callout *tim,
+ uint16_t expire)
+{
+ uint8_t flags;
+
+ callout_dprintf_P("cm=%p tim=%p expire=%d\r\n",
+ cm, tim, expire);
+
+ IRQ_LOCK(flags);
+ CALLOUT_STAT_ADD(cm, schedule, 1);
+
+ /* remove it from list */
+ if (tim->state != CALLOUT_STATE_STOPPED) {
+ /* stats */
+ if (tim->state == CALLOUT_STATE_SCHEDULED)
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ else if (tim->state == CALLOUT_STATE_EXPIRED)
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ if (tim->state == CALLOUT_STATE_RUNNING)
+ CALLOUT_STAT_ADD(cm, cur_running, -1);
+
+ callout_del(cm, tim);
+ }
+
+ tim->expire = expire;
+ CALLOUT_STAT_ADD(cm, cur_scheduled, 1);
+ callout_add_in_sched_list(cm, tim);
+ IRQ_UNLOCK(flags);
+
+ return 0;
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+int
+callout_schedule(struct callout_mgr *cm, struct callout *tim,
+ uint16_t ticks)
+{
+ return __callout_schedule(cm, tim, cm->get_time() + ticks);
+}
+
+/* Reset and start the timer associated with the timer handle tim */
+int
+callout_reschedule(struct callout_mgr *cm, struct callout *tim,
+ uint16_t ticks)
+{
+ return __callout_schedule(cm, tim, tim->expire + ticks);
+}
+
+/* Stop the timer associated with the timer handle tim */
+void
+callout_stop(struct callout_mgr *cm, struct callout *tim)
+{
+ uint8_t flags;
+
+ callout_dprintf_P("cm=%p tim=%p\r\n", cm, tim);
+
+ IRQ_LOCK(flags);
+ if (tim->state != CALLOUT_STATE_STOPPED) {
+
+ /* stats */
+ if (tim->state == CALLOUT_STATE_SCHEDULED)
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ else if (tim->state == CALLOUT_STATE_EXPIRED)
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ if (tim->state == CALLOUT_STATE_RUNNING)
+ CALLOUT_STAT_ADD(cm, cur_running, -1);
+ CALLOUT_STAT_ADD(cm, stop, 1);
+
+ /* remove it from list */
+ callout_del(cm, tim);
+ tim->state = CALLOUT_STATE_STOPPED;
+ }
+ IRQ_UNLOCK(flags);
+}
+
+/* must be called periodically, run all timer that expired */
+void callout_manage(struct callout_mgr *cm)
+{
+ struct callout_list expired_list;
+ struct callout_list reschedule_list;
+ struct callout *tim, *tim_next;
+ uint16_t cur_time;
+ uint8_t old_prio;
+ int16_t diff;
+
+ CALLOUT_STAT_ADD(cm, manage, 1);
+ callout_dprintf_P("cm=%p\r\n", cm);
+
+ /* maximize the number of self-recursions */
+ if (cm->nb_recursion >= CALLOUT_MAX_RECURSION) {
+ CALLOUT_STAT_ADD(cm, max_recursion, 1);
+ return;
+ }
+
+ cli();
+ cm->nb_recursion++;
+ LIST_INIT(&expired_list);
+ LIST_INIT(&reschedule_list);
+ cur_time = cm->get_time();
+ old_prio = cm->cur_priority;
+
+ /* move all expired timers in a local list */
+ LIST_FOREACH_SAFE(tim, tim_next, &cm->sched_list, next) {
+
+ diff = cur_time - tim->expire;
+
+ /* check the expiration time (tasks are sorted) */
+ if (diff < 0)
+ break;
+
+ callout_dprintf_P("cm=%p diff=%d\r\n", cm, diff);
+
+ /* check the priority, if it's too low, inc stats */
+ if (tim->priority <= cm->cur_priority) {
+ if (diff < 16484)
+ CALLOUT_STAT_ADD(cm, delayed, 1);
+ else {
+ /* reschedule to avoid an overflow */
+ CALLOUT_STAT_ADD(cm, hard_delayed, 1);
+ LIST_REMOVE(tim, next);
+ tim->expire = cur_time;
+ LIST_INSERT_HEAD(&reschedule_list, tim, next);
+ }
+ continue;
+ }
+
+ LIST_REMOVE(tim, next);
+ callout_add_in_expired_list(cm, &expired_list, tim);
+ CALLOUT_STAT_ADD(cm, cur_scheduled, -1);
+ CALLOUT_STAT_ADD(cm, cur_expired, 1);
+ }
+
+ /* reschedule hard_delayed timers, this does not happen usually */
+ while (!LIST_EMPTY(&reschedule_list)) {
+ tim = LIST_FIRST(&reschedule_list);
+ LIST_REMOVE(tim, next);
+ callout_add_in_sched_list(cm, tim);
+ }
+
+ /* for each timer of 'expired' list, execute callback */
+ while (!LIST_EMPTY(&expired_list)) {
+ tim = LIST_FIRST(&expired_list);
+ LIST_REMOVE(tim, next);
+
+ /* execute callback function */
+ CALLOUT_STAT_ADD(cm, cur_expired, -1);
+ CALLOUT_STAT_ADD(cm, cur_running, 1);
+ tim->state = CALLOUT_STATE_RUNNING;
+ cm->cur_priority = tim->priority;
+ sei();
+ tim->f(cm, tim, tim->arg);
+ cli();
+ }
+
+ cm->cur_priority = old_prio;
+ cm->nb_recursion--;
+ sei();
+}
+
+/* set the current priority level */
+uint8_t callout_mgr_set_prio(struct callout_mgr *cm, uint8_t new_prio)
+{
+ uint8_t old_prio;
+
+ old_prio = cm->cur_priority;
+ if (new_prio <= old_prio)
+ return old_prio;
+
+ cm->cur_priority = new_prio;
+ return old_prio;
+}
+
+/* restore the current priority level */
+void callout_mgr_restore_prio(struct callout_mgr *cm, uint8_t old_prio)
+{
+ cm->cur_priority = old_prio;
+}
+
+/* dump statistics about timers */
+void callout_dump_stats(struct callout_mgr *cm)
+{
+#ifdef CALLOUT_STATS
+ printf_P(PSTR("Timer statistics:\r\n"));
+ printf_P(PSTR(" schedule = %"PRIu32"\r\n"), cm->stats.schedule);
+ printf_P(PSTR(" stop = %"PRIu32"\r\n"), cm->stats.stop);
+ printf_P(PSTR(" manage = %"PRIu32"\r\n"), cm->stats.manage);
+ printf_P(PSTR(" max_recursion = %"PRIu32"\r\n"), cm->stats.max_recursion);
+ printf_P(PSTR(" delayed = %"PRIu32"\r\n"), cm->stats.delayed);
+ printf_P(PSTR(" hard_delayed = %"PRIu32"\r\n"), cm->stats.hard_delayed);
+
+ printf_P(PSTR(" cur_scheduled = %u\r\n"), cm->stats.cur_scheduled);
+ printf_P(PSTR(" cur_expired = %u\r\n"), cm->stats.cur_expired);
+ printf_P(PSTR(" cur_running = %u\r\n"), cm->stats.cur_running);
+#else
+ printf_P(PSTR("No timer statistics, CALLOUT_STATS is disabled\r\n"));
+#endif
+}
--- /dev/null
+/*
+ * Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Inspired from Intel DPDK rte_timer library */
+/*-
+ * Copyright (c) <2010>, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * - Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CALLOUT_H_
+#define _CALLOUT_H_
+
+#include <aversive/queue.h>
+
+#define CALLOUT_STATS
+/* #define CALLOUT_DEBUG */
+
+/**
+ * This module provides a timer service to Aversive similar to the old
+ * "scheduler" module. The manager function callout_manage() can be called from
+ * an interrupt (like the scheduler does) or from a standard function (usually a
+ * main-loop).
+ *
+ * Each timer has a priority: the timers with higher priorities are scheduled
+ * before the others. This feature is mostly useful when the manager is called
+ * from an interrupt. Indeed, the callback function of a timer with a high
+ * priority cannot be preempted by a timer with a lower priority.
+ *
+ * The module locks interrupts when doing critical operations, ensuring that
+ * critical data are accessed atomically.
+ *
+ * State of timers:
+ * - stopped: initial state after callout_init()
+ * - scheduled: after a call to callout_schedule(), the timer is in the
+ * scheduled list of the callout manager
+ * - expired: after a call to callout_manage(), if the expire time of a
+ * timer is reached, it is moved in a local list and its state is
+ * changed to "expired".
+ * - before starting the callback, the timer goes in state "running".
+ *
+ * Once running, the associated timer is not touched anymore by
+ * callout_manage(). As a result, the timer MUST be either reloaded or stopped
+ * (and potentially freed).
+ */
+
+#define CALLOUT_MAX_RECURSION 5
+
+#ifdef CALLOUT_STATS
+/**
+ * The structure that stores the timer statistics, mostly useful for debug
+ * purposes.
+ */
+struct callout_debug_stats {
+ uint32_t schedule; /**< nb of calls to callout_(re)schedule() */
+ uint32_t stop; /**< nb of calls to callout_stop() */
+ uint32_t manage; /**< nb of calls to callout_manage() */
+ uint32_t max_recursion; /** manage() skipped due to max recursion */
+ uint32_t delayed; /** task delayed a bit due to low prio */
+ uint32_t hard_delayed; /** task recheduled later due to low priority */
+
+ uint8_t cur_scheduled; /**< current number of scheduled timers */
+ uint8_t cur_expired; /**< current number of expired timers */
+ uint8_t cur_running; /**< current number of running timers */
+};
+#endif
+
+struct callout;
+struct callout_mgr;
+
+/**
+ * The tyoe of a callout callback function.
+ */
+typedef void (callout_cb_t)(struct callout_mgr *cm, struct callout *tim,
+ void *arg);
+
+/**
+ * A callout structure, storing all data associated to a timer.
+ */
+struct callout {
+ LIST_ENTRY(callout) next; /**< next/prev in list */
+
+#define CALLOUT_STATE_STOPPED 0 /**< not scheduled */
+#define CALLOUT_STATE_SCHEDULED 1 /**< pres*/
+#define CALLOUT_STATE_EXPIRED 2
+#define CALLOUT_STATE_RUNNING 3
+ uint8_t state; /**< stopped, scheduled, expired */
+ uint8_t priority; /**< the priority of the timer */
+ uint16_t expire; /**< time when timer should expire */
+
+ callout_cb_t *f; /**< callback function pointer */
+ void *arg; /**< argument given to the cb function. */
+};
+
+/* define the callout list */
+LIST_HEAD(callout_list, callout);
+
+/* static initializer for a timer structure */
+#define CALLOUT_INITIALIZER { }
+
+/**
+ * Type of the function used by a callout manager to get a time reference
+ */
+typedef uint16_t (get_time_t)(void);
+
+/**
+ * An instance of callout manager. It is possible to have several managers. A
+ * callout is attached to one manager at a time.
+ */
+struct callout_mgr {
+ get_time_t *get_time; /**< func used to get the time reference */
+ uint16_t prev_time; /**< time of previous call */
+ uint8_t cur_priority; /** priority of running event */
+ uint8_t nb_recursion; /** number of recursion */
+ struct callout_list sched_list; /**< list of scheduled timers */
+
+#ifdef CALLOUT_STATS
+ struct callout_debug_stats stats; /**< stats */
+#endif
+};
+
+/**
+ * Initialize a callout manager
+ *
+ * The callout manager must be initialized before callout_add() or
+ * callout_manage() can be called.
+ *
+ * @param cm
+ * Pointer to the uninitialized callout manager structure.
+ * @param get_time
+ * Pointer to a function that returns a time reference (unsigned 16 bits).
+ */
+void callout_mgr_init(struct callout_mgr *cm, get_time_t *get_time);
+
+/**
+ * Initialize a callout structure and set callback function
+ *
+ * Before doing any operation on the callout structure, it has to be initialized
+ * with this function. It is possible to reinitialize a timer that has been
+ * previously scheduled, but it must be stopped.
+ *
+ * @param tim
+ * The timer to initialize.
+ * @param priority
+ * The priority of the callout (high value means higher priority)
+ * @param f
+ * The callback function of the timer.
+ * @param arg
+ * The user argument of the callback function.
+ */
+void callout_init(struct callout *tim, callout_cb_t f, void *arg,
+ uint8_t priority);
+
+/**
+ * Schedule a callout
+ *
+ * The callout_schedule() function adds the timer in the scheduled list. After
+ * the specified amount of ticks are elapsed, the callback function of the timer
+ * previously given to callout_init() will be invoked with its argument.
+ *
+ * The given "tick" value is relative to the current time, and is 16 bits
+ * wide. As it internally uses signed 16 bits comparison, the max value for
+ * ticks is 32767.
+ *
+ * @param cm
+ * The callout manager where the timer should be scheduled
+ * @param tim
+ * The timer handle
+ * @param ticks
+ * The number of ticks before the callback function is called, relative to now
+ * (the reference is given by the get_time() function of the callout manager).
+ * @return
+ * 0 on success, negative on error
+ */
+int callout_schedule(struct callout_mgr *cm, struct callout *tim,
+ uint16_t ticks);
+
+/**
+ * Reschedule a callout
+ *
+ * This function does exactly the same than callout_schedule() except that
+ * the given time "ticks" is not relative to the current time but to the
+ * "expire" field of the timer.
+ *
+ * Using this function is advised to avoid drift if you want to have periodic
+ * timers.
+ *
+ * This function should preferably be called from the callback function of
+ * the timer. Indeed, if the "expire" field should be a known value or it
+ * can result in an undefined behavior
+ *
+ * The given "tick" value is relative to the "expire" field of the timer, and is
+ * 16 bits wide. As it internally uses signed 16 bits comparison, the max value
+ * for ticks is 32767.
+ *
+ * @param cm
+ * The callout manager where the timer should be scheduled
+ * @param tim
+ * The timer handle
+ * @param ticks
+ * The number of ticks before the callback function is called, relative to
+ * the "expire" value of the timer
+ * @return
+ * 0 on success, negative on error
+ */
+int callout_reschedule(struct callout_mgr *cm, struct callout *tim,
+ uint16_t ticks);
+
+
+/**
+ * Stop a timer.
+ *
+ * The callout_stop() function stops a timer associated with the
+ * timer handle tim.
+ *
+ * If the timer is scheduled or expired, it is removed from the list: the
+ * callback function won't be invoked. If the timer is stopped or running the
+ * function does nothing.
+ *
+ * If a timer structure is dynamically allocated, invoking callout_stop() is
+ * needed before freeing the structure, even if the freeing occurs in a
+ * callback. Indeed, this function can be called safely from a timer
+ * callback. If it succeeds, the timer is not referenced anymore by the callout
+ * manager.
+ *
+ * @param cm
+ * The callout manager where the timer is or was scheduled
+ * @param tim
+ * The timer
+ * @return
+ * 0 on success, negative on error
+ */
+void callout_stop(struct callout_mgr *cm, struct callout *tim);
+
+
+/**
+ * Return the state of a timer
+ *
+ * @param tim
+ * The timer
+ * @return
+ * - CALLOUT_STATE_STOPPED: the timer is stopped
+ * - CALLOUT_STATE_SCHEDULED: the timer is scheduled
+ * - CALLOUT_STATE_EXPIRED: the timer was moved in a local list before
+ * execution
+ */
+static inline uint8_t callout_state(struct callout *tim)
+{
+ return tim->state;
+}
+
+/**
+ * Manage the timer list and execute callback functions.
+ *
+ * This function must be called periodically, either from a loop of from an
+ * interrupt. It browses the list of scheduled timers and runs all timers that
+ * are expired.
+ *
+ * This function must be called at least every 16384 reference ticks of
+ * cm->get_time(), but calling it more often is recommanded to avoid delaying
+ * task abusively.
+ *
+ * The function must be called with IRQ allowed.
+ */
+void callout_manage(struct callout_mgr *cm);
+
+/**
+ * Dump statistics about timers.
+ */
+void callout_dump_stats(struct callout_mgr *cm);
+
+/**
+ * Set the current priority level
+ *
+ * Prevent callout with a priority lower than "new_prio" to be executed.
+ * If the current priority of the callout manager is already lower higher
+ * than "new_prio", the function won't change the running priority.
+ *
+ * The returned value should be stored by the caller and restored with
+ * callout_mgr_restore_prio(), preferably in the same function.
+ *
+ * @param cm
+ * The callout manager
+ * @param new_prio
+ * The new running priority
+ *
+ * @return
+ * The value of the running priority before the call og this function
+ */
+uint8_t callout_mgr_set_prio(struct callout_mgr *cm, uint8_t new_prio);
+
+/**
+ * Restore the current priority level
+ *
+ * Used after a call to callout_mgr_set_prio().
+ *
+ * @param cm
+ * The callout manager
+ * @param old_prio
+ * The old running priority
+ */
+void callout_mgr_restore_prio(struct callout_mgr *cm, uint8_t old_prio);
+
+#endif /* _CALLOUT_H_ */
--- /dev/null
+#
+# Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+TARGET = main
+
+AVERSIVE_DIR = ../../../..
+
+SRC = $(TARGET).c
+
+ASRC =
+
+-include .aversive_conf
+include $(AVERSIVE_DIR)/mk/aversive_project.mk
+
--- /dev/null
+/*
+ * Copyright Droids Corporation, Microb Technology, Eirbot (2005)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Revision : $Id: error_config.h,v 1.4.6.1 2006-11-26 21:06:03 zer0 Exp $
+ *
+ */
+
+#ifndef _ERROR_CONFIG_
+#define _ERROR_CONFIG_
+
+/** enable the dump of the comment */
+#define ERROR_DUMP_TEXTLOG
+
+/** enable the dump of filename and line number */
+#define ERROR_DUMP_FILE_LINE
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) <2014>, Olivier Matz <zer0@droids-corp.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the University of California, Berkeley nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include <aversive/wait.h>
+
+#include <callout.h>
+#include <timer.h>
+#include <uart.h>
+#include <hostsim.h>
+
+static struct callout_mgr global_cm;
+static volatile uint16_t time_ref;
+
+#define C1_TIME_MS 500
+#define C2_TIME_MS 500
+#define C3_TIME_MS 1000
+#define C4_TIME_MS 4000
+
+/* return the current time reference (the variable is incremented in the
+ * interuption */
+static uint16_t get_time_ms(void)
+{
+ uint8_t flags;
+ uint16_t ret;
+
+ IRQ_LOCK(flags);
+ ret = time_ref;
+ IRQ_UNLOCK(flags);
+ return ret;
+}
+
+/* printf with a timestamp */
+static void ts_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ printf("%d: ", get_time_ms());
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+}
+
+static void f1(struct callout_mgr *cm, struct callout *tim, void *arg)
+{
+ (void)arg;
+ ts_printf("%s\n", __FUNCTION__);
+
+ callout_reschedule(cm, tim, C1_TIME_MS);
+}
+
+static void f2(struct callout_mgr *cm, struct callout *tim, void *arg)
+{
+ (void)arg;
+ ts_printf("%s\n", __FUNCTION__);
+
+ callout_reschedule(cm, tim, C2_TIME_MS);
+}
+
+static void f3(struct callout_mgr *cm, struct callout *tim, void *arg)
+{
+ (void)arg;
+ ts_printf("%s START\n", __FUNCTION__);
+ wait_ms(600);
+ ts_printf("%s END\n", __FUNCTION__);
+
+ callout_reschedule(cm, tim, C3_TIME_MS);
+}
+
+static void supp(struct callout_mgr *cm, struct callout *tim, void *arg)
+{
+ struct callout *c2 = arg;
+
+ ts_printf("stopping c1\n");
+ callout_stop(cm, c2);
+}
+
+static void timer_interrupt(void)
+{
+#ifndef HOST_VERSION
+ static uint16_t cycles;
+
+ cycles += 256 * 8; /* 8 bits timer + 8 divisor */
+ if (cycles > (CONFIG_QUARTZ/1000)) {
+ cycles -= (CONFIG_QUARTZ/1000);
+ time_ref++;
+ }
+#else
+ time_ref++;
+#endif
+
+ sei(); /* callout_manage() must be called with irq allowed */
+ callout_manage(&global_cm);
+}
+
+static void dump_stats(char c)
+{
+ if (c != 's')
+ return;
+
+ callout_dump_stats(&global_cm);
+}
+
+int main(void)
+{
+ struct callout c1, c2, c3, c4;
+ uint8_t old_prio;
+
+#ifdef HOST_VERSION
+ hostsim_uart_init();
+ hostsim_ittimer_add(timer_interrupt, 1 * 1000 * 1000); /* 1ms period */
+ hostsim_ittimer_enable(100); /* 100 us */
+#else
+ uart_init();
+ fdevopen(uart0_dev_send, uart0_dev_recv);
+ timer_init();
+ timer0_register_OV_intr(timer_interrupt);
+#endif
+ uart_register_rx_event(0, dump_stats);
+
+ callout_mgr_init(&global_cm, get_time_ms);
+ sei();
+
+ printf("f1 every %d ms, high prio (200)\n", C1_TIME_MS);
+ printf("f2 every %d ms, low prio (50)\n", C2_TIME_MS);
+ printf("f3 every %d ms, med prio (100), the function lasts 600ms\n",
+ C3_TIME_MS);
+ printf("f4 only once after %d ms, very high prio (250), "
+ "stop task f2\n", C4_TIME_MS);
+ printf("type s to dump stats\n");
+
+ callout_init(&c1, f1, NULL, 200);
+ callout_init(&c2, f2, NULL, 50);
+ callout_init(&c3, f3, NULL, 100);
+ callout_init(&c4, supp, &c2, 250);
+
+ callout_schedule(&global_cm, &c1, C1_TIME_MS);
+ callout_schedule(&global_cm, &c2, C2_TIME_MS);
+ callout_schedule(&global_cm, &c3, C3_TIME_MS);
+ callout_schedule(&global_cm, &c4, C4_TIME_MS);
+
+ while (get_time_ms() < 2900)
+ ;
+
+ old_prio = callout_mgr_set_prio(&global_cm, 150);
+ ts_printf("set prio 150\n");
+
+ while (get_time_ms() < 3100)
+ ;
+
+ ts_printf("set prio 0\n");
+ callout_mgr_restore_prio(&global_cm, old_prio);
+
+ while (get_time_ms() < 5000)
+ ;
+
+ callout_stop(&global_cm, &c1);
+ callout_stop(&global_cm, &c3);
+ callout_stop(&global_cm, &c4);
+
+ callout_dump_stats(&global_cm);
+ wait_ms(10);
+
+#ifdef HOST_VERSION
+ hostsim_uart_exit();
+#endif
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright Droids Corporation, Microb Technology, Eirbot (2006)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Revision : $Id: timer_config.h,v 1.1 2009-02-20 21:10:01 zer0 Exp $
+ *
+ */
+
+#define TIMER0_ENABLED
+
+/* #define TIMER1_ENABLED */
+/* #define TIMER1A_ENABLED */
+/* #define TIMER1B_ENABLED */
+/* #define TIMER1C_ENABLED */
+
+/* #define TIMER2_ENABLED */
+
+/* #define TIMER3_ENABLED */
+/* #define TIMER3A_ENABLED */
+/* #define TIMER3B_ENABLED */
+/* #define TIMER3C_ENABLED */
+
+#define TIMER0_PRESCALER_DIV 8
--- /dev/null
+/*
+ * Copyright Droids Corporation, Microb Technology, Eirbot (2005)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Revision : $Id: uart_config.h,v 1.3.10.1 2006-11-26 21:06:02 zer0 Exp $
+ *
+ */
+
+/* Droids-corp 2004 - Zer0
+ * config for uart module
+ */
+
+#ifndef UART_CONFIG_H
+#define UART_CONFIG_H
+
+/*
+ * UART0 definitions
+ */
+
+/* compile uart0 fonctions, undefine it to pass compilation */
+#define UART0_COMPILE
+
+/* enable uart0 if == 1, disable if == 0 */
+#define UART0_ENABLED 1
+
+/* enable uart0 interrupts if == 1, disable if == 0 */
+#define UART0_INTERRUPT_ENABLED 1
+
+#define UART0_BAUDRATE 38400
+
+/*
+ * if you enable this, the maximum baudrate you can reach is
+ * higher, but the precision is lower.
+ */
+#define UART0_USE_DOUBLE_SPEED 0
+//#define UART0_USE_DOUBLE_SPEED 1
+
+#define UART0_RX_FIFO_SIZE 4
+#define UART0_TX_FIFO_SIZE 4
+//#define UART0_NBITS 5
+//#define UART0_NBITS 6
+//#define UART0_NBITS 7
+#define UART0_NBITS 8
+//#define UART0_NBITS 9
+
+#define UART0_PARITY UART_PARTITY_NONE
+//#define UART0_PARITY UART_PARTITY_ODD
+//#define UART0_PARITY UART_PARTITY_EVEN
+
+#define UART0_STOP_BIT UART_STOP_BITS_1
+//#define UART0_STOP_BIT UART_STOP_BITS_2
+
+
+
+
+/* .... same for uart 1, 2, 3 ... */
+
+#endif
+