# coding: Shift_JIS
# coding: UTF-8

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


# ==============================================================================
#
# RubyIo : Test and sample program
#
#   Construct a message in AP and simply send and receive SECS messages.
#
#   (Note) In this sample, when making an HSMS connection, it is assumed that
#      the HOST side executes Passive connection and the EQUIP side executes
#      Active connection.
#
#
# Starting method
#
#   ruby RubyIo.rb {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, "RubyIo h" and "RubyIo e" both operate on same machine or
#   different machines to communicate with each other. The communication
#   partner may be another sample AP such as 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 _TDSCommXxxx() 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.
#
#   "FUNC_TYPE" is defined to select type of processing function to be used.
#   If you use _TDSUDrvXxxx(), 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 _TDSwitches 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 _TDSUDrvXxxx() 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.
#
#
# ==============================================================================
#
# RubyIo : テスト 及び サンプル・プログラム
#
#   ＡＰ内でメッセージを構築し、単純に SECS メッセージの送受信を行う。
#
#   (注) 本サンプルでは HSMS 接続する場合、HOST 側が Passive 接続、EQUIP 側が
#      Active 接続を実行すると仮定している。
#
#
# 起動方法
#
#   ruby RubyIo.rb {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
#
#   通常、RubyIo h 及び RubyIo e の両方を、同一マシン、もしくは異なるマシン上で
#   動作させて、相互通信を行う。通信相手は、BasicIo.exe、Callbackio.exe 等、
#   他のサンプルＡＰでもよい。
#
#   起動後、メニュ表示を参照し、要求コード等を入力し、機能を実行する。
# 
#   ホスト側は起動すると、装置側からの接続を待つ。装置側を起動すると、自動的
#   にホスト側に接続要求、Select 要求を発行する。ホスト側では、1:Recv 処理を
#   繰り返し行い、表示が「STATUS=951 : No data」となるのを確認する。その後、
#   任意のメッセージのやりとりを行う。受信側では、受信データの刈り取りを「
#   STATUS=951」になるまで行うことを忘れぬこと。
#
#   ２次メッセージを送信する際のトランザクションＩＤは、直前に受信した１次
#   メッセージのものを使用する。
#
#   本サンプルは、異常時処理を一部省略している。
#
#   以下で定義する "SECS_MODE" は、処理関数として _TDSCommXxxx() を使用する
#   場合で Active 接続の場合の Passive 側への接続処理の実行の有無を判断する
#   ために定義する。
#   (注) この値の変更だけで TDS が SECS1 or HSMS の変更を認識するわけではない。 
#      TDS は SECS1 or HSMS を判断するのは設定ファイル (.ini) の SECSMODE の
#      設定によるので、この値を変更する場合は .ini の SECSMODE の設定変更を
#      しなければならない。
#
#   "FUNC_TYPE" は、使用する処理関数の種別を選択するために定義する。
#   _TDSUDrvXxxx() を使用する場合は、HSMS-SS Active 接続の場合の接続処理を
#   行う必要がないので、本来であれば "SECS_MODE" の設定も必要がない。
#   TDS は、SECS-1 接続 or HSMS-SS 接続の切替は、設定ファイル (.ini) にて行う
#   ため、処理関数として _TDSUDrvXxxx() を使用する限りは、ユーザＡＰでは、
#   接続方式（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 とすると、受信処理を行うスレッドを起動し、そ
#   のスレッド内で受信メッセージの表示、２次メッセージの出力を自動で行う。
#   受信スレッドを使用する場合、入力促進用メッセージに乱れが生じる事に留意
#   すること。
#
# ==============================================================================

require "fiddle/import"

module TDS
  extend Fiddle::Importer
  dlload File.expand_path("TDS.dll")
  extern "int   __TDSCommOpen           (int,char*,char*,int,int,int,int,int,int)"
  extern "int   __TDSCommOpen0          (int,char*,char*)"
  extern "int   __TDSCommClose          (int,int)"
  extern "int   __TDSCommRecv           (int,int,int*,int*,unsigned int*,void*,int,TDSECSHead*)"
  extern "int   __TDSCommSend           (int,int,int ,int ,unsigned int ,void*,int,TDSECSHead*)"
  extern "int   __TDSCommSendError      (int,int,int ,int ,TDSECSHead*,TDSECSHead*,void*)"
  extern "int   __TDSCommSendComment    (int,int,char*,char*,int)"
  extern "int   __TDSCommStatus         (int,int)"
  extern "int   __TDSCommSelectStatus   (int,int,int)"

  extern "int   __TDSErrorValue         (int)"
  extern "int   __TDSErrorPosition      (int)"
  extern "void  __TDSErrorStatus                (int,int*,int*)"
  extern "int   __TDSMssgErrorValue     (int)"
  extern "int   __TDSMssgErrorPosition  (int)"
  extern "void  __TDSMssgErrorStatus    (int,int*,int*)"

  extern "int   __TDSMssgInit           (int,void*,int,int)"
  extern "int   __TDSMssgEnd            (int,int,void*)"
  extern "int   __TDSMssgBuild          (int,int,void*,int,int,void*)"
  extern "int   __TDSMssgBuildL         (int,int,void*,char*)"
  extern "int   __TDSMssgFind           (int,void*,int,int,TDSECSHead*,char*)"
  extern "int   __TDSMssgExit           (int,int,void*)"
  extern "int   __TDSMssgNext           (int,int,void*,int*,int*,int*,void*,int)"
  extern "int   __TDSMssgNextL          (int,int,void*,int*,int*,char*,int)"

  extern "int   __TDSMDMssgInitialize   (int,int,char*)"
  extern "void  __TDSMDMssgTerminate    (int,int)"
  extern "int   __TDSMDMssgInit         (int,int,void*,int,char*)"
  extern "int   __TDSMDMssgEnd          (int,int,void*)"
  extern "int   __TDSMDMssgBuild        (int,int,void*,char*,int,void*)"
  extern "int   __TDSMDMssgFind         (int,int,void*,int,int,char*)"
  extern "int   __TDSMDMssgExit         (int,int,void*)"
  extern "int   __TDSMDMssgNext         (int,int,void*,char*,int,void*)"
  extern "int   __TDSMDMssgNextEx       (int,int,void*,char*,int,void*,int*,int*)"
  extern "int   __TDSMDMssgNextL        (int,int,void*,int*,int*,char*,int)"
  extern "int   __TDSMDMssgAutoRes      (int,int,TDSECSHead*,void*,int,int,char*,char*,int*)"

  extern "int   __TDSUDrvOpen           (int,char*,char*,unsigned int)"
  extern "int   __TDSUDrvClose          (int,int)"
  extern "int   __TDSUDrvRecv           (int,int,int*,int*,unsigned int*,void*,int,TDSECSHead*)"
  extern "int   __TDSUDrvSend           (int,int,int ,int ,unsigned int ,void*,int,TDSECSHead*)"
  extern "int   __TDSUDrvSendError      (int,int,int ,int ,TDSECSHead*,TDSECSHead*,void*)"
  extern "int   __TDSUDrvSendComment    (int,int,char*,char*,int)"
  extern "int   __TDSUDrvStatus         (int,int)"
  extern "int   __TDSUDrvSelectStatus   (int,int,int)"

  VSI1 =struct( ["char                  sc",])
  VUI1 =struct( ["unsigned char         uc",])
  VSI2 =struct( ["short                 ss",])
  VUI2 =struct( ["unsigned short        us",])
  VSI4 =struct( ["int                   si",])
  VUI4 =struct( ["unsigned int          ui",])
  VSI8 =struct( ["long long             sl",])
  VUI8 =struct( ["unsigned long long    ul",])
  SHead=struct( ["unsigned short        did"	\
		,"unsigned char         scd"	\
		,"unsigned char         fcd"	\
		,"unsigned char         ptp"	\
		,"unsigned char         stp"	\
		,"unsigned short        sid"	\
		,"unsigned short        xid",])
end



# ------------------------------------------------------------------------------

E_BADF		=9
E_BUSY		=16
E_NOMEM 	=12
E_NODEV 	=19
E_2BIG		=7

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


# ------------------------------------------------------------------------------

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

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

MSSG_USE_FILE	=0x00		# Message definition file
				# 0x00 : Not use
				# 0x80 : Use to display item names
				#	  使用して項目名表示する
USE_RECVTHREAD	=1		# Use of Callback function
				# 0    : Not use
				# 1    : Use

SYNC_STATUS	=1		# Synchronize connection status
				# 接続状態の同期
				# 0    : No
				# 1    : Yes

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

PARAMFILE	="Sample.ini"


# ------------------------------------------------------------------------------

$FuncType	=FUNC_TYPE	# ARGV[1]&0x0001
$HeaderBO	=HEADER_BO	# ARGV[1]&0x0002
$MssgDispType	=MSSG_DISP_TYPE # ARGV[1]&0x0004
$MssgUseNextL	=MSSG_USE_NEXTL # ARGV[1]&0x0008
$MssgUseFile	=MSSG_USE_FILE	# ARGV[1]&0x0010
$UseRecvThrd	=USE_RECVTHREAD # ARGV[1]&0x0020
$SyncStatus	=SYNC_STATUS	# ARGV[1]&0x8000

$SendWait	=SEND_WAIT	# ARGV[2]
$SendSleep	=SEND_SLEEP	# ARGV[3]


$Fd		=0		# Communication identifier
$Md		=0		# Message analysis identifier
$OType		=0		# Operation type  (0:Host  1:Equipment)
$Break		=0		# End instruction to thread
				# スレッド終了指示

$cnt249 	=0
$cnt250 	=0
$cnt611 	=0

$Cs1		=Mutex.new


# ==============================================================================
# Common functions =============================================================


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

def DispSECSMssg(		#
		tp,		# i  : Message type
				#	=0 : Transmission result
				#	 1 : Received message
				#	 2 : Send message
		hd,		# i  : SECS Message Header
		did,		# i  : SECS Message Device ID
		sf,		# i  : SECS Message SF-Code
		xid,		# i  : SECS Message Transaction ID
		msg,		# i  : SECS Message strage area
				#	     (Header not included)
		len)		# i  : SECS Message byte length

  ctp		=["SRES","RECV","SEND"]
  form		=TDS::VUI4.malloc
  sz		=TDS::VSI4.malloc
  noi		=TDS::VSI4.malloc
  str		="\0"*512
  mname 	="\0"*32
  item		="\0"*256

  md  =0;	dp=$MssgUseFile|$MssgDispType
  rbit=" ";	if (did&0x8000)!=0 then rbit="R"	end
  wbit=" ";	if (sf &0x8000)!=0 then wbit="W"	end
  if did<0 then sdid=sprintf("%6d"    ,did)
  else		sdid=sprintf("0x%04x" ,did)
  end
  sfcode=sprintf("S%dF%d",(sf&0x7f00)/0x0100,sf&0xff)
  if	hd.is_a?(String) then
    hv	=hd.unpack("C10");
    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" \
	,ctp[tp],sdid,sfcode,rbit,wbit,(xid>>16)&0xffff,xid&0xffff,len	\
	,hv[0],hv[1],hv[2],hv[3],hv[4],hv[5],hv[6],hv[7],hv[8],hv[9])
  elsif hd.is_a?(TDS::SHead) then
    printf("[%s]  Dev=%-6s  %-8s  %s%s  XId=0x%04x.%04x  Len=%4d"  \
	   +"  Head:did=0x%04x sf=0x%02x%02x ptp=0x%02x,%02x txid=0x%04x,%04x\n" \
	,ctp[tp],sdid,sfcode,rbit,wbit,(xid>>16)&0xffff,xid&0xffff,len	\
	,hd.did,hd.scd,hd.fcd,hd.ptp,hd.stp,hd.sid,hd.xid)
  else
    printf("[%s]  Dev=0x%04x  %-8s  %s%s  XId=0x%04x.%04x  Len=%4d\n"  \
	,ctp[tp],did,sfcode,rbit,wbit,(xid>>16)&0xffff,xid&0xffff,len)
  end

  if ($MssgUseFile&0x80)!=0 then	fm =0x8000	# Use message definition file
  else					fm =0x0000	# Not use
  end

  if len>0   then
    if tp==1 then	dp|=0x3000;	fm|=0x3000	# In case of receiving
    else		dp|=0x2000;	fm|=0x2000	# In case of sending
    end

    md=TDS.__TDSMssgFind(fm,msg,len,$Fd,hd,mname)
    if md	> 0	then
      ln=mname.index("\0")
      if ln>0 then	printf("[%s]\n",mname[0,ln])	# Message name
      end

      la=0
      while true do
	if $MssgUseNextL==0 then	# Get item value
	  rtn=TDS.__TDSMssgNext(md,0,msg,form,sz,noi,item,256)
	  form.ui&=0o077
	  if rtn< 0 then		break		end
	  printf("%03o:%d*%3d:",form.ui,sz.si,noi.si)
	  case form.ui			# Display of field value
	  when 0o000 then			printf("L [%2d]\n"	,noi.si)
	  when 0o010 then vb=item.unpack("C*"); printf("B [%2d]=0x"	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%02x "	,vb[i]) end;	printf("\n")
	  when 0o011 then vb=item.unpack("C*"); printf("T [%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%d "	,vb[i]) end;	printf("\n")
	  when 0o020 then va=item.unpack("Z*"); printf("A [%2d]=%s\n"	,noi.si,va[0])
	  when 0o021 then va=item.unpack("Z*"); printf("J [%2d]=%s\n"	,noi.si,va[0])
	  when 0o022 then va=item.unpack("Z*"); printf("K [%2d]=%s\n"	,noi.si,va[0])
	  when 0o030 then vi=item.unpack("q*"); printf("I8[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%d "	,vi[i]) end;	printf("\n")
	  when 0o031 then vi=item.unpack("c*"); printf("I1[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%d "	,vi[i]) end;	printf("\n")
	  when 0o032 then vi=item.unpack("s*"); printf("I2[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%d "	,vi[i]) end;	printf("\n")
	  when 0o034 then vi=item.unpack("l*"); printf("I4[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%d "	,vi[i]) end;	printf("\n")
	  when 0o040 then vf=item.unpack("d*"); printf("F8[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%e "	,vf[i]) end;	printf("\n")
	  when 0o044 then vf=item.unpack("f*"); printf("F4[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%e "	,vf[i]) end;	printf("\n")
	  when 0o050 then vu=item.unpack("Q*"); printf("U8[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%u "	,vu[i]) end;	printf("\n")
	  when 0o051 then vu=item.unpack("C*"); printf("U1[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%u "	,vu[i]) end;	printf("\n")
	  when 0o052 then vu=item.unpack("S*"); printf("U2[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%u "	,vu[i]) end;	printf("\n")
	  when 0o054 then vu=item.unpack("L*"); printf("U4[%2d]="	,noi.si)
	    for i in 0..(noi.si-1) do	printf("%u "	,vu[i]) end;	printf("\n")
	  else					printf("\n")
	  end

	else						# Get in list format
							# リスト表示形式で取得
	  rtn=TDS.__TDSMssgNextL(md,dp,msg,form,noi,str,512)
	  form.ui&=0o077
	  if  rtn	< 0	then	break		end
	  if (dp&0x70)	> 0x10	then			# In case of SML
	    i=la
	    while i>rtn do
	      printf("%*s>\n"	,i*2,"")		# Display '>' 
	      i-=1
	    end
	  end
	  la=rtn					# Save current hierarchy
							# 現在の階層を保存
	  printf("  %s\n"	,str.unpack("Z*")[0])	# Display acquired field value
							# 取得した項目値を表示
	  if (dp&0x70)>0x10 && form.ui==000 && noi.si==0 then
	    printf("%*s>\n"	,(la+1)*2,"")		# '>' Processing for L0
	  end						# L0 の場合の '>' 処理
	end
      end

      if $MssgUseNextL	!=0	then
	if (dp&0x70)	> 0x10	then
	   i=la
	   while i>0 do
	     printf("%*s>\n"	,i*2,"")		# Show remaining '>'
	     i-=1					# 残りの '>' 表示
	   end
	end
      end
      TDS.__TDSMssgExit(md,0,msg)
    end

    if ($MssgUseFile&0x80)!=0  &&  $MssgUseNextL!=0 then
		# Refer to the comment in corresponding section of SubFuncsion.h
		# SubFuncsion.h の該当箇所のコメントを参照すること
      sf&=0x7fff
      rtn=TDS.__TDSMDMssgFind($Md,0,msg,len,sf,mname)
      if rtn	      >0 then
	ln=mname.index("\0")
	printf("Message Definition Name = '%s'\n"	,mname[0,ln])

	if    sf==0x0115 then			# S1F21
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"VB"	, 0,item)
	  if no0>=0 then  vb=item.unpack("C*")
	    printf("VB          [%2d]=0x"	,no0)
	    for i in 0..no0-1 do  printf("%02x ",vb[i]);  end;	printf("\n")
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"MDLN"	, 0,item)
	  if no0>=0 then  va=item.unpack("Z*")
	    printf("MDLN        [%2d]='%s'\n"	,no0	,va[0])
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"VI4"	, 0,item)
	  if no0>=0 then  vi=item.unpack("l*")
	    printf("VI4         [%2d]=" 	,no0)
	    for i in 0..no0-1 do  printf("%d "	,vi[i]);  end;	printf("\n")
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"VF4"	, 0,item)
	  if no0>=0 then  vf=item.unpack("f*")
	    printf("VF4         [%2d]=" 	,no0)
	    for i in 0..no0-1 do  printf("%e "	,vf[i]);  end;	printf("\n")
	  end

	elsif sf==0x0116 then			# S1F22
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"VT"	, 0,item)
	  if no0>=0 then  vb=item.unpack("C*")
	    printf("VT          [%2d]=0x"	,no0)
	    for i in 0..no0-1 do  printf("%02x ",vb[i]);  end;	printf("\n")
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"COMMENT"	, 0,item)
	  if no0>=0 then  va=item.unpack("Z*")
	    printf("COMMENT     [%2d]='%s'\n"	,no0	,va[0])
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"AU8"	, 0,item)
	  if no0>=0 then  vu=item.unpack("Q*")
	    printf("AU8         [%2d]=" 	,no0)
	    for i in 0..no0-1 do  printf("%u "	,vu[i]);  end;	printf("\n")
	  end
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"VF8"	, 0,item)
	  if no0>=0 then  vf=item.unpack("d*")
	    printf("VF8         [%2d]=" 	,no0)
	    for i in 0..no0-1 do  printf("%e "	,vf[i]);  end;	printf("\n")
	  end

	elsif sf==0x0231 then			# S2F49
	  rtn=TDS.__TDSMDMssgNext($Md,0,msg,"NOI1"	, 0,item)
	  if rtn> 0 then  vi=item.unpack("l*"); no1=vi[0]
	    printf("NOI1        [%2d]\n"	,no1)
	    for i in 0..no1-1 do
	      iname=sprintf("NOI2:%d"		,i+1)
		# Refer to the comment in corresponding section of SubFuncsion.h
		# SubFuncsion.h の該当箇所のコメントを参照すること
	      rtn=TDS.__TDSMDMssgNext($Md,0,msg,iname	, 0,item)
	      if rtn> 0 then  vi=item.unpack("l*"); no2=vi[0]
		printf("%-12s[%2d]\n"		,iname,no2)
		for j in 0..no2-1 do
		  iname=sprintf("WAFERID:%d:%d" ,i+1,j+1)
		  no0=TDS.__TDSMDMssgNext($Md,0,msg,iname, 0,item)
		  if no0>=0 then  va=item.unpack("Z*")
		    printf("%-12s[%2d]=\"%s\"\n",iname,no0,va[0])
		  end
		end
	      end
	    end
	  end

	elsif sf==0x060b then			# S6F11
	  no0=TDS.__TDSMDMssgNext($Md,0,msg,"DATAID"	, 0,item)
	  if no0>=0 then  vi=item.unpack("s*")
	    printf("DATAIDB     [%2d]=" 	,no0)
	    for i in 0..no0-1 do  printf("%d "	,vi[i]);  end;	printf("\n")
	  end
	end 
	TDS.__TDSMDMssgExit($Md,0,msg)
      end
    end
  end

end



# ------------------------------------------------------------------------------
# Display sent and received data -----------------------------------------------

def	DispData(
		tp,		# i  : Message type
				#	=0 : Transmission result
				#	 1 : Received message
				#	 2 : Send message
		hd,		# i  : SECS Message Header
		did,		# i  : SECS Message Device ID
		sf,		# i  : SECS Message SF-Code
		xid,		# i  : SECS Message Transaction ID
		msg,		# i  : SECS Message Body
		len,		# i  : Byte length of 'msg'
		rtn)		# i  : I/O return value

  ok=0

  $Cs1.lock
  if rtn<0 then
    ok=1
    if (rtn<(-E_NOTCONNECT) || (-E_ILLBLOCK)<rtn) && rtn!=(-E_NODATA) then
      printf("ERROR  [%d]"			,rtn)
      if    rtn==(-E_NODEV) then
	printf(" : No such device ID\n");	len=ok=0
      elsif rtn==(-E_2BIG ) then
	printf(" : Data size to large\n");	len=ok=0
      else			printf("\n")
      end

    else
      if $FuncType==0 then	stat=TDS.__TDSCommStatus($Fd,0)
      else			stat=TDS.__TDSUDrvStatus($Fd,0)
      end
      printf("STATUS = %d,%d : "		,-rtn,stat)
      case -rtn
      when E_NODATA	then	printf("No data\n")
      when E_ILLBLOCK	then	printf("Illegal block#\n")
      when E_T1TIMEDOUT then	printf("T1 Timeout occur\n")
      when E_T2TIMEDOUT then	printf("T2 Timeout occur\n")
      when E_T3TIMEDOUT then	printf("T3 Timeout occur\n")
      when E_T4TIMEDOUT then	printf("T4 Timeout occur\n")
      when E_T5TIMEDOUT then	printf("T5 Timeout occur\n")
      when E_T6TIMEDOUT then	printf("T6 Timeout occur\n")
      when E_T7TIMEDOUT then	printf("T7 Timeout occur\n")
      when E_T8TIMEDOUT then	printf("T8 Timeout occur\n")
      when E_RETRYOVER	then	printf("Retry over\n")
      when E_CONNECT	then	printf("Connected\n")
      when E_SELECT	then	printf("Selected   (0x%04x)\n" ,did)
      when E_REJECT	then	printf("Rejected XId=0x%04x\n" ,xid)
      when E_DESELECT	then	printf("Deselected (0x%04x)\n" ,did)
      when E_SEPARATE	then	printf("Separated  (0x%04x)\n" ,did)
      when E_NOTCONNECT then	printf("Not connected\n")
      else			printf("\n")
      end
    end
  end

  if ok==0 then DispSECSMssg(tp,hd,did,sf,xid,msg,len)	end
  $Cs1.unlock
end



# ==============================================================================
# S1F1 message construction and sending ----------------------------------------

def SendS1F1()
# hd =TDS::SHead.malloc
  hd ="\0"*16
  msg="\0"*16
  sf =0x8101
  cmd=0x0000
  len=0

  if $HeaderBO!=0 then	cmd=0x2000  end
  if $FuncType==0 then	rtn=TDS.__TDSCommSend($Fd,cmd, -1,sf,  0,msg,len,hd)
  else			rtn=TDS.__TDSUDrvSend($Fd,cmd, -1,sf,  0,msg,len,hd)
  end
  DispData(2,hd, -1,sf,rtn,msg,len,rtn)

  return rtn
end


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

def SendS1F2H(
		did,
		xid)
# hd =TDS::SHead.malloc
  hd ="\0"* 16
  msg="\0"*256
  sf =0x0102
  cmd=0x0000
  
  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md =	TDS.__TDSMssgInit(	0,msg, 256,$Fd) 		# S1F2
		TDS.__TDSMssgBuild(  md,0,msg,0x00,  0,0)		# L0
    len=	TDS.__TDSMssgEnd(    md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit($Md,0,msg, 256,"S1F2_H")
    len=	TDS.__TDSMDMssgEnd( $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd,did,sf,xid,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd,did,sf,xid,msg,len,hd)
    end
  end
  DispData(2,hd,did,sf,rtn,msg,len,rtn)

  return rtn
end


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

def SendS1F2E(
		did,
		xid)
  hd =TDS::SHead.malloc
# hd ="\0"* 16
  msg="\0"*256
  sf =0x0102
  cmd=0x0000
  
  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md =	TDS.__TDSMssgInit(	0,msg,	256,$Fd)		# S1F2
		TDS.__TDSMssgBuild(  md,0,msg,0o000,  2,0)		# L2
		TDS.__TDSMssgBuild(  md,0,msg,0o020,  6,"EQUIP1")	#  MDLN
		TDS.__TDSMssgBuild(  md,0,msg,0o020,  6,"01.000")	#  SOFTREV
    len=	TDS.__TDSMssgEnd(    md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit($Md,0,msg,	256,"S1F2_E")
    len=	TDS.__TDSMDMssgEnd( $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd,did,sf,xid,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd,did,sf,xid,msg,len,hd)
    end
  end
  DispData(2,hd,did,sf,rtn,msg,len,rtn)

  return rtn
end


# ==============================================================================
# S1F21 message construction and sending ---------------------------------------

def SendS1F21()
  vb =[ 		     1, 		     0xff	].pack('C*')
  vt =[ 		     0, 			1	].pack('C*')
  vs0=["MSG91"							].pack('Z*')
  vs1=["ｿﾌﾄ 09" 						].pack('Z*')
  vs2=["これは ｺﾒﾝﾄ (RubyIo) です"				].pack('Z*')
  vi1=[ 		     2, 		     -128	].pack('c*')
  vi2=[ 		 32767, 		   -32768	].pack('s*')
  vi4=[ 	    0x7ffffffe, 	       0xfffffffe	].pack('l*')
  vi8=[     0x7fffffffffffffff,        0x800080008000800b	].pack('q*')
  vu1=[ 		  0x7f, 		     0xff	].pack('C*')
  vu2=[ 		0x7ffe, 		   0xfffe	].pack('S*')
  vu4=[ 	    0x7ffffffd, 	       0xfffffffd	].pack('L*')
  vu8=[     0x7fffffffffffffff,        0x800080008000800b	].pack('Q*')
  au8=[  7, -6,  5, -4,  3, -2,  1,  0				].pack('Q*')
  vf4=[ 	9.87654321e-21, 	  -8.642097531e13	].pack('f*')
  vf8=[-1.9283746574839201e123,9.1827364546372819208e-213	].pack('d*')

# hd =TDS::SHead.malloc
  hd ="\0"* 16
  msg="\0"*1024
  sf =0x8100+21
  cmd=0x0000

  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg, 1024,$Fd)		# S1F21
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  4,0)		# L4
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#  L2
		TDS.__TDSMssgBuild(   md,0,msg,0o010,  2,vb)		#   VB
		TDS.__TDSMssgBuild(   md,0,msg,0o011,  2,vt)		#   VT
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  3,0)		#  L3
		TDS.__TDSMssgBuild(   md,0,msg,0o020,  6,vs0)		#   MDLN
		TDS.__TDSMssgBuild(   md,0,msg,0o021,  0,vs1)		#   SOFTREV
		TDS.__TDSMssgBuild(   md,0,msg,0o022,  0,vs2)		#   COMMENT
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  9,0)		#  L9
		TDS.__TDSMssgBuild(   md,0,msg,0o031,  2,vi1)		#   VI1
		TDS.__TDSMssgBuild(   md,0,msg,0o032,  2,vi2)		#   VI2
		TDS.__TDSMssgBuild(   md,0,msg,0o034,  2,vi4)		#   VI4
		TDS.__TDSMssgBuild(   md,0,msg,0o030,  2,vi8)		#   VI8
		TDS.__TDSMssgBuild(   md,0,msg,0o051,  2,vu1)		#   VU1
		TDS.__TDSMssgBuild(   md,0,msg,0o052,  2,vu2)		#   VU2
		TDS.__TDSMssgBuild(   md,0,msg,0o054,  2,vu4)		#   VU4
		TDS.__TDSMssgBuild(   md,0,msg,0o050,  2,vu8)		#   VU8
		TDS.__TDSMssgBuild(   md,0,msg,0o050,  8,au8)		#   AU8
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#  L2
		TDS.__TDSMssgBuild(   md,0,msg,0o044,  2,vf4)		#   VF4
		TDS.__TDSMssgBuild(   md,0,msg,0o040,  2,vf8)		#   VF8
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg, 1024,"S1F21_HE")
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    end
  end
  DispData(2,hd, -1,sf,rtn,msg,len,rtn)

  return rtn
end


# ------------------------------------------------------------------------------
# S1F22 message construction and sending ---------------------------------------

def SendS1F22(
		did,
		xid)
  vb =[ 		     2, 		      0xfe	].pack('C*')
  vt =[ 		     1, 			 0	].pack('C*')
  vs0=["MSG92"							].pack('Z*')
  vs1=["ﾚﾋﾞｼﾞｮﾝ"						].pack('Z*')
  vs2=["This is コメント (RubyIo)"				].pack('Z*')
  vi1=[ 		   127, 			-2	].pack('c*')
  vi2=[ 		 32766, 		    -32768	].pack('s*')
  vi4=[ 	    2147483646, 	       -2147483647	].pack('l*')
  vi8=[     0x8000000000000000, 	0x7ffffffffffffffe	].pack('q*')
  vu1=[ 		   254, 		      0xff	].pack('C*')
  vu2=[ 		 65534, 		    0xffff	].pack('S*')
  vu4=[ 	    4294967294, 		0xffffffff	].pack('L*')
  vu8=[   18446744073709551614, 	0xffffffffffffffff	].pack('Q*')
  au8=[ -1,  2, -3,  4, -5,  6, -7,  0				].pack('Q*')
  vf4=[ 	7.89012345e-12, 	   -4.321098765e31	].pack('f*')
  vf8=[ 5.6473829101928374e189,-3.2109876543210987654e-179	].pack('d*')

# hd =TDS::SHead.malloc
  hd ="\0"*  16
  msg="\0"*1024
  sf =0x0100+22
  cmd=0x0000
  
  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg, 1024,$Fd)		# S1F22
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  4,0)		# L4
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#  L2
		TDS.__TDSMssgBuild(   md,0,msg,0o010,  2,vb)		#   VB
		TDS.__TDSMssgBuild(   md,0,msg,0o011,  2,vt)		#   VT
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  3,0)		#  L3
		TDS.__TDSMssgBuild(   md,0,msg,0o020,  6,vs0)		#   MDLN
		TDS.__TDSMssgBuild(   md,0,msg,0o021,  0,vs1)		#   SOFTREV
		TDS.__TDSMssgBuild(   md,0,msg,0o022,  0,vs2)		#   COMMENT
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  9,0)		#  L9
		TDS.__TDSMssgBuild(   md,0,msg,0o031,  2,vi1)		#   VI1
		TDS.__TDSMssgBuild(   md,0,msg,0o032,  2,vi2)		#   VI2
		TDS.__TDSMssgBuild(   md,0,msg,0o034,  2,vi4)		#   VI4
		TDS.__TDSMssgBuild(   md,0,msg,0o030,  2,vi8)		#   VI8
		TDS.__TDSMssgBuild(   md,0,msg,0o051,  2,vu1)		#   VU1
		TDS.__TDSMssgBuild(   md,0,msg,0o052,  2,vu2)		#   VU2
		TDS.__TDSMssgBuild(   md,0,msg,0o054,  2,vu4)		#   VU4
		TDS.__TDSMssgBuild(   md,0,msg,0o050,  2,vu8)		#   VU8
		TDS.__TDSMssgBuild(   md,0,msg,0o050,  8,au8)		#   AU8
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#  L2
		TDS.__TDSMssgBuild(   md,0,msg,0o044,  2,vf4)		#   VF4
		TDS.__TDSMssgBuild(   md,0,msg,0o040,  2,vf8)		#   VF8
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg,  256,"S1F22_HE")
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd,did,sf,xid,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd,did,sf,xid,msg,len,hd)
    end
  end
  DispData(2,hd,did,sf,rtn,msg,len,rtn)

  return rtn
end


# ==============================================================================
# S2F49 message construction and sending ---------------------------------------

def SendS2F49()
# hd =TDS::SHead.malloc
  hd ="\0"*  16
  vu1=TDS::VUI1.malloc
  vu4=TDS::VUI4.malloc
  msg="\0"*1024
  sf =0x8200+49
  cmd=0x0000

  $cnt249+=1
  str=sprintf("LOTID (%4d)",$cnt249)
  no1=($cnt249%2)+1;	no2=($cnt249%10)+1
  
  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg, 1024,$Fd)		# S2F49
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  3,0)		# L3
    vu1.uc=0;	TDS.__TDSMssgBuild(   md,0,msg,0o010,  1,vu1)		#  DATAIDB
		TDS.__TDSMssgBuild(   md,0,msg,0o020,  0,"LOAD")	#  RCMD
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  4,0)		#  L4
    vu1.uc=1;	TDS.__TDSMssgBuild(   md,0,msg,0o010,  1,vu1)		#   STID
    vu1.uc=0;	TDS.__TDSMssgBuild(   md,0,msg,0o010,  1,vu1)		#   MTKD
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 20,str)		#   LOTID
		TDS.__TDSMssgBuild(   md,0,msg,0o000,no1,0)		#   L[no1]
    i=0
    while i<no1 do
		TDS.__TDSMssgBuild(   md,0,msg,0o000,no2,0)		#    L[no2]
      j=0
      while j<no2 do
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#     L[2]
	str=sprintf("WAFER(%04d-%d-%02d)",$cnt249	,i+1,j+1)
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 20,str)		#      WAFERID
	str=sprintf("PPID (%04d-%d-%02d)",$cnt249	,i+1,j+1)
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 16,str)		#      PPID
	j+=1
      end
      i+=1
    end
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg, 1024,"S2F49_H")
		TDS.__TDSMDMssgBuild($Md,0,msg,"LOTID",0,str)		#   LOTID
    vu4.ui=no1; TDS.__TDSMDMssgBuild($Md,0,msg,"NOI1" ,1,vu4)		#   L[no1]
    i=0
    while i<no1 do
      itm	=sprintf("NOI2:%d"			,i+1)
      vu4.ui=no2
		TDS.__TDSMDMssgBuild($Md,0,msg,itm    ,1,vu4)		#    L[no2]
      j=0
      while j<no2 do
	itm=sprintf("WAFERID:%d:%d"			,i+1,j+1)
	str=sprintf("WAFER[%04d-%d-%02d]",$cnt249	,i+1,j+1)
		TDS.__TDSMDMssgBuild($Md,0,msg,itm    ,0,str)		#     WAFERID
	itm=sprintf("PPID:%d:%d"			,i+1,j+1)
	str=sprintf("PPID [%04d-%d-%02d]",$cnt249	,i+1,j+1)
		TDS.__TDSMDMssgBuild($Md,0,msg,itm    ,0,str)		#     PPID
	j+=1
      end
      i+=1
    end
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    end
  end
  DispData(2,hd, -1,sf,rtn,msg,len,rtn)

  return rtn
end


# ------------------------------------------------------------------------------
# S2F50 message construction and sending ---------------------------------------

def SendS2F50(
		did,
		xid)
# hd =TDS::SHead.malloc
  hd ="\0"* 16
  vu1=TDS::VUI1.malloc
  msg="\0"*256
  sf =0x0200+50
  cmd=0x0000
  
  str=sprintf("LOTID (%4d)"	,$cnt250+=1)

  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg,  256,$Fd)		# S2F50
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		# L2
    vu1.uc=0;	TDS.__TDSMssgBuild(   md,0,msg,0o010,  1,vu1)		#  HCACK
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  2,0)		#  L2
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 16,"PPID")	#   PPID
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 20,str)		#   LOTID
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg,  256,"S2F50_E")
		TDS.__TDSMDMssgBuild($Md,0,msg,"LOTID",  0,str) 	#   LOTID
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd,did,sf,xid,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd,did,sf,xid,msg,len,hd)
    end
  end
  DispData(2,hd,did,sf,rtn,msg,len,rtn)

  return rtn
end


# ==============================================================================
# S6F11 message construction and sending ---------------------------------------

def SendS6F11()
# hd =TDS::SHead.malloc
  hd ="\0"* 16
  vu2=TDS::VUI2.malloc
  msg="\0"*256
  sf =0x8600+11
  cmd=0x0000

  $cnt611+=1;	if $cnt611==65536 then	$cnt611=0	end

  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg,  256,$Fd)		# S6F11
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  3,0)		# L3
    vu2.us=$cnt611
		TDS.__TDSMssgBuild(   md,0,msg,0o052,  1,vu2)		#  DATAID
    vu2.us=8;	TDS.__TDSMssgBuild(   md,0,msg,0o052,  1,vu2)		#  CEID
		TDS.__TDSMssgBuild(   md,0,msg,0o000,  3,0)		#  L3
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 16,"DATA1")	#   DATA1
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 16,"DATA2")	#   DATA2
		TDS.__TDSMssgBuild(   md,0,msg,0o020, 14,"YYYYMMDDhhmmss")
			# @TIME Actually I set current time, but omitted.
			# @TIME (本当は現在時刻を設定するのだが、省略。
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg,  256,"S6F11_E0")
    vu2.us=$cnt611
		TDS.__TDSMDMssgBuild($Md,0,msg,"DATAID",1,vu2); 	#  DATAID
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd, -1,sf,	0,msg,len,hd)
    end
  end
  DispData(2,hd, -1,sf,rtn,msg,len,rtn)

  return rtn
end



# ------------------------------------------------------------------------------
# S6F12 message construction and sending ---------------------------------------

def SendS6F12(
		did,
		xid)
# hd =TDS::SHead.malloc
  hd ="\0"* 16
  vu1=TDS::VUI1.malloc
  msg="\0"*256
  sf =0x0600+12
  cmd=0x0000

  if ($MssgUseFile&0x80)==0 then		# Do not use message definition
    md= 	TDS.__TDSMssgInit(	 0,msg,  256,$Fd)		# S6F12
    vu1.uc=0;	TDS.__TDSMssgBuild(   md,0,msg,0o010,  1,vu1)		# ACKC
    len=	TDS.__TDSMssgEnd(     md,0,msg)

  else						# Use message definition
		TDS.__TDSMDMssgInit( $Md,0,msg,  256,"S6F12_H")
    len=	TDS.__TDSMDMssgEnd(  $Md,0,msg)
  end

  if len<0	then rtn=len
  else
    if $HeaderBO!=0 then  cmd=0x2000  end
    if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,cmd,did,sf,xid,msg,len,hd)
    else		 rtn=TDS.__TDSUDrvSend($Fd,cmd,did,sf,xid,msg,len,hd)
    end
  end
  DispData(2,hd,did,sf,rtn,msg,len,rtn)

  return rtn
end



# ==============================================================================
# Callback function ============================================================

def CBRecvProc(
		req,		# i  : Request code to library
		rtn,		# i  : Return code from library
		did,		# i  : SECS Message Device ID
		xsf,		# i  : SECS Message SF-Code
		xid,		# i  : SECS Message Transaction ID
		xhd,		# i  : SECS Message Header
		xmsg)		# i  : SECS Message Body
# hd   =TDS::SHead.malloc
  hd   ="\0"*16
  vu4  =TDS::VUI4.malloc
  rname="\0"*32
  sname="\0"*32
  msg  ="\0"*1024
  cmd  =0x0000

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

  if req==0 && rtn>=0 then
    if ($MssgUseFile&0x80)==0 then
		# 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==0x8101 && $OType==0	then SendS1F2H(did,xid)
      elsif xsf==0x8101 && $OType==1	then SendS1F2E(did,xid)
      elsif xsf==0x8115 		then SendS1F22(did,xid)
      elsif xsf==0x8231 		then SendS2F50(did,xid)
      elsif xsf==0x860b 		then SendS6F12(did,xid)
      end

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

  return 0
end



# ------------------------------------------------------------------------------

def RecvProcThread()
# hd =TDS::SHead.malloc
  hd ="\0"*16
  did=TDS::VUI4.malloc
  xid=TDS::VUI4.malloc
  sf =TDS::VUI4.malloc
  msg="\0"*1024

  while $Break==0 do
    req=0
    if $HeaderBO!=0 then  cmd=0x2000
    else		  cmd=0x0000
    end
    if $FuncType==0 then
      rtn=TDS.__TDSCommRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
    else
      rtn=TDS.__TDSUDrvRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
    end
    if rtn==(-951) then
      sleep(0.1)
    else
      if (-1000)<rtn && rtn<(-959) then req=(-rtn)-900	end
      CBRecvProc(req,rtn,did.ui,sf.ui,xid.ui,hd,msg)
    end
  end
end



# ==============================================================================
# Host side process ------------------------------------------------------------

def Host()
# hd =TDS::SHead.malloc
  hd ="\0"*16
  did=TDS::VUI4.malloc
  xid=TDS::VUI4.malloc
  sf =TDS::VUI4.malloc
  msg="\0"*1024

  catch :Exit do
  $OType=0;		 $Break=0
  if $SyncStatus==0 then omd=0x0002
  else			 omd=0x1002
  end
  if $FuncType	==0 then $Fd=TDS.__TDSCommOpen(omd,PARAMFILE,"HOST",0,0,0,0,0,0)
  else			 $Fd=TDS.__TDSUDrvOpen(omd,PARAMFILE,"HOST",UDRV_MASK)
  end
  if $Fd					< 0 then	throw :Exit end
  printf("(H) Opened (%d)\n",$Fd)
  if ($MssgUseFile&0x80)!=0 then
    $Md=TDS.__TDSMDMssgInitialize(0x4000,$Fd,"")
  end

  if $UseRecvThrd!=0 then
    th=Thread.start{
      RecvProcThread()
    }
  end

  while true do
    rtn=0
    if $UseRecvThrd==0 then	printf("Req (0:Exit 1:Recv 2:Send) : ")
    else			printf("Req (0:Exit 2:Send 3:Continuous) : ")
    end
    req=$stdin.gets.to_i
    if	  req==0 then						break

    elsif req==1 then
      if $HeaderBO!=0 then  cmd=0x2000
      else		    cmd=0x0000
      end
      if $FuncType==0 then
	rtn=TDS.__TDSCommRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
      else
	rtn=TDS.__TDSUDrvRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
      end
      if rtn >=0 then
	dids=did.ui;	xids=xid.ui
      end
      DispData(1,hd,did.ui,sf.ui,xid.ui,msg,rtn,rtn)

    elsif req==2 then
      if $UseRecvThrd==0 then
	printf("Message(1:S1F1 2:S1F21 3:S2F49  6:S1F2 7:S1F22 8:S6F12) : ")
      else
	printf("Message(1:S1F1 2:S1F21 3:S2F49) : ")
      end
      mno=$stdin.gets.to_i
      case mno
      when 1 then	rtn=SendS1F1( )
      when 2 then	rtn=SendS1F21()
      when 3 then	rtn=SendS2F49()
      when 6 then	rtn=SendS1F2H(dids,xids)
      when 7 then	rtn=SendS1F22(dids,xids)
      when 8 then	rtn=SendS6F12(dids,xids)
      end

    elsif req==3 then
      i=0;  $Break= 0
      while $Break==0 do
	sleep($SendWait/1000)
	if  $FuncType==0 then	stat=TDS.__TDSCommStatus($Fd,0)
	else			stat=TDS.__TDSUDrvStatus($Fd,0)
	end
	if stat==3 then
	  rtn=SendS2F49()
	  if rtn<0 then
	    printf("(H) Send error (%d)\n",rtn);  sleep(ERROR_SLEEP/1000)
	  end
	  if (i%SEND_NO)==0 then		  sleep($SendSleep/1000)  end
	end
      end
      rtn=0
    end

    if rtn<(-999) || ((-900)<rtn && rtn<0) then
      printf("(H) I/O Error (%d)\n"	,rtn)
    end
  end

  end						# :Exit
  $Break=1
  if $Fd>0 then
    if $FuncType==0 then TDS.__TDSCommClose($Fd,0)
    else		 TDS.__TDSUDrvClose($Fd,0)
    end
  else
    printf("(H) Error (%d)\n"	,$Fd)
  end
  if $Md>0 then 	 TDS.__TDSMDMssgTerminate($Md,0)	end
end



# ==============================================================================
# Equipment side process -------------------------------------------------------

def Equip()
# hd =TDS::SHead.malloc
  hd ="\0"*16
  did=TDS::VUI4.malloc
  xid=TDS::VUI4.malloc
  sf =TDS::VUI4.malloc
  msg="\0"*1024

  catch :Exit do
  $OType=1;		 $Break=0
  if $SyncStatus==0 then omd=0x0002
  else			 omd=0x1002
  end
  if $FuncType	==0 then $Fd=TDS.__TDSCommOpen(omd,PARAMFILE,"EQUIP",0,0,0,0,0,0)
  else			 $Fd=TDS.__TDSUDrvOpen(omd,PARAMFILE,"EQUIP",UDRV_MASK)
  end
  if $Fd					< 0 then	throw :Exit end
  printf("(E) Opened (%d)\n",$Fd)
  if ($MssgUseFile&0x80)!=0 then
    $Md=TDS.__TDSMDMssgInitialize(0x4000,$Fd,"")
  end

  if $UseRecvThrd!=0 then
    th=Thread.start{
      RecvProcThread()
    }
  end

  if SECS_MODE!=0 && $FuncType==0 then	# In case of HSMS and use TDSCommXxxxx()
					# HSMS で TDSCommXxxx() 使用の場合
    if TDS.__TDSCommSend($Fd,0x0100,0,0,0,msg,0,hd)< 0 then	throw :Exit end
    printf("(E) Connected\n")
    if TDS.__TDSCommSend($Fd,0x0200,0,0,0,msg,0,hd)< 0 then	throw :Exit end
    printf("(E) Selected\n")
  end

  while true do
    rtn=0
    if $UseRecvThrd==0 then	printf("Req (0:Exit 1:Recv 2:Send) : ")
    else			printf("Req (0:Exit 2:Send 3:Continuous) : ")
    end
    req=$stdin.gets.to_i
    if	  req==0 then						break

    elsif req==1 then
      if $HeaderBO!=0 then  cmd=0x2000
      else		    cmd=0x0000
      end
      if $FuncType==0 then
	rtn=TDS.__TDSCommRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
      else
	rtn=TDS.__TDSUDrvRecv($Fd,cmd,did,sf,xid,msg,1024,hd)
      end
      if rtn >=0 then
	dids=did.ui;	xids=xid.ui
      end
      DispData(1,hd,did.ui,sf.ui,xid.ui,msg,rtn,rtn)

    elsif req==2 then
      if $UseRecvThrd==0 then
	printf("Message(1:S1F1 2:S1F21 3:S6F11  6:S1F2 7:S1F22 8:S2F50) : ")
      else
	printf("Message(1:S1F1 2:S1F21 3:S6F11) : ")
      end
      mno=$stdin.gets.to_i
      case mno
      when 1 then	rtn=SendS1F1( )
      when 2 then	rtn=SendS1F21()
      when 3 then	rtn=SendS6F11()
      when 6 then	rtn=SendS1F2E(dids,xids)
      when 7 then	rtn=SendS1F22(dids,xids)
      when 8 then	rtn=SendS2F50(dids,xids)
      end

    elsif req==3 then
      i=0;  $Break= 0
      while $Break==0 do
	sleep($SendWait/1000)
	if  $FuncType==0 then	stat=TDS.__TDSCommStatus($Fd,0)
	else			stat=TDS.__TDSUDrvStatus($Fd,0)
	end
	if stat==3 then
	  rtn=SendS6F11()
	  if rtn<0 then
	    printf("(E) Send error (%d)\n",rtn);  sleep(ERROR_SLEEP/1000)
	  end
	  if (i%SEND_NO)==0 then		  sleep($SendSleep/1000) end
	end
      end
      rtn=0
    end

    if rtn<(-999) || ((-900)<rtn && rtn<0) then
      printf("(E) I/O Error (%d)\n"	,rtn)
    end
  end

  if   SECS_MODE!=0 then		# In case of HSMS, Shutdown process
					# HSMS 接続の場合、切断処理
    if $FuncType==0 then	rtn=TDS.__TDSCommStatus($Fd,0)
    else			rtn=TDS.__TDSUDrvStatus($Fd,0)
    end
    if rtn	==3 then
    # 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 then rtn=TDS.__TDSCommSend($Fd,0x0800,0,0,0,msg,0,hd)
    # else		   rtn=TDS.__TDSUDrvSend($Fd,0x0800,0,0,0,msg,0,hd)
    # end
    # if rtn					< 0 then	throw :Exit end
    # printf("(E) Deselected\n")
      if $FuncType==0 then rtn=TDS.__TDSCommSend($Fd,0x0900,0,0,0,msg,0,hd)
      else		   rtn=TDS.__TDSUDrvSend($Fd,0x0900,0,0,0,msg,0,hd)
      end
      if rtn					< 0 then	throw :Exit end
      printf("(E) Separated\n")
    end
  end

  end						# :Exit
  $Break=1
  if $Fd>0 then
    if $FuncType==0 then TDS.__TDSCommClose($Fd,0)
    else		 TDS.__TDSUDrvClose($Fd,0)
    end
  else
    printf("(E) Error (%d)\n"	,$Fd)
  end
  if $Md>0 then 	 TDS.__TDSMDMssgTerminate($Md,0)	end
end



# ==============================================================================
# Main process -----------------------------------------------------------------

opt=0
if $FuncType	!=0	then		opt|=0x0001   end
if $HeaderBO	!=0	then		opt|=0x0002   end
if $MssgDispType!=0x00	then		opt|=0x0004   end
if $MssgUseNextL!=0	then		opt|=0x0008   end
if $MssgUseFile !=0x00	then		opt|=0x0010   end
if $UseRecvThrd !=0	then		opt|=0x0020   end
if $SyncStatus	!=0	then		opt|=0x8000   end

if ARGV.size>1 then
  if	ARGV[1][0, 1].casecmp("x")==0 then
    opt=ARGV[1][1,16].to_i(16)
  elsif ARGV[1][0, 1].casecmp("0")==0 &&
	ARGV[1][1, 1].casecmp("x")==0 then
    opt=ARGV[1][2,16].to_i(16)
  else
    opt=ARGV[1].to_i(10)
  end
  if (opt&0x0001)!=0 then $FuncType    =1
  else			  $FuncType    =0
  end
  if (opt&0x0002)!=0 then $HeaderBO    =1
  else			  $HeaderBO    =0
  end
  if (opt&0x0004)!=0 then $MssgDispType=0x20
  else			  $MssgDispType=0x00
  end
  if (opt&0x0008)!=0 then $MssgUseNextL=1
  else			  $MssgUseNextL=0
  end
  if (opt&0x0010)!=0 then $MssgUseFile =0x80
  else			  $MssgUseFile =0x00
  end
  if (opt&0x0020)!=0 then $UseRecvThrd =1
  else			  $UseRecvThrd =0
  end
  if (opt&0x8000)!=0 then $SyncStatus =1
  else			  $SyncStatus =0
  end
end

if(ARGV.size>2) then	  $SendWait   =ARGV[2].to_i(10) end
if(ARGV.size>3) then	  $SendSleep  =ARGV[3].to_i(10) end

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


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