
//
// Trust Design LLC : SECS/PLC Communication Connection Program
//
// Pseudo PLC Sample Program
//
// (c) Copyright Trust Design LLC.  2015-2021.  All rights reserved.
//

// =============================================================================
//
// PseudoPLC : Test and sample program
//
//  Performs SECS communication with the upper host using a pseudo PLC device.
//
//  Allocate the shared memory (in the setting file tdlSPLCE.ini attached to
//  this sample, Shared memory identification name is 'tdlSPLC00') as pseudo PLC
//  device memory. The SECS Message communication is performed by setting and
//  acquiring the message item value that composes the SECS Message there.
//  The message sending/receiving timing is performed by bit monitoring and bit
//  setting of the flag area on the shared memory.
//  Refer to tdlSPLC Operation Manual (tdlSPLCE.pdf) Chapter 2 for details.
//
//  Connect to the upper host (tdlSSim etc.) via tdlSPLC.
//  When SECS Message from upper host is received, content is displayed, and
//  corresponding secondary message is automatically sent back according to 
//  necessity (reception of primary message that requires a reply).
//  Sending of primary message from pseudo PLC device (this sample) is performed
//  by selecting primary message to be sent according to instruction of operator.
//
//
// Startup and operation
//
//   PseudoPLC
//   ~~~~~~~~~
//   Usually, perform operation tests using tdlSPLCE.exe and tdlSSimE.exe.
//   Make sure that the AP that does not have the SECS communication function
//   using the shared memory in Windows using pseudo PLC device performs
//   connection with the upper host (in this case, tdlSSim.exe) by performing
//   SECS communication.
//
//   This sample runs on the command prompt. [Enter] displays a list of primary
//   messages to be sent out, so that ID# is selected and keyed in to send the
//   specified primary message.
//   In addition, you can enter the following ID#.
//    0   : End this sample program
//    1 - : Select primary message to send to HOST
//   97   : Change the operation status of pseudo PLC device (this sample)
//          (OFF-->ON, ON-->OFF)
//   98   : Clear '\0' of shared memory excluding operation status part (ssb)
//   99   : Display the contents of the header area excluding the item data part
//          of the shared memory
//
//   In this sample, abnormal processing and the like are omitted.
//   The first half of this sample (DispSxFx(), SendSxFx(), RecvSxFx()
//   functions) is not an important part of this sample.
//
//
//   tdlSPLCE.exe copies ../tdlSPLCE.exe to this directory and then starts it.
//   After start PLC<-->SECS communication processing is started by [Start] on
//   the [Execute] menu.
//
//   Download tdlSSimE.exe from our company web site etc., copy tdlSSimE.exe to
//   this directory and start it.
//   After startup, specify [tdlSPLCE.ini] as [Conditions], and specify [HOST]
//   as [Section] and then [Start].
//   After that, it is possible to select the primary message to be sent and
//   send it from the SECS message list pane (upper right pane).
//   For details of the operation, refer to the tdlSSim instruction manual
//   (tdlSSimE.pdf).
//
//   (Note) If you want prompt messages etc. to be displayed in English, enable
//      the macro constant "ENGLISH" defined below.
//
//
// =============================================================================
//
// PseudoPLC : テスト 及び サンプル・プログラム
//
//  疑似 PLC 装置を利用して、上位ホストと SECS 通信を行う。
//
//  疑似 PLC 装置メモリとして、共有メモリ (本サンプルに付属する設定ファイル
//  tdlSPLC.ini の設定では、共有メモリ識別名称 tdlSPLC00) を割り付け、そこでの
//  SECS Message を構成するメッセージ項目値の設定、取得を行うことにより、SECS
//  Message 通信を行う。メッセージの送受信タイミングは、共有メモリ上のフラグ
//  領域のビット監視、ビット設定にて行う。
//  詳細は、tdlSPLC.exe 取扱説明書 (tdlSPLC.pdf) 第２章を参照すること。
//
//  tdlSPLC を介して上位ホスト（tdlSSim 等）と接続する。
//  上位ホストからの SECS Message を受信すると、その内容を表示し、必要 (返信が
//  必要な１次メッセージの受信）に応じて、対応する２次メッセージを自動返信する。
//  疑似 PLC 装置（本サンプル）からの１次メッセージの送出は、操作者の指示により
//  送出対象の１次メッセージを選択することにより行う。
//
//
// 起動方法 及び 操作方法
//
//   PseudoPLC
//   ~~~~~~~~~
//   通常、tdlSPLC.exe 及び tdlSSim.exe を使用して、疑似 PLC 装置を利用した
//   Windows での共有メモリを利用した、SECS 通信機能を持たないＡＰが SECS 通信
//   により、上位ホスト（この場合 tdlSSim.exe）と接続する事を確認する。
//
//   本サンプルは、コマンド・プロンプト上で動作するが、[Enter] により、送出対象
//   １次メッセージの一覧を表示するので、その ID# を選択しキーインすることにより
//   指定の１次メッセージを送出する。
//   その他、以下の ID# の入力が可能。
//    0   : 本サンプル・プログラムを終了
//    1 - : HOST に送付する１次メッセージの選択
//   97   : 疑似 PLC 装置（本サンプル）の稼動状態を変更（OFF-->ON、ON-->OFF）
//   98   : 稼動状態部 (ssb) を除く共有メモリを '\0' クリア
//   99   : 共有メモリの項目データ部を除くヘッダ領域の内容を表示
//
//   本サンプルは、異常時処理等を省略している。
//   本サンプルの前半部（DispSxFx()、SendSxFx()、RecvSxFx() 各関数）は、本サン
//   プルの重要な部分ではない。
//
//
//   tdlSPLC.exe は、../tdlSPLC.exe を本ディレクトリにコピーしてから起動する。
//   起動後 [実行] メニュの [開始] により、PLC <--> SECS 通信処理を開始する。
//
//   tdlSSim.exe は、弊社ＨＰ等よりダウンロードし、tdlSSim.exe を、本ディレク
//   トリにコピーしてから起動すること。
//   起動後 [動作条件] として tdlSPLC.ini を指定し、[セクション] として "HOST"
//   を指定して [Start] する。
//   その後、SECS メッセージ一覧ペイン（右上のペイン）から、送信対象の１次メッ
//   セージを選択して、送信する事が可能となる。
//   操作の詳細は、tdlSSim の取扱説明書 (tdlSSim.pdf) を参照すること。
//
//
// =============================================================================

#include	<stdio.h>
#include	<signal.h>
#include	<time.h>
#include	<windows.h>
#include	<process.h>

//#define 	ENGLISH		// If this macro is defined, prompt messages
				// will be displayed in English.
				//
				// このマクロを定義すると、プロンプトメッセージ
				// を英語表示とする


#define		PO		fprintf(stdout	// Output to standard out
#define		PE		fprintf(stderr	// Output to standard error 

#define		SMKEY		"tdlSPLC00"	// Shared memory name
#define		SMSIZE		(0x4200)	// Shared memory size
#define		SDSIZE		(SMSIZE-(1*2+1*2+1*2*2+2*2*32))
					// SECS item data storage area size

#define		INTER0		100	// Shared memory monitoring cycle


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

typedef union{
  char			sc [128];
  short			ss  [ 1];
  int			si  [ 1];
  long long		sl  [ 1];
  unsigned char		uc  [ 1];
  unsigned short	us  [ 1];
  unsigned int		ui  [ 1];
  unsigned long long	ul  [ 1];
  float			fs  [ 1];
  double		fl  [ 1];
} AllType;

typedef struct{
  unsigned char		ssb [ 2];	// Status    bit value (Use only 0th bit)
  unsigned char		dmy0[ 2];
  unsigned char		hsb [ 2][ 2];	// Handshake bit value (Use only 0th bit)
  unsigned short	msd [ 2][32];	// SECS Basic data
  unsigned short	ssd [SDSIZE];	// SECS Item  data storage area
} DevPseudo;


static DevPseudo	*Md=0;		// Shared memory address
static int		Break=0;	// End instruction and signal
					// reception status

static void	ObserveMemory(void*);	// Shared memory monitoring thread
static void	InterProcess (void*);	// Primary message transmission
					// instruction thread



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

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



// =============================================================================
// Display SECS message contents -----------------------------------------------
//
// Display header information of sent/received SECS Message and field values
// that compose the message
//
// SECS メッセージ内容の表示 ---------------------------------------------------
// 送受信 SECS Message のヘッダ情報 及び メッセージを構成する項目値の表示をする

static char	*DCode[]={"\r>>"   ,"\r<<"};
static char	*DMssg[]={"Send   ","Receive"};


// -----------------------------------------------------------------------------
// S1F1, S1F2 ------------------------------------------------------------------

static void
DispS1F1(
int		io,		// i  : 0: Send  1:Receive
int		fcd)		// i  : F-Code (1 or 2)
{
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  if((io==0 && fcd== 2)){
    PO,"MDLN      = %.6s\n"	,&Md->ssd[0x0020+off]);
    PO,"SOFTREV   = %.6s\n"	,&Md->ssd[0x0023+off]);
  }
}


// -----------------------------------------------------------------------------
// S1F13, S1F14 ----------------------------------------------------------------

static void
DispS1F13(
int		io,		// i  : 0: Send  1:Receive
int		fcd)		// i  : F-Code (13 or 14)
{
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  if((io==0)){
    PO,"MDLN      = %.6s\n"	,&Md->ssd[0x0020+off]);
    PO,"SOFTREV   = %.6s\n"	,&Md->ssd[0x0023+off]);
  }
}


// -----------------------------------------------------------------------------
// S1F21, S1F22 ----------------------------------------------------------------

static void
DispS1F21(
int		io,		// i  : 0: Send  1:Receive
int		fcd)		// i  : F-Code (21 or 22)
{
  AllType	*at;
  int		off,i;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)				(&Md->ssd[0x0029+off]);
  PO,"VB        = 0x%02x,%02x\n"	, at->uc [0],at->uc[1]);
  at=(AllType*)				(&Md->ssd[0x002a+off]);
  PO,"VT        = 0x%02x,%02x\n"	, at->uc [0],at->uc[1]);

  PO,"MDLN      = %.6s\n"		,&Md->ssd[0x0020+off]);
  PO,"SOFTREV   = %.20s\n"		,&Md->ssd[0x0100+off]);
  PO,"COMMENT   = %.80s\n"		,&Md->ssd[0x0110+off]);

  at=(AllType*)				(&Md->ssd[0x013c+off]);
  PO,"VI1       = %d,%d\n"		, at->sc [0],at->sc[1]);
  at=(AllType*)				(&Md->ssd[0x013e+off]);
  PO,"VI2       = %hd,%hd\n"		, at->ss [0],at->ss[1]);
  at=(AllType*)				(&Md->ssd[0x0140+off]);
  PO,"VI4       = %d,%d\n"		, at->si [0],at->si[1]);
  at=(AllType*)				(&Md->ssd[0x0144+off]);
  PO,"VI8       = %lld,%lld\n"		, at->sl [0],at->sl[1]);

  at=(AllType*)				(&Md->ssd[0x014c+off]);
  PO,"VU1       = %u,%u\n"		, at->uc [0],at->uc[1]);
  at=(AllType*)				(&Md->ssd[0x014e+off]);
  PO,"VU2       = %hu,%hu\n"		, at->us [0],at->us[1]);
  at=(AllType*)				(&Md->ssd[0x0150+off]);
  PO,"VU4       = %u,%u\n"		, at->ui [0],at->ui[1]);
  at=(AllType*)				(&Md->ssd[0x0154+off]);
  PO,"VU8       = %llu,%llu\n"		, at->ul [0],at->ul[1]);

  at=(AllType*)				(&Md->ssd[0x015c+off]);
  PO,"AU8       = %llu"			, at->ul [0]);
  for(i=1;i<10;i++) PO,",%llu"		, at->ul [i]);
  PO,"\n");

  at=(AllType*)				(&Md->ssd[0x0184+off]);
  PO,"VF4       = %13.8e,%13.8e\n"	, at->fs [0],at->fs[1]);
  at=(AllType*)				(&Md->ssd[0x0188+off]);
  PO,"VF8       = %22.17le,%22.17le\n"	, at->fl [0],at->fl[1]);
}


// -----------------------------------------------------------------------------
// S2F49, S2F50 ----------------------------------------------------------------

static void
DispS2F49(
int		io,		// i  : 0: Send  1:Receive
int		type)		// i  : 0: S2F49_01
				//	1: S2F49_02
{
  AllType	*at;
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)			(&Md->ssd[0x11a0+off]);
  PO,"DATAIDB   = 0x%02x\n"	, at->uc [0]);
  PO,"RCMD      = %.10s\n"	,&Md->ssd[0x01a1+off]);

  at=(AllType*)			(&Md->ssd[0x01ab+off]);
  PO,"STID      = 0x%02x\n"	, at->uc [0]);
  at=(AllType*)			(&Md->ssd[0x01ac+off]);
  PO,"MTKD      = 0x%02x\n"	, at->uc [0]);
  PO,"LOTID     = %.20s\n"	,&Md->ssd[0x01ad+off]);

  PO,"WAFERID01 = %.20s\n"	,&Md->ssd[0x0200+off]);
  PO,"PPID01    = %.12s\n"	,&Md->ssd[0x020a+off]);

  if(type==1){
    PO,"WAFERID02 = %.20s\n"	,&Md->ssd[0x0210+off]);
    PO,"PPID02    = %.12s\n"	,&Md->ssd[0x021a+off]);
  }
}


static void
DispS2F50(
int		io)		// i  : 0: Send  1:Receive
{
  AllType	*at;
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)			(&Md->ssd[0x01a0+off]);
  PO,"HCACK     = 0x%02x\n"	, at->uc [0]);
  PO,"LOTID     = %.20s\n"	,&Md->ssd[0x01a1+off]);
}


// -----------------------------------------------------------------------------
// S5F1, S5F2 ------------------------------------------------------------------

static void
DispS5F1(
int		io,		// i  : 0: Send  1:Receive
int		type)		// i  : 0: S5F1_E1
				//	1: S5F1_E2
{
  AllType	*at;
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)			(&Md->ssd[0x0200+off]);
  PO,"ALCD      = 0x%02x\n"	, at->uc [0]);
  at=(AllType*)			(&Md->ssd[0x0201+off]);
  PO,"ALID      = %u\n"		, at->us [0]);
  PO,"ALTX      = %.40s\n"	,&Md->ssd[0x0202+off]);
  if(type==1){
    PO,"ALTY      = %.40s\n"	,&Md->ssd[0x0216+off]);
    PO,"ALTZ      = %.40s\n"	,&Md->ssd[0x022c+off]);
  }
}


static void
DispS5F2(
int		io)		// i  : 0: Send  1:Receive
{
  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);
}


// -----------------------------------------------------------------------------
// S6F11, S6F12 ----------------------------------------------------------------

static void
DispS6F11(
int		io,		// i  : 0: Send  1:Receive
int		type)		// i  : 0: S6F11
				//	1: S6F11_T1
				//	2: S6F11_T2
{
  AllType	*at;
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)			(&Md->ssd[0x0300+off]);
  PO,"DATAID    = %u\n"		, at->us [0]);
  at=(AllType*)			(&Md->ssd[0x0301+off]);
  PO,"CEID      = %u\n"		, at->us [0]);

  if	  (type==0){
    PO,"DATA1     = %.16s\n"	,&Md->ssd[0x0310+off]);
    PO,"DATA2     = %.16s\n"	,&Md->ssd[0x0318+off]);
    PO,"@TIME     = %.14s\n"	,&Md->ssd[0x0320+off]);
  }else if(type==1){
    at=(AllType*)		(&Md->ssd[0x0328+off]);
    PO,"STID1     = 0x%02x\n"	, at->uc [0]);
    PO,"CARRIER1  = %.14s\n"	,&Md->ssd[0x0329+off]);
    at=(AllType*)		(&Md->ssd[0x0330+off]);
    PO,"STID2     = 0x%02x\n"	, at->uc [0]);
    PO,"CARRIER2  = %.14s\n"	,&Md->ssd[0x0331+off]);
  }else if(type==2){
    at=(AllType*)		(&Md->ssd[0x0340+off]);
    PO,"STID      = 0x%02x\n"	, at->uc [0]);
    at=(AllType*)		(&Md->ssd[0x0341+off]);
    PO,"MTKD      = 0x%02x\n"	, at->uc [0]);
    PO,"PODID     = %.5s\n"	,&Md->ssd[0x0343+off]);
    PO,"CASID     = %.5s\n"	,&Md->ssd[0x0346+off]);
    PO,"LOTID     = %.20s\n"	,&Md->ssd[0x0349+off]);
    at=(AllType*)		(&Md->ssd[0x0342+off]);
    PO,"NOWAF     = %u\n"	, at->uc [0]);
  }
}


static void
DispS6F12(
int		io)		// i  : 0: Send  1:Receive
{
  AllType	*at;
  int		off;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  at=(AllType*)			(&Md->ssd[0x0300+off]);
  PO,"ACKC6     = 0x%02x\n"	, at->uc [0]);
}


// -----------------------------------------------------------------------------
// S9Fx ------------------------------------------------------------------------

static void
DispS9Fx(
int		io,		// i  : 0: Send  1:Receive
int		fcd)		// i  : F-Code (1,3,5,7,9,11,13)
{
  AllType	*at;
  int		off,i;

  PO,"%s %s SECS Message\n"	, DCode[io],DMssg[io]);
  PO,"SF-Code   = 0x%04x : %s\n", Md->msd[io][ 0],&Md->msd[io][ 4]);
  PO,"DeviceID  = 0x%04x\n"	, Md->msd[io][ 1]);
  PO,"XID       = 0x%04x,%04x\n", Md->msd[io][ 2], Md->msd[io][ 3]);

  if(io==0)	off=0x0000;
  else		off=0x1000;

  if(fcd<13){
    at=(AllType*)		(&Md->ssd[0x0f00+off]);
    PO,"MHEAD     = 0x%02x"	, at->uc [0]);
    for(i=1;i<10;i++) PO,",%02x", at->uc [i]);
    PO,"\n");
  }else{
    PO,"MEXP      = %.6s\n"	,&Md->ssd[0x0f00+off]);
  }
}



// =============================================================================
// Message construction and transmission processing start ----------------------
// Information necessary for SECS Message to be sent to host (SF-Code, name,
// item value, etc.) is set on the shared memory, and after set value is
// displayed, transmission processing is started.
// In this sample, the value set for each item that configures each SECS Message
// has no meaning. Set the value in each item only for the purpose of checking
// whether the message can be sent and received correctly.
// In transmission of S2F50, set LOTID as the sample of received data reference
// by using the received value of S2F49 immediately before.
//
// メッセージ構築 及び 送信処理開始 --------------------------------------------
// ホストへ送信する SECS Message に必要な情報 (SF-Code、名称、項目値等) を、共有
// メモリ上に設定し、設定値を表示後、送信処理を開始する。
// 本サンプルにおいて、各 SECS Message を構成する各項目に設定する値には、なんら
// 意味は無い。正しくメッセージの送受信ができているのかを確認するためだけの目的
// で各項目に値設定を行う。
// S2F50 の送信においては、設定する LOTID を直前の S2F49 の受信値を使用する事に
// より、受信データ参照のサンプルとする。

StrCpy(
void		*dst,
void		*src,
int		sz)
{
  int		len;

//strncpy((char*)dst,char*(src),sz);
//
// In strncpy(), if 'dst' is not cleared if string length of 'src' is smaller
// than 'sz', which is size of 'dst', dust may be left behind '\0' in 'dst'.
// Therefore, unexpected problems may occur. Therefore, clear the area '\0'
// beforehand.
//
// strncpy() では、src の文字列長が dst のサイズである sz よりも小さい場合に
// dst がクリアされていないと、dst 内の '\0' の後ろにゴミが残る場合があり、予期
// せぬ問題が発生する可能性があるので、予め領域を '\0' クリアする。

  if((len=strlen(src))	> sz)	len=sz;
  memset(dst,'\0',sz);
  memcpy(dst,src ,len);
}


// -----------------------------------------------------------------------------
// S1F1, S1F2 ------------------------------------------------------------------

static void
SendS1F1()
{
  memset(	 Md->msd[0],'\0',sizeof(Md->msd[0]));	// PLC-->PC Area clear
		 Md->msd[0][  0]=0x8000|( 1<<8)| 1;	// W-Bit + SF-Code
  StrCpy((char*)&Md->msd[0][  4],"S1F1_HE"	,56);	// Message name
  DispS1F1(0,1);					// Display message 
  Md->hsb[0][  0]=1;					// PLC-->PC Send request
}


static void
SendS1F2()
{
  static int	rev=0;
  char		wc[128];

  memset(	 Md->msd[0],'\0',sizeof(Md->msd[0]));	// PLC-->PC Area clear
		 Md->msd[0][  0]=0x0000|( 1<<8)| 2;	// W-Bit + SF-Code

			// In the case of a secondary message, DeviceID,
			// SourceID and TransactionID copy those of the received
			// primary message.
			//
			// ２次メッセージの場合、DeviceID、SourceID、Transaction
			// ID は、受信した１次メッセージのものをコピーする。
		 Md->msd[0][  1]=Md->msd[1][  1];	// Device ID
		 Md->msd[0][  2]=Md->msd[1][  2];	// Source ID
		 Md->msd[0][  3]=Md->msd[1][  3];	// Transaction ID
  StrCpy((char*)&Md->msd[0][  4],"S1F2_E"	,56);	// Message name

  StrCpy(	&Md->ssd[0x0020],"pSEUDO"	, 6);	// MDLN
  sprintf(wc	,"01.%03d"	,(rev++)%1000);
  StrCpy(	&Md->ssd[0x0023],wc		, 6);	// SOFTREV
  DispS1F1(0,2);					// Display message
  Md->hsb[0][  0]=1;					// PLC-->PC Send request
}


// -----------------------------------------------------------------------------
// S1F13, S1F14 ----------------------------------------------------------------

static void
SendS1F13()
{
  static int	rev=0;
  char		wc[128];

  memset(	 Md->msd[0],'\0',sizeof(Md->msd[0]));
		 Md->msd[0][  0]	=0x8000|( 1<<8)|13;
  StrCpy((char*)&Md->msd[0][  4]	,"S1F13_E"	,56);

  StrCpy(	&Md->ssd[0x0020]	,"Pseude"	, 6);	// MDLN
  sprintf(wc	,"01.%03d"	,(rev++)%1000);
  StrCpy(	&Md->ssd[0x0023]	,wc		, 6);	// SOFTREV
  DispS1F13(0,13);
  Md->hsb[0][  0]=1;
}


static void
SendS1F14()
{
  static int	rev=0;
  char		wc[128];

  memset(	 Md->msd[0],'\0',sizeof(Md->msd[0]));
		 Md->msd[0][  0]	=0x0000|( 1<<8)|14;
		 Md->msd[0][  1]	=Md->msd[1][  1];
		 Md->msd[0][  2]	=Md->msd[1][  2];
		 Md->msd[0][  3]	=Md->msd[1][  3];
  StrCpy((char*)&Md->msd[0][  4]	,"S1F14_E"	,56);

		 Md->ssd[0x0028]	=(0x01<<0);		// COMMACK
  StrCpy(	&Md->ssd[0x0020]	,"Pseude"	, 6);	// MDLN
  sprintf(wc	,"01.%03d"	,(rev++)%1000);
  StrCpy(	&Md->ssd[0x0023]	,wc		, 6);	// SOFTREV
  DispS1F13(0,14);
  Md->hsb[0][  0]	=1;
}


// -----------------------------------------------------------------------------
// S1F21, S1F22 ----------------------------------------------------------------

static void
SendS1F21(
int		fcd)		// i  : F-Code (21 or 22)
{
  static int	rev=0;
  static int	vb0=0,vb1=-1,vt0=0,vt1=1;
  static int	vi10=200,vi11=-200,vi20=300,vi21=-300;
  static int	vi40=400,vi41=-400,vi80=500,vi81=-500,au8=10;
  static int	com=1;
  static float	vf40=(float)7.89012345e-12 ,vf41=(float)-4.321098765e31;
  static double	vf80=5.6473829101928374e189,vf81=-3.2109876543210987654e-179;
  AllType	*at;
  char		wc[128];
  int		i;

  memset(		 Md->msd[0],'\0',sizeof(Md->msd[0]));
  if(fcd==21){
			 Md->msd[0][  0]=0x8000|( 1<<8)|21;
    StrCpy((char*)	&Md->msd[0][  4],"S1F21_HE"	,56);
  }else{
			 Md->msd[0][  0]=0x0000|( 1<<8)|22;
			 Md->msd[0][  1]=Md->msd[1][  1];
			 Md->msd[0][  2]=Md->msd[1][  2];
			 Md->msd[0][  3]=Md->msd[1][  3];
    StrCpy((char*)	&Md->msd[0][  4],"S1F22_HE"	,56);
  }

  at=(AllType*)		&Md->ssd[0x0029];
  at->uc[0]=(unsigned char)		((vb0++)&0xff);		// VB
  at->uc[1]=(unsigned char)		((vb1--)&0xff);
  at=(AllType*)		&Md->ssd[0x002a];
  at->uc[0]=(unsigned char)		((vt0++)&0x01);		// VT
  at->uc[1]=(unsigned char)		((vt1--)&0x01);

  StrCpy(		&Md->ssd[0x0020],"PsEuDe"	, 6);	// MDLN
  sprintf(wc	,"01.%03d"		,(rev++)%1000);
  StrCpy(		&Md->ssd[0x0100],wc		, 6);	// SOFTREV
  sprintf(wc	,"This is #%04d comment",com++);
  StrCpy(		&Md->ssd[0x0110],wc		,80);	// COMMENT

  at=(AllType*)		&Md->ssd[0x013c];
  at->sc[0]=(char)			((vi10++)&0xff);	// VI1
  at->sc[1]=(char)			((vi11--)&0xff);
  at=(AllType*)		&Md->ssd[0x013e];
  at->ss[0]=(short)			(vi20++);		// VI2
  at->ss[1]=(short)			(vi21--);
  at=(AllType*)		&Md->ssd[0x0140];
  at->si[0]=				(vi40++);		// VI4
  at->si[1]=				(vi41--);
  at=(AllType*)		&Md->ssd[0x0144];
  at->sl[0]=				(vi80++);		// VI8
  at->sl[1]=				(vi81--);

  at=(AllType*)		&Md->ssd[0x014c];
  at->uc[0]=(unsigned char)		((vi10++)&0xff);	// VU1
  at->uc[1]=(unsigned char)		((vi11--)&0xff);	// VU1
  at=(AllType*)		&Md->ssd[0x014e];
  at->us[0]=(unsigned short)		(vi20++);		// VU2
  at->us[1]=(unsigned short)		(vi21--);
  at=(AllType*)		&Md->ssd[0x0150];
  at->ui[0]=				(vi40++);		// VU4
  at->ui[1]=				(vi41--);
  at=(AllType*)		&Md->ssd[0x0154];
  at->ul[0]=				(vi80++);		// VU8
  at->ul[1]=				(vi81--);

  at=(AllType*)		&Md->ssd[0x015c];
  for(i=0;i< 8;i++)	at->ul[i]=	(au8++);		// AU8

  at=(AllType*)		&Md->ssd[0x0184];
  at->fs[0]=				vf40=(float)(vf40*1.23);// VF4
  at->fs[1]=				vf41=(float)(vf41/2.34);
  at=(AllType*)		&Md->ssd[0x0188];
  at->fl[0]=				vf80*=1.234;		// VF8
  at->fl[1]=				vf81/=1.234;

  DispS1F21(0,fcd);
  Md->hsb[0][  0]=1;
}


// -----------------------------------------------------------------------------
// S2F50 -----------------------------------------------------------------------

static void
SendS2F50()
{
  static int	hcack=0;

  memset(		 Md->msd[0],'\0',sizeof(Md->msd[0]));
			 Md->msd[0][  0]=0x0000|( 2<<8)|50;
			 Md->msd[0][  1]= Md->msd[1][  1];
			 Md->msd[0][  2]= Md->msd[1][  2];
			 Md->msd[0][  3]= Md->msd[1][  3];
  StrCpy((char*)	&Md->msd[0][  4],"S2F50_E"	 ,56);
			 Md->ssd[0x01a0]=(((hcack++)&0xff)<0);	// HCACK
  StrCpy(		&Md->ssd[0x01a1],&Md->ssd[0x11ad],20);	// LOTID
			// LOTID copies the LOTID specified by S2F49 received
			// immediately before.
			//
			// LOTID は、直前に受信した S2F49 で指定された LOTID を
			// コピーする。
  DispS2F50(0);
  Md->hsb[0][  0]=1;
}


// -----------------------------------------------------------------------------
// S5F1 ------------------------------------------------------------------------

static void
SendS5F1(
int		type)		// i  : 0: S5F1_E1
				//	1: S5F1_E2
{
  static char	*sfname[2]={"S5F1_E1","S5F1_E2"};
  static int	alid=0x01,alno=1;
  AllType	at;
  char		wc[128];

  memset  (		 Md->msd[0],'\0',sizeof(Md->msd[0]));
			 Md->msd[0][  0]=0x8000|( 5<<8)| 1;
  StrCpy  ((char*)	&Md->msd[0][  4],sfname[type]	,56);
			 Md->ssd[0x0200]=0x81;			// ALCD
  at.si[0]=alid++;	 Md->ssd[0x0201]= at.us[0];		// ALID
  sprintf(wc	,"Alarm message #%03d"	,(alno++)%1000);
  StrCpy ((char*)	&Md->ssd[0x0202],wc		,40);	// ALTX
  if(type==1){
    sprintf(wc	,"ALARM MESSAGE #%03d"	,(alno++)%1000);
    StrCpy ((char*)	&Md->ssd[0x0216],wc		,40);	// ALTY
    sprintf(wc	,"#%03d Alarm Test"	,(alno++)%1000);
    StrCpy ((char*)	&Md->ssd[0x022c],wc		,40);	// ALTZ
  }
  DispS5F1(0,type);
  Md->hsb[0][  0]=1;
}


// -----------------------------------------------------------------------------
// S6F11 -----------------------------------------------------------------------

static void
SendS6F11(
int		type)		// i  : 0: S6F11_E
				//	1: S6F11_ET1
				//	2: S6F11_ET2
{
  static char		*sfname[]={"S6F11_E","S6F11_ET1","S6F11_ET2"};
  static unsigned short	ceid   []={8,9,10};
  static int		dataid=0,dt1=0,dt2=10;
  static int		stid=0,mtkd=0,carid=0;
  AllType		at;
  struct tm		*lt;
  time_t		tm;
  char			wc[128];

  memset(		 Md->msd[0],'\0',sizeof(Md->msd[0]));
			 Md->msd[0][  0]=0x8000|( 6<<8)|11;
  StrCpy((char*)	&Md->msd[0][  4],sfname[type]	,56);
  at.si[0]=dataid++;	 Md->ssd[0x0300]= at.us[0];		// DATAID
			 Md->ssd[0x0301]=ceid  [type];		// CEID
  if      (type==0){
    sprintf(wc	,"Data1 #%03d"		,(dt1++)%1000);
    StrCpy ((char*)	&Md->ssd[0x0310],wc		,16);	// DATA1
    sprintf(wc	,"Data2 #%03d"		,(dt2++)%1000);
    StrCpy((char*)	&Md->ssd[0x0318],wc		,16);	// DATA2
    tm=time(0);		lt=localtime(&tm);
    sprintf(wc	,"%04d%02d%02d%02d%02d%02d"
	,lt->tm_year+1900,lt->tm_mon+1,lt->tm_mday
	,lt->tm_hour	 ,lt->tm_min  ,lt->tm_sec);
    StrCpy (		&Md->ssd[0x0320],wc		,14);	// @TIME
  }else if(type==1){
			 Md->ssd[0x0328]=(((stid++)&0xff)<<0);	// STID1
    sprintf(wc	,"CAR%06d"		, (carid++)%1000000);
    StrCpy ((char*)	&Md->ssd[0x0329],wc		,14);	// CARRIER1
			 Md->ssd[0x0330]=(((stid++)&0xff)<<0);	// STID2
    sprintf(wc	,"CAR%06d"		, (carid++)%1000000);
    StrCpy ((char*)	&Md->ssd[0x0331],wc		,14);	// CARRIER2
  }else if(type==2){
			 Md->ssd[0x0340]=(((stid++)&0xff)<<0);	// STID
			 Md->ssd[0x0341]=(((mtkd++)&0xff)<<0);	// MTKD
    sprintf(wc	,"P%04d"		, (carid++)%10000);
    StrCpy (		&Md->ssd[0x0343],wc		, 5);	// PODID
    sprintf(wc	,"C%04d"		, (carid++)%10000);
    StrCpy (		&Md->ssd[0x0346],wc		, 5);	// CASID
    sprintf(wc	,"LOT%06d"		, (carid++)%1000000);
    StrCpy ((char*)	&Md->ssd[0x0349],wc		,20);	// LOTID
			 Md->ssd[0x0342]=(((stid++)%  26)<<0);	// NOWAF
  }

  DispS6F11(0,type);
  Md->hsb[0][  0]=1;
}



// =============================================================================
// Message analysis ------------------------------------------------------------
// Parses SECS Message received from host (in this sample, displays SECS Message
// field value)
//
// メッセージ解析 --------------------------------------------------------------
// ホストから受信した SECS Message を解析（本サンプルでは、SECS Message 項目値
// を表示）する

// -----------------------------------------------------------------------------
// S1F1, S1F2 ------------------------------------------------------------------

static void
RecvS1F1(
int		fcd)		// i  : F-Code (1 or 2)
{
  DispS1F1(1,fcd);
}


// -----------------------------------------------------------------------------
// S1F13, S1F14 ----------------------------------------------------------------

static void
RecvS1F13(
int		fcd)		// i  : F-Code (13 or 14)
{
  DispS1F13(1,fcd);
}


// -----------------------------------------------------------------------------
// S1F21, S1F22 ----------------------------------------------------------------

static void
RecvS1F21(
int		fcd)		// i  : F-Code (21 or 22)
{
  DispS1F21(1,fcd);
}


// -----------------------------------------------------------------------------
// S2F49 -----------------------------------------------------------------------

static void
RecvS2F49(
int		type)		// i  : 0: S2F49_H01
				//	1: S2F49_H02
{
  DispS2F49(1,type);
}


// -----------------------------------------------------------------------------
// S5F2 ------------------------------------------------------------------------

static void
RecvS5F2()
{
  DispS5F2(1);
}


// -----------------------------------------------------------------------------
// S6F12 -----------------------------------------------------------------------

static void
RecvS6F12()
{
  DispS6F12(1);
}


// -----------------------------------------------------------------------------
// S9Fx ------------------------------------------------------------------------

static void
RecvS9Fx(
int		fcd)		// i  : Function code (1,3,5,7,9,11,13)
{
  DispS9Fx(1,fcd);
}



// =============================================================================
// Main process ----------------------------------------------------------------
// +  Allocation of shared memory
// +  Activation of processing thread (shared memory monitoring, primary message
//    sending)
// +  Set process start (PLC start) to shared memory
// +  Wait for end instruction (set Break!=0 in the primary message sending
//    thread)
// +  Set process end (PLC stop) to shared memory
// +  Release shared memory and exit
//
// メイン処理 ------------------------------------------------------------------
// ・ 共有メモリの割り付け
// ・ 処理スレッド（共有メモリ監視、１次メッセージ送出）の起動
// ・ 処理開始（PLC 起動）を共有メモリに設定
// ・ 終了指示（１次メッセージ送出スレッドでの Break!=0 設定）を待つ
// ・ 処理終了（PLC 停止）を共有メモリに設定
// ・ 共有メモリを開放して終了

int
main(
int			argc,
char			*argv[])
{
  HANDLE		sd;
  int			ok0=0;

  signal(SIGINT,CBSignal);
						// Shared memory allocation
  if(  (sd=  OpenFileMapping(FILE_MAP_ALL_ACCESS,0,SMKEY))	==0){	ok0=1;
    if((sd=CreateFileMapping(INVALID_HANDLE_VALUE,0
			,PAGE_READWRITE,0,SMSIZE,SMKEY))	==0){
      #if defined ENGLISH
      PE,"Shared memory allocation error\n");				exit(1);
      #else
      PE,"共有メモリ割り付けエラー\n");					exit(1);
      #endif
  } }
  Md=(DevPseudo*)MapViewOfFile(sd,FILE_MAP_ALL_ACCESS,0,0,SMSIZE);
  if(ok0!=0)	memset(Md,'\0',SMSIZE);		// Initialize if Create SHMem

  _beginthread(ObserveMemory,0,0);		// Monitoring thread
  _beginthread(InterProcess ,0,0);		// Primary message sending thread

  Md->ssb[0]=1;					// PLC start
  for(Break=0;Break==0;)	Sleep(500);	// Loop to end instruction
  Sleep(500);					// Wait a while
  Md->ssb[0]=0;					// PLC stop

  UnmapViewOfFile(Md);				// Shared memory release
  CloseHandle    (sd);

  exit(0);
}



// =============================================================================
// Shared memory monitoring thread ---------------------------------------------
// +  Infinite loop until end instruction (Break!=0)
// +  Perform processing in a fixed cycle
// +  Monitor the shared memory flag area (hsb[][])
//   -  Message sending completion processing
//   -  Message receiving completion processing
//   -  Message receiving process
//     .  Processing on received message
//     .  If the received message is primary message that requires a reply,
//        send secondary message
//
// 共有メモリ監視スレッド ------------------------------------------------------
// ・ 終了指示（Break!=0）まで無限ループ
// ・ 一定周期で処理を行う
// ・ 共有メモリのフラグ領域（hsb[][]）を監視
//   ・ メッセージ送信完了処理
//   ・ メッセージ受信完了処理
//   ・ メッセージ受信処理
//     ・ 受信メッセージに関する処理
//     ・ 受信メッセージが返信が必要な１次メッセージの場合２次メッセ−ジ送信

static void
ObserveMemory(
void		*par)
{
  char		*mname;

  for(;Break==0;){				// Loop to end
    Sleep(INTER0);				// Monitoring cycle
  //if(	 Md->ssb[1]	==0) continue;		// PC not working

    if(	 Md->hsb[0][0]	!=0){			// Sending to PC
      if(Md->hsb[0][1]	!=0) Md->hsb[0][0]= 0;	// Exit if PC receiving is
    }						// complete

    if(	 Md->hsb[1][1]	==0){			// No recive message from PC
      if(Md->hsb[1][0]	!=0) Md->hsb[1][0]= 0;	// PLC receiving completed

    }else{					// Receive instruction from PC
      if(Md->hsb[1][0]	==0){			// PLC if not processed
	mname=(char*)(&Md->msd[1][4]);		// SECS Message name
	// All the device side receiving target messages defined in the message
	// definition file are processed below. In the case of primary message
	// that requires reply process, the corresponding secondary message is
	// sent after the receiving process.
	//
	// メッセージ定義ファイルに規定する、装置側受信対象メッセージの全てを
	// 以下にて処理する。返信処理が必要な１次メッセージの場合は、受信処理後
	// 対応する２次メッセージを送信する。
	if      (strcmp(mname,"S1F1_HE"  )==0){	RecvS1F1 ( 1);	SendS1F2 ();
	}else if(strcmp(mname,"S1F2_H"   )==0){	RecvS1F1 ( 2);
	}else if(strcmp(mname,"S1F13_H"  )==0){	RecvS1F13(13);	SendS1F14();
	}else if(strcmp(mname,"S1F14_H"  )==0){	RecvS1F13(14);
	}else if(strcmp(mname,"S1F21_HE" )==0){	RecvS1F21(21);	SendS1F21(22);
	}else if(strcmp(mname,"S1F22_HE" )==0){	RecvS1F21(22);
	}else if(strcmp(mname,"S2F49_H01")==0){	RecvS2F49( 0);	SendS2F50();
	}else if(strcmp(mname,"S2F49_H02")==0){	RecvS2F49( 1);	SendS2F50();
	}else if(strcmp(mname,"S5F2_H"   )==0){	RecvS5F2 ();
	}else if(strcmp(mname,"S5F2_H2"  )==0){	RecvS5F2 ();
	}else if(strcmp(mname,"S6F12_H"  )==0){	RecvS6F12();
	}else if(strcmp(mname,"S9F1_HE"  )==0){	RecvS9Fx ( 1);
	}else if(strcmp(mname,"S9F3_HE"  )==0){	RecvS9Fx ( 3);
	}else if(strcmp(mname,"S9F5_HE"  )==0){	RecvS9Fx ( 5);
	}else if(strcmp(mname,"S9F7_HE"  )==0){	RecvS9Fx ( 7);
	}else if(strcmp(mname,"S9F9_HE"  )==0){	RecvS9Fx ( 9);
	}else if(strcmp(mname,"S9F11_HE" )==0){	RecvS9Fx (11);
	}else if(strcmp(mname,"S9F13_HE0")==0){	RecvS9Fx (13);
	}else if(strcmp(mname,"S9F13_HE1")==0){	RecvS9Fx (13);
	}else if(strcmp(mname,"S9F13_HE2")==0){	RecvS9Fx (13);
	}else if(strcmp(mname,"S9F13_HE3")==0){	RecvS9Fx (13);
	}else{
	  PE,"Illegal SECS message received [S%dF%d:%s]\n"
		,(Md->msd[1][0]&0x7f)>>8,(Md->msd[1][0]&0xff),mname);
	}
	// Here, the reception completion is reported. If secondary message
	// needs to be sent back, the TransactionID of the primary message is
	// required when constructing the secondary message. Therefore, it is
	// not possible to report reception completion until after constructing
	// the secondary message with SendSxFx(). Therefore, reception
	// completion can not be performed in RecvSxFx().
	//
	// ここで、受信完了を報告する。２次メッセージの返信が必要な場合、２次
	// メッセージの構築時に、１次メッセージの TransactionID が必要となるの
	// で、２次メッセージの構築を SendSxFx() で行った後でないと、受信完了
	// を報告してはいけない。従って、受信完了を RecvSxFx() 内で行うことは
	// できない。
		Md->hsb[1][0]= 1;	// PLC reception processing completed
  } } }
}



// =============================================================================
// Primary message sending instruction thread ----------------------------------
// Display the list of primary messages that can be sent out, and select Send
// primary message.
// The selected message is sent to the upper host via tdlSPLCE.exe by setting
// the information in the shared memory with the SendSxFx() function.
// In addition, perform the following processing.
//  0 : End instruction of this sample AP
// 97 : Setting the operating status (ssb[0]) of this sample
// 98 : Clear shared memory
// 99 : Display shared memory contents
//
// １次メッセージ送信指示スレッド ----------------------------------------------
// 送出可能な１次メッセージ一覧を表示し、送出１次メッセージする選択する。
// 選択したメッセージは SendSxFx() 関数により共有メモリに情報を設定することに
// より tdlSPLC.exe を介して上位ホストに送信する。
// その他、以下の処理を行う。
//  0 : 本サンプルＡＰの終了指示
// 97 : 本サンプルの稼動状態（ssb[0]）設定
// 98 : 共有メモリのクリア
// 99 : 共有メモリ内容の表示

static void
InterProcess(
void		*par)
{
  unsigned char	ssb[ 2];
  char		str[32];
  int		req;

  for(;Break==0;){
    #if defined ENGLISH
    PE,"\rPlease select a primary message to send\n");
    PE,"  0: Exit    97: Toggle Status  98: All clear   99: Display\n");
    PE,"  1: S1F1_HE  2: S1F13_E         3: S1F21_HE\n");
    PE,"  4: S5F1_E1  5: S5F1_E2\n");
    PE,"  6: S6F11_E  7: S6F11_ET1       8: S6F11_ET2\n");
    PE,"Primary message to send : ");
    #else
    PE,"\r送信する１次メッセージを選択してください\n");
    PE,"  0: Exit    97: Toggle Status  98: All clear   99: Display\n");
    PE,"  1: S1F1_HE  2: S1F13_E         3: S1F21_HE\n");
    PE,"  4: S5F1_E1  5: S5F1_E2\n");
    PE,"  6: S6F11_E  7: S6F11_ET1       8: S6F11_ET2\n");
    PE,"送信する１次メッセージ : ");
    #endif
    fgets(str,sizeof(str)-1,stdin);
    req=(-1);	sscanf(str,"%d",&req);
    #if defined ENGLISH
    if(0<req && req<90){	// Check if it can currently be sent
      if	(Md->ssb[0]   ==0){
	PE,"PLC can not send : PLC not available\n");		       continue;
      }else if	(Md->ssb[1]   ==0){
	PE,"PC can not send : PC not available\n");		       continue;
      }else if	(Md->hsb[0][0]!=0 || Md->hsb[0][1]!=0){
	PE,"Can not send : Now sending SECS Message\n");	       continue;
      }else if	(Md->hsb[1][0]!=0 || Md->hsb[1][1]!=0){
	PE,"Can not send : Now receiving SECS Message\n");	       continue;
    } }
    #else
    if(0<req && req<90){	// 現在送信可能か否かをチェック
      if	(Md->ssb[0]   ==0){
	PE,"PLC は使用可能状態でないため、送信できません\n");	       continue;
      }else if	(Md->ssb[1]   ==0){
	PE,"PC は使用可能状態でないため、送信できません\n");	       continue;
      }else if	(Md->hsb[0][0]!=0 || Md->hsb[0][1]!=0){
	PE,"現在 SECS Message 送信中のため、送信できません\n");	       continue;
      }else if	(Md->hsb[1][0]!=0 || Md->hsb[1][1]!=0){
	PE,"現在 SECS Message 受信中のため、送信できません\n");	       continue;
    } }
    #endif

    switch(req){
      case  0:	Break	= 1;						  break;
      case  1:	SendS1F1 ();						  break;
      case  2:	SendS1F13();						  break;
      case  3:	SendS1F21(21);						  break;
      case  4:	SendS5F1 (0);						  break;
      case  5:	SendS5F1 (1);						  break;
      case  6:	SendS6F11(0);						  break;
      case  7:	SendS6F11(1);						  break;
      case  8:	SendS6F11(2);						  break;
      case 97:	Md->ssb[0]=1-Md->ssb[0];				  break;
      case 98:	ssb[0]=Md->ssb[0];	 ssb[1]=Md->ssb[1]; // Save 'ssb'
		memset(Md,'\0',SMSIZE);			    // Clear all area
		Md->ssb[0]=ssb[0];	 Md->ssb[1]=ssb[1];		  break;
      case 99:	PO,"ssb  = %d, %d\n"	,Md->ssb[0]	, Md->ssb[1]);
		PO,"hsb.0= %d, %d\n"	,Md->hsb[0][0]	, Md->hsb[0][1]);
		PO,"hsb.1= %d, %d\n"	,Md->hsb[1][0]	, Md->hsb[1][1]);
		PO,"msd.0= 0x%04x,0x%04x:0x%04x,0x%04x:%s\n"
			,Md->msd[0][0]	,Md->msd[0][1]
			,Md->msd[0][2]	,Md->msd[0][3]	,&Md->msd[0][4]);
		PO,"msd.1= 0x%04x,0x%04x:0x%04x,0x%04x:%s\n"
			,Md->msd[1][0]	,Md->msd[1][1]
			,Md->msd[1][2]	,Md->msd[1][3]	,&Md->msd[1][4]); break;
  } }
}
