1. TOP
  2. OMRON
  3. 上位アプリケーション
  4. メッセージ通信
  5. FinsTCP

概略

PCはEthernet経由でFINSコマンドをPLCに送信することでPLCのメモリの値を読み書きすることができます
FinsTCPの場合は最初に「FINS ノードアドレス情報送信コマンド」を送信してクライアントとサーバのFINSノードアドレスを取得します
取得したFINSノードアドレスをFINSヘッダにセットしてFINSフレームの前にFINS-TCPヘッダを付けて送信することになります

全体のメッセージは以下のようになります

FINS-TCPヘッダFINSフレーム
Header LEN CMD Err FINSヘッダ FINSコマンド
'F''I''N''S'
※ 「FINS ノードアドレス情報送信コマンド」で取得したFINSノードアドレス

サンプル

ここではFinsTCPを使ってDMの値を読み出します Com

PLCのIPアドレス192.168.250.1
PCのIPアドレス192.168.250.48
送信コマンドの内容DM100から10CH分の値を読出す

PLCのメモリの値

+0+1+2+3+4+5+6+7+8+9
DM100000100020003000400050006000700080009000A

以下サンプルコードは同期通信でのやり方をC#で書いてあります
フォームの作成(ボタンの配置など)は省略しているので適宜ボタンなどは配置してください

同期通信

同期通信はコマンド送信してから受信待ちの状態になります
受信タイムアウトは1000msとしているので1秒以内にレスポンスがなければ受信待ち状態から抜けます

private void TcpFinsMessage()
{
	System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient("192.168.250.1", 9600);
	System.Net.Sockets.NetworkStream ns = tcp.GetStream();

	ns.ReadTimeout = 1000;
	ns.WriteTimeout = 1000;

	// FINS ノードアドレス情報送信コマンド
	byte[] FinsTcpHeader = new byte[20];
	FinsTcpHeader[0] = 0x46;       // "F"
	FinsTcpHeader[1] = 0x49;       // "I"
	FinsTcpHeader[2] = 0x4E;       // "N"
	FinsTcpHeader[3] = 0x53;       // "S"
	FinsTcpHeader[4] = 0x00;
	FinsTcpHeader[5] = 0x00;
	FinsTcpHeader[6] = 0x00;
	FinsTcpHeader[7] = 0x0C;
	FinsTcpHeader[8] = 0x00;
	FinsTcpHeader[9] = 0x00;
	FinsTcpHeader[10] = 0x00;
	FinsTcpHeader[11] = 0x00;
	FinsTcpHeader[12] = 0x00;
	FinsTcpHeader[13] = 0x00;
	FinsTcpHeader[14] = 0x00;
	FinsTcpHeader[15] = 0x00;
	FinsTcpHeader[16] = 0x00;
	FinsTcpHeader[17] = 0x00;
	FinsTcpHeader[18] = 0x00;
	FinsTcpHeader[19] = 0x00;

	ns.Write(FinsTcpHeader, 0, FinsTcpHeader.Length);

	byte[] resHeader = new byte[256];
	int resHeaderSize = ns.Read(resHeader, 0, resHeader.Length);

	if ((resHeader[8] == 0x00 && resHeader[9] == 0x00) &&
		(resHeader[10] == 0x00 && resHeader[11] == 0x01))
	{

	byte ClientNodeNo = resHeader[19];
	byte ServerNodeNo = resHeader[23];


	//FINS-TCPヘッダ+FINSフレームの送信
	byte[] cmd = new byte[34];
	// ----------------- FINS-TCPヘッダ
	cmd[0] = 0x46;          // "F"
	cmd[1] = 0x49;          // "I"
	cmd[2] = 0x4E;          // "N"
	cmd[3] = 0x53;          // "S"
	cmd[4] = 0x00;          // Length
	cmd[5] = 0x00;
	cmd[6] = 0x00;
	cmd[7] = 18 + 8;        // (Command以降のバイト数)
	cmd[8] = 0x00;          // Command
	cmd[9] = 0x00;
	cmd[10] = 0x00;
	cmd[11] = 0x02;
	cmd[12] = 0x00;         // ErrorCode
	cmd[13] = 0x00;
	cmd[14] = 0x00;
	cmd[15] = 0x00;
	// ----------------- FINSヘッダ
	cmd[16] = 0x80;          // ICF
	cmd[17] = 0x00;          // RSV
	cmd[18] = 0x02;          // GCT
	cmd[19] = 0;             // DNA  相手先ネットワークアドレス
	cmd[20] = ServerNodeNo;  // DA1  相手先ノードアドレス
	cmd[21] = 0;             // DA2  相手先号機アドレス
	cmd[22] = 0;             // SNA  発信元ネットワークアドレス
	cmd[23] = ClientNodeNo;  // SA1  発信元ノードアドレス
	cmd[24] = 0;             // SA2  発信元号機アドレス
	cmd[25] = 1;             // SID  識別子 00-FFの任意の数値
	// ----------------- FINSコマンド
	cmd[26] = 0x01;         // MRC  読出しコマンド 0101
	cmd[27] = 0x01;         // SRC
	cmd[28] = 0x82;         // MemoryType = DM
	cmd[29] = 0x00;         // ReadAddress = 100CH
	cmd[30] = 0x64;
	cmd[31] = 0x00;
	cmd[32] = 0x00;         // ReadSize = 10CH
	cmd[33] = 0x0A;

	ns.Write(cmd, 0, cmd.Length);

	byte[] resCmd = new byte[2048];
	int resCmdSize = ns.Read(resCmd, 0, resCmd.Length);

	if ((resCmd[8] == 0x00 && resCmd[9] == 0x00) &&
		(resCmd[10] == 0x00 && resCmd[11] == 0x02))
	{
		byte[] rcvData = new byte[resCmdSize];
		Array.Copy(resCmd, rcvData, resCmdSize);

		textBox1.AppendText(BitConverter.ToString(rcvData) + "\r\n");
	}
}
ns.Close();
tcp.Close();

解説

3-4行目


System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient("192.168.250.1", 9600);
System.Net.Sockets.NetworkStream ns = tcp.GetStream();
	

PCのIPアドレスとTCPポートNoを指定してTCPクライアントを作成します
データ送受信で使用するネットワークストリームをGetStreamで作成します

6-7行目


ns.ReadTimeout = 1000;
ns.WriteTimeout = 1000;
	

読み取りと書き込みのタイムアウト時間を1000msに設定します

9-30行目


// FINS ノードアドレス情報送信コマンド
byte[] FinsTcpHeader = new byte[20];
FinsTcpHeader[0] = 0x46;       // "F"
~
FinsTcpHeader[19] = 0x00;
	

FINSノードアドレス情報送信コマンドを送信するバイト配列にセットします
FINS/TCPでは空いているFINSノードアドレスを取得するためにこのコマンドを送信します
詳しくはFINS/UDPとFINS/TCPの比較を参照してください

32行目


ns.Write(FinsTcpHeader, 0, FinsTcpHeader.Length);
	

FINSノードアドレス情報送信コマンドを送信します

34-35行目


byte[] resHeader = new byte[256];
int resHeaderSize = ns.Read(resHeader, 0, resHeader.Length);
	

FINSノードアドレス情報送信コマンドに対するレスポンスを受信します

37-38行目


if ((resHeader[8] == 0x00 && resHeader[9] == 0x00) &&
(resHeader[10] == 0x00 && resHeader[11] == 0x01))
	

レスポンスのFINS/TCPヘッダのCommandの項目の値が0x00000001のときに処理を進めます

41-42行目


byte ClientNodeNo = resHeader[19];
byte ServerNodeNo = resHeader[23];
	

レスポンスの19byte目を発信元(Client)ノード番号、23byte目を相手先(server)ノード番号として格納します

45-83行目


//FINS-TCPヘッダ+FINSフレームの送信
byte[] cmd = new byte[34];
// ----------------- FINS-TCPヘッダ
cmd[0] = 0x46;          // "F"
~
cmd[33] = 0x0A;
	

FINS-TCPヘッダを含んでFINSコマンドを送信用バイト配列にセットします
ここではDM100から10CH分のデータを読み出すコマンドをセットしています
FINSコマンドの内容についてはFINSコマンドを参照してください

85行目


ns.Write(cmd, 0, cmd.Length);
	

FINSコマンドを送信します

87-88行目


byte[] resCmd = new byte[2048];
int resCmdSize = ns.Read(resCmd, 0, resCmd.Length);
	

FINSコマンドに対するレスポンスを受信します

90-97行目


if ((resCmd[8] == 0x00 && resCmd[9] == 0x00) &&
(resCmd[10] == 0x00 && resCmd[11] == 0x02))
{
byte[] rcvData = new byte[resCmdSize];
Array.Copy(resCmd, rcvData, resCmdSize);

textBox1.AppendText(BitConverter.ToString(rcvData) + "\r\n");
}
	

レスポンスのFINS/TCPヘッダのCommandの項目の値が0x00000002のときにレスポンスデータをrcvDataに格納してテキストボックス(txtBox1)に追加書込みします

99-1000行目


ns.Close();
tcp.Close();
	

ネットワークストリームとTCPクライアントのインスタンスを破棄します

サンプルソース

GitHub SampleFins

GitHubからここで紹介したソースがダウンロードできます

この記事へのコメント