///////////////////////////////////////////////////////////////////////////
// Timer
//
// 2015/11/18
///////////////////////////////////////////////////////////////////////////
#define	MONITOR_DEF_TIMER
#include "Monitorbase.h"

DWORD gdw1usecCounter = 0;
DWORD gdw10usecCounter = 0;
DWORD gdw100usecCounter = 0;

DWORD gdw1msecCounter = 0;
DWORD gdw10msecCounter = 0;
DWORD gdw100msecCounter = 0;
DWORD gdw1000msecCounter = 0;
#define		MSECMASK		((DWORD)0x0FFFFFFF)

extern	void	disk_timerproc(void);								// for FatFs Called in period of 10ms

///////////////////////////////////////////////////////////////////////////
// Timer初期化
///////////////////////////////////////////////////////////////////////////
void	TimerXInit(DWORD dwSysClock){
	// 使用許可
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
	// タイマー初期化 周期タイマー
	ROM_TimerConfigure(TIMER0_BASE,TIMER_CFG_PERIODIC);
	ROM_TimerConfigure(TIMER1_BASE,TIMER_CFG_PERIODIC);
	// 周期のセット SysCtlClockGet() = 1sec : 1msec = Clock / 1000
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, (uint32_t)(dwSysClock / 1000));
	// 周期のセット SysCtlClockGet() = 1sec : 1μsec = Clock / 1000000
	ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, (uint32_t)(dwSysClock / 1000000));
	// 割り込みの許可
	ROM_IntEnable(INT_TIMER0A);
	ROM_IntEnable(INT_TIMER1A);
	ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
	ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
	// タイマーの有効化
	ROM_TimerEnable(TIMER0_BASE,TIMER_A);
	ROM_TimerEnable(TIMER1_BASE,TIMER_A);
	return;
}

///////////////////////////////////////////////////////////////////////////
// Timer0の割り込み関数 1msec
///////////////////////////////////////////////////////////////////////////
void	Timer0IntHandler(void){
	//
	// Clear the timer interrupt.
	//
	ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

	gdw1msecCounter++;
	gdw1msecCounter &= MSECMASK;
	if(gdw1msecCounter % 10 == 0){
		gdw10msecCounter++;
		gdw10msecCounter &= MSECMASK;
		disk_timerproc();													// for FatFs Called in period of 10ms
		if(gdw10msecCounter % 10 == 0){
			gdw100msecCounter++;
			gdw100msecCounter &= MSECMASK;
			if(gdw100msecCounter % 10 == 0){
				gdw1000msecCounter++;
				gdw1000msecCounter &= MSECMASK;
			}
		}
	}
	return;
}

///////////////////////////////////////////////////////////////////////////
// Timer1の割り込み関数 1μsec
///////////////////////////////////////////////////////////////////////////
void	Timer1IntHandler(void){
	//
	// Clear the timer interrupt.
	//
	ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

	gdw1usecCounter++;
	gdw1usecCounter &= MSECMASK;
	if(gdw1usecCounter % 10 == 0){
		gdw10usecCounter++;
		gdw10usecCounter &= MSECMASK;
		if(gdw10usecCounter % 10 == 0){
			gdw100usecCounter++;
			gdw100usecCounter &= MSECMASK;
		}
	}

	return;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数
// 引数
//		CheckVal		: 現在のカウント値（ex.gdw1msecCounter）
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoopTimeOut(DWORD CheckVal,DWORD SavePoint,DWORD TimeOutVal){
	DWORD	dwTmp;

	if(SavePoint > MSECMASK){
		// この値より大きいということはありえないのでタイムアウト扱い
		return true;
	}
	dwTmp = CheckVal;
	if(dwTmp < SavePoint){
		// 現在の値が保存した値より小さいということは、ループして戻ったと思われる
		dwTmp += MSECMASK;
	}
	if(dwTmp >= ( SavePoint + TimeOutVal )){
		// 現在の値がセーブポイント＋タイムアウト値より大きい → タイムアウト
		return true;
	} else {
		// まだタイムアウトではない
		return false;
	}
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（1μsec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop1usecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw1usecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（10μsec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop10usecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw10usecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（100μsec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop100usecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw100usecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（1msec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop1msecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw1msecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（10msec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop10msecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw10msecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（100msec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop100msecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw100msecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// タイムアウトしているかチェックする関数（1000msec）
// 引数
//		SavePoint		: 保存したカウント値
//		TimeOutVal	: タイムアウト値
// 戻り値
//		true : タイムアウト / false : 非タイムアウト
///////////////////////////////////////////////////////////////////////////
bool	CheckLoop1000msecTimeOut(DWORD SavePoint,DWORD TimeOutVal){
	bool bTmp;
	bTmp = CheckLoopTimeOut(gdw1000msecCounter,SavePoint,TimeOutVal);
	return bTmp;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（1μsec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get1usecTimeCounter(void){
	return gdw1usecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（10μsec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get10usecTimeCounter(void){
	return gdw10usecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（100μsec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get100usecTimeCounter(void){
	return gdw100usecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（1msec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get1msecTimeCounter(void){
	return gdw1msecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（10msec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get10msecTimeCounter(void){
	return gdw10msecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（100msec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get100msecTimeCounter(void){
	return gdw100msecCounter;
}

///////////////////////////////////////////////////////////////////////////
// 現在のカウント値を取得する（1000msec）
// 引数
//		ナシ
// 戻り値
//		現在のカウント値
///////////////////////////////////////////////////////////////////////////
DWORD	Get1000msecTimeCounter(void){
	return gdw1000msecCounter;
}

///////////////////////////////////////////////////////////////////////////
// スリープ（1msec） ※ ウォッチドッグタイマーに気をつけること
// 引数
//		SleepTime	: 待ち時間
// 戻り値
//		ナシ
///////////////////////////////////////////////////////////////////////////
void	Wait1msec(DWORD SleepTime){
	DWORD	dwCounter;
	DWORD	i = 0;
	dwCounter = Get1msecTimeCounter();
	while(CheckLoop1msecTimeOut(dwCounter,SleepTime) == false){
		// 待ち
		i++;
	}
	return;
}

///////////////////////////////////////////////////////////////////////////
// スリープ（1μsec） ※ ウォッチドッグタイマーに気をつけること
// 引数
//		SleepTime	: 待ち時間
// 戻り値
//		ナシ
///////////////////////////////////////////////////////////////////////////
void	Wait1usec(DWORD SleepTime){
	DWORD	dwCounter;
	DWORD	i = 0;
	dwCounter = Get1usecTimeCounter();
	while(CheckLoop1usecTimeOut(dwCounter,SleepTime) == false){
		// 待ち
		i++;
	}
	return;
}
