/*
 *	cliptimm.h
 *
 *	タイマ管理
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Sat May 30 00:59:40 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Tue Aug 02 22:11:15 JST 2016 Naoyuki Sawa
 *	- ST_TimMgrFunc.fn の関数プロトタイプを変更しました。
 *	  ST_TimMgrFunc.argフィールドを追加しました。
 *	  これまでは、引数を取る関数をタイマに登録するためには、中継関数を経由する必要が有りました。
 *	  今回の変更によって、引数を取る関数も直接、タイマに登録する事が出来るようになりました。
 *	* Mon Aug 28 23:20:51 JST 2017 Naoyuki Sawa
 *	- 'TimMgrCh_1exec'を追加しました。
 *	  経過時間に関係無く、TimMgr_Exec()呼び出し一回毎に一回実行される同期タイマの、タイマ管理チャネル番号です。
 *	  'TimMgrCh_1exec'を追加する事にした理由は、以下の通りです。
 *	- 様々なモジュールの周期処理の呼び出しを、一元管理したいと思う事有りました。
 *	  アプリケーションのschedule()関数等から明示的に呼び出しても同じではあるのですが、一元管理する方が判り易いと思ったからです。
 *	  そこで、タイマ管理モジュール(当モジュール)の既存のTimMgr_Exec()関数に、その役割を担わさせる事にしました。
 *	  今回、タイマ管理モジュールの関数仕様には一切変更は無く、新たなタイマ管理チャネルとして'TimMgrCh_1exec'を追加しただけです。
 *	- ちなみに別の案として、タイマ管理チャネルも追加せずに、既存の'TimMgrCh_1f'を使用する方法も考えましたが、それは間違いです。
 *	  なぜなら、TimMgrCh_1fチャネルは経過時間に依存するので、TimMgr_Exec()呼び出し一回毎に一回実行されるとは限らないからです。
 *	  アプリケーションのメインループを1f単位で回していても、微妙な処理時間のずれによって、TimMgr_Exec()の呼び出し間隔が1f未満や1f超過になる可能性が有ります。
 *	  TimMgrCh_1fを使用していると、メインループのある回では周期処理が呼び出されなかったり、ある回では二回以上呼び出されたりして、意図と異なる動作になります。
 *	  上記の問題を避けるために、アプリケーションのメインループに必ず同期するチャネルとして、新たに'TimMgrCh_1exec'を設けました。
 *	- これまで、アプリケーションのschedule()関数等から明示的に呼び出していた周期処理は、今後は、タイマ管理モジュールの'TimMgrCh_1exec'チャネルに登録出来ます。
 *	  必須ではなく、これまで通りアプリケーションのschedule()関数等から明示的に呼び出しても構いませんが、判り易さのために、なるべく上記の方法を利用して下さい。
 *	  ■注意!!
 *	  │上記はあくまでも、アプリケーションのschedule()関数等の中で、一回だけTimMgr_Exec()を呼び出している構造のアプリケーションについてです。
 *	  │アプリケーションのschedule()関数等の中で、経過時間をポーリングしながら何度もTimMgr_Exec()を呼び出している構造のアプリケーションには、適用出来ません。
 *	  │具体的には、2017/08/28現在の/clip/test.win/cpp.cppの構造は後者であるため、現在の所、Windowsアプリケーションの雛形ではTimMgrCh_1execを使用出来ません。
 *	  │後者のような構造のアプリケーションについては、これまで通り、TimMgrCh_1fを使用して下さい。
 *	* Mon Aug 28 23:46:08 JST 2017 Naoyuki Sawa
 *	- TimMgr_AddFunc_New(),TimMgrFunc_New(),TimMgrFunc_Init()を追加しました。
 *	  元々、当モジュールは組み込み環境を想定していたので、呼び出し側にてST_TimMgrFunc構造体を静的に確保する事を想定しており、TimMgr_AddFunc()の関数仕様がやや使い辛い問題が有りました。
 *	  そこで、動的なメモリ確保が容易な環境ではもっと簡単に使えるように、上記の関数を追加しました。
 *	  具体的な使用例は、cliptimm.cの「使用例」の「□ST_TimMgrFunc構造体を動的に確保して登録する例。P/ECEやWindows等で動的なメモリ確保が容易な場合はこちら。」のコードを参照して下さい。
 */
#ifndef __CLIP_TIMM_H__
#define __CLIP_TIMM_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	定数、構造体
 ****************************************************************************/
//タイマ管理チャネル番号
enum {
	TimMgrCh_1f,		// 0 1f		　同期タイマ
	TimMgrCh_10ms,		// 1 10ms	　同期タイマ
	TimMgrCh_100ms,		// 2 100ms	　同期タイマ
	TimMgrCh_1s,		// 3 1s		　同期タイマ
	TimMgrCh_1ms,		// 4 1ms	非同期タイマ
//{{2017/08/28変更:'TimMgrCh_1exec'を追加しました。
//	TimMgrCh_SIZE,		// 5
//↓2017/08/28変更:'TimMgrCh_1exec'を追加しました。
	TimMgrCh_1exec,		// 5 1exec	　同期タイマ
	TimMgrCh_SIZE,		// 6
//}}2017/08/28変更:'TimMgrCh_1exec'を追加しました。
};
/*--------------------------------------------------------------------------*/
//関数ノード構造体
typedef struct _ST_TimMgrFunc {
	void				(*fn)(void* arg);	//+ 0, 4   関数			NULL不可	アプリケーションがTimMgr_AddFunc()を呼び出す前に設定せよ。
	void*				arg;			//+ 4, 4   関数引数		NULL可		アプリケーションがTimMgr_AddFunc()を呼び出す前に設定せよ。
	unsigned short			uItv;			//+ 6, 2   関数インターバル	   0不可	アプリケーションがTimMgr_AddFunc()を呼び出す前に設定せよ。
	unsigned short			uCnt;			//+ 8, 2   関数カウンタ		   0~uCnt	アプリケーションがTimMgr_AddFunc()を呼び出す時に不定値で構わない。
	struct _ST_TimMgrFunc*		pNext;			//+12, 4   次の関数ノード	NULL=終端	アプリケーションがTimMgr_AddFunc()を呼び出す時に不定値で構わない。
} ST_TimMgrFunc;						//=16
/*--------------------------------------------------------------------------*/
//タイマ管理チャネル構造体
typedef struct _ST_TimMgrCh {
//{{2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
//	         unsigned short		uSub;			//+ 0, 2   減算値				1000,(uAdd*10),(uAdd*100),(uAdd*1000),0/*終端*/
//↓2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
	         unsigned short		uSub;			//+ 0, 2   減算値				1000,(uAdd*10),(uAdd*100),(uAdd*1000),0/*終端*/,0/*1exec*/
//}}2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
	volatile unsigned short		uErr;			//+ 2, 2   チャネル誤差項			1msチャネルでは使用しない。
	volatile int			uCnt;			//+ 4, 4   チャネルカウンタ
	struct _ST_TimMgrFunc*		pNext;			//+ 8, 4   関数チェイン
} ST_TimMgrCh;							//=12
/*--------------------------------------------------------------------------*/
//タイマ管理構造体
typedef struct _ST_TimMgr {
	unsigned char	uAdd;					//+ 0, 1   加算値		1~65		フレームレートと同じ。
	//							//+ 1, 3   (パディング)
//{{2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
//	ST_TimMgrCh	TBL_TimMgrCh[TimMgrCh_SIZE];		//+ 4,12*5 タイマ管理チャネル
//} ST_TimMgr;							//=64
//↓2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
	ST_TimMgrCh	TBL_TimMgrCh[TimMgrCh_SIZE];		//+ 4,12*6 タイマ管理チャネル
} ST_TimMgr;							//=76
//}}2017/08/28コメント変更:'TimMgrCh_1exec'を追加しました。
/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/
void TimMgr_Init(ST_TimMgr* pTimMgr, int uFps);
void TimMgr_AddFunc(ST_TimMgr* pTimMgr, int iCh, ST_TimMgrFunc* pFunc);
int TimMgr_GetCnt(ST_TimMgr* pTimMgr, int iCh);
void TimMgr_Intr(ST_TimMgr* pTimMgr);
void TimMgr_Exec(ST_TimMgr* pTimMgr);
/****************************************************************************
 *	ユーティリティ関数
 ****************************************************************************/
//{{2017/08/28追加:TimMgr_AddFunc_New(),TimMgrFunc_New(),TimMgrFunc_Init()を追加しました。
ST_TimMgrFunc* TimMgr_AddFunc_New(ST_TimMgr* pTimMgr, int iCh, void (*fn)(void* arg), void* arg, int uItv);
ST_TimMgrFunc* TimMgrFunc_New(void (*fn)(void* arg), void* arg, int uItv);
void TimMgrFunc_Init(ST_TimMgrFunc* pFunc, void (*fn)(void* arg), void* arg, int uItv);
//}}2017/08/28追加:TimMgr_AddFunc_New(),TimMgrFunc_New(),TimMgrFunc_Init()を追加しました。
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_TIMM_H__
