/*
 *	clipruds.h
 *
 *	パルスモーターの台形制御シーケンサ
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2015 Naoyuki Sawa
 *
 *	* Thu Apr 24 19:33:48 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Apr 26 09:27:47 JST 2014 Naoyuki Sawa
 *	- シーケンサコンパイラを作成しました。⇒clip/tool/dRudSeqC/
 *	  もう命令コード定義用マクロを使ってデータを作成する必要はありません。
 *	  スクリプトを書いて、シーケンサコンパイラでデータを作成してください。
 *	* Mon May 05 19:19:03 JST 2014 Naoyuki Sawa
 *	- cliprudc.c に停止励磁時間を追加したことに伴い、「wait stop」の条件を変更しました。
 *	  [変更前] 停止中になるまで待つ。
 *	  [変更後] 停止中,かつ,停止励磁終了するまで待つ。
 *	* Fri Nov 28 21:28:11 JST 2014 Naoyuki Sawa
 *	- パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
 *	* Mon Dec 01 21:15:08 JST 2014 Naoyuki Sawa
 *	- RudSeq_Decompile()を追加しました。
 *	  逆コンパイラツール「/clip/tool/dRudSeqD」から使用します。
 *	* Fri Dec 12 21:12:36 JST 2014 Naoyuki Sawa
 *	- 条件分岐'if on','if off'を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
 *	- 条件分岐の'if on','if off'を追加したので、直接制御の'if on','if off'サフィックスは不要になりましたが、現在は残してあります。
 *	  条件分岐の'if on','if off'はシーケンサ(cliprudsモジュール)の機能であり、直接制御の'if on','if off'サフィックスはコントローラ(cliprudcモジュール)の機能であり、概念が異なるからです。
 *	  前者を用いて後者と同じ制御を行うことは可能なのですが、シーケンサを使用せずにコントローラのみを使用するケースで後者の機能が必要となることも有るかと思い、後者の機能も残してあります。
 *	  とはいえ、シーケンサの書式としては後者は不要ですので、いずれ、シーケンサの書式から、直接制御の'if on','if off'サフィックスを削除することを、検討しようと思います。
 *	  その分、直接制御のパラメータ用の、ビット数を増やせるはずです。
 *	* Fri Apr 10 21:48:53 JST 2015 Naoyuki Sawa
 *	- RudSeqCh_Stat()を追加しました。
 *	* Tue May 05 17:15:43 JST 2015 Naoyuki Sawa
 *	- RudSeqCh_PlayNo()を追加しました。
 *	* Sat Aug 01 21:04:32 JST 2015 Naoyuki Sawa
 *	- RudSeqCh_Play()が、シーケンスデータ先頭の0msタイミングに相当する処理を即実行するように、修正しました。
 *	  修正の意図は、'Fri Nov 01 17:54:30 JST 2013' にclipsnds.cのSndSeq_Play()に対して行った修正と同じです。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_RUDS_H__
#define __CLIP_RUDS_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	パルスモーターの台形制御シーケンサ
 ****************************************************************************/
/*==========================================================================*/
////□命令セット仕様
////
////	[def]	(ラベル)
////
////		goto	(ラベル)
////		call	(ラベル)
////		repeat	[繰り返し回数]		省略値=0(無限)
////
////		speed	(分周比)
////		[move]	init
////		move	rel	(相対位置)
////		move	[abs]	(絶対位置)
////		[move]	stop
////
////		wait	[rel]	(相対時間)
////		wait	abs	(絶対時間)
////		wait	[stop]
////
////		user	(番号)
////
////	end					再生終了,call戻り,repeat戻り、いずれもendで表す。
////
///*--------------------------------------------------------------------------*/
////□命令コード仕様
////
////	end		0000 0000 0000 0000
////	[move] init	0000 0000 0000 0001
////	[move] stop	0000 0000 0000 0010
////	wait  [stop]	0000 0000 0000 0011
////	user       u	0000 0000 0000 0100	┬アプリケーション定義命令(0〜4091)						//今後、新しい命令を追加する必要が生じた場合、この範囲を狭める予定
////			0000 1111 1111 1111	┘
////	goto       s	0001 ssss ssss ssss	s:この命令の位置を基準とした相対位置						//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ
////	call       s	0010 ssss ssss ssss	s:この命令の位置を基準とした相対位置						//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ
////	repeat    [u]	0011 uuuu uuuu uuuu	u:0=無限,1〜=繰り返し回数
////	speed      u	0100 uuuu uuuu uuuu	u:分周比(0=最速)
////	move  rel  s	0101 ssss ssss ssss	s:相対位置
////	move [abs] s	0110 ssss ssss ssss	s:絶対位置
////	wait [rel] u	0111 uuuu uuuu uuuu	u:直前の命令完了からの相対時間
////	wait  abs  u	1uuu uuuu uuuu uuuu	u:データ再生開始からの絶対時間
////
///*--------------------------------------------------------------------------*/
////□命令コード定義用マクロ
//#define RudSeq_Inst_end			((0<<12)|      0         )
//#define RudSeq_Inst_move_init		((0<<12)|      1         )
//#define RudSeq_Inst_move_stop		((0<<12)|      2         )
//#define RudSeq_Inst_wait_stop		((0<<12)|      3         )
//#define RudSeq_Inst_user(u)		((0<<12)|(((u)+4)&0x0FFF))	//u:0〜4091
//#define RudSeq_Inst_goto(s)		((1<<12)|( (s)   &0x0FFF))
//#define RudSeq_Inst_call(s)		((2<<12)|( (s)   &0x0FFF))
//#define RudSeq_Inst_repeat(u)		((3<<12)|( (u)   &0x0FFF))
//#define RudSeq_Inst_speed(u)		((4<<12)|( (u)   &0x0FFF))
//#define RudSeq_Inst_move_rel(s)		((5<<12)|( (s)   &0x0FFF))
//#define RudSeq_Inst_move_abs(s)		((6<<12)|( (s)   &0x0FFF))
//#define RudSeq_Inst_wait_rel(u)		((7<<12)|( (u)   &0x0FFF))	//u: 4.096[秒]まで対応可能
//#define RudSeq_Inst_wait_abs(u)		((1<<15)|( (u)   &0x7FFF))	//u:32.767[秒]まで対応可能
//// * Sat Apr 26 09:27:47 JST 2014 Naoyuki Sawa
//// - シーケンサコンパイラを作成しました。⇒clip/tool/dRudSeqC/
////   もう命令コード定義用マクロを使ってデータを作成する必要はありません。
////   スクリプトを書いて、シーケンサコンパイラでデータを作成してください。
/*==========================================================================*/
//↓2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
/*==========================================================================*/
////□命令セット仕様
////
////	[def]	(ラベル)
////
////		goto	(ラベル)
////		call	(ラベル)
////		repeat	[繰り返し回数]		省略値=0(無限)
////
////		speed	(分周比)
////		[move]	init
////		move	rel	(相対位置)
////		move	[abs]	(絶対位置)
////		move	direct	(相対位置) if on    [until c]
////		move	direct	(相対位置) if off   [until c]
////		move	direct	(相対位置) [always] [until c]
////		[move]	stop
////		[move]	stop	direct
////
////		wait	[rel]	(相対時間)
////		wait	abs	(絶対時間)
////		wait	[stop]
////
////		user	(番号)
////
////	end					再生終了,call戻り,repeat戻り、いずれもendで表す。
////
///*--------------------------------------------------------------------------*/
////□命令コード仕様
////
////	end						0x0000			0000 0000 0000 0000	シーケンスを終了する
////	wait   [stop]					0x0001			0000 0000 0000 0001	動作完了を待つ
////	[move] init					0x0002			0000 0000 0000 0010	初期動作を行う
////	[move] stop					0x0003			0000 0000 0000 0011	減速停止を行う
////
////	user			u			0x0004〜0x0FFF		0000 uuuu uuuu uuuu	fnUser()を呼び出す
////
////	wait   [rel]		u			0x1000〜0x1FFF		0001 uuuu uuuu uuuu	相対時間待ちを行う			u:直前の命令完了からの相対時間
////	goto			s			0x2000〜0x2FFF		0010 ssss ssss ssss	処理へ分岐する				s:この命令の位置を基準とした相対位置		//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ。
////	call			s			0x3000〜0x3FFF		0011 ssss ssss ssss	処理を呼び出す				s:この命令の位置を基準とした相対位置		//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ。
////
////	repeat [u]					0x4000〜0x43FF		0100 00uu uuuu uuuu	リピート区間を開始する			u:0=無限,1〜=繰り返し回数
////	speed			u			0x4400〜0x47FF		0100 01uu uuuu uuuu	次回以降の動作速度を設定する		u:分周比(0=最速)
////
////	move   rel		s			0x4800〜0x4BFF		0100 10ss ssss ssss	相対位置へ移動する			s:相対位置
////	move   [abs]		s			0x4C00〜0x4FFF		0100 11ss ssss ssss	絶対位置へ移動する			s:絶対位置
////
////	move   direct		u if on    [until c]	0x5000〜0x5FFF		0101 ccss ssss ssss	直接制御を行う(センサOnならば実行)	s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_SnsOn ,[11:10]=RudCtlReq_When_*」と見なして処理できる。
////	move   direct		u if off   [until c]	0x6000〜0x6FFF		0110 ccss ssss ssss	直接制御を行う(センサOffならば実行)	s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_SnsOff,[11:10]=RudCtlReq_When_*」と見なして処理できる。
////	move   direct		u [always] [until c]	0x7000〜0x7FFF		0111 ccss ssss ssss	直接制御を行う(無条件で実行)		s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_Always,[11:10]=RudCtlReq_When_*」と見なして処理できる。
////
////	[move] stop direct				0x7000			0111 0000 0000 0000	直接制御による停止を行う		「move direct 0」と同義。RudCtlCh_MoveDirect(〜,RelPos:=0,〜)の呼出しとなり、RudCtlCh_StopDirect()と同じ動作を行う。
////
////	wait   abs		u			0x8000〜0xFFFF		1uuu uuuu uuuu uuuu	u:データ再生開始からの絶対時間
////
///*--------------------------------------------------------------------------*/
////□命令コード定義用マクロ
//#define RudSeq_Inst_end				 (0x0000)
//#define RudSeq_Inst_wait_stop			 (0x0001)
//#define RudSeq_Inst_move_init			 (0x0002)
//#define RudSeq_Inst_move_stop			 (0x0003)
//#define RudSeq_Inst_user(u)			((0x0004+(u))&0x0FFF)					//u:0〜4091
//#define RudSeq_Inst_wait_rel(u)			 (0x1000|((u)&0x0FFF))					//u:0〜4096[ms]
//#define RudSeq_Inst_goto(s)			 (0x2000|((s)&0x0FFF))					//s:-2048〜+2047[命令]
//#define RudSeq_Inst_call(s)			 (0x3000|((s)&0x0FFF))					//s:-2048〜+2047[命令]
//#define RudSeq_Inst_repeat(u)			 (0x4000|((u)&0x03FF))					//u:0=無限|1〜1023[回]
//#define RudSeq_Inst_speed(u)			 (0x4400|((u)&0x03FF))					//u:0=最速|1〜1023[分周]
//#define RudSeq_Inst_move_rel(s)			 (0x4800|((s)&0x03FF))					//s:=-512〜+511[パルス]
//#define RudSeq_Inst_move_abs(s)			 (0x4C00|((s)&0x03FF))					//s:=-512〜+511[パルス]
//#define RudSeq_Inst_move_direct(s,c1,c2)	 (0x5000|((s)&0x03FF)|(((c1)&3)<<12)|(((c2)&3)<<10))	//s:=-512〜+511[パルス],c1:RudCtlReq_If_SnsOn|RudCtlReq_If_SnsOff|RudCtlReq_If_Always,c2:RudCtlReq_When_Never|RudCtlReq_When_SnsRise|RudCtlReq_When_SnsFall|RudCtlReq_When_SnsEdge
//#define RudSeq_Inst_wait_abs(u)			 (0x8000|((u)&0x7FFF))					//u:0〜32767[ms]
/*==========================================================================*/
//↓2014/12/12変更:条件分岐'if on','if off'を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
/*==========================================================================*/
//□命令セット仕様
//
//	[def]	(ラベル)
//
//		goto	(ラベル)
//		call	(ラベル)
//		repeat	[繰り返し回数]		省略値=0(無限)
//
//		speed	(分周比)
//		[move]	init
//		move	rel	(相対位置)
//		move	[abs]	(絶対位置)
//		move	direct	(相対位置) if on    [until c]
//		move	direct	(相対位置) if off   [until c]
//		move	direct	(相対位置) [always] [until c]
//		[move]	stop
//		[move]	stop	direct
//
//		wait	[rel]	(相対時間)
//		wait	abs	(絶対時間)
//		wait	[stop]
//
//		if	on
//		if	off
//
//		user	(番号)
//
//	end					再生終了,call戻り,repeat戻り、いずれもendで表す。
//
/*--------------------------------------------------------------------------*/
//□命令コード仕様
//
//	user			u			0x0000〜0x0FF9		0000 uuuu uuuu uuuu	fnUser()を呼び出す			u:アプリケーションが解釈する任意の値
//
//	if     on					0x0FFA			0000 1111 1111 1010	センサOn でなければ次の命令を飛ばす							//PICマイコンの'BTFSC'命令みたいな感じです。
//	if     off					0x0FFB			0000 1111 1111 1011	センサOffでなければ次の命令を飛ばす							//PICマイコンの'BTFSS'命令みたいな感じです。
//	wait   [stop]					0x0FFC			0000 1111 1111 1100	動作完了を待つ
//	[move] stop					0x0FFD			0000 1111 1111 1101	減速停止を行う
//	[move] init					0x0FFE			0000 1111 1111 1110	初期動作を行う
//	end						0x0FFF			0000 1111 1111 1111	シーケンスを終了する
//
//	wait   [rel]		u			0x1000〜0x1FFF		0001 uuuu uuuu uuuu	相対時間待ちを行う			u:直前の命令完了からの相対時間
//	goto			s			0x2000〜0x2FFF		0010 ssss ssss ssss	処理へ分岐する				s:この命令の位置を基準とした相対位置		//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ。
//	call			s			0x3000〜0x3FFF		0011 ssss ssss ssss	処理を呼び出す				s:この命令の位置を基準とした相対位置		//「*次の*命令の位置を基準とした相対位置」*ではない*ことに注意せよ。
//
//	repeat [u]					0x4000〜0x43FF		0100 00uu uuuu uuuu	リピート区間を開始する			u:0=無限,1〜=繰り返し回数
//	speed			u			0x4400〜0x47FF		0100 01uu uuuu uuuu	次回以降の動作速度を設定する		u:分周比(0=最速)
//
//	move   rel		s			0x4800〜0x4BFF		0100 10ss ssss ssss	相対位置へ移動する			s:相対位置
//	move   [abs]		s			0x4C00〜0x4FFF		0100 11ss ssss ssss	絶対位置へ移動する			s:絶対位置
//
//	move   direct		u if on    [until c]	0x5000〜0x5FFF		0101 ccss ssss ssss	直接制御を行う(センサOnならば実行)	s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_SnsOn ,[11:10]=RudCtlReq_When_*」と見なして処理できる。
//	move   direct		u if off   [until c]	0x6000〜0x6FFF		0110 ccss ssss ssss	直接制御を行う(センサOffならば実行)	s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_SnsOff,[11:10]=RudCtlReq_When_*」と見なして処理できる。
//	move   direct		u [always] [until c]	0x7000〜0x7FFF		0111 ccss ssss ssss	直接制御を行う(無条件で実行)		s:相対位置,c:中断条件(rise,fall,edge)		//実装時は「[13:12]=RudCtlReq_If_Always,[11:10]=RudCtlReq_When_*」と見なして処理できる。
//
//	[move] stop direct				0x7000			0111 0000 0000 0000	直接制御による停止を行う		「move direct 0」と同義。RudCtlCh_MoveDirect(〜,RelPos:=0,〜)の呼出しとなり、RudCtlCh_StopDirect()と同じ動作を行う。
//
//	wait   abs		u			0x8000〜0xFFFF		1uuu uuuu uuuu uuuu	u:データ再生開始からの絶対時間
//
/*--------------------------------------------------------------------------*/
//□命令コード定義用マクロ
#define RudSeq_Inst_user(u)			(0x0000|((u)&0x0FFF))					//u:0〜4089
#define RudSeq_Inst_if_on			(0x0000|     0x0FFA )
#define RudSeq_Inst_if_off			(0x0000|     0x0FFB )
#define RudSeq_Inst_wait_stop			(0x0000|     0x0FFC )
#define RudSeq_Inst_move_stop			(0x0000|     0x0FFD )
#define RudSeq_Inst_move_init			(0x0000|     0x0FFE )
#define RudSeq_Inst_end				(0x0000|     0x0FFF )
#define RudSeq_Inst_wait_rel(u)			(0x1000|((u)&0x0FFF))					//u:0〜4096[ms]
#define RudSeq_Inst_goto(s)			(0x2000|((s)&0x0FFF))					//s:-2048〜+2047[命令]
#define RudSeq_Inst_call(s)			(0x3000|((s)&0x0FFF))					//s:-2048〜+2047[命令]
#define RudSeq_Inst_repeat(u)			(0x4000|((u)&0x03FF))					//u:0=無限|1〜1023[回]
#define RudSeq_Inst_speed(u)			(0x4400|((u)&0x03FF))					//u:0=最速|1〜1023[分周]
#define RudSeq_Inst_move_rel(s)			(0x4800|((s)&0x03FF))					//s:=-512〜+511[パルス]
#define RudSeq_Inst_move_abs(s)			(0x4C00|((s)&0x03FF))					//s:=-512〜+511[パルス]
#define RudSeq_Inst_move_direct(s,c1,c2)	(0x5000|((s)&0x03FF)|(((c1)&3)<<12)|(((c2)&3)<<10))	//s:=-512〜+511[パルス],c1:RudCtlReq_If_SnsOn|RudCtlReq_If_SnsOff|RudCtlReq_If_Always,c2:RudCtlReq_When_Never|RudCtlReq_When_SnsRise|RudCtlReq_When_SnsFall|RudCtlReq_When_SnsEdge
#define RudSeq_Inst_wait_abs(u)			(0x8000|((u)&0x7FFF))					//u:0〜32767[ms]
/*==========================================================================*/
#define RudSeqCh_Max RudCtlCh_Max	/* シーケンサチャネル番号の最大値(この値も含む) */					//（台形制御チャネル番号＝台形制御シーケンサチャネル番号）という前提
#define RudSeqCh_StackSize 4		/* スタッサイズ */		//調整可
/*--------------------------------------------------------------------------*/
/* スタック */
typedef struct _ST_RudSeqCh_Stack {
	const uint16_t* pInst;		/* 戻り先の命令ポインタ */								//「call,repeatの次の命令」*ではなく*、「call,repeat命令自身」を指す。end命令による戻り処理時に、次の命令へ進める。実装上の都合である。
	int16_t Repeat;			/* 0=Callスタック,0以外=Repeatスタックの残り繰り返し回数(負=無限) */
} ST_RudSeqCh_Stack;
/*--------------------------------------------------------------------------*/
/* 台形制御シーケンサチャネル */
typedef struct _ST_RudSeqCh {
	const uint16_t* pInst;		/* 次に実行する命令ポインタ */
	uint16_t AbsTime;		/* データ再生開始からの絶対時間 */
	uint16_t RelTime;		/* 直前の命令完了からの相対時間 */
	uint16_t Speed;			/* 分周比(0=最速) */
	uint8_t StackLevel;		/* スタックレベル(0〜RudSeqCh_StackSize) */
	ST_RudSeqCh_Stack TBL_Stack[RudSeqCh_StackSize];	/* スタック */
} ST_RudSeqCh;
/*--- グローバル関数 ---*/
void RudSeqCh_Play(int iRudSeqCh, const uint16_t* pInst);
void RudSeqCh_Stop(int iRudSeqCh);
int  RudSeqCh_Stat(int iRudSeqCh);
/*--------------------------------------------------------------------------*/
/* 台形制御シーケンサ */
typedef struct _ST_RudSeq {
	void (*fnUser)(int iRudSeqCh, int no);		/* アプリケーション定義命令処理関数(アプリケーション定義) */
	ST_RudSeqCh TBL_RudSeqCh[RudSeqCh_Max+1];	/* 台形制御シーケンサチャネル */
} ST_RudSeq;
/*--- グローバル変数 ---*/
extern ST_RudSeq stRudSeq;
/*--- グローバル関数 ---*/
void RudSeq_Init(void (*fnUser)(int iRudSeqCh, int no));
void RudSeq_Stop();
void RudSeq_Exec();
/****************************************************************************
 *	dRudSeqC.exeが出力したバイナリ形式を扱うためのユーティリティ関数
 ****************************************************************************/
#define USE_RUDDEF_BIN	//ユーティリティ関数が不要ならばこのシンボル定義をコメントアウトしてください。
#ifdef  USE_RUDDEF_BIN
void RudSeqCh_PlayNo(int iRudSeqCh, const void* pRudDefBin, int iRudSeqNo);
#endif//USE_RUDDEF_BIN
/****************************************************************************
 *	逆コンパイラ
 ****************************************************************************/
#ifdef  WIN32
void RudSeq_Decompile(const uint16_t TBL_Data[/*iDataLen*/], int iDataLen);
#endif//WIN32
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif/*__CLIP_RUDS_H__*/
