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


// =============================================================================
//
// CSIo : Test and sample program
//
//   Construct a message in AP and simply send and receive SECS messages.
//
//   (Note 1) This sample uses MSVCRT.
//   (Note 2) 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
//
//   CSIo {h|e} [option]
//   ~~~~~~~~~~~~~~~~~~~
//   h    : Refer to [HOST]  section of Sample.ini to determine operation
//   e    : Refer to [EQUIP] section of Sample.ini to determine operation
//
//   option : Options for setting the details of operation (optional)
//	      Specify as a decimal number or as a hexadecimal number with 0x or
//	      x as a prefix.
//	      The details of the specified value for each bit are shown below.
//    F		  54 3210
//   +----+----+----+----+
//    |		  || |||+-- Function to use
//    |		  || |||    =0: _TDSCommXxxxx()		1:_TDSUDrvXxxx()
//    |		  || ||+--- SECS Header Byte order
//    |		  || ||	    =0: System order		1: Network order
//    |		  || |+---- Format for displaying messages in SECS list format
//    |		  || |	    =0: TDS Format		1: SML Format
//    |		  || +----- Whether to use MssgNextL() for SECS message display
//    |		  ||	    =0: Not use			1: Use
//    |		  |+------- Whether to use the SECS message definition file
//    |		  |	    =0: Not use			1: Use
//    |		  +-------- Whether to execute SECS message reception in a
//    |			    dedicated thread
//    |			    =0: No			1: Yes
//    +-------------------- Synchronize the connection status with communication
//			    control processing thread
//			    =0: No			1: Yes
//
//   Normally, "CSIo h" and "CSIo e" both operate on same machine or
//   different machines to communicate with each other. The communication
//   partner may be BasicIo.exe or Callbackio.exe.
//
//   After startup, refer to the menu display, enter request code etc. and the
//   function is executed.
// 
//   When host starts up, it waits for a connection from equipment.
//   When device side is started, connection request and Select request are
//   automatically issued to host side.
//   On host side, repeat '1:Recv' processing, and confirm that display is
//   'STATUS=951: No data'. After that, exchange any message. On receiving side,
//   do not forget to reap received data until 'STATUS=951'.
//
//   The transaction ID used when sending secondary message uses that of primary
//   message received immediately before.
//
//   This sample omits some of abnormal processing.
//
//   "SECS_MODE" defined below is defined to determine whether or not connection
//   processing to Passive side in case of Active connection is performed when
//   using TDS._CommXxxx() as processing function.
//   (Note) Changing this value alone does not make TDS aware of the change in
//      SECS1 or HSMS.  TDS determines SECS1 or HSMS based on the setting of
//      SECSMODE in the configuration file (.ini).  To change this value, you
//      must change the setting of SECSMODE in .ini.
//
//   If the second parameter (option) at startup is not specified, the details
//   of operation are determined by the following constants.
//
//   "FUNC_TYPE" is defined to select type of processing function to be used.
//   If you use TDS._UDrvXxxx(), there is no need to perform connection
//   processing for HSMS-SS Active connection, so there is no need to set
//   "SECS_MODE" in principle.
//   Since TDS switches SECS-1 connection or HSMS-SS connection in setting file
//   (.ini), user AP does not need to know connection method (SECS-1or HSMS and
//   Passive/Active at HSMS) as long as TDS._UDrvXxxx() is used as processing
//   function.
//
//   By changing values of "MSSG_USE_FILE" and "MSSG_DISP_TYPE" defined below,
//   you can change output format of SECS message displayed by this AP.
//   By changing value of "MSSG_USE_NEXTL", it is possible to change whether to
//   acquire field values as data or display list format when analyzing message
//   contents.
//   If "HEADER_BO" is set to 1, Byte Order of SECS message header obtained at
//   the time of Receive and Send can be obtained as the original network Byte
//   Order of the SECS message.
//   Similarly, when "USE_RECVTHREAD" is set to =1, a thread for performing
//   receiving process is activated, and display of received message and output
//   of the secondary message are automatically performed in the thread.
//   When using the receiving thread, keep in mind that prompt message may be
//   distorted.
//
//
// =============================================================================
//
// CSIo : テスト 及び サンプル・プログラム
//
//   ＡＰ内でメッセージを構築し、単純に SECS メッセージの送受信を行う。
//
//   (注1) 本サンプルは、MSVCRT を使用する。
//   (注2) 本サンプルでは HSMS 接続する場合、HOST 側が Passive 接続、EQUIP 側が
//	Active 接続を実行すると仮定している。
//
//
// 起動方法
//
//   CSIo {h|e} [option]
//   ~~~~~~~~~~~~~~~~~~~
//   h    : Sample.ini の [HOST]  セクションを参照し動作を決定する
//   e    : Sample.ini の [EQUIP]      :              :
//
//   option : 動作の詳細を設定するオプション (省略可能)
//	      10進数 もしくは 接頭文字として 0x もしくは x を付与した 16進数
//	      で指定する。
//	      以下に指定値のビット毎の詳細を以下に示す。
//    F		  54 3210
//   +----+----+----+----+
//    |		  || |||+-- 使用する関数
//    |		  || |||    =0: _TDSCommXxxxx()		1:_TDSUDrvXxxx()
//    |		  || ||+--- SECS Header Byte order
//    |		  || ||	    =0: System order		1: Network order
//    |		  || |+---- SECS リスト形式でメッセージを表示する場合の形式
//    |		  || |	    =0: TDS 形式		1: SML 形式
//    |		  || +----- SECS メッセージ表示に MssgNextL() を使用するか否か
//    |		  ||	    =0: 使用しない		1: 使用する
//    |		  |+------- SECS メッセージ定義ファイル使用の有無
//    |		  |	    =0: 使用しない		1: 使用する
//    |		  +-------- SECS メッセージ受信を専用スレッドで実行するか否か
//    |			    =0: No			1: Yes
//    +-------------------- 接続状態を通信制御部に同期する
//			    =0: No			1: Yes
//
//   通常、CSIo h 及び CSIo e の両方を、同一マシン、もしくは異なるマシン上で
//   動作させて、相互通信を行う。通信相手は、BasicIo.exe、Callbackio.exe でも
//   よい。
//
//   起動後、メニュ表示を参照し、要求コード等を入力し、機能を実行する。
// 
//   ホスト側は起動すると、装置側からの接続を待つ。装置側を起動すると、自動的
//   にホスト側に接続要求、Select 要求を発行する。ホスト側では、1:Recv 処理を
//   繰り返し行い、表示が「STATUS=951 : No data」となるのを確認する。その後、
//   任意のメッセージのやりとりを行う。受信側では、受信データの刈り取りを「
//   STATUS=951」になるまで行うことを忘れぬこと。
//
//   ２次メッセージを送信する際のトランザクションＩＤは、直前に受信した１次
//   メッセージのものを使用する。
//
//   本サンプルは、異常時処理を一部省略している。
//
//   以下で定義する "SECS_MODE" は、処理関数として TDS._CommXxxx() を使用する
//   場合で Active 接続の場合の Passive 側への接続処理の実行の有無を判断する
//   ために定義する。
//   (注) この値の変更だけで TDS が SECS1 or HSMS の変更を認識するわけではない。 
//      TDS は SECS1 or HSMS を判断するのは設定ファイル (.ini) の SECSMODE の
//      設定によるので、この値を変更する場合は .ini の SECSMODE の設定変更を
//      しなければならない。
//
//   起動時の2番目のパラメータ (option) を指定しない場合は、以下の定数により
//   動作の詳細を決定する。
//
//   "FUNC_TYPE" は、使用する処理関数の種別を選択するために定義する。
//   TDS._UDrvXxxx() を使用する場合は、HSMS-SS Active 接続の場合の接続処理を
//   行う必要がないので、本来であれば "SECS_MODE" の設定も必要がない。
//   TDS は、SECS-1 接続 or HSMS-SS 接続の切替は、設定ファイル (.ini) にて行う
//   ため、処理関数として TDS._UDrvXxxx() を使用する限りは、ユーザＡＰでは、
//   接続方式（SECS-1/HSMS-SS そして HSMS-SS時の Passive/Active）を知る必要は
//   ない。
//
//   以下で定義する "MSSG_USE_FILE"、"MSSG_DISP_TYPE" の値を変更すると、本ＡＰ
//   にて表示する SECS メッセージの出力形式を変更できる。
//   "MSSG_USE_NEXTL" の値を変更すると、メッセージ内容を解析する際に、項目値を
//   データとして取得するか、表示リスト形式で取得するかを変更できる。
//   "HEADER_BO" を 1 とすると、Receive、Send 時に取得する SECS メッセージ・
//   ヘッダのバイトオーダーを SECS メッセージ本来のネットワーク・バイトオーダー
//   として取得できる。
//   同様に "USE_RECVTHREAD" を =1 とすると、受信処理を行うスレッドを起動し、そ
//   のスレッド内で受信メッセージの表示、２次メッセージの出力を自動で行う。
//   受信スレッドを使用する場合、入力促進用メッセージに乱れが生じる事に留意
//   すること。
//
// =============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

using TDCSL;


namespace TDCSSTest{

unsafe class CSIo{
[DllImport( "msvcrt", CallingConvention=CallingConvention.Cdecl)]
public static extern int printf(string form);
[DllImport( "msvcrt", CallingConvention=CallingConvention.Cdecl)]
public static extern int printf(string form, __arglist);
[DllImport( "msvcrt", CallingConvention=CallingConvention.Cdecl)]
public static extern int sprintf(byte[] str, string form, __arglist);
[DllImport( "msvcrt", CallingConvention=CallingConvention.Cdecl)]
public static extern int scanf(string form, __arglist);


// -----------------------------------------------------------------------------

private const int	EBADF		=9;
private const int	EBUSY		=16;
private const int	ENOMEM		=12;
private const int	ENODEV		=19;
private const int	E2BIG		=7;

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


// -----------------------------------------------------------------------------

private static int	SECS_MODE	=1;	// SECS/HSMS mode
						// 0    : SECS-1
						// 1    : HSMS
						// (Note) See comments above
						// (注) 上部コメント参照
private static uint	UDRV_MASK	=0x8383ffff;
						// Mask value of UDrvOpen()
						// 0          : Set =0x49
						// 0x8383ffff : All event

private static int	FUNC_TYPE	=1;	// Type of function used
						// 通信に使用する関数の種別
						// 0    : TDS._CommXxxxx
						// 1    : TDS._UDrvXxxxx
private static int	HEADER_BO	=1;	// Header byte order
						// 取得するヘッダの Byte Order
						// 0    : System  Order
						// 1    : Network Order
private static int	MSSG_DISP_TYPE	=0x20;	// SECS Message display format
						// 0x00 : TDS Format
						// 0x20 : SML Format
private static int	MSSG_USE_NEXTL	=1;	// Use MssgNextL() or not
						// 0    : Not use
						// 1    : Use

private static int	MSSG_USE_FILE	=0x00;	// Message definition file
						// 0x00 : Not use
						// 0x80 : Use to display item
						//	  names
						//	  使用して項目名表示する
private static int	USE_RECVTHREAD	=1;	// Execute receiving process on
						// its own thread
						// 受信処理を自前スレッドで実行
						// 0    : No
						// 1    : Yes

private static int	SYNC_STATUS	=1;	// Synchronize connection status
						// 接続状態の同期
						// 0    : No
						// 1    : Yes

private static int	SEND_WAIT	=2000;	// Message sending interval (ms)
private static int	SEND_NO		=10;	// #of times until message
						// transmission break
private static int	SEND_SLEEP	=10000;	// Waiting time		    (ms)
private static int	ERROR_SLEEP	=10000;	// Waiting time when an  error
						// occurs		    (ms)

private static string	PARAMFILE	="Sample.ini";


// -----------------------------------------------------------------------------

private static int	FuncType	=FUNC_TYPE;		// argv[1]&0x0001
private static int	HeaderBO	=HEADER_BO;		// argv[1]&0x0002
private static int	MssgDispType	=MSSG_DISP_TYPE;	// argv[1]&0x0004
private static int	MssgUseNextL	=MSSG_USE_NEXTL;	// argv[1]&0x0008
private static int	MssgUseFile	=MSSG_USE_FILE;		// argv[1]&0x0010
private static int	UseRecvThrd	=USE_RECVTHREAD;	// argv[1]&0x0020
private static int	SyncStatus	=SYNC_STATUS;		// argv[1]&0x8000

private static int	SendWait	=SEND_WAIT;		// argv[2]
private static int	SendSleep	=SEND_SLEEP;		// argv[3]

private static int	Fd    =0;	// Communication identifier
private static int	Md    =0;	// Message analysis identifier
private static int	OType =0;	// Operation type  (0:Host  1:Equipment)
private static int	Break =0;	// End instruction to thread
					// スレッドへの終了指示

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

private static System.Object	Cs1=new System.Object();


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


// -----------------------------------------------------------------------------
// Display SECS messages on standard output ------------------------------------
// SECS メッセージを標準出力に表示する -----------------------------------------

private static void
DispSECSMssg(			//
int		tp,		// i  : Message type
				//	=0 : Transmission result
				//	 1 : Received message
				//	 2 : Send message
byte[]		hd,		// i  : SECS Message Header
int		did,		// i  : SECS Message DeiceID
int		sf,		// i  : SECS Message SF-Cide
uint		xid,		// i  : SECS Message TransactionID
byte[]		msg,		// i  : SECS Message strage area
				//	     (Header not included)
int		len)		// i  : SECS Message byte length
{
  string[]	ctp={"SRES","RECV","SEND"};
  string	mname,sitem,mnam,inam;
  byte  []	itm=new byte  [256];
  sbyte []	vi1=new sbyte [256];
  short []	vi2=new short [128];
  int   []	vi4=new int   [ 64];
  long  []	vi8=new long  [ 32];
  byte  []	vu1=new byte  [256];
  ushort[]	vu2=new ushort[128];
  uint  []	vu4=new uint  [ 64];
  ulong []	vu8=new ulong [ 32];
  float []	vf4=new float [ 64];
  double[]	vf8=new double[ 32];
  string	str,rbit,wbit;
  byte  []	sfcode=new byte[16];
  byte  []	sdid  =new byte[16];
  byte  []	iname =new byte[16];
  int		rtn,md=0,dp=MssgUseFile|MssgDispType,fm,form,sz,noi,la;
  int		no0,no1,no2,i,j;
	// [Note] Refer to [Note] described in DispSECSMssg () in SubFuncsion.h
	// [注意] SubFuncsion.h の DispSECSMssg() に記述の [注意] を参照すること

  rbit=" ";	if((did&0x8000)!=0)	rbit="R";
  wbit=" ";	if((sf &0x8000)!=0)	wbit="W";
  if(did < 0)	sprintf(sdid,"%6d"	,__arglist(did));
  else		sprintf(sdid,"0x%04x"	,__arglist(did));
  sprintf(sfcode,"S%dF%d",__arglist((sf&0x7f00)/0x0100,sf&0xff));
  printf("[%s]  Dev=%-6s  %-8s  %s%s  XId=0x%04x.%04x  Len=%4d"+
	 "  Head=0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n"
		,__arglist(ctp[tp],sdid,sfcode,rbit,wbit
		,(xid>>16)&0xffff,xid&0xffff,len
		,hd[0],hd[1],hd[2],hd[3],hd[4],hd[5],hd[6],hd[7],hd[8],hd[9]));

  if((MssgUseFile&0x80)!=0)	fm =0x8000;	// Use message definition file
  else				fm =0x0000;	// Not use

  if(len>0){
    if(tp==1){	dp|=0x3000;	fm|=0x3000;}	// In case of receiving
    else{	dp|=0x2000;	fm|=0x2000;}	// In case of sending

    if((md=TDS._MssgFind(fm,msg,len,Fd,hd,out mname))	> 0){
      if(mname!="") printf("[%s]\n",__arglist(mname));	// Message name

      for(la=0;;){
	if(MssgUseNextL==0){	// Get item value
	  fixed(byte* pm=itm){
	    rtn=TDS._MssgNext(md,0,msg,out form,out sz,out noi,pm,256,out sitem);
	    form&=0x3f;
	    if(rtn					< 0)	break;
	    printf("%03o:%d*%3d:",__arglist(form,sz,noi));
	    switch(form){	// Display field value
				// The third and subsequent numbers are omitted
				// 数値の３番目以降は省略
	      case 0x00: Console.WriteLine("L [{0,2:d}]"	 ,noi);			break;
	      case 0x08: Console.WriteLine("B [{0,2:d}]=0x{1,0:x2},{2,0:x2}"
								 ,noi,itm[0],itm[1]);	break;
	      case 0x09: Console.WriteLine("T [{0,2:d}]={1,0},{2,0}"
								 ,noi,itm[0],itm[1]);	break;
	      case 0x10: Console.WriteLine("A [{0,2:d}]={1}"     ,noi,sitem);		break;
	      case 0x11: Console.WriteLine("J [{0,2:d}]={1}"     ,noi,sitem);		break;
	      case 0x12: Console.WriteLine("K [{0,2:d}]={1}"     ,noi,
		System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(itm,0,noi));	break;
	      case 0x18: Buffer.BlockCopy(itm,0,vi8,0,sz*noi);
			 Console.WriteLine("I8[{0,2:d}]={1},{2}" ,noi,vi8[0],vi8[1]);	break;
	      case 0x19: Buffer.BlockCopy(itm,0,vi1,0,sz*noi);
			 Console.WriteLine("I1[{0,2:d}]={1},{2}" ,noi,vi1[0],vi1[1]);	break;
	      case 0x1a: Buffer.BlockCopy(itm,0,vi2,0,sz*noi);
			 Console.WriteLine("I2[{0,2:d}]={1},{2}" ,noi,vi2[0],vi2[1]);	break;
	      case 0x1c: Buffer.BlockCopy(itm,0,vi4,0,sz*noi);
			 Console.WriteLine("I4[{0,2:d}]={1},{2}" ,noi,vi4[0],vi4[1]);	break;
	      case 0x20: Buffer.BlockCopy(itm,0,vf8,0,sz*noi);
			 Console.WriteLine("F8[{0,2:d}]={1},{2}" ,noi,vf8[0],vf8[1]);	break;
	      case 0x24: Buffer.BlockCopy(itm,0,vf4,0,sz*noi);
			 Console.WriteLine("F4[{0,2:d}]={1},{2}" ,noi,vf4[0],vf4[1]);	break;
	      case 0x28: Buffer.BlockCopy(itm,0,vu8,0,sz*noi);
			 Console.WriteLine("U8[{0,2:d}]={1},{2}" ,noi,vu8[0],vu8[1]);	break;
	      case 0x29: Buffer.BlockCopy(itm,0,vu2,0,sz*noi);
			 Console.WriteLine("U1[{0,2:d}]={1},{2}" ,noi,vu1[0],vu1[1]);	break;
	      case 0x2a: Buffer.BlockCopy(itm,0,vu2,0,sz*noi);
			 Console.WriteLine("U2[{0,2:d}]={1},{2}" ,noi,vu2[0],vu2[1]);	break;
	      case 0x2c: Buffer.BlockCopy(itm,0,vu4,0,sz*noi);
			 Console.WriteLine("U4[{0,2:d}]={1},{2}" ,noi,vu4[0],vu4[1]);	break;
	      default:	 Console.WriteLine("");						break;
	  } }

	}else{					// Get in list format
						// リスト表示形式で取得
	  rtn=TDS._MssgNextL(md,dp,msg,out form,out noi,out str);
	  form&=0x3f;
	  if(rtn					< 0)	break;
	  if((dp&0x70)>0x10){			// In case of SML
	    for(i=la;i>rtn;i--){
	      printf("%*s>\n"	,__arglist(i*2,""));	// Display '>'
	  } }
	  la=rtn;				// Save current hierarchy
						// 現在の階層を保存
	  printf("  %s\n"	,__arglist(str));//Display acquired field value
						// 取得した項目値を表示
	  if((dp&0x70)>0x10 && form==000 && noi==0){
	    printf("%*s>\n"	,__arglist((la+1)*2,""));
						// '>' Processing for L0
      } } }					// L0 の場合の '>' 処理
      if(MssgUseNextL!=0){
	if((dp&0x70)>0x10){
	   for(i=la;i>0;i--){
	     printf("%*s>\n"	,__arglist(i*2,""));	// Show remaining '>'
      } } }						// 残りの '>' 表示
      TDS._MssgExit(md,0,msg);
    }

    if((MssgUseFile&0x80)!=0  &&  MssgUseNextL	!=0){
		// Refer to the comment in corresponding section of SubFuncsion.h
		// SubFuncsion.h の該当箇所のコメントを参照すること
      sf&=0x7fff;
      if((rtn=TDS._MDMssgFind(Md,0,msg,len,sf,out mnam))>0){
	printf("Message Definition Name = '%s'\n"	,__arglist(mnam));

	if	(sf	==0x0115){		// S1F21
	  if((no0=TDS._MDMssgNext(Md,0,msg,"VB"		, 0,itm))>=0){
	    printf("VB          [%2d]=0x"	,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%02x "	,__arglist(itm[i])); printf("\n");
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"MDLN"	, 0,out sitem))>=0){
	    printf("MDLN        [%2d]='%s'\n"	,__arglist(no0	,sitem));
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"VI4"	, 0,vi4))>=0){
	    printf("VI4         [%2d]="		,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%d "	,__arglist(vi4[i])); printf("\n");
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"VF4"	, 0,vf4))>=0){
	    printf("VF4         [%2d]="		,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%le "	,__arglist((double)vf4[i])); printf("\n");
	  }

	}else if(sf	==0x0116){		// S1F22
	  if((no0=TDS._MDMssgNext(Md,0,msg,"VT"		, 0,itm))>=0){
	    printf("VT          [%2d]=0x"	,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%02x "	,__arglist(itm[i])); printf("\n");
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"COMMENT"	, 0,out sitem))>=0){
	    printf("COMMENT     [%2d]='%s'\n"	,__arglist(no0	,sitem));
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"AU8"	, 0,vu8))>=0){
	    printf("AU8         [%2d]="		,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%llu "	,__arglist(vu8[i])); printf("\n");
	  }
	  if((no0=TDS._MDMssgNext(Md,0,msg,"VF8"	, 0,vf8))>=0){
	    printf("VF8         [%2d]="		,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%le "	,__arglist(vf8[i])); printf("\n");
	  }

	}else if(sf	==0x0231){		// S2F49
	  if(TDS._MDMssgNext	 (Md,0,msg,"NOI1"	, 0,vi4) > 0){
	    printf("NOI1        [%2d]\n"	,__arglist(no1=vi4[0]));
	    for(i=0;i<no1;i++){
	      sprintf(iname,"NOI2:%d"		,__arglist(i+1));
	      inam = System.Text.Encoding.ASCII.GetString(iname);
		// Refer to the comment in corresponding section of SubFuncsion.h
		// SubFuncsion.h の該当箇所のコメントを参照すること
	      if(TDS._MDMssgNext (Md,0,msg,inam		, 0,vi4)> 0){
		printf("%-12s[%2d]\n"		,__arglist(inam,no2=vi4[0]));
		for(j=0;j<no2;j++){
		  sprintf(iname,"WAFERID:%d:%d"	,__arglist(i+1,j+1));
		  inam = System.Text.Encoding.ASCII.GetString(iname);
		  if((no0=TDS._MDMssgNext(Md,0,msg,inam	, 0,out sitem))>=0){
		    printf("%-12s[%2d]='%s'\n"	,__arglist(inam,no0,sitem));
	  } } } } }

	}else if(sf	==0x060b){		// S6F11
	  if((no0=TDS._MDMssgNext(Md,0,msg,"DATAID"	, 0,vi2))>=0){
	    printf("DATAIDB     [%2d]="		,__arglist(no0));
	    for(i=0;i<no0;i++) printf("%hu "	,__arglist(vi2[i])); printf("\n");
	} } 
	TDS._MDMssgExit(Md,0,msg);
  } } }
}



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

private static int
DispData(
int		tp,		// i  : Message type
				//	=0 : Transmission result
				//	 1 : Received message
				//	 2 : Send message
byte[]		hd,		// i  : SECS Message Header
int		did,		// i  : SECS Message Device ID
int		sf,		// i  : SECS Message SF-Code
uint		xid,		// i  : SECS Message Transaction ID
byte[]		msg,		// i  : SECS Message Body
int		len,		// i  : Byte length of 'msg'
int		rtn)		// i  : I/O return value
{
  int		ok=0,stat;

  lock(Cs1){			// See notes in SubFuncsion.h
				// SubFuncsion.h の注記を参照すること
  if(rtn<0){							 ok=1;
    if((rtn<(-E_NOTCONNECT) || (-E_ILLBLOCK)<rtn) && rtn!=(-E_NODATA)){
      printf("ERROR  [%d]"			,__arglist(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{
      if(FuncType==0)	stat=TDS._CommStatus(Fd,0);
      else		stat=TDS._UDrvStatus(Fd,0);
      printf("STATUS = %d,%d : "		,__arglist(-rtn,stat));
      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   (0x%04x)\n"
						,__arglist(did));	break;
	case E_REJECT:		printf("Rejected XId=0x%04x\n"
						,__arglist(xid));	break;
	case E_DESELECT:	printf("Deselected (0x%04x)\n"
						,__arglist(did));	break;
	case E_SEPARATE:	printf("Separated  (0x%04x)\n"
						,__arglist(did));	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 message construction and sending ---------------------------------------

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

		// See (Note) in SendS1F1() of SubFunction.h.
  		// SubFunction.h の SendS1F1() 内 (注) を参照すること。
  if(HeaderBO	!=0)	cmd=0x2000;
  if(FuncType	==0)	rtn=TDS._CommSend(Fd,cmd, -1,sf,  0,msg,len,hd);
  else		   	rtn=TDS._UDrvSend(Fd,cmd, -1,sf,  0,msg,len,hd);
  DispData(2,hd, -1,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}


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

private static int
SendS1F2H(
int		did,
uint		xid)
{
  byte[]	hd=new byte[12],msg=new byte[256];
  byte[]	vb=new byte[32];
  int		rtn,md,sf=0x0102,cmd=0x0000,len;
  
  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg, 256,Fd);		// S1F2
		TDS._MssgBuild  (md,0,msg,0x00,  0,vb);		// L0
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg, 256,"S1F2_H");
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;
  else{
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd,did,sf,xid,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd,did,sf,xid,msg,len,hd);
  }
  DispData(2,hd,did,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}


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

private static int
SendS1F2E(
int		did,
uint		xid)
{
  byte[]	hd=new byte[12],msg=new byte[256];
  byte[]	vb=new byte[32];
  int		rtn,md,sf=0x0102,cmd=0x0000,len;
  
  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg, 256,Fd);		// S1F2
		TDS._MssgBuild  (md,0,msg,0x00, 2,vb);		// L2
		TDS._MssgBuild  (md,0,msg,0x10, 6,"EQUIP1");	//  MDLN
		TDS._MssgBuild  (md,0,msg,0x10, 6,"01.000");	//  SOFTREV
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg, 256,"S1F2_E");
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;
  else{
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd,did,sf,xid,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd,did,sf,xid,msg,len,hd);
  }
  DispData(2,hd,did,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}


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

static private int
SendS1F21()
{
  unchecked{
  byte	[] hd =new byte  [12];
  byte	[] msg=new byte  [1024];
  byte	[] vb =new byte  [ 2]{                      1,                      0xff};
  byte	[] vt =new byte  [ 2]{                      0,                         1};
  string   vs0=		      "MSG51";
  string   vs1=		      "ｿﾌﾄ 51";
  string   vs2=		      "これは ｺﾒﾝﾄ (CSIo) です";
  sbyte	[] vi1=new sbyte [ 2]{                      2,                      -128};
  short	[] vi2=new short [ 2]{                  32767,                    -32768};
  int	[] vi4=new int   [ 2]{             0x7ffffffe,           (int)0xfffffffe};
  long	[] vi8=new long  [ 2]{    0x7fffffffffffffffL, (long)0x800080008000800bL};
  byte	[] vu1=new byte  [ 2]{                   0x7f,                      0xff};
  ushort[] vu2=new ushort[ 2]{                 0x7ffe,            (ushort)0xfffe};
  uint	[] vu4=new uint  [ 2]{             0x7ffffffd,          (uint)0xfffffffd};
  ulong	[] vu8=new ulong [ 2]{    0x7fffffffffffffffL,       0x800080008000800bL};
  long	[] au8=new long  [ 8]{  7, -6,  5, -4,  3, -2,  1,  0};
  float	[] vf4=new float [ 2]{  (float)9.87654321e-21,    (float)-8.642097531e13};
  double[] vf8=new double[ 2]{-1.9283746574839201e123,9.1827364546372819208e-213};
  int		rtn,md,sf=0x8100+21,cmd=0x0000,len=0;

  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg,1024,Fd);		// S1F21
  		TDS._MssgBuild  (md,0,msg,0x00,  4,vb);		// L4
  		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//  L2
		TDS._MssgBuild  (md,0,msg,0x08,  2,vb);		//   VB
		TDS._MssgBuild  (md,0,msg,0x09,  2,vt);		//   VT
  		TDS._MssgBuild  (md,0,msg,0x00,  3,vb);		//  L3
  		TDS._MssgBuild  (md,0,msg,0x10,  6,vs0);	//   MDLN
  		TDS._MssgBuild  (md,0,msg,0x11,  0,vs1);	//   SOFTREV
  		TDS._MssgBuild  (md,0,msg,0x12,  0,vs2);	//   COMMENT
  		TDS._MssgBuild  (md,0,msg,0x00,  9,vb);		//  L9
		TDS._MssgBuild  (md,0,msg,0x19,  2,vi1);	//   VI1
		TDS._MssgBuild  (md,0,msg,0x1a,  2,vi2);	//   VI2
		TDS._MssgBuild  (md,0,msg,0x1c,  2,vi4);	//   VI4
		TDS._MssgBuild  (md,0,msg,0x18,  2,vi8);	//   VI8
		TDS._MssgBuild  (md,0,msg,0x29,  2,vu1);	//   VU1
		TDS._MssgBuild  (md,0,msg,0x2a,  2,vu2);	//   VU2
		TDS._MssgBuild  (md,0,msg,0x2c,  2,vu4);	//   VU4
		TDS._MssgBuild  (md,0,msg,0x28,  2,vu8);	//   VU8
		TDS._MssgBuild  (md,0,msg,0x28,  8,au8);	//   AU8
  		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//  L2
		TDS._MssgBuild  (md,0,msg,0x24,  2,vf4);	//   VF4
		TDS._MssgBuild  (md,0,msg,0x20,  2,vf8);	//   VF8
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg,1024,"S1F21_HE");
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;// See (Note) in SendS1F1() of SubFunction.h
  else{				// SubFunction.h の SendS1F1() 内 (注) を参照
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd, -1,sf,  0,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd, -1,sf,  0,msg,len,hd);
  }
  DispData(2,hd, -1,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
  }
}


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

static private int
SendS1F22(
int		did,
uint		xid)
{
  unchecked{
  byte	[] hd =new byte  [12];
  byte	[] msg=new byte  [1024];
  byte	[] vb =new byte  [ 2]{                        2,                 (byte)0xfe};
  byte	[] vt =new byte  [ 2]{                        1,                          0};
  string   vs0= 	      "MSG52";
  string   vs1= 	      "ﾚﾋﾞｼﾞｮﾝ";
  string   vs2= 	      "This is コメント (CSIo)";
  sbyte	[] vi1=new sbyte [ 2]{                      127,                         -2};
  short	[] vi2=new short [ 2]{                    32766,                     -32768};
  int	[] vi4=new int   [ 2]{               2147483646,                -2147483648};
  long	[] vi8=new long  [ 2]{(long)0x8000000000000000L,        0x7ffffffffffffffeL};
  byte	[] vu1=new byte  [ 2]{                (byte)254,                 (byte)0xff};
  ushort[] vu2=new ushort[ 2]{                    65534,                     0xffff};
  uint	[] vu4=new uint  [ 2]{               4294967294,                 0xffffffff};
  ulong	[] vu8=new ulong [ 2]{    18446744073709551614L,        0xffffffffffffffffL};
//ulong	[] vu8=new ulong [ 2]{      0xffffffffffffffffL,        0xffffffffffffffffL};
  long	[] au8=new long  [ 8]{ -1,  2, -3,  4, -5,  6, -7,  0};
  float	[] vf4=new float [ 2]{    (float)7.89012345e-12,     (float)-4.321098765e31};
  double[] vf8=new double[ 2]{   5.6473829101928374e189,-3.2109876543210987654e-179};
  int		rtn,md,sf=0x0100+22,cmd=0x0000,len=0;
  
  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg,1024,Fd);		// S1F22
  		TDS._MssgBuild  (md,0,msg,0x00,  4,vb);		// L4
  		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//  L2
		TDS._MssgBuild  (md,0,msg,0x08,  2,vb);		//   VB
		TDS._MssgBuild  (md,0,msg,0x09,  2,vt);		//   VT
  		TDS._MssgBuild  (md,0,msg,0x00,  3,vb);		//  L3
  		TDS._MssgBuild  (md,0,msg,0x10,  6,vs0);	//   MDLN
  		TDS._MssgBuild  (md,0,msg,0x11,  0,vs1);	//   SOFTREV
  		TDS._MssgBuild  (md,0,msg,0x12,  0,vs2);	//   COMMENT
  		TDS._MssgBuild  (md,0,msg,0x00,  9,vb);		//  L9
		TDS._MssgBuild  (md,0,msg,0x19,  2,vi1);	//   VI1
		TDS._MssgBuild  (md,0,msg,0x1a,  2,vi2);	//   VI2
		TDS._MssgBuild  (md,0,msg,0x1c,  2,vi4);	//   VI4
		TDS._MssgBuild  (md,0,msg,0x18,  2,vi8);	//   VI8
		TDS._MssgBuild  (md,0,msg,0x29,  2,vu1);	//   VU1
		TDS._MssgBuild  (md,0,msg,0x2a,  2,vu2);	//   VU2
		TDS._MssgBuild  (md,0,msg,0x2c,  2,vu4);	//   VU4
		TDS._MssgBuild  (md,0,msg,0x28,  2,vu8);	//   VU8
		TDS._MssgBuild  (md,0,msg,0x28,  8,au8);	//   AU8
  		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//  L2
		TDS._MssgBuild  (md,0,msg,0x24,  2,vf4);	//   VF4
		TDS._MssgBuild  (md,0,msg,0x20,  2,vf8);	//   VF8
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg,1024,"S1F22_HE");
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;
  else{
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd,did,sf,xid,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd,did,sf,xid,msg,len,hd);
  }
  DispData(2,hd,did,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
  }
}


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

private static 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,cmd=0x0000,no1,no2,len,i,j;

  cnt249++;	no1=(cnt249%2)+1;	no2=(cnt249%10)+1;
  str=string.Format("LOTID ({0,0:d4})",cnt249);
  
  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg,1024,Fd);		// S2F49
  		TDS._MssgBuild  (md,0,msg,0x00,  3,vb);		// L3
    vb[0]=0;	TDS._MssgBuild  (md,0,msg,0x08,  1,vb);		//  DATAIDB
  		TDS._MssgBuild  (md,0,msg,0x10,  0,"LOAD");	//  RCMD
  		TDS._MssgBuild  (md,0,msg,0x00,  4,vb);		//  L4
    vb[0]=1;	TDS._MssgBuild  (md,0,msg,0x08,  1,vb);		//   STID
    vb[0]=0;	TDS._MssgBuild  (md,0,msg,0x08,  1,vb);		//   MTKD
  		TDS._MssgBuild  (md,0,msg,0x10, 20,str);	//   LOTID
		TDS._MssgBuild  (md,0,msg,0x00,no1,vb);		//   L[no1]
    for(i=0;i<no1;i++){
		TDS._MssgBuild  (md,0,msg,0x00,no2,vb);		//    L[no2]
      for(j=0;j<no2;j++){
		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//     L[2]
	str=string.Format("WAFER({0,0:d4}-{1,0:d1}-{2,0:d2})",cnt249,i+1,i+2);
  		TDS._MssgBuild  (md,0,msg,0x10, 20,str);	//      WAFERID
	str=string.Format("PPID ({0,0:d4}-{1,0:d1}-{2,0:d2})",cnt249,i+1,i+2);
  		TDS._MssgBuild  (md,0,msg,0x10, 16,str);	//      PPID
    } }
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg,1024,"S2F49_H");
  		TDS._MDMssgBuild(Md,0,msg,"LOTID",0,str);	//   LOTID
    vi[0]=no1;	TDS._MDMssgBuild(Md,0,msg,"NOI1" ,1,vi);	//   L[no1]
    for(i=0;i<no1;i++){
      itm  =string.Format("NOI2:{0,0:d1}"		,i+1);
      vi[0]=no2;TDS._MDMssgBuild(Md,0,msg,itm   ,1,vi);		//    L[no2]
      for(j=0;j<no2;j++){
	itm=string.Format("WAFERID:{0,0:d1}:{1,0:d1}"	,i+1,j+1);
	str=string.Format("WAFERID[{0,0:d4}-{1,0:d1}-{1,0:d2}]"
						,cnt249	,i+1,j+1);
  		TDS._MDMssgBuild(Md,0,msg,itm    ,0,str);	//     WAFERID
	itm=string.Format("PPID:{0,0:d1}:{1,0:d1}"	,i+1,j+1);
	str=string.Format("PPID [{0,0:d4}-{1,0:d1}-{1,0:d2}]"
						,cnt249	,i+1,j+1);
  		TDS._MDMssgBuild(Md,0,msg,itm    ,0,str);	//     PPID
    } }
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;// See (Note) in SendS1F1() of SubFunction.h
  else{				// SubFunction.h の SendS1F1() 内 (注) を参照
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd, -1,sf,  0,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd, -1,sf,  0,msg,len,hd);
  }
  DispData(2,hd, -1,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}


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

private static int
SendS2F50(
int		did,
uint		xid)
{
  byte[]	hd=new byte[12],msg=new byte[256];
  byte[]	vb=new byte[32];
  string	str;
  int		rtn,md,sf=0x0200+50,cmd=0x0000,len;
  
  str=string.Format("LOTID ({0,0:d4})"	,++cnt250);

  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg, 256,Fd);		// S2F50
		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		// L2
    vb[0]=0;	TDS._MssgBuild  (md,0,msg,0x08,  1,vb);		//  HCACK
		TDS._MssgBuild  (md,0,msg,0x00,  2,vb);		//  L2
  		TDS._MssgBuild  (md,0,msg,0x10, 16,"PPID");	//   PPID
  		TDS._MssgBuild  (md,0,msg,0x10, 20,str);	//   LOTID
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg, 256,"S2F50_E");
		TDS._MDMssgBuild(Md,0,msg,"LOTID",  0,str);	//   LOTID
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;
  else{
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd,did,sf,xid,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd,did,sf,xid,msg,len,hd);
  }
  DispData(2,hd,did,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}


// =============================================================================
// S6F11 message construction and sending --------------------------------------

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

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

  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit   (   0,msg, 256,Fd);		// S6F11
  		TDS._MssgBuild  (md,0,msg,0x00,  3,vs);		// L3
    vs[0]=(ushort)cnt611;
		TDS._MssgBuild	(md,0,msg,0x2a,  1,vs);		//  DATAID
    vs[0]=8;	TDS._MssgBuild  (md,0,msg,0x2a,  1,vs);		//  CEID
  		TDS._MssgBuild  (md,0,msg,0x00,  3,vs);		//  L3
  		TDS._MssgBuild  (md,0,msg,0x10, 16,"DATA1");	//   DATA1
  		TDS._MssgBuild  (md,0,msg,0x10, 16,"DATA2");	//   DATA2
  		TDS._MssgBuild  (md,0,msg,0x10, 14,"YYYYMMDDhhmmss");
			// @TIME Actually I set current time, but omitted.
			// @TIME 本当は現在時刻を設定するのだが、省略
    len=	TDS._MssgEnd    (md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg, 256,"S6F11_E0");
    vs[0]=(ushort)cnt611;
		TDS._MDMssgBuild(Md,0,msg,"DATAID",1,vs);	//  DATAID
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;// See (Note) in SendS1F1().
  else{				// SubFunction.h の SendS1F1() 内 (注) を参照。
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd, -1,sf,  0,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd, -1,sf,  0,msg,len,hd);
  }
  DispData(2,hd, -1,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}



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

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

  if((MssgUseFile&0x80)==0){			// Do not use message definition
    md=		TDS._MssgInit	(   0,msg, 256,Fd);		// S6F12
    vb[0]=0;	TDS._MssgBuild	(md,0,msg,0x08,  1,vb);		// ACKC
    len=	TDS._MssgEnd 	(md,0,msg);

  }else{					// Use message definition
		TDS._MDMssgInit (Md,0,msg, 256,"S6F12_H");
    len=	TDS._MDMssgEnd  (Md,0,msg);
  }

  if(len	< 0)	rtn=len;
  else{
    if(HeaderBO	!=0)	cmd=0x2000;
    if(FuncType	==0)	rtn=TDS._CommSend (Fd,cmd,did,sf,xid,msg,len,hd);
    else		rtn=TDS._UDrvSend (Fd,cmd,did,sf,xid,msg,len,hd);
  }
  DispData(2,hd,did,sf,(uint)rtn,msg,len,rtn);

  return(rtn);
}



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

private static int
CBRecvProc(
int		req,		// i  : Request code to library
int		rtn,		// i  : Return code from library
int		did,		// i  : SECS Message Device ID
int		xsf,		// i  : SECS Message SF-Code
uint		xid,		// i  : SECS Message Transaction ID
byte[]		xhd,		// i  : SECS Message Header
byte[]		xmsg)		// i  : SECS Message Body
{
  byte[]	hd=new byte[12],msg=new byte[1024];
  string	rname,sname;
  int		len,sf,cmd=0x0000;

  DispData(1,xhd,did,xsf,xid,xmsg,rtn,rtn);

  if      (req== 0 && rtn>=0){
    if((MssgUseFile&0x80)==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     (xsf==(0x8100+ 1)&&OType==0)	SendS1F2H (did,xid);
      else if(xsf==(0x8100+ 1)&&OType==1)	SendS1F2E (did,xid);
      else if(xsf==(0x8100+21))			SendS1F22 (did,xid);
      else if(xsf==(0x8200+49))			SendS2F50 (did,xid);
      else if(xsf==(0x8600+11))			SendS6F12 (did,xid);

    }else if((xsf & 0x8000)!=0){// When using a message definition file, this
				// sample uses automatic reply function.
				// メッセージ定義ファイルを使用する場合は、本サ
				// ンプルでは、自動返信機能を使用する。
      msg=xmsg;
      if((len=TDS._MDMssgAutoRes(Md,0,xhd
		,msg,rtn,1024,out rname,out sname,out sf))	>=0){
	printf("RECV %s ..  Auto respond %s [S%dF%d]\n"
		,__arglist(rname,sname,sf/0x100,sf&0xff));
	if(HeaderBO!=0)	cmd=0x2000;
	if(FuncType==0) rtn=TDS._CommSend(Fd,cmd,did,sf,xid,msg,len,hd);
	else		rtn=TDS._UDrvSend(Fd,cmd,did,sf,xid,msg,len,hd);
	DispData(2,hd,did,sf,xid,msg,len,rtn);
      }else{
	if(len!=(-930) && len!=(-931)){
	  printf("RECV Auto response error (%d)\n",__arglist(len));
  } } } }

  return(0);
}



// -----------------------------------------------------------------------------

private static void
RecvProcThread(
object		param)
{
  byte[]	msg=new byte[1024],hd=new byte[12];
  uint		xid;
  int		rtn,req,cmd,did,sf;

  for(;Break==0;){
    req=0;
    if(HeaderBO	!=0)	cmd=0x2000;
    else		cmd=0x0000;
    if(FuncType==0){
      rtn=TDS._CommRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
    }else{
      rtn=TDS._UDrvRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
    }
    if(rtn==(-951)){
      Thread.Sleep(100);
    }else{
      if((-1000)<rtn && rtn<(-959))	req=(-rtn)-900;
      CBRecvProc(req,rtn,did,sf,xid,hd,msg);
  } }
}



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

static int
Main(
string[]		argv)
{
  int			opt=0;

  // ---------------------------------------------------------------------------
  {				// Display TDS information
    int			bits;	// This code has nothing to do with running TDS.
    string		tvers,svers,tdate,sdate,tcomp,scomp;
    bits=TDS._GetInform(out tvers,out svers,out tdate,out sdate
		      ,out tcomp,out scomp);
    printf("Version = %-20s %-20s\n"	,__arglist(tvers,tvers));
    printf("Date    = %-20s %-20s\n"	,__arglist(tdate,tdate));
    printf("Compile = %-20s %-20s\n"	,__arglist(tcomp,tcomp));
    printf("#of Bit = %d\n"		,__arglist(bits));
  }
  // ---------------------------------------------------------------------------

  // ---------------------------------------------------------------------------
  if(FuncType		!=0)		opt|=0x0001;
  if(HeaderBO		!=0)		opt|=0x0002;
  if(MssgDispType	!=0x00)		opt|=0x0004;
  if(MssgUseNextL	!=0)		opt|=0x0008;
  if(MssgUseFile	!=0x00)		opt|=0x0010;
  if(UseRecvThrd	!=0)		opt|=0x0020;
  if(SyncStatus		!=0)		opt|=0x8000;
  if     (argv.Length>1){	// Analysis of running parameters
    if      (string.Compare(argv[1].Substring(0,1),"x",true)==0){
      opt = Convert.ToInt32(argv[1].Substring(1  ),16);
    }else if(string.Compare(argv[1].Substring(0,1),"0",true)==0 &&
	     string.Compare(argv[1].Substring(1,1),"x",true)==0){
      opt = Convert.ToInt32(argv[1].Substring(2  ),16);
    }else{
      opt = Convert.ToInt32(argv[1]);
    }
    if((opt&0x0001)!=0) FuncType    =1;		else FuncType    =0;
    if((opt&0x0002)!=0) HeaderBO    =1;		else HeaderBO	 =0;
    if((opt&0x0004)!=0) MssgDispType=0x20;	else MssgDispType=0x00;
    if((opt&0x0008)!=0) MssgUseNextL=1;		else MssgUseNextL=0;
    if((opt&0x0010)!=0) MssgUseFile =0x80;	else MssgUseFile =0x00;
    if((opt&0x0020)!=0) UseRecvThrd =1;		else UseRecvThrd =0;
    if((opt&0x8000)!=0) SyncStatus  =1;		else SyncStatus	 =0;
  }
  if(argv.Length>2)	SendWait    =Convert.ToInt32(argv[2]);
  if(argv.Length>3)	SendSleep   =Convert.ToInt32(argv[3]);

  printf("option      =0x%02x,%d\n"		,__arglist(opt,opt));
  printf("FuncType    =%d\n"			,__arglist(FuncType));
  printf("HeaderBO    =%d\n"			,__arglist(HeaderBO));
  printf("MssgDispType=0x%02x\n"		,__arglist(MssgDispType));
  printf("MssgUseNextL=%d\n"			,__arglist(MssgUseNextL));
  printf("MssgUseFile =0x%02x\n"		,__arglist(MssgUseFile));
  printf("UseRecvThrd =%d\n"			,__arglist(UseRecvThrd));
  printf("SyncStatus  =%d\n"			,__arglist(SyncStatus));
  printf("SendWait    =%d\n"			,__arglist(SendWait));
  printf("SendSleep   =%d\n"			,__arglist(SendSleep));
  // ---------------------------------------------------------------------------

  if(argv.Length<1 || (argv[0]!="h" && argv[0]!="e")){
    printf("\nUsage: CSIo {h|e} [option [send_wait [send_sleep]]]\n");
    printf("\n  option\n");
    printf(  "   F           54 3210\n");
    printf(  "  +----+----+----+----+\n");
    printf(  "   |           || |||+-- Function to use\n");
    printf(  "   |           || |||    =0: _TDSCommXxxxx()           1:_TDSUDrvXxxx()\n");
    printf(  "   |           || ||+--- SECS Header Byte order\n");
    printf(  "   |           || ||     =0: System order              1: Network order\n");
    printf(  "   |           || |+---- Format for displaying messages in SECS list format\n");
    printf(  "   |           || |      =0: TDS Format                1: SML Format\n");
    printf(  "   |           || +----- Whether to use MssgNextL() for SECS message display\n");
    printf(  "   |           ||        =0: Not use                   1: Use\n");
    printf(  "   |           |+------- Whether to use the SECS message definition file\n");
    printf(  "   |           |         =0: Not use                   1: Use\n");
    printf(  "   |           +-------- Whether to execute SECS message reception in a dedicated thread\n");
    printf(  "   |                     =0: No                        1: Yes\n");
    printf(  "   +-------------------- Synchronize connection status\n");
    printf(  "                         =0: No                        1: Yes\n");
    printf(  "  send_wait   : Message sending interval     (%5dms)\n",__arglist(SendWait));
    printf(  "  send_sleep  : Wait time                    (%5dms)\n",__arglist(SendSleep));
    printf("\n");
  }else{
    if(argv[0]=="h")	Host ();
    else		Equip();
  }

  return(0);
}



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

private static void
Host()
{
  Thread		th;
  byte[]		hd=new byte[12],msg=new byte[1024];
  uint			xid,xids=0;
  int			did,dids=0;
  int			req,rtn,omd,cmd,mno,sf=0,stat,i;

  OType=0;		Break=0;
  if(SyncStatus	==0)	omd  =0x0002;
  else			omd  =0x1002;
  if(FuncType	==0)	Fd=TDS._CommOpen(omd,PARAMFILE,"HOST");
  else			Fd=TDS._UDrvOpen(omd,PARAMFILE,"HOST",(int)UDRV_MASK);
  if(Fd								< 0) goto Exit;
  printf("(H) Opened (%d)\n",__arglist(Fd));	
  if((MssgUseFile&0x80)!=0) Md=TDS._MDMssgInitialize(0x4000,Fd,"");

  if(UseRecvThrd!=0){
    th=new Thread(new ParameterizedThreadStart(RecvProcThread));
    th.Start("");
  }

  for(;;){		rtn=0;
    if(UseRecvThrd==0)	printf("Req (0:Exit 1:Recv 2:Send) : ");
    else		printf("Req (0:Exit 2:Send 3:Continuous) : ");
  //scanf ("%d",__arglist(out req));
    req=int.Parse(Console.ReadLine());
    if      (req==0){						break;

    }else if(req==1){
      if(HeaderBO!=0)	cmd=0x2000;
      else		cmd=0x0000;
      if(FuncType==0){
	rtn=TDS._CommRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
      }else{
	rtn=TDS._UDrvRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
      }
      if(rtn	>=0){	dids=did;	xids=xid;}
      DispData(1,hd,did,sf,xid,msg,rtn,rtn);

    }else if(req==2){
      if(UseRecvThrd==0){
	printf("Message(1:S1F1 2:S1F21 3:S2F49   6:S1F2 7:S1F22 8:S6F12) : ");
      }else{
	printf("Message(1:S1F1 2:S1F21 3:S2F49) : ");
      }
    //scanf("%d",__arglist(out mno));
      mno=int.Parse(Console.ReadLine());
      switch(mno){
	case 1: rtn=SendS1F1 ();		break;
	case 2: rtn=SendS1F21();		break;
	case 3: rtn=SendS2F49();		break;
	case 6: rtn=SendS1F2H(dids,xids);	break;
	case 7: rtn=SendS1F22(dids,xids);	break;
	case 8: rtn=SendS6F12(dids,xids);	break;
      }

    }else if(req==3){
      for(Break=i=0;Break==0;i++){
	Thread.Sleep(SendWait);
	if(FuncType==0)	stat=TDS._CommStatus(Fd,0);
	else		stat=TDS._UDrvStatus(Fd,0);
	if(stat==3){
	  if((rtn=SendS2F49())	< 0){
	    printf("(H) Send error (%d)\n"
			,__arglist(rtn));	Thread.Sleep(ERROR_SLEEP);
	  }
	  if((i%SEND_NO)		==0)	Thread.Sleep(SendSleep);
      } }
      rtn=0;
    }

    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      printf("(H) I/O Error (%d)\n"	,__arglist(rtn));
  } }

Exit:
  Break=1;
  if(Fd> 0){
    if(FuncType==0)	TDS._CommClose(Fd,0);
    else		TDS._UDrvClose(Fd,0);
  } else		printf("(H) Error (%d)\n"	,__arglist(Fd));
  if(Md> 0)		TDS._MDMssgTerminate(Md,0);
}



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

private static void
Equip()
{
  Thread		th;
  byte[]		hd=new byte[12],msg=new byte[1024];
  uint			xid,xids=0;
  int			did,dids=0;
  int			req,rtn,omd,cmd,mno,sf=0,stat,i;

  OType=1;		Break=0;
  if(SyncStatus	==0)	omd  =0x0002;
  else			omd  =0x1002;
  if(FuncType	==0)	Fd=TDS._CommOpen(omd,PARAMFILE,"EQUIP");
  else			Fd=TDS._UDrvOpen(omd,PARAMFILE,"EQUIP",(int)UDRV_MASK);
  if(Fd								< 0) goto Exit;
  printf("(E) Opened (%d)\n",__arglist(Fd));
  if((MssgUseFile&0x80)!=0) Md=TDS._MDMssgInitialize(0x4000,Fd,"");

  if(UseRecvThrd!=0){
    th=new Thread(new ParameterizedThreadStart(RecvProcThread));
    th.Start("");
  }

  if(SECS_MODE!=0 && FuncType==0){ // In case of HSMS and use TDS._CommXxxxx()
				    // HSMS で TDS._CommXxxxx() 使用の場合
    if(TDS._CommSend(Fd,0x0100,0,0,0,msg,0,hd)			< 0) goto Exit;
    printf("(E) Connected\n");
    if(TDS._CommSend(Fd,0x0200,0,0,0,msg,0,hd)			< 0) goto Exit;
    printf("(E) Selected\n");
  }

  for(;;){		rtn=0;
    if(UseRecvThrd==0)	printf("Req (0:Exit 1:Recv 2:Send) : ");
    else		printf("Req (0:Exit 2:Send 3:Continuous) : ");
  //scanf ("%d",__arglist(out req));
    req=int.Parse(Console.ReadLine());
    if      (req==0){						 break;

    }else if(req==1){
      if(HeaderBO!=0)	cmd=0x2000;
      else		cmd=0x0000;
      if(FuncType==0){
	rtn=TDS._CommRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
      }else{
	rtn=TDS._UDrvRecv(Fd,cmd,out did,out sf,out xid,msg,1024,hd);
      }
      if(rtn	>=0){	dids=did;	xids=xid;}
      DispData(1,hd,did,sf,xid,msg,rtn,rtn);

    }else if(req==2){
      if(UseRecvThrd==0){
	printf("Message(1:S1F1 2:S1F21 3:S6F11   6:S1F2 7:S1F22 8:S2F50) : ");
      }else{
	printf("Message(1:S1F1 2:S1F21 3:S6F11) : ");
      }
    //scanf("%d",__arglist(out mno));
      mno=int.Parse(Console.ReadLine());
      switch(mno){
	case 1: rtn=SendS1F1 ();		break;
	case 2: rtn=SendS1F21();		break;
	case 3: rtn=SendS6F11();		break;
	case 6: rtn=SendS1F2E(dids,xids);	break;
	case 7: rtn=SendS1F22(dids,xids);	break;
	case 8: rtn=SendS2F50(dids,xids);	break;
      }

    }else if(req==3){
      for(Break=i=0;Break==0;i++){
	Thread.Sleep(SendWait);
	if(FuncType==0)	stat=TDS._CommStatus(Fd,0);
	else		stat=TDS._UDrvStatus(Fd,0);
	if(stat==3){
	  if((rtn=SendS6F11())	< 0){
	    printf("(E) Send error (%d)\n"
			,__arglist(rtn));	Thread.Sleep(ERROR_SLEEP);
	  }
	  if((i%SEND_NO)		==0)	Thread.Sleep(SendSleep);
      } }
      rtn=0;
    }

    if(rtn<(-999) || ((-900)<rtn && rtn<0)){
      printf("(E) I/O Error (%d)\n"	,__arglist(rtn));
  } }

  if(SECS_MODE!=0){			// In case of HSMS, Shutdown process
					// HSMS 接続の場合、切断処理
    if(FuncType==0)	rtn=TDS._TDSCommStatus(Fd,0);
    else		rtn=TDS._TDSUDrvStatus(Fd,0);
    if(rtn	==3){
    // Deselect request is not performed. (Of course you may go. However SEMI
    // claims that HSMS-SS does not perform Deselect request.)
    // Deselect request は行わない。 (もちろん行ってもよい。SEMI では HSMS-SS
    // において、Deselect request は行わない、としている。)
    //if(FuncType==0)	rtn=TDS._CommSend(Fd,0x0800,0,0,0,msg,0,hd);
    //else		rtn=TDS._UDrvSend(Fd,0x0800,0,0,0,msg,0,hd);
    //if(rtn							< 0) goto Exit;
    //printf("(E) Deselected\n");
      if(FuncType==0)	rtn=TDS._CommSend(Fd,0x0900,0,0,0,msg,0,hd);
      else		rtn=TDS._UDrvSend(Fd,0x0900,0,0,0,msg,0,hd);
      if(rtn							< 0) goto Exit;
      printf("(E) Separated\n");
  } }

Exit:
  Break=1;
  if(Fd> 0){
    if(FuncType==0)	TDS._CommClose(Fd,0);
    else		TDS._UDrvClose(Fd,0);
  } else		printf("(E) Error (%d)\n",	__arglist(Fd));
  if(Md> 0)		TDS._MDMssgTerminate(Md,0);
}

}
}
