Написал небольшой модуль для создания таймеров. Вроде работает :) Хотел бы услышать ваше мнение - что криво, что не так.
Небольшие пояснения:
- Таймера основаны на PIT'e, точность 1мс
- Функции add_timer и kill_timer статические - юзаются только внутри модуля. Для юзера функции start_timer и stop_timer.
Недостатки/баги/вопросы, которые я вижу:
- невозможно сделать проверку на валидность структуры для stop_timer'a
- не очень красиво запрещать прерывания для SYS на время обработки функций. может быть мьютексы?
- если экспаряться сразу несколько таймеров, то их обработчики дёргаются в цикле без возвращения управления. Если заводится очень маленький таймер, то вообще может получится вечный цикл
- может быть не самая оптимальная реализация порядка таймеров - по времени экспирейшена, но я чет лучше не знаю
Заранее спасибо за ревью )
typedef struct s_timer_tag
{
void (*callback) (struct s_timer_tag *);
struct s_timer_tag * next;
struct s_timer_tag * prev;
int mode;
unsigned int duration;
unsigned long expiration;
} s_timer;
#define TIMER_MODE_SINGLE 0
#define TIMER_MODE_CYCLIC 1
static s_timer * sys_timers=0;
static unsigned long sys_ticks=0;
static void add_timer(s_timer * new_timer)
{
s_timer * timer=sys_timers;
new_timer->expiration+=new_timer->duration;
while(timer)
{
if(new_timer->expiration < timer->expiration)
{
new_timer->next=timer;
if(new_timer->prev=timer->prev) timer->prev->next=new_timer; else sys_timers=new_timer;
timer->prev=new_timer;
return;
}
if(0 == timer->next)
{
new_timer->next=0;
new_timer->prev=timer;
timer->next=new_timer;
return;
}
timer=timer->next;
}
sys_timers=new_timer;
new_timer->next=0;
new_timer->prev=0;
}
static void kill_timer(s_timer * timer)
{
if(timer->next) timer->next->prev=timer->prev;
if(timer->prev) timer->prev->next=timer->next; else sys_timers=timer->next;
timer->next=0;
timer->prev=0;
}
void stop_timer(s_timer * timer)
{
AT91C_BASE_AIC->AIC_IDCR=(1 << AT91C_ID_SYS);
kill_timer(timer);
AT91C_BASE_AIC->AIC_IECR =(1 << AT91C_ID_SYS);
}
void start_timer(s_timer * timer, int mode, unsigned int duration, void (*callback) (struct s_timer_tag *))
{
AT91C_BASE_AIC->AIC_IDCR=(1 << AT91C_ID_SYS);
timer->callback=callback;
timer->duration=duration;
timer->mode=mode;
timer->expiration=sys_ticks;
add_timer(timer);
AT91C_BASE_AIC->AIC_IECR =(1 << AT91C_ID_SYS);
}
int sys_irq_handler(void)
{
s_timer * next, * timer=sys_timers;
sys_ticks++;
while(timer && timer->expiration<=sys_ticks)
{
next=timer->next;
kill_timer(timer);
if(TIMER_MODE_CYCLIC == timer->mode) add_timer(timer);
if(timer->callback) timer->callback(timer);
timer=next;
}
return AT91C_BASE_PITC->PITC_PIVR;
}
void init_timers(void)
{
// Disable the interrupt on the interrupt controller
AT91C_BASE_AIC->AIC_IDCR=(1 << AT91C_ID_SYS);
// Save the interrupt handler routine pointer and the interrupt priority
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (unsigned int) &sys_irq_handler;
// Store the Source Mode Register
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 7;
// Clear the interrupt on the interrupt controller
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SYS);
//enable interrupt in AIC
AT91C_BASE_AIC->AIC_IECR =(1 << AT91C_ID_SYS);
AT91C_BASE_PITC->PITC_PIMR=(3000 & AT91C_PITC_PIV) | AT91C_PITC_PITEN | AT91C_PITC_PITIEN;
}