
/*
 * Trust Design LLC : SECS/HSMS Communication library
 *
 * (c) Copyright Trust Design LLC.  2010-2015.  All rights reserved.
 */


/* ========================================================================== */
/*
 * CallbackIo : テスト 及び サンプル・プログラム
 *
 *  Callback 関数を使用して受信メッセージに対する応答処理を行う。また、ユーザ
 *  定義トレース出力関数を使用し、トレース出力を自力で行う。
 *
 *
 * 起動方法
 *
 *   CallbackIo {h|e}
 *   ~~~~~~~~~~~~~~~~
 *   h    : Sample.ini の [HOST]  セクションを参照し動作を決定する
 *   e    : Sample.ini の [EQUIP]      :              :
 *
 *
 *   通常、CallbackIo h 及び CallbackIo e の両方を、同一マシン、もしくは異なる
 *   マシン上で動作させて、相互通信を行う。
 *
 *   起動後の操作としては、^C の入力によりメニュ表示を行い、要求コード等を入力
 *   して、相手側にメッセージを送出する。
 *   受信したメッセージ、及び各種イベント情報は Callback 関数の中で処理を完結
 *   する。下記 "MSSG_USE_FILE" を 0x80 に設定すると、CallbackIo.ini 中で設定
 *   したメッセージ定義ファイル Sample.sml の内容により、受信１次メッセージ
 *   に対応する２次メッセージを自動送出する。
 *   MSSG_USE_FILE=0x80（メッセージ定義ファイルを使用する）場合は、メッセージ
 *   定義ファイルに定義した任意のメッセージの名称を指定することにより、その
 *   メッセージを送出する。
 * 
 *   また、要求コードにより、一定間隔（SEND_WAIT にて指定）での連続送受信を行
 *   う。連続送受信は、^C の入力により終了する。
 *   この場合、１次メッセージの送信と、２次メッセージの送信が同時に発生する可
 *   能性がある。メッセージ定義ファイルを使用して送信メッセージを作成する場合、
 *   本サンプルでは、メッセージ解析用のデスクリプタは１つしか用意していないの
 *   で、送信処理、返信処理でのメッセージ構築がバッティングしないようにロック
 *   制御をする必要がある。詳細は SunFunctions.h の先頭部分を参照すること。
 * 
 *   本サンプルは、異常時処理を省略している。
 *   以下で定義する "MSSG_USE_FILE"、"MSSG_DISP_TYPE" の値を変更すると、本ＡＰ
 *   にて表示する SECS メッセージの出力形式を変更できる。
 *   また MSSG_USE_NEXTL の値を変更すると、メッセージ内容を解析する際に、項目
 *   値をデータとして取得するか、表示リスト形式で取得するかを変更できる。
 *   同様に USE_USER_TRACE の値を変更すると、User Trace 出力用 Callback の使用
 *   の有無を変更できる。
 */
/* ========================================================================== */

#include	"TDS.h"


#define		PO		fprintf(stdout
#define		PE		fprintf(stderr

#define		SECS_MODE	0x01		// SECS/HSMS モード
						// 0x00 : SECS-1
						// 0x01 : HSMS
#define		MSSG_USE_FILE	0x80		// メッセージ定義ファイル
						// 0x00 : 使用しない
						// 0x80 : 使用して項目名表示する
#define		MSSG_DISP_TYPE	0x20		// SECS メッセージ表示形式
						// 0x00 : 通常形式
						// 0x10 : ????形式
						// 0x20 : SML 形式
						// 0x40 : NSG/TS300 形式
#define		MSSG_USE_NEXTL	1		// MssgNextL を使用するか否か
						// 0    : 使用しない
						// 1    : 使用する
#define		USE_USER_TRACE	0		// UserTrace用CB を使用するか否か
						// 0    : 使用しない
						// 1    : 使用する

#define		SEND_WAIT	2000		// メッセージ送信間隔      (m秒)
#define		SEND_NO		10		// メッセージ送信休みまでの回数
#define		SEND_SLEEP	10000		// お休み時間              (m秒)
#define		ERROR_SLEEP	10000		// エラー発生時お休み時間  (m秒)

#define		PARAMFILE	"Sample.ini"


static void	Host();
static void	Equip();



/* ========================================================================== */
/* 共通関数 ================================================================= */

#include	"SubFunctions.h"



/* ========================================================================== */
/* Main 処理 ---------------------------------------------------------------- */

int
main(
int			argc,
char			*argv[])
{
  if(argc<2 || (argv[1][0]!='h' && argv[1][0]!='e')){
    PE,"%s {host|equip}\n"	,argv[0]);			exit(1);
  }

  signal(SIGINT,CBSignal);
//InitializeCriticalSection(&Cs0);
  InitializeCriticalSection(&Cs1);

  if(argv[1][0]=='h')	Host ();
  else			Equip();

//DeleteCriticalSection(&Cs0);
  DeleteCriticalSection(&Cs1);
  exit(0);
}



/* ========================================================================== */
/* ホスト側処理 ------------------------------------------------------------- */

static void
Host()
{
  int			(*cbtrace)(void*,TDSTRData*)=0;
  char			mname[64];
  int			req,rtn,mno,i;

  if(USE_USER_TRACE!=0)	cbtrace=CBTrace;
  if((Fd=_TDSCommOpen(0x02,PARAMFILE,"HOST"
				,CBRecv,0,CBSend,0,cbtrace,0))	< 0) goto Exit;
  PO,"(H) Opened (%d)\n",Fd);	OType=0;
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDSMDMssgInitialize(0x4000,Fd,0);
  if((SECS_MODE&0x01)==0)	Status=2;	// SECS-1 の場合、接続状態

  for(Break=0;;){
    Sleep(500);
    if(Break!=0){	Break=rtn=0;	req=99;
      PE,"Req (0:Exit 2:Send 3:Continuous) : "); scanf("%d",&req);
      if      (req==0){						break;
      }else if(req==2){
	PE,"Message(1:S1F1 2:S2F49   9:Any) : ");
	scanf("%d",&mno);
	switch(mno){
	  case 1: rtn=SendS1F1 ();			break;
	  case 2: rtn=SendS2F49();			break;
	  case 9: if((MSSG_USE_FILE&0x80)!=0){
		    PE,"Message Name : ");	scanf("%s",mname);
		    rtn=SendNamedMssg(0,mname);
		  }					break;
	}
      }else if(req==3){
	for(i=0;Break==0;i++){
	  Sleep(SEND_WAIT);
	  if(Status==2){
	    if((rtn=SendS2F49())	< 0){
	      PE,"(H) Send error (%d)\n",rtn);	Sleep(ERROR_SLEEP);
	    }
	    if((i%SEND_NO)		==0)	Sleep(SEND_SLEEP);
	} }
	rtn=0;
      }
      if(rtn<(-999) || ((-900)<rtn && rtn<0) ){
	PE,"(H) Send error (%d)\n"	,rtn);
  } } }

Exit:
  if(Md>0) _TDSMDMssgTerminate(Md,0);
  if(Fd>0) _TDSCommClose(Fd,0);
  else	   PE,"(H) Error (%d)\n",Fd);
}



/* ========================================================================== */
/* 装置側処理 --------------------------------------------------------------- */

static void
Equip()
{
  int			(*cbtrace)(void*,TDSTRData*)=0;
  char			mname[64];
  int			req,rtn,mno,cnt,i;

  if(USE_USER_TRACE!=0)	cbtrace=CBTrace;
  if((Fd=_TDSCommOpen(0x02,PARAMFILE,"EQUIP"
				,CBRecv,0,CBSend,0,cbtrace,0))	< 0) goto Exit;
  PO,"(E) Opened (%d)\n",Fd);	OType=1;
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDSMDMssgInitialize(0x4000,Fd,0);
  if((SECS_MODE&0x01)==0)	Status=2;	// SECS-1 の場合、接続状態
  else{						// HSMS   の場合、接続処理
    if(_TDSCommSend(Fd,0x0100,0,0,0,0,0,0)			< 0) goto Exit;
    for(;Status!=1;) Sleep(100);		// Connected まで待つ
    if(_TDSCommSend(Fd,0x0200,0,0,0,0,0,0)			< 0) goto Exit;
    for(;Status!=2;) Sleep(100);		// Selected まで待つ
  }

  for(Break=0;;){
    Sleep(500);
    if(Break!=0){	Break=rtn=0;	req=99;
      PE,"Req (0:Exit 2:Send 3:Continuous) : "); scanf("%d",&req);
      if      (req==0){						 break;
      }else if(req==2){
	PE,"Message(1:S1F1 2:S6F11   9:Any) : ");
	scanf("%d",&mno);
	switch(mno){
	  case 1: rtn=SendS1F1 ();			break;
	  case 2: rtn=SendS6F11();			break;
	  case 9: if((MSSG_USE_FILE&0x80)!=0){
		    PE,"Message Name : ");	scanf("%s",mname);
		    rtn=SendNamedMssg(0,mname);
		  }					break;
	}
      }else if(req==3){
	for(i=0;Break==0;i++){
	  Sleep(SEND_WAIT);
	  if(Status==2){
	    if((rtn=SendS6F11())	< 0){
	      PE,"(H) Send error (%d)\n",rtn);	Sleep(ERROR_SLEEP);
	    }
	    if((i%SEND_NO)		==0)	Sleep(SEND_SLEEP);
        } }
	rtn=0;
      }
      if(rtn<(-999) || ((-900)<rtn && rtn<0)){
	PE,"(E) Send error (%d)\n"	,rtn);
  } } }

  if((SECS_MODE&0x01)!=0){			// HSMS の場合、切断処理
  // Deselect request は行わない。（SEMI では HSMS-SS において、Deselect request
  // は行ってはならない、としている。）
  //if(_TDSCommSend(Fd,0x0800,0,0,0,0,0,0)			< 0) goto Exit;
  //for(cnt=0;Status!=1 && cnt<50;cnt++) Sleep(100);// Deselected まで待つ
    if(_TDSCommSend(Fd,0x0900,0,0,0,0,0,0)			< 0) goto Exit;
    for(cnt=0;Status!=0 && cnt<50;cnt++) Sleep(100);// Not Connected まで、
  }						    // もしくは５秒経過まで待つ

Exit:
  if(Md>0) _TDSMDMssgTerminate(Md,0);
  if(Fd>0) _TDSCommClose(Fd,0);
  else	   PE,"(E) Error (%d)\n",Fd);
}
