/*****************************************************
timer6.c :
  μITRON サンプルプログラム
  Copyright(C) 1998-2003 佐々木芳

タイマタスクの実装

*****************************************************/

#include "hal.h"
#include "itron.h"
#include "event6.h"
#include "debug.h"
#include "timer6.h"

/* タイマ管理テーブルの確保 */
TIMERSLOT	TimerSlot[NUM_TIMERS];

/*システム起動時からのカウント値*/
DWORD	TimerCount;

/*****************************************************
タイマ制御のＡＰＩ
*****************************************************/
/*****************************************************
////タイマの設定
	タイマは起動しない
*****************************************************/
static void timSetTimer(TNO tno,			/*タイマ番号（TNO_xxx)*/
			 TIMEOUT timeout,			/*タイムアウト値（ミリ秒）*/
			 ID		evMbx,				/*メッセージボックスのＩＤ*/
			 int	szEvent,			/*メッセージサイズ*/
			 EVENT* pEvent)				/*メッセージアドレス*/
{
	DECLARE_MASK;
	if(TimerSlot[tno].pEvent){
		kpDeleteEvent(TimerSlot[tno].pEvent);
	}
	SET_MASK;						/* 割込み禁止 */
	TimerSlot[tno].evMbx	= evMbx;
	TimerSlot[tno].szEvent	= szEvent;
	TimerSlot[tno].pEvent	= pEvent;
	TimerSlot[tno].count	= 0;
	TimerSlot[tno].timeout	= timeout/TIMERUNIT;
	RESTORE_MASK;					/* 割込み許可／禁止状態の復帰 */
}

/*****************************************************
////タイマの起動
*****************************************************/
static void timStartTimer(TNO tno)
{
	DECLARE_MASK;
	SET_MASK;						/* 割込み禁止 */
	if(TimerSlot[tno].pEvent){
		TimerSlot[tno].count = TimerSlot[tno].timeout;
	}
	RESTORE_MASK;					/* 割込み許可／禁止状態の復帰 */
}

/*****************************************************
////タイマの停止
*****************************************************/
static void timStopTimer(TNO tno)
{
	DECLARE_MASK;
	SET_MASK;						/* 割込み禁止 */
	TimerSlot[tno].count = 0;
	RESTORE_MASK;					/* 割込み許可／禁止状態の復帰 */
}


/*****************************************************
//汎用タイマタスク
*****************************************************/
void TimerTask(VP_INT exinf)
{
	ER ercd;
	int i;
	DebugPrintf("\rTimerTask: started.\r");
	TimerCount = 0;
	/*タイマ管理テーブルを初期化*/
	for(i=0; i<NUM_TIMERS; i++){
		kpCancelTimer((TNO)i);
	}
	/**/
	while(1){
		tslp_tsk(TIMERUNIT);
		++ TimerCount;
		for(i=0; i<NUM_TIMERS; i++){
			if(TimerSlot[i].count){
				/*起動中のタイマ*/
				if(--TimerSlot[i].count == 0){
					/*タイムアップしたのでイベント（メッセージ）を送る*/
					EVENT* pEvent	= TimerSlot[i].pEvent;
					ID evMbx		= TimerSlot[i].evMbx;
					TimerSlot[i].pEvent = NULL;
					TimerSlot[i].evMbx	= 0;
					//DIS_INT
					ercd = kpSendEvent(evMbx, pEvent);
					//ENA_INT
					if(ercd != E_OK){
						kpDeleteEvent(pEvent);
						CMTRACE("▲TimerTask: イベント送信でエラー %d が起きました。\n", ercd);
					}
				}
			}
		}
	}
}


/*****************************************************
////タイマイベントの設定
	タイマを起動
//使い方
//EVENT* pEvent = kpCreateEvent(TIMEOUT_EVENT);
//pEvent->evMbx = タイマイベントを受け取るメイルボックスＩＤを指定;
//kpSetTimerEvent(tno, 1000, pEvent);
*****************************************************/
void kpSetTimerEvent(TNO tno, TIMEOUT timeout, EVENT* pEvent )
{
	/*タイマ定義*/
	if(timeout == 0) timeout = 1;
	timSetTimer(tno,					/*タイマ番号*/
			timeout,					/*タイムアウト値*/
			pEvent->evMbx,				/*通知メッセージを受け取るメイルボックスID*/
			sizeof(EVENT),				/*メッセージサイズ*/
			pEvent						/*通知イベント*/
			);
	timStartTimer(tno);	/*タイマ起動*/
}


/*****************************************************
////タイマイベントの無効化
*****************************************************/
void kpCancelTimer(TNO tno)
{
	DECLARE_MASK;
	if(TimerSlot[tno].pEvent){
		kpDeleteEvent(TimerSlot[tno].pEvent);
	}
	SET_MASK;						/* 割込み禁止 */
	TimerSlot[tno].evMbx	= 0;
	TimerSlot[tno].szEvent	= 0;
	TimerSlot[tno].pEvent	= NULL;
	TimerSlot[tno].count	= 0;
	TimerSlot[tno].timeout	= 0;
	RESTORE_MASK;					/* 割込み許可／禁止状態の復帰 */
}

