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

#include	"TDS.h"
#include	<string.h>
#include	<signal.h>
#include	<process.h>

// See the comment at beginning of "Sample0/SubFunction.h".
// "Sample0/SubFunction.h" の冒頭のコメントを参照すること。

static int	Fd=0;		// Communication identification
static int	OType=0;	// Operation type	(0:Host	  1:Equipment)
static int	Break=0;	// Signal reception status
				// シグナル受信状態

static CRITICAL_SECTION	Cs1;	// For message display processing lock
				// メッセージ表示処理ロック用	


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

static void
DispSECSMssg(			//
int		tp,		// i  : Message type
				//	=0 : Transmission result
				//	 1 : Received message
				//	 2 : Send message
TDSECSHead	*hd,		// i  : SECS Message header
int		did,		// i  : DeciceID
int		sf,		// i  : SF-Code
int		xid,		// i  : TransactionID
void		*msg,		// i  : SECS Message storage area
				//	     (Header not included)
int		len)		// i  : SECS Message byte length
{
  static char	*ctp[]={"SRES","RECV","SEND"};
  unsigned char	*hh;
  char		str[512],adsf[128],sfcode[12],sdid[32],rbit,wbit;
  int		md=0,form,noi;
  	// [Note] See the comment at DispSECSMssg() of "Sample0/SubFunction.h".
	// [注意] "Sample0/SubFunction.h" の DispSECSMssg() のコメント参照

  rbit=' ';	if((did&0x8000)!=0)	 rbit='R';
  wbit=' ';	if((sf &0x8000)!=0)	 wbit='W';
  hh  =(unsigned char*)hd;
  sprintf(sfcode,"S%dF%d",(sf&0x7f00)>>8,sf&0xff);
  if		  ((sf &0x7f00)==0x0600) sprintf(adsf,"  %s"	    ,sfcode);
  else if	  ((sf &0x7f00)==0x0200) sprintf(adsf,"          %s",sfcode);
  else						 adsf[0]='\0';
  if		  ( did		<0)	 sprintf(sdid,"%6d"	,did);
  else					 sprintf(sdid,"0x%04x"	,did);
  PO,"[%s]  Dev=%s  %-8s  %c%c  XId=0x%04x.%04x  Len=%4d"
     "  Head=0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x%s\n"
		,ctp[tp],sdid,sfcode,rbit,wbit
		,(xid>>16)&0xffff,xid&0xffff,len
		,hh[0],hh[1],hh[2],hh[3],hh[4],hh[5],hh[6],hh[7],hh[8],hh[9]
		,adsf);

  if(msg !=0){
    if((md=_TDSMssgFind(0,msg,len,Fd,hd,0))			> 0){
      for(;;){
	if(_TDSMssgNextL(md,0,msg,&form,&noi,str,sizeof(str))	< 0)	break;
	PO,"  %s\n",str);			// Display acquired field value
      }						// 取得した項目値を表示
      _TDSMssgExit(md,0,msg);
  } }
}



// -----------------------------------------------------------------------------
// Display sent and received data ----------------------------------------------

static int
DispData(
int		tp,		// i  : Message type
				//	=0 : Transmission result
				//	 1 : Received message
				//	 2 : Send message
TDSECSHead	*hd,		// i  : SECS Message header
int		did,		// i  : DeciceID
int		sf,		// i  : SF-Code
int		xid,		// i  : TransactionID
void		*msg,		// i  : SECS Message body
int		len,		// i  : Byte length of 'msg'
int		rtn)		// i  : I/O return value
{
  int		err,pos,ok=0;

  EnterCriticalSection(&Cs1);
	// This lock is important! See DispSECSMssg() for details
	// このロックは重要！ 詳細は DispSECSMssg() 参照

  if(rtn<0){					ok=1;
    if((rtn<(-E_NOTCONNECT) || (-E_ILLBLOCK)<rtn) && rtn!=(-E_NODATA)){
      _TDSErrorStatus(Fd,&err,&pos);
      PO,"ERROR  [%d.%d.%d]",rtn,err,pos);
      if      (rtn==(-ENODEV)){
	PO," : No such device ID\n");	len=ok=0;
      }else if(rtn==(-E2BIG )){
	PO," : Data size to large\n");	len=ok=0;
      }else			PO,"\n");
    }else{
      PO,"STATUS = %d : ",-rtn);
      switch(-rtn){
	case E_NODATA:		PO,"No data\n");		break;
	case E_ILSEQ:		PO,"No selected state\n");	break;
	case E_CONNECT:		PO,"Connected\n");		break;
	case E_SELECT:		PO,"Selected   (0x%04x)\n"
				,did);				break;
	case E_REJECT:		PO,"Rejected XId=0x%04x.%04x\n"
				,(xid>>16)&0xffff,xid&0xffff);	break;
	case E_DESELECT:	PO,"Deselected (0x%04x)\n"
				,did);				break;
	case E_SEPARATE:	PO,"Separated  (0x%04x)\n"
				,did);				break;
	case E_NOTCONNECT:	PO,"Not connected\n");		break;
	default:		PO,"\n");			break;
  } } }

  if(ok==0) DispSECSMssg(tp,hd,did,sf,xid,msg,len);
  LeaveCriticalSection(&Cs1);

  return(0);
}



// =============================================================================
// S1F1 message construction and sending ---------------------------------------

static int
SendS1F1()
{
  TDSECSHead	hd;
  char		msg[16];
  int		rtn,sf=0x8101,len=0;

  	// [Note] See the comment at SendS1F1() of "Sample0/SubFunction.h".
	// [注意] "Sample0/SubFunction.h" の SendS1F1() のコメント参照

  rtn=_TDSUDrvSend(Fd,0, -1,sf,  0,msg,len,&hd);
  DispData(2,&hd, -1,sf,rtn,msg,len,rtn);

  return(rtn);
}


// -----------------------------------------------------------------------------
// S1F2 message (Host) construction and sending --------------------------------

static int
SendS1F2H(
unsigned int	did,
unsigned int	xid)
{
  TDSECSHead	hd;
  char		msg[256];
  int		rtn,md,sf=0x0102,len;
  
  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S1F2
		_TDSMssgBuild  (md,0,msg,000,  0,  0);		// L0
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0,did,sf,xid,msg,len,&hd);
  DispData(2,&hd,did,sf,rtn,msg,len,rtn);

  return(rtn);
}


// -----------------------------------------------------------------------------
// S1F2 message (Equipment) construction and sending ---------------------------

static int
SendS1F2E(
int		did,
unsigned int	xid)
{
  TDSECSHead	hd;
  char		msg[256];
  int		rtn,md,sf=0x0102,len;
  
  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S1F2
		_TDSMssgBuild  (md,0,msg,000,  2,  0);		// L2
		_TDSMssgBuild  (md,0,msg,020,  6,"EQUIP1");	//  MDLN
		_TDSMssgBuild  (md,0,msg,020,  6,"01.000");	//  SOFTREV
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0,did,sf,xid,msg,len,&hd);
  DispData(2,&hd,did,sf,rtn,msg,len,rtn);

  return(rtn);
}


// =============================================================================
// S1F21 message construction and sending --------------------------------------

static int
SendS1F21()
{
  TDSECSHead		hd;
  char			msg[1024];
  char			vb [2]={                      1,                  0xff};
  char			vt [2]={                      0,                     1};
  char*			vs0   ="MSG11";
  char* 		vs1   ="ｿﾌﾄ 02";
  char* 		vs2   ="これは ｺﾒﾝﾄ (FirstSubFunction.h) です";
  char			vi1[2]={                      2,                  -128};
  short			vi2[2]={                  32767,                -32768};
  int			vi4[2]={             0x7ffffffe,            0xfffffffe};
  long long		vi8[2]={   0x7fffffffffffffffLL,  0x800080008000800bLL};
  unsigned char		vu1[2]={                  0x7fU,                 0xffU};
  unsigned short	vu2[2]={                0x7ffeU,               0xfffeU};
  unsigned int		vu4[2]={            0x7ffffffdU,           0xfffffffdU};
  unsigned long	long	vu8[2]={  0x7fffffffffffffffULL, 0x800080008000800bULL};
  unsigned long	long	au8[8]={  7, -6,  5, -4,  3, -2,  1,  0};
  float			vf4[2]={  (float)9.87654321e-21,(float)-8.642097531e13};
  double		vf8[2]={-1.9283746574839201e123,9.1827364546372819208e-213};
  int			rtn,md,sf=0x8100+21,len;


  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S1F21
  		_TDSMssgBuild  (md,0,msg,000,  4, 0);		// L4
  		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//  L2
		_TDSMssgBuild  (md,0,msg,010,  2,vb);		//   VB
		_TDSMssgBuild  (md,0,msg,011,  2,vt);		//   VT
  		_TDSMssgBuild  (md,0,msg,000,  3, 0);		//  L3
  		_TDSMssgBuild  (md,0,msg,020,  6,vs0);		//   MDLN
  		_TDSMssgBuild  (md,0,msg,021,  0,vs1);		//   SOFTREV
  		_TDSMssgBuild  (md,0,msg,022,  0,vs2);		//   COMMENT
  		_TDSMssgBuild  (md,0,msg,000,  9, 0);		//  L9
		_TDSMssgBuild  (md,0,msg,031,  2,vi1);		//   VI1
		_TDSMssgBuild  (md,0,msg,032,  2,vi2);		//   VI2
		_TDSMssgBuild  (md,0,msg,034,  2,vi4);		//   VI4
		_TDSMssgBuild  (md,0,msg,030,  2,vi8);		//   VI8
		_TDSMssgBuild  (md,0,msg,051,  2,vu1);		//   VU1
		_TDSMssgBuild  (md,0,msg,052,  2,vu2);		//   VU2
		_TDSMssgBuild  (md,0,msg,054,  2,vu4);		//   VU4
		_TDSMssgBuild  (md,0,msg,050,  2,vu8);		//   VU8
		_TDSMssgBuild  (md,0,msg,050,  8,au8);		//   AU8
  		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//  L2
		_TDSMssgBuild  (md,0,msg,044,  2,vf4);		//   VF4
		_TDSMssgBuild  (md,0,msg,040,  2,vf8);		//   VF8
  len=	_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0, -1,sf,  0,msg,len,&hd);
  DispData(2,&hd, -1,sf,rtn,msg,len,rtn);

  return(rtn);
}


// -----------------------------------------------------------------------------
// S1F22 message construction and sending --------------------------------------

static int
SendS1F22(
int		did,
unsigned int	xid)
{
  TDSECSHead		hd;
  char			msg[1024];
  char			vb [2]={                      2,                  0xfe};
  char			vt [2]={                      1,                     0};
  char* 		vs0   ="MSG12";
  char* 		vs1   ="ﾚﾋﾞｼﾞｮﾝ";
  char* 		vs2   ="This is コメント (FirstSubFunction.h)";
  char			vi1[2]={                    127,                    -2};
  short			vi2[2]={                  32766,                -32768};
  int			vi4[2]={             2147483646,           -2147483647};
  long long		vi8[2]={   0x8000000000000000LL,  0x7ffffffffffffffeLL};
  unsigned char		vu1[2]={                   254U,                 0xffU};
  unsigned short	vu2[2]={                 65534U,               0xffffU};
  unsigned int		vu4[2]={            4294967294U,           0xffffffffU};
  unsigned long	long	vu8[2]={18446744073709551614ULL, 0xffffffffffffffffULL};
  unsigned long	long	au8[8]={ -1,  2, -3,  4, -5,  6, -7,  0};
  float			vf4[2]={  (float)7.89012345e-12,(float)-4.321098765e31};
  double		vf8[2]={ 5.6473829101928374e189,-3.2109876543210987654e-179};
  int			rtn,md,sf=0x0100+22,len;

  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S1F22
  		_TDSMssgBuild  (md,0,msg,000,  4, 0);		// L4
  		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//  L2
		_TDSMssgBuild  (md,0,msg,010,  2,vb);		//   VB
		_TDSMssgBuild  (md,0,msg,011,  2,vt);		//   VT
  		_TDSMssgBuild  (md,0,msg,000,  3, 0);		//  L3
  		_TDSMssgBuild  (md,0,msg,020,  6,vs0);		//   MDLN
  		_TDSMssgBuild  (md,0,msg,021,  0,vs1);		//   SOFTREV
  		_TDSMssgBuild  (md,0,msg,022,  0,vs2);		//   COMMENT
  		_TDSMssgBuild  (md,0,msg,000,  9, 0);		//  L9
		_TDSMssgBuild  (md,0,msg,031,  2,vi1);		//   VI1
		_TDSMssgBuild  (md,0,msg,032,  2,vi2);		//   VI2
		_TDSMssgBuild  (md,0,msg,034,  2,vi4);		//   VI4
		_TDSMssgBuild  (md,0,msg,030,  2,vi8);		//   VI8
		_TDSMssgBuild  (md,0,msg,051,  2,vu1);		//   VU1
		_TDSMssgBuild  (md,0,msg,052,  2,vu2);		//   VU2
		_TDSMssgBuild  (md,0,msg,054,  2,vu4);		//   VU4
		_TDSMssgBuild  (md,0,msg,050,  2,vu8);		//   VU8
		_TDSMssgBuild  (md,0,msg,050,  8,au8);		//   AU8
  		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//  L2
		_TDSMssgBuild  (md,0,msg,044,  2,vf4);		//   VF4
		_TDSMssgBuild  (md,0,msg,040,  2,vf8);		//   VF8
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0,did,sf,xid,msg,len,&hd);
  DispData(2,&hd,did,sf,rtn,msg,len,rtn);

  return(rtn);
}



// =============================================================================
// S2F49 message construction and sending --------------------------------------

static int
SendS2F49()
{
  static int	cnt=0;
  TDSECSHead	hd;
  char		msg[1024];
  char		vb[4],str[128];
  int		rtn,md,sf=0x8200+49,cmd=0x0000,no1,no2,len,i,j;

  sprintf(str,"LOTID (%4d)",++cnt);	no1=(cnt%2)+1;	no2=(cnt%10)+1;
  
  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S2F49
  		_TDSMssgBuild  (md,0,msg,000,  3, 0);		// L3
  vb[0]=0;	_TDSMssgBuild  (md,0,msg,010,  1,vb);		//  DATAIDB
  		_TDSMssgBuild  (md,0,msg,020,  0,"LOAD");	//  RCMD
  		_TDSMssgBuild  (md,0,msg,000,  4, 0);		//  L4
  vb[0]=1;	_TDSMssgBuild  (md,0,msg,010,  1,vb);		//   STID
  vb[0]=0;	_TDSMssgBuild  (md,0,msg,010,  1,vb);		//   MTKD
  		_TDSMssgBuild  (md,0,msg,020, 20,str);		//   LOTID
    		_TDSMssgBuild  (md,0,msg,000,no1, 0);		//   L[no1]
  for(i=0;i<no1;i++){
    		_TDSMssgBuild  (md,0,msg,000,no2, 0);		//    L[no2]
    for(j=0;j<no2;j++){
    		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//     L[2]
      sprintf(str,"WAFER(%04d-%d-%02d)",cnt,i+1,j+1);
  		_TDSMssgBuild  (md,0,msg,020, 20,str);		//      WAFERID
      sprintf(str,"PPID (%04d-%d-%02d)",cnt,i+1,j+1);
  		_TDSMssgBuild  (md,0,msg,020, 16,str);		//      PPID
  } }
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0, -1,sf,  0,msg,len,&hd);
  DispData(2,&hd, -1,sf,rtn,msg,len,rtn);

  return(rtn);
}


// -----------------------------------------------------------------------------
// S2F50 message construction and sending --------------------------------------

static int
SendS2F50(
int		did,
unsigned int	xid)
{
  static int	cnt=0;
  TDSECSHead	hd;
  char		msg[256];
  char		vb[4],str[128];
  int		rtn,md,sf=0x0200+50,len;
  
  sprintf(str,"LOTID (%4d)",++cnt);
  
  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S2F50
		_TDSMssgBuild  (md,0,msg,000,  2, 0);		// L2
  vb[0]=0;	_TDSMssgBuild  (md,0,msg,010,  1,vb);		//  HCACK
		_TDSMssgBuild  (md,0,msg,000,  2, 0);		//  L2
  		_TDSMssgBuild  (md,0,msg,020, 16,"PPID");	//   PPID
  		_TDSMssgBuild  (md,0,msg,020, 20,str);		//   LOTID
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0,did,sf,xid,msg,len,&hd);
  DispData(2,&hd,did,sf,rtn,msg,len,rtn);

  return(rtn);
}


// =============================================================================
// S6F11 message construction and sending --------------------------------------
// S6F11 メッセージ構築及び送信 ------------------------------------------------

static int
SendS6F11()
{
  static int	cnt=0;
  TDSECSHead	hd;
  char		msg[256];
  unsigned short vs[4];
  int		rtn,md,sf=0x8600+11,len;

  if((++cnt)==65536) cnt=0;

  md =		_TDSMssgInit   (   0,msg,sizeof(msg),Fd);	// S6F11
  		_TDSMssgBuild  (md,0,msg,000,  3, 0);		// L3
  vs[0]=cnt;	_TDSMssgBuild  (md,0,msg,052,  1,vs);		//  DATAID
  vs[0]=8;	_TDSMssgBuild  (md,0,msg,052,  1,vs);		//  CEID
  		_TDSMssgBuild  (md,0,msg,000,  3, 0);		//  L3
  		_TDSMssgBuild  (md,0,msg,020, 16,"DATA1 です");	//   DATA1
  		_TDSMssgBuild  (md,0,msg,020, 16,"DATA2 です");	//   DATA2
  		_TDSMssgBuild  (md,0,msg,020, 14,"YYYYMMDDhhmmss");
			// @TIME Actually I set current time, but omitted.
			// @TIME 本当は現在時刻を設定するのだが、省略。
  len=		_TDSMssgEnd    (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0, -1,sf,  0,msg,len,&hd);
  DispData(2,&hd, -1,sf,rtn,msg,len,rtn);

  return(rtn);
}



// -----------------------------------------------------------------------------
// S6F12 message construction and sending --------------------------------------

static int
SendS6F12(
int		did,
unsigned int	xid)
{
  TDSECSHead	hd;
  char		msg[256];
  char		vb[4];
  int		rtn,md,sf=0x0600+12,len;

  md =		_TDSMssgInit (   0,msg,sizeof(msg),Fd);		// S6F12
  vb[0]=0;	_TDSMssgBuild(md,0,msg,010,  1,vb);		// ACKC
  len=		_TDSMssgEnd  (md,0,msg);

  if(len<0)	rtn=len;
  else		rtn=_TDSUDrvSend (Fd,0,did,sf,xid,msg,len,&hd);
  DispData(2,&hd,did,sf,rtn,msg,len,rtn);

  return(rtn);
}



// =============================================================================
// Callback function ===========================================================

// -----------------------------------------------------------------------------
// Callback for receiving SECS message from the other side ---------------------
// 相手からの SECS メッセージ受信用 Callback -----------------------------------

static int
CBRecvProc(
void		*par,
TDSCBData	*cbd)
{
  DispData(1,&cbd->thd,cbd->devid,cbd->sf,cbd->xid,cbd->msg,cbd->rtn,cbd->rtn);

  if(cbd->req== 0 && cbd->rtn>=0){
	// If you do not use message definition file, check SF-Code on your own,
	// determine necessity of sending secondary message, and send it if
	// necessary.
	// メッセージ定義ファイルを使用しない場合は、自力で SF-Code を調べ、２
	// 次メッセージの送出の必要性を判断し、必要な場合は、送出する。
    if     (cbd->sf==(0x8100+ 1)&&OType==0)	SendS1F2H (cbd->devid,cbd->xid);
    else if(cbd->sf==(0x8100+ 1)&&OType==1)	SendS1F2E (cbd->devid,cbd->xid);
    else if(cbd->sf==(0x8100+21))		SendS1F22 (cbd->devid,cbd->xid);
    else if(cbd->sf==(0x8200+49))		SendS2F50 (cbd->devid,cbd->xid);
    else if(cbd->sf==(0x8600+11))		SendS6F12 (cbd->devid,cbd->xid);
  }

  return(0);
}



// =============================================================================
// Signal handler --------------------------------------------------------------

static void
CBSignal(
int		vec)
{
  signal(SIGINT,CBSignal);
  Break=1;
}
