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


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

import		java.lang.*;
import		java.util.*;
import		java.io.*;
import		java.nio.*;

import static	TDL.TDS.TDJVS.*;


public class	JVIo{


/* -------------------------------------------------------------------------- */

static final int	EBADF		=9;
static final int	EBUSY		=16;
static final int	ENOMEM		=12;
static final int	ENODEV		=19;
static final int	E2BIG		=7;

static final int	E_NOTCONNECT	=999;
static final int	E_DESELECT	=998;
static final int	E_REJECT	=997;
static final int	E_SELECT	=992;
static final int	E_CONNECT	=991;
static final int	E_RETRYOVER	=989;
static final int	E_T8TIMEDOUT	=988;
static final int	E_T7TIMEDOUT	=987;
static final int	E_T6TIMEDOUT	=986;
static final int	E_T5TIMEDOUT	=985;
static final int	E_T4TIMEDOUT	=984;
static final int	E_T3TIMEDOUT	=983;
static final int	E_T2TIMEDOUT	=982;
static final int	E_T1TIMEDOUT	=981;
static final int	E_ILLBLOCK	=980;
static final int	E_NODATA	=951;


/* -------------------------------------------------------------------------- */

static final int	MSSG_USE_FILE	=0x80;	// メッセージ定義ファイル
						// 0x00 : 使用しない
						// 0x80 : 使用して項目名表示する
static final int	MSSG_DISP_TYPE	=0x20;	// SECS メッセージ表示形式
						// 0x00 : 通常形式
						// 0x10 : ????形式
						// 0x20 : SML 形式
						// 0x40 : NSG/TS300 形式
static final int	MSSG_USE_NEXTL	=1;	// MssgNextL を使用するか否か
						// 0    : 使用しない
						// 1    : 使用する

static final int	USE_CALLBACK	=1;	// Callback 関数使用の有無
						// 0    : 使用しない
						// 1    : 使用する

static final String	PARAMFILE	="Sample.ini";


/* -------------------------------------------------------------------------- */

static int		Fd=0;		// 通信用識別子
static int		Md=0;		// メッセージ解析用識別子
static int		Break=0;	// スレッド終了指示
static int		OType=0;	// 動作タイプ (0:Host 1:Equip)
static int		Status=0;	// 動作状態
					// (0:未接続 1:未Select 2:Select)

static int		cnt249=0;
static int		cnt250=0;
static int		cnt611=0;


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

static private void
printf(
String		form,
Object...	arg)
{
  try{
    System.out.printf(form,arg);
  }catch(UnknownFormatConversionException	err){
    System.out.printf("Format error\n");
  }catch(Exception				err){
    System.out.printf("Printf error\n");
  }
}


/* -------------------------------------------------------------------------- */

static private void
Sleep(
int		msec)
{
  try{
    Thread.sleep((long)msec);
  }catch(InterruptedException	err){
  }catch(Exception		err){
  }finally{
  }
}


/* -------------------------------------------------------------------------- */

static private String
ReadLine(			//  o : 入力文字列
BufferedReader	in,		// i  : 入力記述子
String		msg)		// i  : 入力促進メッセージ
{
  String	line;

  for(;;){
    printf("%s"	,msg);
    try{			line=in.readLine();
    }catch(Exception		err){			continue;
    }							break;
  }

  return(line);
}


static private int
ReadInt(			//  o : 入力値
BufferedReader	in,		// i  : 入力記述子
String		msg,		// i  : 入力促進メッセージ
int		base)		// i  : 整数基数
{
  String	line;
  int		val;

  for(;;){
    line=ReadLine(in,msg);
    try{			val=Integer.parseInt(line,base);
    }catch(Exception		err){			continue;
    }							break;
  }

  return(val);
}


/* -------------------------------------------------------------------------- */
/* SECS メッセージを標準出力に表示する。 ------------------------------------ */

static private void
DispSECSMssg(			//
int		tp,		// i  : メッセージ種別
				//	=0 : 送信結果
				//	 1 : 受信メッセージ
				//	 2 : 送信メッセージ
byte		hd[],		// i  : SECS メッセージ・ヘッダ
int		did,		// i  : SECS メッセージのデバイスＩＤ
int		sf,		// i  : SECS メッセージのＳＦコード
int		xid,		// i  : SECS メッセージのトランザクションＩＤ
byte		msg[],		// i  : SECS メッセージ格納領域（ヘッダ含まず）
int		len)		// i  : SECS メッセージのバイト長
{
  String	ctp[]={"SRES","RECV","SEND"};
  String	rbit,wbit,sfcode,c;
  StringBuffer	mname=new StringBuffer(),sitem=new StringBuffer();
  ByteBuffer	pm;
  byte		msg1[];
  int		form[]=new int[1],sz[]=new int[1],noi[]=new int[1];
  int		rtn,md=0,dp=MSSG_USE_FILE|MSSG_DISP_TYPE,fm,la,i,j;

  rbit=" ";	if((did&0x8000)!=0)	rbit="R";
  wbit=" ";	if((sf &0x8000)!=0)	wbit="W";
  sfcode=String.format("S%dF%d",(sf&0x7f00)/0x0100,sf&0xff);
  printf("[%s]  Dev=0x%04x  %-8s  %s%s  XId=0x%04x  Len=%4d\n"
		,ctp[tp],did&0x7fff,sfcode,rbit,wbit,xid,len);

  if((MSSG_USE_FILE&0x80)!=0)	fm =0x8000;		// メッセージ定義を使用
  else				fm =0x0000;		// 使用せず

  if(len>0){
    if(tp==1){	dp|=0x3000;	fm|=0x3000;}		// 受信の場合
    else{	dp|=0x2000;	fm|=0x2000;}		// 送信の場合
    pm=ByteBuffer.allocate(1024);	pm.order(ByteOrder.nativeOrder());
    msg1=pm.array();

    if((md=_TDJVSMssgFind(fm,msg,len,Fd,hd,mname))	> 0){
      printf("[%s]\n",mname.toString());		// メッセージ名称

      for(la=0;;){
	if(MSSG_USE_NEXTL==0){				// 項目値を取得
	  rtn=_TDJVSMssgNext(md,0,msg,form,sz,noi,pm,1024);
	  if(rtn						< 0)	break;
	  printf("%03o:%d*%3d:"	,form[0],sz[0],noi[0]);
	  switch(form[0]){
	    case 000: printf("L[%d]\n"	,noi[0]);		break;
	    case 010: printf("B[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s0x%02x",c,msg1[i]);		if(i==0) c=",";
		      } printf("\n");				break; 
	    case 011: printf("T[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s0x%02x",c,msg1[i]);		if(i==0) c=",";
		      } printf("\n");				break; 
	    case 020: c=new String(msg1,0 ,noi[0]);
		      printf("A[%d]=%s.\n",noi[0],c);	c=null;	break;
	    case 021: c=new String(msg1,0 ,noi[0]);
		      printf("J[%d]=%s.\n",noi[0],c);	c=null;	break;
	    case 022: c=new String(msg1,0 ,noi[0]);
		      printf("K[%d]=%s.\n",noi[0],c);	c=null;	break;
	    case 030: printf("I8[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getLong());	if(i==0) c=",";
		      } printf("\n");				break;
	    case 031: printf("I1[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,msg1[i]);		if(i==0) c=",";
		      } printf("\n");				break; 
	    case 032: printf("I2[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getShort());	if(i==0) c=",";
		      } printf("\n");				break; 
	    case 034: printf("I4[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getInt());	if(i==0) c=",";
		      } printf("\n");				break; 
	    case 040: printf("F8[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%e"	,c,pm.getDouble());	if(i==0) c=",";
		      } printf("\n");				break; 
	    case 044: printf("F4[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%e"	,c,pm.getFloat());	if(i==0) c=",";
		      } printf("\n");				break; 
	    case 050: printf("U8[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getLong());	if(i==0) c=",";
		      } printf("\n");				break;
	    case 051: printf("U1[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,msg1[i]);		if(i==0) c=",";
		      } printf("\n");				break; 
	    case 052: printf("U2[%d]"	,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getShort());	if(i==0) c=",";
		      } printf("\n");				break; 
	    case 054: printf("U4[%d]"		,noi[0]);
		      for(c="=",i=0;i<noi[0];i++){
		        printf("%s%d"	,c,pm.getInt());	if(i==0) c=",";
		      } printf("\n");				break; 
	    default:  printf("\n");				break;
	  }

	}else{						// リスト表示形式で取得
	  rtn=_TDJVSMssgNextL(md,dp,msg,form,noi,mname);
	  if(rtn						< 0)	break;
	  if((dp&0x70)>0x10){				// SML、NSG/TS300 の場合
	    for(  i=la;i>rtn;i--){
	      for(j= 0;j<i  ;j++) printf("  ");
	      printf(">\n");				// '>' 表示
	  } }
	  la=rtn;					// 現在の階層を保存
	  printf("  %s\n",mname.toString());		// 取得した項目値を表示
	  if((dp&0x70)>0x10 && form[0]==000 && noi[0]==0){
	    for(  j= 0;j<=la;j++) printf("  ");
	    printf(">\n");				// L0 の場合の '>' 処理
      } } }
      if(MSSG_USE_NEXTL!=0){
	if((dp&0x70)>0x10){
	  for(  i=la;i>0;i--){
	    for(j= 0;j<i;j++)	  printf("  ");
	    printf(">\n");				// 残りの '>' 表示
      } } }
      _TDJVSMssgExit(md,0,msg);
  } }
}



/* -------------------------------------------------------------------------- */
/* 送受信データを表示する。-------------------------------------------------- */

static private int
DispData(
int		tp,		// i  : メッセージ種別
				//	=0 : 送信結果
				//	 1 : 受信メッセージ
				//	 2 : 送信メッセージ
byte		hd[],		// i  : SECS メッセージ・ヘッダ
int		did,		// i  : SECS メッセージのデバイスＩＤ
int		sf,		// i  : SECS メッセージのＳＦコード
int		xid,		// i  : SECS メッセージのトランザクションＩＤ
byte		msg[],		// i  : SECS メッセージ本体
int		len,		// i  : msg の長さ
int		rtn)		// i  : I/O の戻り値
{
  int		ok=0;

  if(rtn<0){							 ok=1;
    if((rtn<(-E_NOTCONNECT) || (-E_ILLBLOCK)<rtn) && rtn!=(-E_NODATA)){
      printf("ERROR  [%d]"			,rtn);
      if      (rtn==(-ENODEV)){
	printf(" : No such device ID\n");	len=ok=0;
      }else if(rtn==(-E2BIG )){
	printf(" : Data size to large\n");	len=ok=0;
      }else			printf("\n");
    }else{
      printf("STATUS = %d,%d : "		,-rtn,Status);
      switch(-rtn){
	case E_NODATA:		printf("No data\n");			break;
	case E_ILLBLOCK:	printf("Illegal block#\n");		break;
	case E_T1TIMEDOUT:	printf("T1 Timeout occur\n");		break;
	case E_T2TIMEDOUT:	printf("T2 Timeout occur\n");		break;
	case E_T3TIMEDOUT:	printf("T3 Timeout occur\n");		break;
	case E_T4TIMEDOUT:	printf("T4 Timeout occur\n");		break;
	case E_T5TIMEDOUT:	printf("T5 Timeout occur\n");		break;
	case E_T6TIMEDOUT:	printf("T6 Timeout occur\n");		break;
	case E_T7TIMEDOUT:	printf("T7 Timeout occur\n");		break;
	case E_T8TIMEDOUT:	printf("T8 Timeout occur\n");		break;
	case E_RETRYOVER:	printf("Retry over\n");			break;
	case E_CONNECT:		printf("Connected\n");			break;
	case E_SELECT:		printf("Selected\n");			break;
	case E_REJECT:		printf("Rejected XId=0x%04x\n",xid);	break;
	case E_DESELECT:	printf("Deselected\n");			break;
	case E_NOTCONNECT:	printf("Not connected\n");		break;
	default:		printf("\n");				break;
  } } }

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

  return(0);
}



/* ========================================================================== */
/* S1F1 メッセージ構築及び送信 ---------------------------------------------- */

static private int
SendS1F1()
{
  byte		hd[]=new byte[12],msg[]=new byte[16];
  int		rtn,sf=0x8101,len=0;

  		// SubFunction.h の SendS1F1() 内 (注) を参照すること。
  rtn=_TDJVSCommSend(Fd,0x0000,0,sf,0,msg,len,hd);
  DispData(2,hd,0x00,sf,rtn,msg,len,rtn);

  return(rtn);
}


/* ---------------------------------------------------------------------------*/
/* S1F2 メッセージ (Host) 構築及び送信 -------------------------------------- */

static private int
SendS1F2H(
int		did,
int		xid)
{
  byte		hd[]=new byte[12],msg[]=new byte[256];
  byte		vb[]=new byte[32];
  int		rtn,md,sf=0x0102,len;
  
  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit   (   0,msg, 256,Fd);		// S1F2
		_TDJVSMssgBuild  (md,0,msg, 000,  0,vb);	// L0
    len=	_TDJVSMssgEnd    (md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit (Md,0,msg, 256,"S1F2_H");
    len=	_TDJVSMDMssgEnd  (Md,0,msg);
  }

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

  return(rtn);
}


/* ---------------------------------------------------------------------------*/
/* S1F2 メッセージ (Equip) 構築及び送信 ------------------------------------- */

static private int
SendS1F2E(
int		did,
int		xid)
{
  byte		hd[]=new byte[12],msg[]=new byte[256];
  byte		vb[]=new byte[32];
  int		rtn,md,sf=0x0102,len;
  
  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit   (   0,msg, 256,Fd);		// S1F2
		_TDJVSMssgBuild  (md,0,msg, 000, 2,vb);		// L2
		_TDJVSMssgBuild  (md,0,msg, 020, 6,"EQUIP1");	//  MDLN
		_TDJVSMssgBuild  (md,0,msg, 020, 6,"01.000");	//  SOFTREV
    len=	_TDJVSMssgEnd    (md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit (Md,0,msg, 256,"S1F2_E");
    len=	_TDJVSMDMssgEnd  (Md,0,msg);
  }

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

  return(rtn);
}


/* ========================================================================== */
/* S2F49 メッセージ構築及び送信 --------------------------------------------- */

static private int
SendS2F49()
{
  byte		hd[]=new byte[12],msg[]=new byte[1024];
  byte		vb[]=new byte[32];
  int		vi[]=new int[4];
  String	str,itm;
  int		rtn,md,sf=0x8200+49,no1,no2,len,i,j;

  cnt249++;	no1=(cnt249%2)+1;	no2=(cnt249%10)+1;
  str=String.format("LOTID (%04d)"	,cnt249);
  
  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit   (   0,msg,1024,Fd);		// S2F49
  		_TDJVSMssgBuild  (md,0,msg, 000,  3,vb);	// L3
    vb[0]=0;	_TDJVSMssgBuild  (md,0,msg, 010,  1,vb);	//  DATAIDB
  		_TDJVSMssgBuild  (md,0,msg, 020,  0,"LOAD");	//  RCMD
  		_TDJVSMssgBuild  (md,0,msg, 000,  4,vb);	//  L4
    vb[0]=1;	_TDJVSMssgBuild  (md,0,msg, 010,  1,vb);	//   STID
    vb[0]=0;	_TDJVSMssgBuild  (md,0,msg, 010,  1,vb);	//   MTKD
  		_TDJVSMssgBuild  (md,0,msg, 020, 20,str);	//   LOTID
		_TDJVSMssgBuild  (md,0,msg, 000,no1,vb);	//   L[no1]
    for(i=0;i<no1;i++){
		_TDJVSMssgBuild  (md,0,msg, 000,no2,vb);	//    L[no2]
      for(j=0;j<no2;j++){
		_TDJVSMssgBuild  (md,0,msg, 000,  2,vb);	//     L[2]
	str=String.format("WAFER(%04d-%d-%02d)",cnt249,i+1,i+2);
  		_TDJVSMssgBuild  (md,0,msg, 020, 20,str);	//      WAFERID
	str=String.format("PPID (%04d-%d-%02d)",cnt249,i+1,i+2);
  		_TDJVSMssgBuild  (md,0,msg, 020, 16,str);	//      PPID
    } }
    len=	_TDJVSMssgEnd    (md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit (Md,0,msg,1024,"S2F49");
  		_TDJVSMDMssgBuild(Md,0,msg,"LOTID",0,str);	//   LOTID
    vi[0]=no1;	_TDJVSMDMssgBuild(Md,0,msg,"NOI1" ,1,vi);	//   L[no1]
    for(i=0;i<no1;i++){
      itm  =String.format("NOI2:%d"			,i+1);
      vi[0]=no2;_TDJVSMDMssgBuild(Md,0,msg,itm   ,1,vi);	//    L[no2]
      for(j=0;j<no2;j++){
	itm=String.format("WAFERID:%d:%d"		,i+1,j+1);
	str=String.format("WAFERID[%04d-%d-%02d]",cnt249,i+1,j+1);
  		_TDJVSMDMssgBuild(Md,0,msg,itm    ,0,str);	//     WAFERID
	itm=String.format("PPID:%d:%d"			,i+1,j+1);
	str=String.format("PPID [%04d-%d-%02d]"	 ,cnt249,i+1,j+1);
  		_TDJVSMDMssgBuild(Md,0,msg,itm    ,0,str);	//     PPID
    } }
    len=	_TDJVSMDMssgEnd  (Md,0,msg);
  }

  if(len<0)	rtn=len;	// SubFunction.h の SendS1F1() 内 (注) を参照。
  else		rtn=_TDJVSCommSend (Fd,0x0000,0,sf,0,msg,len,hd);
  DispData(2,hd,0x00,sf,rtn,msg,len,rtn);

  return(rtn);
}


/* ---------------------------------------------------------------------------*/
/* S2F50 メッセージ構築及び送信 --------------------------------------------- */

static private int
SendS2F50(
int		did,
int		xid)
{
  byte		hd[]=new byte[12],msg[]=new byte[256];
  byte		vb[]=new byte[32];
  String	str;
  int		rtn,md,sf=0x0200+50,len;
  
  str=String.format("LOTID (%04d)"		,++cnt250);

  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit   (   0,msg, 256,Fd);		// S2F50
		_TDJVSMssgBuild  (md,0,msg, 000,  2,vb);	// L2
    vb[0]=0;	_TDJVSMssgBuild  (md,0,msg, 010,  1,vb);	//  HCACK
		_TDJVSMssgBuild  (md,0,msg, 000,  2,vb);	//  L2
  		_TDJVSMssgBuild  (md,0,msg, 020,  5,"PODID");	//   PODID
  		_TDJVSMssgBuild  (md,0,msg, 020, 20,str);	//   LOTID
    len=	_TDJVSMssgEnd    (md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit (Md,0,msg, 256,"S2F50");
		_TDJVSMDMssgBuild(Md,0,msg,"LOTID",  0,str);	//   LOTID
    len=	_TDJVSMDMssgEnd  (Md,0,msg);
  }

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

  return(rtn);
}


/* ========================================================================== */
/* S6F11 メッセージ構築及び送信 --------------------------------------------- */

static private int
SendS6F11()
{
  byte		hd[]=new byte[12],msg[]=new byte[256];
  short		vs[]=new short[4];
  int		rtn,md,sf=0x8600+11,len;

  if((++cnt611)==32768) cnt611=0;

  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit   (   0,msg, 256,Fd);		// S6F11
  		_TDJVSMssgBuild  (md,0,msg, 000,  3,vs);	// L3
    vs[0]=(short)cnt611;
		_TDJVSMssgBuild	 (md,0,msg, 052,  1,vs);	//  DATAID
    vs[0]=8;	_TDJVSMssgBuild  (md,0,msg, 052,  1,vs);	//  CEID
  		_TDJVSMssgBuild  (md,0,msg, 000,  3,vs);	//  L3
  		_TDJVSMssgBuild  (md,0,msg, 020, 16,"DATA1");	//   DATA1
  		_TDJVSMssgBuild  (md,0,msg, 020, 16,"DATA2");	//   DATA2
  		_TDJVSMssgBuild  (md,0,msg, 020, 14,"YYYYMMDDhhmmss");
						// @TIME (本当は現在時刻を設定
						// するのだが、省略。
    len=	_TDJVSMssgEnd    (md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit (Md,0,msg, 256,"S6F11");
    vs[0]=(short)cnt611;
		_TDJVSMDMssgBuild(Md,0,msg,"DATAID",1,vs);	//  DATAID
    len=	_TDJVSMDMssgEnd  (Md,0,msg);
  }

  if(len<0)	rtn=len;	// SubFunction.h の SendS1F1() 内 (注) を参照。
  else		rtn=_TDJVSCommSend (Fd,0x0000,0,sf,0,msg,len,hd);
  DispData(2,hd,0x00,sf,rtn,msg,len,rtn);

  return(rtn);
}



/* ---------------------------------------------------------------------------*/
/* S6F12 メッセージ構築及び送信 --------------------------------------------- */

static private int
SendS6F12(
int		did,
int		xid)
{
  byte		hd[]=new byte[12],msg[]=new byte[256];
  byte		vb[]=new byte[32];
  int		rtn,md,sf=0x0600+12,len;

  if((MSSG_USE_FILE&0x80)==0){			// メッセージ定義を使用しない
    md=		_TDJVSMssgInit	(   0,msg, 256,Fd);		// S6F12
    vb[0]=0;	_TDJVSMssgBuild	(md,0,msg, 010,  1,vb);		// ACKC
    len=	_TDJVSMssgEnd 	(md,0,msg);

  }else{					// メッセージ定義を使用する
		_TDJVSMDMssgInit(Md,0,msg, 256,"S6F12");
    len=	_TDJVSMDMssgEnd (Md,0,msg);
  }

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

  return(rtn);
}



/* ========================================================================== */
/* Callback 関数 ============================================================ */

static private int
CBRecvProc(
int		req,		// i  : ライブラリへの要求コード
int		rtn,		// i  : ライブラリからの戻り値
int		did,		// i  : SECS メッセージのデバイスＩＤ
int		xsf,		// i  : SECS メッセージのＳＦコード
int		xid,		// i  : SECS メッセージのトランザクションＩＤ
byte		xhd[],		// i  : SECS メッセージ・ヘッダ
byte		xmsg[])		// i  : SECS メッセージ
{
  StringBuffer	rname=new StringBuffer(),sname=new StringBuffer();
  byte		hd[]=new byte[12],msg[]=new byte[1024];
  int		sf[]=new int[1];
  int		len;

  DispData(1,xhd,did,xsf,xid,xmsg,rtn,rtn);
  switch(rtn){
    case -E_CONNECT:	Status=1;	break;		// Connected
    case -E_SELECT:	Status=2;	break;		// Selected
    case -E_DESELECT:	Status=1;	break;		// Deselected
    case -E_NOTCONNECT:	Status=0;	break;		// Not connected
  }

  if      (req== 0 && rtn>=0){
    if((MSSG_USE_FILE&0x80)==0){	// メッセージ定義ファイルを使用しない
					// 場合は、自力で SF-Code を調べ、２次
					// メッセージの送出の必要性を判断し、
					// 必要な場合は、送出する。
      if     (xsf==(0x8100+ 1)&&OType==0)	SendS1F2H (did,xid);
      else if(xsf==(0x8100+ 1)&&OType==1)	SendS1F2E (did,xid);
      else if(xsf==(0x8200+49))			SendS2F50 (did,xid);
      else if(xsf==(0x8600+11))			SendS6F12 (did,xid);

    }else if((xsf&0x8000)!=0){		// メッセージ定義ファイルを使用する
					// 場合は、本サンプルでは、自動返信機能
					// を使用する。
      msg=xmsg;
      if((len=_TDJVSMDMssgAutoRes(Md,0,xhd
			,msg,rtn,1024,rname,sname,sf))		>=0){
	printf("RECV %s ..  Auto respond %s [S%dF%d]\n"
		,rname.toString(),sname.toString(),sf[0]/0x100,sf[0]&0xff);
	rtn=_TDJVSCommSend(Fd,0x0000,0,sf[0],xid,msg,len,hd);
	DispData(2,hd,did,sf[0],xid,msg,len,rtn);
      }else{
	if(len!=(-930) && len!=(-931)){
	  printf("RECV Auto response error (%d)\n",len);
  } } } }

  return(0);
}



/* -------------------------------------------------------------------------- */

static class RecvProcThread extends Thread{
public void
run()
{
  byte		msg[]=new byte[1024],hd[]=new byte[12];
  int		xid[]=new int[1],devid[]=new int[1],sf[]=new int[1];
  int		rtn,req;

  for(;Break==0;){
    req=0;
    rtn=_TDJVSCommRecv(Fd,0,devid,sf,xid,msg,1024,hd);
    if(rtn==(-951)){
      Sleep(100);
    }else{
      if((-1000)<rtn && rtn<(-979))	req=(-rtn)-900;
      CBRecvProc(req,rtn,devid[0],sf[0],xid[0],hd,msg);
  } }
}
}



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

public static void
main(
String[]		argv)
{
  if     (argv.length<1)		printf("JVIo {h|e}\n");
  else if(argv[0].equals("h")==false &&
	  argv[0].equals("e")==false)	printf("JVIo {h|e}\n");
  else{
    if(argv[0].equals("h")==true)	Host ();
    else				Equip();
  }
}



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

static private void
Host()
{
  BufferedReader	in;
  RecvProcThread	th;
  String		str;
  byte			hd[]=new byte[12],msg[]=new byte[1024];
  int			xid[]=new int[1],did[]=new int[1],sf[]=new int[1];
  int			req,rtn,mno,xsd=0;

  OType=0;	Break=0;
  in=new BufferedReader(new InputStreamReader(System.in));

L0:{
  if((Fd=_TDJVSCommOpen(0x02,PARAMFILE,"HOST"))			< 0) break L0;
  printf("(H) Opened (%d)\n",Fd);
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDJVSMDMssgInitialize(0x4000,Fd,"");

  if(USE_CALLBACK!=0){
    th=new RecvProcThread();
    th.start();
  }

  for(;;){		rtn=0;
    if(USE_CALLBACK==0)	str="Req (0:Exit 1:Recv 2:Send) : ";
    else		str="Req (0:Exit 2:Send) : ";
    req=ReadInt(in,str,10);
    if      (req==0){						break;

    }else if(req==1){
      if((rtn=_TDJVSCommRecv(Fd,0,did,sf,xid,msg,1024,hd))	>=0) xsd=xid[0];
      DispData(1,hd,did[0],sf[0],xid[0],msg,rtn,rtn);

    }else if(req==2){
      if(USE_CALLBACK==0) str="Message(1:S1F1 2:S2F49  6:S1F2 7:S6F12) : ";
      else		  str="Message(1:S1F1 2:S2F49) : ";
      mno=ReadInt(in,str,10);
      switch(mno){
	case 1: rtn=SendS1F1 ();		break;
	case 2: rtn=SendS2F49();		break;
	case 6: rtn=SendS1F2H(did[0],xsd);	break;
	case 7: rtn=SendS6F12(did[0],xsd);	break;
    } }
    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      printf("(H) I/O Error (%d)\n"	,rtn);
  } }
  }

  Break=1;
  if(Md>0) _TDJVSMDMssgTerminate(Md,0);
  if(Fd>0) _TDJVSCommClose(Fd,0);
  else	   printf("(H) Error (%d)\n"	,Fd);
}



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

static private void
Equip()
{
  BufferedReader	in;
  RecvProcThread	th;
  String		str;
  byte			hd[]=new byte[12],msg[]=new byte[1024];
  int			xid[]=new int[1],did[]=new int[1],sf[]=new int[1];
  int			req,rtn,mno,xsd=0;

  OType=1;	Break=0;
  in=new BufferedReader(new InputStreamReader(System.in));

L0:{
  if((Fd=_TDJVSCommOpen(0x02,PARAMFILE,"EQUIP"))		< 0) break L0;
  printf("(E) Opened (%d)\n",Fd);
  if((MSSG_USE_FILE&0x80)!=0) Md=_TDJVSMDMssgInitialize(0x4000,Fd,"");

  if(USE_CALLBACK!=0){
    th=new RecvProcThread();
    th.start();
  }

  if(_TDJVSCommSend(Fd,0x0100,0,0,0,msg,0,hd)			< 0) break L0;
  printf("(E) Connected\n");
  if(_TDJVSCommSend(Fd,0x0200,0,0,0,msg,0,hd)			< 0) break L0;
  printf("(E) Selected\n");

  for(;;){		rtn=0;
    if(USE_CALLBACK==0)	str="Req (0:Exit 1:Recv 2:Send) : ";
    else		str="Req (0:Exit 2:Send) : ";
    req=ReadInt(in,str,10);
    if      (req==0){						 break;

    }else if(req==1){
      if((rtn=_TDJVSCommRecv(Fd,0,did,sf,xid,msg,1024,hd))	>=0) xsd=xid[0];
      DispData(1,hd,did[0],sf[0],xid[0],msg,rtn,rtn);

    }else if(req==2){
      if(USE_CALLBACK==0) str="Message(1:S1F1 2:S6F11  6:S1F2 7:S2F50) : ";
      else		  str="Message(1:S1F1 2:S6F11) : ";
      mno=ReadInt(in,str,10);
      switch(mno){
	case 1: rtn=SendS1F1 ();		break;
	case 2: rtn=SendS6F11();		break;
	case 6: rtn=SendS1F2E(did[0],xsd);	break;
	case 7: rtn=SendS2F50(did[0],xsd);	break;
    } }
    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      printf("(E) I/O Error (%d)\n"	,rtn);
  } }

// Deselect request は行わない。（SEMI では HSMS-SS において、Deselect request
// は行ってはならない、としている。）
//if(_TDJVSCommSend(Fd,0x0800,0,0,0,msg,0,hd)			< 0) break L0;
//printf("(E) Deselected\n");
  if(_TDJVSCommSend(Fd,0x0900,0,0,0,msg,0,hd)			< 0) break L0;
  printf("(E) Separate\n");
  }

  Break=1;
  if(Md>0) _TDJVSMDMssgTerminate(Md,0);
  if(Fd>0) _TDJVSCommClose(Fd,0);
  else	   printf("(E) Error (%d)\n"	,Fd);
}

}
