📄 tmrtsk.c
字号:
/*************************************************************************
*
* Copyright 2001 National ASIC Center, All right Reserved
*
* FILE NAME: timertask.c
* PROGRAMMER: caihongliang
* Date of Creation: 2001/10/23
*
* DESCRIPTION: the server for application using RTC timer. It includes TimerProc
* CreateTimer,FreeTimer,StartTimer,StopTimer,ans so on.
*
* NOTE:
*
*
* FUNCTIONS LIST:
* -------------------------------------------------------------------------
* void timer_task(void);
* STATUS CreateTimer(P_U32 t_id,U32 interval,void (*func)(void *),void *arg, U16 mode);
* STATUS FreeTimer(U32 t_id);
* STATUS StartTimer(U32 t_id);
* STATUS StopTimer(U32 t_id);
* U32 ReadTimer(U32 t_id);
* U32 rdclock();
* void DefaultTimerProc(struct timer *t);
* SetDateTime
* ReadDateTime
*
* GLOBAL VARS LIST:
*
* static struct timer *Timers;
* define the head point of timer task chain
*
*
*
*
**************************************************************************
* MODIFICATION HISTORY
*
* 2001/10/23 by caihongliang Creation of this file
* 2001/10/26 by Pessia Add Critical Section Protection(turn ON/OFF interrupt)
* Change TimerProc to timer_task
* Use TWF_CLR to clear event flag(Line 90)
* Use System Clock Ticks to take place of CLOCK used before by Cai
* 2001/10/27 by Pessia Fix Serious Bug!!!
* original code : (clock - Timers->expiration) >= 0
* while clock and expiration are all in type of U32,
* so the result will always be true!!!
* It should be changed into (clock >= Timers->expiration)!
* 2001/12/10 by Pessia Add mode in SysCreateTimer()
* 2002/4/4 by Pessia Fix Serious Bug in SysFreeTimer()(L401)!
*************************************************************************/
#include <kernel\ros33\Ros33.h>
#include <asixsys.h>
#include <asixapp.h>
#include <sys\rtc.h>
#include "xtmrtsk.h"
/* System Clock Ticks which is increased in RTC interrupt */
extern DWORD currentclock;
extern DWORD passedticks;
/* Head of running timer chain.
* The list of running timers is sorted in increasing order of expiration;
* i.e., the first timer to expire is always at the head of the list.
*/
static struct timer *Timers = NULL;
static void DefaultTimerProc(struct timer *t);
UINT MSPTICK = 32; /* Milliseconds per tick: 32 ==1000/32 */
#define rdclock(rval) \
vDisableInterrupt(); \
rval = currentclock; \
vEnableInterrupt()
/*
static DWORD rdclock()
{
DWORD rval;
vDisableInterrupt();
rval = currentclock;
vEnableInterrupt();
return rval;
}
*/
BYTE MonthDay[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
WORD AccumMonthDays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
WORD StdYear = 2002;
DWORD timer_tsk_stk[STACK_SIZE];
TASKDESCRIPTION TimerTskDesp =
{"timer_task", ASIX_SERVICE, NOT_IN_ANYGROUP, NULL, STACK_SIZE, 0, 0, 0, timer_task, SERVICE_PRI};
TASKDESCRIPTIONLIST TimerTskDespLst =
{NULL, NULL, &TimerTskDesp, TIMERTASK_ID, timer_tsk_stk};
/* Process that handles clock ticks */
void timer_task(void)
{
register struct timer *t;
register struct timer *expired;
DWORD clock;
static UINT flgptn;
for(;;){
/* Atomic read and decrement of Tick */
for(;;){
vDisableInterrupt();
if(passedticks != 0){
passedticks--;
vEnableInterrupt();
break;
}
vEnableInterrupt();
/*Pessia : use TWF_CLR to clear event flag */
wai_flg(&flgptn,TIMER_EVENT,TIMER_FLG,TWF_ORW | TWF_CLR);
}
if(Timers == NULL)
continue; /* No active timers, all done */
/* Initialize null expired timer list */
expired = NULL;
//clock = rdclock();
rdclock(clock);
/* Move expired timers to expired list. Note use of
* subtraction and comparison to zero rather than the
* more obvious simple comparison; this avoids
* problems when the clock count wraps around.
*/
/* shit code */
/*while(Timers != NULL && (clock - Timers->expiration) >= 0){*/
/* right code */
while(Timers != NULL && (clock >= Timers->expiration)){
/* Save Timers since stop_timer will change it */
t = Timers;
SysStopTimer((DWORD)t);/*Timers = Timers->next*/
t->state = TIMER_EXPIRE;
/* Add to expired timer list */
t->next = expired;
expired = t;
}
/* Now go through the list of expired timers, removing each
* one and kicking the notify function, if there is one
*/
while((t = expired) != NULL){
expired = t->next;
if(t->func){
(*t->func)(t->arg);
} else {
DefaultTimerProc(t);
}
if(t->mode & (ALARM_MODE|AUTO_CLEAR_MODE))
SysFreeTimer((DWORD) t);
else
if(t->mode & (CYC_MODE|AUTO_START_MODE))
SysStartTimer((DWORD)t);
}
}
}
/* Start a timer */
STATUS
SysStartTimer(DWORD t_id)
{
register struct timer *tnext;
struct timer *tprev = NULL;
DWORD clock;
struct timer *t;
if((struct timer *)t_id == NULL)
return TIMER_ERROR;
t = (struct timer *)t_id;
if(t -> flag != 0xface)
return TIMER_ERROR;
if(t->duration == 0)
return TIMER_ERROR; /* A duration value of 0 disables the timer */
if(t->state == TIMER_RUN)
SysStopTimer((DWORD)t);
rdclock(clock);
t->expiration = clock + t->duration;
t->state = TIMER_RUN;
/* Enter Critical Section */
vDisableDispatch();
/* Find right place on list for this guy. Once again, note use
* of subtraction and comparison with zero rather than direct
* comparison of expiration times.
*/
/* shit code */
/*
for(tnext = Timers;tnext != NULL;tprev=tnext,tnext = tnext->next){
if((tnext->expiration - t->expiration) >= 0)
break;
}
*/
for(tnext = Timers;tnext != NULL;tprev=tnext,tnext = tnext->next){
if((tnext->expiration >= t->expiration))
break;
}
/* At this point, tprev points to the entry that should go right
* before us, and tnext points to the entry just after us. Either or
* both may be null.
*/
if(tprev == NULL)
Timers = t; /* Put at beginning */
else
tprev->next = t;
t->next = tnext;
/* Leave Critical Section */
vEnableDispatch();
return TIMER_OK;
}
/* Stop a timer */
STATUS
SysStopTimer(DWORD t_id)
{
register struct timer *t;
struct timer *tlast = NULL;
struct timer *timer;
if((struct timer *)t_id == NULL)
return TIMER_ERROR;
timer = (struct timer *)t_id;
if( (timer -> flag != 0xface)||(timer->state != TIMER_RUN) )
return TIMER_ERROR;
/* Enter Critical Section */
vDisableDispatch();
/* Verify that timer is really on list */
for(t = Timers;t != NULL;tlast = t,t = t->next)
if(t == timer)
break;
if(t == NULL)
{
vEnableDispatch();
return TIMER_ERROR; /* Should probably panic here */
}
/* Delete from active timer list */
if(tlast != NULL)
tlast->next = t->next;
else
Timers = t->next; /* Was first on list */
/* Leave Critical Section */
vEnableDispatch();
t->state = TIMER_STOP;
return TIMER_OK;
}
/* Return milliseconds remaining on this timer */
DWORD
SysReadTimer(DWORD t_id)
{
DWORD clock;
struct timer *t;
if((struct timer *)t_id == NULL)
return TIMER_ERROR;
t = (struct timer *)t_id;
if( (t -> flag != 0xface) || (t->state != TIMER_RUN) )
return TIMER_ERROR;
//clock = rdclock();
rdclock(clock);
if(t->expiration <= clock)
return 0; /* Already expired */
else
return (t->expiration - clock) * MSPTICK;
}
STATUS
SysCreateTimer(PDWORD t_id, DWORD interval, void (*func)(void *),void *arg,WORD mode)
{
struct timer *t;
ID id;
//if((mode & CYC_MODE) ==0 && (mode & ALARM_MODE)==0) return TIMER_ERROR;
if((mode & CYC_MODE) && (mode & ALARM_MODE)) return TIMER_ERROR;
if((mode & CYC_MODE) && (mode & AUTO_CLEAR_MODE)) return TIMER_ERROR;
if((mode & ALARM_MODE) && (mode & AUTO_START_MODE)) return TIMER_ERROR;
/*Pessia : Get id of running task */
get_tid(&id);
t = (struct timer *)SysLcalloc(sizeof(struct timer));
if(t == NULL)
return TIMER_ERROR;
t->next = NULL;
t->flag = 0xface;
if(interval != 0)
{
// 2002/03/27 longn_qi revised
// t->duration = 1 + (interval + MSPTICK - 1)/MSPTICK;
if( interval <= MSPTICK )
t->duration = 1;
else
t->duration = interval/MSPTICK + ((interval%MSPTICK > MSPTICK/2)?1:0);
}
else
t->duration = 0;
t->func = func;
t->arg = arg;
t->taskid = id;
t->state = TIMER_STOP;
t->mode = mode;
*t_id = (DWORD)t;
return TIMER_OK;
}
STATUS
SysSetTimer(DWORD t_id, DWORD interval, void (*func)(void *),void *arg)
{
// struct timer *t,*tlast = NULL;
struct timer *timer;
BYTE oldstate = TIMER_STOP;
if(interval == 0) return TIMER_ERROR;
if((struct timer *)t_id == NULL) return TIMER_ERROR;
timer = (struct timer *)t_id;
if(timer -> flag != 0xface) return TIMER_ERROR;
/* if it is running, stop it */
if(timer->state == TIMER_RUN)
{
oldstate = TIMER_RUN;
SysStopTimer(t_id);
}
/* set values */
// 2002/03/27 longn_qi revised
// timer->duration = 1 + (interval + MSPTICK - 1)/MSPTICK;
if( interval <= MSPTICK )
timer->duration = 1;
else
timer->duration = interval/MSPTICK + ((interval%MSPTICK > MSPTICK/2)?1:0);
/* when func==NULL, use original values */
if(func!=NULL)
{
timer->func = func;
timer->arg = arg;
}
/* if it was running, start it */
if(oldstate == TIMER_RUN)
SysStartTimer(t_id);
return TIMER_OK;
}
STATUS
SysFreeTimer(DWORD t_id)
{
register struct timer *t;
struct timer *tlast = NULL;
struct timer *timer;
if((struct timer *)t_id == NULL)
return TIMER_ERROR;
timer = (struct timer *)t_id;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -