/*
 *	clipdirs.h
 *
 *	演出シーケンサ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 Naoyuki Sawa
 *
 *	* Sun Feb 08 19:01:54 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Thu Apr 23 21:42:53 JST 2015 Naoyuki Sawa
 *	- DirSeq_Stop(),DirSeqCh_Stop()を追加しました。
 *	  演出テーブルをクリアせずに、現在実行中の演出シーケンスを停止したい場合に使用します。
 *	  例えば、'あるトリガ'から??秒後に'ある表示'を行うような演出シーケンスを開始した後に、何らかの条件でその予約を取り消す場合等です。
 *	* Tue May 05 17:15:43 JST 2015 Naoyuki Sawa
 *	- DirSeqCh_SetTblNo()を追加しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Sun Nov 22 21:02:41 JST 2015 Naoyuki Sawa
 *	- DirTrg_setとDirTrg_clrのシンボル定義を追加しました。
 *	  2015/11/20のdDirSeqC.exeの変更により、DirTrg_setとDirTrg_clr以外のトリガ番号のシンボルはdDirSeqC.exeが出力するようになりました。
 *	  dDirSeqC.exeが出力しない固定のトリガ番号のシンボルのみ、当モジュール内で定義する事にしました。
 *	* Tue Aug 02 22:11:15 JST 2016 Naoyuki Sawa
 *	- 演出実行関数(fnAct)の引数仕様を変更しました。
 *	  【変更前】void fnAct(int ActNo);				ActNo = [31]=オーバーフロー,[30:24]=未定義,[23:0]=演出番号
 *	  【変更後】void fnAct(int iCh, int ActNo, int bOverFlow);	iCh = 演出シーケンサチャネル番号, ActNo = 演出番号, bOverFlow = オーバーフロー
 *	- 今回の変更により、演出実行関数に演出シーケンサチャネル番号も通知されるようになりました。
 *	  アプリケーション側で、演出シーケンサチャネル番号も参照して、演出実行処理を行えるようになりました。
 *	- 今回の変更のために、演出番号バッファ(ST_DirSeq.pActBuf)をスタックフレーム上に確保するサイズが増加しました。(clipdirs.cの_DirSeq_SetActBuf())
 *	  (DirSeq_ActBufSize=256)の場合、変更前は(256×3)=768バイトだったのに対し、変更後は(256×4)=1024バイトになりました。
 *	  アプリケーションのMakefileにて、スタックサイズを十分確保するよう、注意して下さい。
 *	* Fri Sep 09 21:13:53 JST 2016 Naoyuki Sawa
 *	- 演出シーケンサを、複数インスタンスに対応しました。
 *	  当モジュールの関数を呼び出している既存のアプリケーションも、修正が必要になります。
 *	  変更点は、以下の通りです:
 *	  ①clipdirs.cのローカル変数stDirSeqを廃止しました。
 *	    │今後は、アプリケーション側でST_DirSeq構造体のメモリを確保するか、ST_DirSeq型のグローバル変数を定義して下さい。
 *	  ②既存の各関数に、pDirSeq引数を追加しました。
 *	    │上記で確保したST_DirSeqインスタンスのポインタを、pDirSeq引数に指定して下さい。
 *	  ③演出実行関数(fnAct)に、pDirSeq引数を追加しました。
 *	    │どの演出シーケンサのインスタンスから呼び出されたかを、判断するための引数です。
 *	    │例えば、一つのオブジェクトに一つの演出シーケンサを関連付ける場合は、オブジェクトの中にST_DirSeq構造体を埋め込んでCONTAINING_RECORD()を使うか、又は、g_dataset_set_data()等でアドレスを関連付けて下さい。
 *	- 今回の変更と一緒に、ロックバッファサイズ(DirSeqCh_LockBufSize),スタッサイズ(DirSeqCh_StackSize),演出シーケンサチャネル番号の最大値(DirSeqCh_Max)等も、
 *	  定数ではなく、実行時に各インスタンス毎に指定出来るようにしようかとも考えたのですが、やっぱり、今回はそれは行わない事にしました。
 *	  一度に変更すると、変更箇所が多すぎて、デバッグが難しくなると思ったからです。
 *	  まずは、今回の変更が安定して動作する事を確認してから、上記の変更も行いたいと思います。							⇒{{2016/09/10コメント追記:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。}}
 *	  特に、今回、複数インスタンスに対応した事によって、各インスタンスの演出シーケンサチャネル番号の最大値(DirSeqCh_Max)はもっと少なくて済むようになった可能性が高いので、
 *	  演出シーケンサチャネル番号の最大値(DirSeqCh_Max)を、定数でなく、実行時に各インスタンス毎に指定出来るようにする変更を、優先して行うべきです。	⇒{{2016/09/10コメント追記:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。}}
 *	* Sat Sep 10 21:46:35 JST 2016 Naoyuki Sawa
 *	- 演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
 *	  この変更を行った理由については、clipdirs.hの'Fri Sep 09 21:13:53 JST 2016'のコメントを参照して下さい。
 *	* Mon Sep 12 21:10:58 JST 2016 Naoyuki Sawa
 *	- 演出シーケンスが動作中であるかを取得する関数を追加しました。
 */
#ifndef __CLIP_DIRS_H__
#define __CLIP_DIRS_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	
 ****************************************************************************/
//□命令仕様
//
//	#--- 疑似命令 ---
//	[def] ﾗﾍﾞﾙ名
//	#--- 共通命令 ---
//	end							#00000000
//	#--- 演出ｼｰｹﾝｽ命令 ---
//	repeat							#00000001 11111111							┐
//	repeat 繰り返し回数					#00000001 uuuuuuuu							┴u:繰返し回数		0=不可(ｴﾗｰ停止),1~254=繰返し回数,255=無限｡
//	wait   待ち時間						#00000010 uuuuuuuu uuuuuuuu						─u:待ち時間		0=不可(ｴﾗｰ停止),1~65535=待ち時間｡
//	call   相対位置						#00000011 ssssssss ssssssss ssssssss					─s:相対位置		次の命令の位置を基準とする｡
//	act    演出番号						#00000100 uuuuuuuu uuuuuuuu uuuuuuuu					┬u:演出番号		ｱﾌﾟﾘｹｰｼｮﾝ定義の任意の24ﾋﾞｯﾄ値｡
//	act    演出番号 flush					#00000101 uuuuuuuu uuuuuuuu uuuuuuuu					┘
//	#--- 演出ﾃｰﾌﾞﾙ命令 ---
//	on ﾄﾘｶﾞ番号        [goto] ﾗﾍﾞﾙ名               		#00000110 uuuuuuuu ssssssss ssssssss ssssssss 00000000 00000000		┐u=ﾄﾘｶﾞ番号		0~255=ﾄﾘｶﾞ番号｡0は'set',255は'clr'でも可｡
//	on ﾄﾘｶﾞ番号        [goto] ﾗﾍﾞﾙ名 [lock] ﾛｯｸ時間		#00000110 uuuuuuuu ssssssss ssssssss ssssssss vvvvvvvv vvvvvvvv		┼s=相対位置		次の命令の位置を基準とする｡
//	on ﾄﾘｶﾞ番号 unlock [goto] ﾗﾍﾞﾙ名               		#00000111 uuuuuuuu ssssssss ssssssss ssssssss 00000000 00000000		┤v=ﾛｯｸ時間		0=ﾛｯｸしない,1~65535=ﾛｯｸ時間｡
//	on ﾄﾘｶﾞ番号 unlock [goto] ﾗﾍﾞﾙ名 [lock] ﾛｯｸ時間		#00000111 uuuuuuuu ssssssss ssssssss ssssssss vvvvvvvv vvvvvvvv		┘
//
/*--------------------------------------------------------------------------*/
//□命令コード定義用マクロ
#define DirSeq_Inst_end()			0x00
#define DirSeq_Inst_repeat(u)			0x01,((uint8_t)(u))
#define DirSeq_Inst_wait(u)			0x02,((uint8_t)(u)),((uint8_t)((u)>>8))
#define DirSeq_Inst_call(s)			0x03,((uint8_t)(s)),((uint8_t)((s)>>8)),((uint8_t)((s)>>16))
#define DirSeq_Inst_act(u)			0x04,((uint8_t)(u)),((uint8_t)((u)>>8)),((uint8_t)((u)>>16))
#define DirSeq_Inst_act_flush(u)		0x05,((uint8_t)(u)),((uint8_t)((u)>>8)),((uint8_t)((u)>>16))
#define DirSeq_Inst_on_lock(            u,  v)	0x06,DirSeq_Inst_on_goto_lock(       u,0,v)
#define DirSeq_Inst_on_goto(            u,s  )	0x06,DirSeq_Inst_on_goto_lock(       u,s,0)
#define DirSeq_Inst_on_goto_lock(       u,s,v)	0x06,((uint8_t)(u)),((uint8_t)(s)),((uint8_t)((s)>>8)),((uint8_t)((s)>>16)),((uint8_t)(v)),((uint8_t)((v)>>8))
#define DirSeq_Inst_on_unlock(          u    )	0x07,DirSeq_Inst_on_unlock_goto_lock(u,0,0)
#define DirSeq_Inst_on_unlock_lock(     u,  v)	0x07,DirSeq_Inst_on_unlock_goto_lock(u,0,v)
#define DirSeq_Inst_on_unlock_goto(     u,s  )	0x07,DirSeq_Inst_on_unlock_goto_lock(u,s,0)
#define DirSeq_Inst_on_unlock_goto_lock(u,s,v)	0x07,((uint8_t)(u)),((uint8_t)(s)),((uint8_t)((s)>>8)),((uint8_t)((s)>>16)),((uint8_t)(v)),((uint8_t)((v)>>8))
/*--------------------------------------------------------------------------*/
#define DirSeqCh_LockBufSize	  3	//ロックバッファサイズ					1～   で調整可		調整可ではあるがアプリケーション毎に調整する事は想定していない。変更する場合はライブラリをリビルドせよ。
#define DirSeqCh_StackSize	  3	//スタッサイズ						1～255で調整可		調整可ではあるがアプリケーション毎に調整する事は想定していない。変更する場合はライブラリをリビルドせよ。
//演出シーケンサチャネル
typedef struct _ST_DirSeqCh {
	const uint8_t*		pDirTbl;					//+ 0, 4 現在設定されている演出テーブル			NULL=無し
	const uint8_t*		pDirSeq;					//+ 4, 4 演出シーケンスの次に実行する命令位置		NULL=停止中
	uint16_t		WaitCnt;					//+ 8, 2 残り待ち時間
	//--- ロック ---
	uint16_t		LockCnt;					//+10, 2 残りロック時間
	const uint8_t*		TBL_LockBuf[DirSeqCh_LockBufSize];		//+12,12 ロック終了を待っている演出シーケンス		NULL要素で終端		'on'命令の3バイト目を指す
	//--- スタック ---
	uint8_t			StackLev;					//+24, 1 スタックレベル
	uint8_t			TBL_StackRep[DirSeqCh_StackSize];		//+25, 3 0=Callスタック,1～254=Repeatスタックの残り繰返し回数,255=Repeatスタック(無限)
	const uint8_t*		TBL_StackRet[DirSeqCh_StackSize];		//+28,12 戻り先の命令位置							call,又は,repeatの次の命令を指す
} ST_DirSeqCh;									//=40
/*--------------------------------------------------------------------------*/
//{{2016/09/10削除:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
//#ifndef DirSeqCh_Max
//#define DirSeqCh_Max		  3	//演出シーケンサチャネル番号の最大値(この値も含む)	1～255で調整可		当モジュールをアプリケーションに含めてビルドする場合はDirSeqCh_Maxをアプリケーション側で定義可能。
//#endif//DirSeqCh_Max
//}}2016/09/10削除:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
#define DirSeq_ActBufSize	256	//演出番号バッファサイズ				1～65535で調整可	調整可ではあるがアプリケーション毎に調整する事は想定していない。変更する場合はライブラリをリビルドせよ。
//演出シーケンサ
typedef struct _ST_DirSeq {
//{{2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
//	void			(*fnAct)(int iCh, int ActNo, int bOverFlow);	//+ 0, 4 演出実行関数へのポインタ
//↓2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
	void (*fnAct)(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow);	//+ 0, 4 演出実行関数へのポインタ
//}}2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
	uint32_t*		pActBuf/*[DirSeq_ActBufSize]*/;			//+ 4, 4 演出番号バッファへのポインタ			_DirSeq_SetActBuf()にてスタック上に確保したバッファのポインタをバッファが有効な期間中のみST_DirSeq.pActBufに設定する。充分なサイズ,かつ,スタックが溢れないようにDirSeq_ActBufSizeを調整せよ。
	uint16_t		ActBufCnt;					//+ 8, 2 演出番号バッファの格納数
	uint16_t		ActBufPos;					//+10, 2 演出番号バッファの読出し位置
//{{2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
//	ST_DirSeqCh		TBL_DirSeqCh[(DirSeqCh_Max+1)];			//+12,40*(DirSeqCh_Max+1)
//} ST_DirSeq;									//=12+40*(DirSeqCh_Max+1)
//↓2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
	int			nCh;						//+12, 4 演出シーケンサチャネル数			一般的に演出シーケンサチャネル数は高々十数個程度だから、nChフィールドの型はuint8_tでも充分なのだが、そうしてもアライメントのためメモリ節約にならないので、とりあえずint型にしておく事にした。もし今後当構造体にフィールドを追加する必要が生じたら、nChフィールドの型をuint8_t,又は,uint16_tに変更して空きスペースを作れ。
#ifndef __RENESAS__
	ST_DirSeqCh		TBL_DirSeqCh[0/*nCh*/];				//+16,40*nCh
#else //__RENESAS__
	ST_DirSeqCh		TBL_DirSeqCh[1/*nCh*/];				//+16,40*nCh		//Hewは要素数[0]の配列に対応していないので、要素数[1]として調整しました。
#endif//__RENESAS__
} ST_DirSeq;									//=16+40*nCh
//}}2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
/*--------------------------------------------------------------------------*/
#define DirTrg_set		  0	//'set'トリガ番号	┐0='set'と255='clr'は、_DirSeqCh_SetTbl()の動作仕様のため固定です。
#define DirTrg_clr		255	//'clr'トリガ番号	┘1～254はアプリケーション定義で、dDirSeqC.exeによって定義されます。
/****************************************************************************
 *	
 ****************************************************************************/
//{{2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
////演出シーケンサを初期化する。
//void DirSeq_Init(void (*fnAct)(int iCh, int ActNo, int bOverFlow));
////演出シーケンサを実行する。
//void DirSeq_Exec();
////演出テーブルを設定,又は,クリアする。
//void DirSeq_ClrTbl();
//void DirSeqCh_SetTbl(int iCh, const uint8_t* pDirTbl/*NULL=クリア*/);
////トリガを送信する。
//void DirSeq_SendTrig(int iTrig);
//void DirSeqCh_SendTrig(int iCh, int iTrig);
////ロックを解除する。
//void DirSeq_Unlock();
//void DirSeqCh_Unlock(int iCh);
////演出シーケンスを停止する。
//void DirSeq_Stop();
//void DirSeqCh_Stop(int iCh);
//↓2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
//{{2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
////演出シーケンサを初期化する。
//void DirSeq_Init(ST_DirSeq* pDirSeq, void (*fnAct)(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow));
//↓2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
//演出シーケンサを初期化する。
ST_DirSeq* DirSeq_New(void (*fnAct)(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow), int nCh);
void DirSeq_Init(ST_DirSeq* pDirSeq, void (*fnAct)(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow), int nCh);
void DirSeq_Free(ST_DirSeq* pDirSeq);
//}}2016/09/10変更:演出シーケンサチャネル数を、定数でなく、実行時に各インスタンス毎に指定出来るようにしました。
//演出シーケンサを実行する。
void DirSeq_Exec(ST_DirSeq* pDirSeq);
//演出テーブルを設定,又は,クリアする。
void DirSeq_ClrTbl(ST_DirSeq* pDirSeq);
void DirSeqCh_SetTbl(ST_DirSeq* pDirSeq, int iCh, const uint8_t* pDirTbl/*NULL=クリア*/);
//トリガを送信する。
void DirSeq_SendTrig(ST_DirSeq* pDirSeq, int iTrig);
void DirSeqCh_SendTrig(ST_DirSeq* pDirSeq, int iCh, int iTrig);
//ロックを解除する。
void DirSeq_Unlock(ST_DirSeq* pDirSeq);
void DirSeqCh_Unlock(ST_DirSeq* pDirSeq, int iCh);
//演出シーケンスを停止する。
void DirSeq_Stop(ST_DirSeq* pDirSeq);
void DirSeqCh_Stop(ST_DirSeq* pDirSeq, int iCh);
//}}2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
//{{2016/09/12追加:演出シーケンスが動作中であるかを取得する関数を追加しました。
//演出シーケンスが動作中であるかを取得する。
int DirSeq_GetStat(ST_DirSeq* pDirSeq);			//演出シーケンスが動作中であるチャネル数を返します。
int DirSeqCh_GetStat(ST_DirSeq* pDirSeq, int iCh);	//このチャネルが動作中ならば1、停止中ならば0を返します。
//}}2016/09/12追加:演出シーケンスが動作中であるかを取得する関数を追加しました。
/****************************************************************************
 *	dDirSeqC.exeが出力したバイナリ形式を扱うためのユーティリティ関数
 ****************************************************************************/
#define USE_DIRSEQ_BIN	//ユーティリティ関数が不要ならばこのシンボル定義をコメントアウトしてください。
#ifdef  USE_DIRSEQ_BIN
//{{2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
//void DirSeqCh_SetTblNo(int iCh, const void* pDirSeqBin, int iDirTblNo);
//↓2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
void DirSeqCh_SetTblNo(ST_DirSeq* pDirSeq, int iCh, const void* pDirSeqBin, int iDirTblNo);
//}}2016/09/09変更:演出シーケンサを、複数インスタンスに対応しました。
#endif//USE_DIRSEQ_BIN
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_DIRS_H__
