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


/* ========================================================================== */
/*
 * BasicIo : テスト 及び サンプル・プログラム
 *
 *  ＡＰ内でメッセージを構築し、単純に SECS メッセージの送受信を行う。
 * 
 *  (注) HSMS 限定。 SECS-1 には未対応。
 *
 *
 * 起動方法
 *
 *   BasicIo {h|e}
 *   ~~~~~~~~~~~~~
 *   h    : Sample.ini の [HOST]  セクションを参照し動作を決定する
 *   e    : Sample.ini の [EQUIP]      :              :
 *
 *
 *   通常、BasicIo h 及び BasicIo e の両方を、同一マシン、もしくは異なる
 *   マシン上で動作させて、相互通信を行う。
 *
 *   起動後、メニュ表示を参照し、要求コード等を入力し、機能を実行する。
 *   ホスト側、装置側共に Callback 関数を使用せず、Receive 処理を要求コード
 *   に応じて行う。
 *   メッセージ定義ファイルを使用する場合は、メッセージ定義ファイルに定義した
 *   任意のメッセージ名称を指定することにより、そのメッセージをを送出する。
 * 
 *   ホスト側は起動すると、装置側からの接続を待つ。装置側を起動すると、自動的
 *   にホスト側に接続要求、Select 要求を発行する。ホスト側では、1:Recv 処理を
 *   繰り返し行い、表示が「STATUS=951 : No data」となるのを確認する。その後、
 *   任意のメッセージのやりとりを行う。受信側では、受信データの刈り取りを「
 *   STATUS=951」になるまで行うことを忘れぬこと。
 *
 *   ２次メッセージを送信する際のトランザクションＩＤは、直前に受信した１次
 *   メッセージのものを使用する。
 *
 *   本サンプルは、異常時処理を省略している。
 *   以下で定義する "MSSG_USE_FILE"、"MSSG_DISP_TYPE" の値を変更すると、本ＡＰ
 *   にて表示する SECS メッセージの出力形式を変更できる。
 *   また MSSG_USE_NEXTL の値を変更すると、メッセージ内容を解析する際に、項目
 *   値をデータとして取得するか、表示リスト形式で取得するかを変更できる。
 */
/* ========================================================================== */

#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		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);
  }
//InitializeCriticalSection(&Cs0);
  InitializeCriticalSection(&Cs1);

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

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



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

static void
Host()
{
  TDSECSHead		hd;
  char			msg[1024],mname[64];
  unsigned int		xid,xids=0;
  int			req,rtn,msz,mno;

  msz=sizeof(msg);
  if((Fd=_TDSCommOpen(0x02,PARAMFILE,"HOST",0,0,0,0,0,0))	< 0) goto Exit;
  PO,"(H) Opened (%d)\n",Fd);
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDSMDMssgInitialize(0x4000,Fd,0);

  for(;;){
    PE,"Req (0:Exit 1:Recv 2:Send) : "); scanf("%d",&req);
    if      (req==0){						break;

    }else if(req==1){
      if((rtn=_TDSCommRecv(Fd,0,0,0,&xid,msg,msz,&hd))	>=0) xids=xid;
      DispData(1,&hd,msg,rtn,rtn);

    }else if(req==2){
      PE,"Message(1:S1F1 2:S2F49   6:S1F2 7:S6F12   9:Any) : ");
      scanf("%d",&mno);
      switch(mno){
	case 1: rtn=SendS1F1 ();			break;
	case 2: rtn=SendS2F49();			break;
	case 6: rtn=SendS1F2H(xids);			break;
	case 7: rtn=SendS6F12(xids);			break;
	case 9: if((MSSG_USE_FILE&0x80)!=0){
		  PE,"Message Name : ");	scanf("%s",mname);
		  rtn=SendNamedMssg(xids,mname);
		}					break;
    } }
    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      PE,"(H) I/O 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()
{
  TDSECSHead		hd;
  char			msg[1024],mname[64];
  unsigned int		xid,xids=0;
  int			req,rtn,msz,mno;

  msz=sizeof(msg);
  if((Fd=_TDSCommOpen(0x02,PARAMFILE,"EQUIP",0,0,0,0,0,0))	< 0) goto Exit;
  PO,"(E) Opened (%d)\n",Fd);
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDSMDMssgInitialize(0x4000,Fd,0);
  if((SECS_MODE&0x01)!=0){			// HSMS の場合、接続処理
    if(_TDSCommSend(Fd,0x0100,0,0,0,0,0,0)			< 0) goto Exit;
    PO,"(E) Connected\n");
    if(_TDSCommSend(Fd,0x0200,0,0,0,0,0,0)			< 0) goto Exit;
    PO,"(E) Selected\n");
  }

  for(;;){		rtn=0;
    PE,"Req (0:Exit 1:Recv 2:Send) : "); scanf("%d",&req);
    if      (req==0){						 break;

    }else if(req==1){
      if((rtn=_TDSCommRecv(Fd,0,0,0,&xid,msg,msz,&hd))	>=0) xids=xid;
      DispData(1,&hd,msg,rtn,rtn);

    }else if(req==2){
      PE,"Message(1:S1F1 2:S6F11   6:S1F2 7:S2F50   9:Any) : ");
      scanf("%d",&mno);
      switch(mno){
	case 1: rtn=SendS1F1 ();			break;
	case 2: rtn=SendS6F11();			break;
	case 6: rtn=SendS1F2E(xids);			break;
	case 7: rtn=SendS2F50(xids);			break;
	case 9: if((MSSG_USE_FILE&0x80)!=0){
		  PE,"Message Name : "); scanf("%s",mname);
		  rtn=SendNamedMssg(xids,mname);
		}					break;
    } }
    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      PE,"(E) I/O 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;
  //PO,"(E) Deselected\n");
    if(_TDSCommSend(Fd,0x0900,0,0,0,0,0,0)			< 0) goto Exit;
    PO,"(E) Separate\n");
  }

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