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


// =============================================================================
//
// FirstCallbackIo : Test and sample program
//
//   Respond to received messages using Callback function.
//
//   A simpler version of "Sample0/CallbackIo.c".
//   Refer to the comments at the beginning of "Sample0/CallbackIo.c" for 
//   the flow of processing, etc.
//
//   (Note) In this sample, when making an HSMS connection, it is assumed that
//	the HOST side executes Passive connection and the EQUIP side executes
//	Active connection.
//
//
// Starting method
//
//   FirstCallbackIo {h|e}
//   ~~~~~~~~~~~~~~~~~~~~~
//   h    : Refer to [HOST]  section of Sample.ini to determine operation
//   e    : Refer to [EQUIP] section of Sample.ini to determine operation
//
//   Normally, "FirstCallbackIo h" and "FirstCallbackIo e" both operate on same
//   machine or different machines to communicate with each other.
//
//   After startup, refer to the menu display, enter request code (0,2,3).
//   And execute functions such as sending a message to the other side.
//
//   Continuous sending and receiving is performed at a fixed interval
//   (specified by SEND_WAIT) according to request code.
//   Continuous sending and receiving is terminated by input of CTRL-C.
//   In this case, sending of primary message and sending of secondary message
//   may occur simultaneously. 
// 
//   This sample omits some of abnormal processing.
//
//   This sample operates under the following conditions.
//    a. for Windows
//    b. use _TDSUDrvXxxxx()
//    c. Do not use message definition file
//    d. The connection state is synchronized with the communication control
//       thread
//    e. SECS header is accessed in internal ByteOrder state
//    f. Use _TDSMssgNextL() for the communication trace displayed on the screen
//       and output in TDL format
//    g. Use the transaction ID of previously received primary message when
//       sending secondary message.
//
//
// =============================================================================
//
// FirstCallbackIo : テスト 及び サンプル・プログラム
//
//   Callback 関数を使用して受信メッセージに対する応答処理を行う。
//
//   "Sample0/CallbackIo.c" の内容をもっと単純にしたもの。
//  処理の流れ等は "Sample0/CallbackIo.c" の冒頭のコメントを参照すること。
//
//   (注) 本サンプルでは HSMS 接続する場合、HOST 側が Passive 接続、EQUIP 側が
//	Active 接続を実行すると仮定している。
//
//
// 起動方法
//
//   FirstCallbackIo {h|e}
//   ~~~~~~~~~~~~~~~~~~~~~
//   h    : Sample.ini の [HOST]  セクションを参照し動作を決定する
//   e    : Sample.ini の [EQUIP]      :              :
//
//   通常、FirstCallbackIo h 及び FirstCallbackIo e の両方を、同一マシン、
//   もしくは異なるマシン上で動作させて、相互通信を行う。
//
//   起動後、メニュ表示を参照し、要求コード (0,2,3) を入力して、相手側にメッ
//   セージを送出する等の機能を実行する。
//   受信したメッセージ、及び各種イベント情報は Callback 関数の中で処理を完結
//   する。
// 
//   要求コードにより、一定間隔（SEND_WAIT にて指定）での連続送受信を行う。
//   連続送受信は、CTRL-C の入力により終了する。
//   この場合、１次メッセージの送信と、２次メッセージの送信が同時に発生する可
//   能性がある。
// 
//   本サンプルは、異常時処理を一部省略している。
//
//   本サンプルは、以下の条件で動作する。
//   a. Windows 用
//   b. _TDSUDrvXxxxx() を使用する
//   c. メッセージ定義ファイルを使用しない
//   d. 接続状態は通信制御スレッドと同期する
//   e. SECS ヘッダは、内部 ByteOrder 状態でアクセスする
//   f. 画面表示する通信トレースには _TDSMssgNextL() を使用し TDL 形式で出力する
//   g. ２次メッセージを送信する際のトランザクションＩＤは、直前に受信した１次
//      メッセージのものを使用する。
//
// =============================================================================

#include	"TDS.h"


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

#define		UDRV_MASK  	0x8383ffff	// Mask value for UDrvOpen()
						// 0          : Set =0x49
						// 0x8383ffff : All event
#define		PARAMFILE	"Sample.ini"


#define		SEND_WAIT	200		// Message sending interval(ms)
						// メッセージ送信間隔      (m秒)
#define		SEND_NO		10		// Number of times until message
						// sending off
						// メッセージ送信休みまでの回数
#define		SEND_SLEEP	1000		// Wait time		   (ms)
						// お休み時間              (m秒)
#define		ERROR_SLEEP	2000		// Wait time in error case (ms)
						// エラー発生時お休み時間  (m秒)



static int	Finish=0;	// End instruction to thread
				// スレッドへの終了指示


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



// =============================================================================
// Common functions ============================================================

#include	"FirstSubFunctions.h"



// =============================================================================
// Receive processing thread ---------------------------------------------------
// 受信処理スレッド ------------------------------------------------------------

static void
RecvProcThread(
void			*par)
{
  TDSCBData		cbd;
  char			msg[1024];
  int			msz,cmd=0;

  cbd.vec=1;		cbd.msg=msg;
  msz=sizeof(msg);

  for(;Finish==0;){
    cbd.rtn=_TDSUDrvRecv(Fd,0,&cbd.devid,&cbd.sf,&cbd.xid,cbd.msg,msz,&cbd.thd);
    if(cbd.rtn	== -E_NODATA)	Sleep(100);
    else{
      if((-1000)<cbd.rtn && cbd.rtn<(-959))	cbd.req=(-cbd.rtn)-900;
      else					cbd.req=0;
      CBRecvProc(par,&cbd);
      if(cbd.rtn== -E_ACCES)	Break=1;
  } }
}



// =============================================================================
// Main process ----------------------------------------------------------------

int
main(
int			argc,
char			*argv[])
{
  signal(SIGINT,CBSignal);
  InitializeCriticalSection(&Cs1);

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

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



// =============================================================================
// Host side process -----------------------------------------------------------

static void
Host()
{
  int			req,rtn,mno,i;

  if((Fd=_TDSUDrvOpen(0x1002,PARAMFILE,"HOST",UDRV_MASK))	< 0) goto Exit;
  PO,"(H) Opened (%d)\n",Fd);	OType=0;

  _beginthread(RecvProcThread,0,0);

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

    }else if(req==2){
      PE,"Message(1:S1F1 2:S1F21 3:S2F49) : ");
      scanf("%d",&mno);	rtn=0;
      switch(mno){
	case 1: rtn=SendS1F1 ();				break;
	case 2: rtn=SendS1F21();				break;
	case 3: rtn=SendS2F49();				break;
      }

    }else if(req==3){
      for(Break=i=0;Break==0;i++){
	Sleep(SEND_WAIT);
	if(_TDSUDrvStatus(Fd,0)	==3){
	  if((rtn=SendS2F49())	< 0){
	    PE,"(H) Send error (%d)\n"	,rtn);	Sleep(ERROR_SLEEP);
	    if(rtn		==-E_ACCES)	Break=1;
	  }
	  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:
  Finish=1;
  if(Fd> 0)	_TDSUDrvClose(Fd,0);
  else		PE,"(H) Error (%d)\n",Fd);
}



// =============================================================================
// Equipment side process ------------------------------------------------------

static void
Equip()
{
  int			req,rtn,mno,i;

  if((Fd=_TDSUDrvOpen(0x1002,PARAMFILE,"EQUIP",UDRV_MASK))	< 0) goto Exit;

  _beginthread(RecvProcThread,0,0);

  PO,"(E) Opened (%d)\n",Fd);	OType=1;

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

    }else if(req==2){
      PE,"Message(1:S1F1 2:S1F21 3:S6F11) : ");
      scanf("%d",&mno);	rtn=0;
      switch(mno){
	case 1: rtn=SendS1F1 ();				break;
	case 2: rtn=SendS1F21();				break;
	case 3: rtn=SendS6F11();				break;
      }

    }else if(req==3){
      for(Break=i=0;Break==0;i++){
	Sleep(SEND_WAIT);
	if(_TDSUDrvStatus(Fd,0)	==3){
	  if((rtn=SendS6F11())	< 0){
	    PE,"(E) Send error (%d)\n"	,rtn);	Sleep(ERROR_SLEEP);
	    if(rtn		==-E_ACCES)	Break=1;
	  }
	  if((i%SEND_NO)		==0)	Sleep(SEND_SLEEP);
      } }
      rtn=0;
    }

    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      PE,"(E) Send error (%d)\n"	,rtn);
  } }

Exit:
  Finish=1;
  if(Fd> 0)	_TDSUDrvClose(Fd,0);
  else		PE,"(E) Error (%d)\n",Fd);
}
