98 lines
2.5 KiB
C
98 lines
2.5 KiB
C
|
|
||
|
/****************************************************************************
|
||
|
* Tick-based interval timers/one-shots - be mindful this is not really
|
||
|
* intended for continuous timers but for events that need to run for a short
|
||
|
* time and be cancelled without further software intervention.
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "config.h"
|
||
|
#include "system.h" /* TIME_AFTER */
|
||
|
#include "kernel.h"
|
||
|
#include "timeout.h"
|
||
|
#include "general.h"
|
||
|
|
||
|
/* list of active timeout events */
|
||
|
static struct timeout *tmo_list[MAX_NUM_TIMEOUTS+1];
|
||
|
|
||
|
/* timeout tick task - calls event handlers when they expire
|
||
|
* Event handlers may alter expiration, callback and data during operation.
|
||
|
*/
|
||
|
static void timeout_tick(void)
|
||
|
{
|
||
|
unsigned long tick = current_tick;
|
||
|
struct timeout **p = tmo_list;
|
||
|
struct timeout *curr;
|
||
|
|
||
|
for(curr = *p; curr != NULL; curr = *(++p))
|
||
|
{
|
||
|
int ticks;
|
||
|
|
||
|
if(TIME_BEFORE(tick, curr->expires))
|
||
|
continue;
|
||
|
|
||
|
/* this event has expired - call callback */
|
||
|
ticks = curr->callback(curr);
|
||
|
if(ticks > 0)
|
||
|
{
|
||
|
curr->expires = tick + ticks; /* reload */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
timeout_cancel(curr); /* cancel */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Cancels a timeout callback - can be called from the ISR */
|
||
|
void timeout_cancel(struct timeout *tmo)
|
||
|
{
|
||
|
int oldlevel = disable_irq_save();
|
||
|
int rc = remove_array_ptr((void **)tmo_list, tmo);
|
||
|
|
||
|
if(rc >= 0 && *tmo_list == NULL)
|
||
|
{
|
||
|
tick_remove_task(timeout_tick); /* Last one - remove task */
|
||
|
}
|
||
|
|
||
|
restore_irq(oldlevel);
|
||
|
}
|
||
|
|
||
|
/* Adds a timeout callback - calling with an active timeout resets the
|
||
|
interval - can be called from the ISR */
|
||
|
void timeout_register(struct timeout *tmo, timeout_cb_type callback,
|
||
|
int ticks, intptr_t data)
|
||
|
{
|
||
|
int oldlevel;
|
||
|
void **arr, **p;
|
||
|
|
||
|
if(tmo == NULL)
|
||
|
return;
|
||
|
|
||
|
oldlevel = disable_irq_save();
|
||
|
|
||
|
/* See if this one is already registered */
|
||
|
arr = (void **)tmo_list;
|
||
|
p = find_array_ptr(arr, tmo);
|
||
|
|
||
|
if(p - arr < MAX_NUM_TIMEOUTS)
|
||
|
{
|
||
|
/* Vacancy */
|
||
|
if(*p == NULL)
|
||
|
{
|
||
|
/* Not present */
|
||
|
if(*tmo_list == NULL)
|
||
|
{
|
||
|
tick_add_task(timeout_tick); /* First one - add task */
|
||
|
}
|
||
|
|
||
|
*p = tmo;
|
||
|
}
|
||
|
|
||
|
tmo->callback = callback;
|
||
|
tmo->data = data;
|
||
|
tmo->expires = current_tick + ticks;
|
||
|
}
|
||
|
|
||
|
restore_irq(oldlevel);
|
||
|
}
|