FX5U TCP 通信 (2016/11/03, 2017/ 2/25 update)
・2017/ 2/25 Read / Write を訂正
・2016/11/03 バイナリ交信で、デバイス番号の指定方法が違っていたのを修正しました。
・2016/10/24a ASCII 更新で文字列書き込み、読み込みの文字列順が違うのを修正しました。
・2016/10/24 文字列書き込み、読み込みのコードを追加しました。
・2016/10/20 バイナリ交信のコードを追加しました。
■FX5U Ethernet ポートの設定
・IPアドレス、サブネットマスクを設定します。
・交信データコードは、パソコンから交信するデータに合わせます。(バイナリの時は、バイナリにします)
・相手機器接続構成設定の<詳細設定>をダブルクリックします。

・「ユニット一覧」から、「Ethernet 機器(汎用)」の「SLMP 接続機器」を赤矢印のように、ドラッグ&ドロップします。
・「SLMP接続機器」が追加されるので、プロトコルを TCP、ポート番号を 1025 に変更します。
・メニューの「設定を反映して閉じる」をクリックします。
・元の画面で、「適用」ボタンをクリックします。
・あとは、PLC へ PC パラメータを書き込み、PLC をリセットします。

■パソコン側のプログラム
・伝文フォーマットは、QCPU と同じ 「MC プロトコルの QnA 互換 3E フレーム」なので、QCPU との通信プログラムがそのまま動きます。
Delphi 10.1 Belin Starter Edition で、Indy10 IdTCPClient コンポーネントを使用しています。

// IOHandler.WriteLnRFC() を IOHandler.WriteLn() に変更しました (2017/ 1/ 6)
unit FX5UTCPUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent,
IdComponent, IdTCPConnection, IdTCPClient, IdGlobal;
type
TForm1 = class(TForm)
IdTCPClient1: TIdTCPClient;
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Label1: TLabel;
Label2: TLabel;
Edit4: TEdit;
Edit5: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// ASCII 交信で、読み込み
// Y0 ~ Y7
procedure TForm1.Button1Click(Sender: TObject);
var
head, snd, cmd, res : string;
iBits : integer;
StrText : string;
B : TBytes;
begin
Edit1.Text := '';
Edit2.Text := '';
EDit3.Text := '';
// ビット単位読み出し数
iBits := 8;
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + '03FF'; // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
cmd := '0010'; // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で読みだす
cmd := cmd + '0401'; // コマンド
cmd := cmd + '0001'; // サブコマンド
cmd := cmd + 'Y*000000'; // 先頭デバイス名(8文字)
cmd := cmd + IntToHex(iBits, 4); // 読み出し数(16進4桁)
snd := head;
snd := snd + IntToHex(cmd.Length, 4);
snd := snd + cmd;
// 送信文字列
Edit1.Text := snd;
// Indy Version 10.6.2.5341
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
B := TEncoding.ANSI.GetBytes(snd);
IOHandler.Write(TIdBytes(B), snd.Length);
// レスポンス受信
SetLength(B, 0);
IOHandler.ReadBytes(TIdBytes(B), -1);
res := TEncoding.ANSI.GetString(B);
// 受信文字列
Edit2.Text := res;
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (res.Length = 22 + iBits) and (Copy(res, 19, 4) = '0000') then
// 正常取得(ビット単位で表示)
// オンオフを文字列で表す
// 文字列の左が先頭
Edit3.Text := Copy(res, 23, iBits)
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// ASCII 交信で、書き込み
// Y0 ~ Y7
procedure TForm1.Button2Click(Sender: TObject);
var
head, cmd, snd, res : string;
StrText : string;
B : TBytes;
begin
Edit1.Text := '';
Edit2.Text := '';
Edit3.Text := '';
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + '03FF'; // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := '0010'; // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で書き込む
cmd := cmd + '1401'; // コマンド
cmd := cmd + '0001'; // サブコマンド
cmd := cmd + 'Y*'; // デバイスコード
cmd := cmd + '000000'; // 先頭デバイス名(6文字)
cmd := cmd + '0008'; // デバイス点数
cmd := cmd + '11001100'; // 書き込みデータ 0=ON, 1=OFF(デバイス点数分の文字数)
snd := head;
snd := snd + IntToHex(cmd.Length, 4); // 要求データ長(16進)
snd := snd + cmd;
// 送信文字列
Edit1.Text := snd;
// Indy Version 10.6.2.5341
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
B := TEncoding.ANSI.GetBytes(snd);
IOHandler.Write(TIdBytes(B), snd.Length);
// レスポンス受信
SetLength(B, 0);
IOHandler.ReadBytes(TIdBytes(B), -1);
res := TEncoding.ANSI.GetString(B);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// ASCII 交信で、書き込み
// Y0 ~ Y7
procedure TForm1.Button3Click(Sender: TObject);
var
head, cmd, snd, res : string;
StrText : string;
B : TBytes;
begin
Edit1.Text := '';
Edit2.Text := '';
Edit3.Text := '';
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + '03FF'; // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := '0010'; // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で書き込む
cmd := cmd + '1401'; // コマンド
cmd := cmd + '0001'; // サブコマンド
cmd := cmd + 'Y*'; // デバイスコード
cmd := cmd + '000000'; // 先頭デバイス名(6文字)
cmd := cmd + '0008'; // デバイス点数
cmd := cmd + '00000000'; // 書き込みデータ 0=ON, 1=OFF(デバイス点数分の文字数)
snd := head;
snd := snd + IntToHex(cmd.Length, 4); // 要求データ長(16進)
snd := snd + cmd;
// 送信文字列
Edit1.Text := snd;
// Indy Version 10.6.2.5341
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
B := TEncoding.ANSI.GetBytes(snd);
IOHandler.Write(TIdBytes(B), snd.Length);
// レスポンス受信
SetLength(B, 0);
IOHandler.ReadBytes(TIdBytes(B), -1);
res := TEncoding.ANSI.GetString(B);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// バイナリ交信のために、文字列のHLを反転
// ex '1234' -> '3412'
function RevStrHL(const s: string): string;
var
i, n :integer;
begin
n := s.Length;
if n > 0 then begin
for i := 0 to n div 4 - 1 do
result := result + s[i * 4 + 3] + s[i * 4 + 4] + s[i * 4 + 1] + s[i * 4 + 2];
if n mod 4 > 0 then
for i := (n div 4) * 4 + 1 to n do
result := result + s[i];
end;
end;
// 2016/11/03 追加
// バイナリ交信のために、文字列のHLを反転
// ex '123456' -> '563412'
function RevStrHL3(const s: string): string;
var
n :integer;
begin
n := s.Length;
if n = 6 then begin
result := s[5] + s[6] + s[3] + s[4] + s[1] + s[2];
end;
end;
// バイナリ交信で、書き込み
// Y0 ~ Y7
procedure TForm1.Button4Click(Sender: TObject);
var
head, cmd, snd, res : string;
sndLen : integer;
i : integer;
StrText : string;
buf: TIdBytes;
s : string;
begin
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + RevStrHL('03FF'); // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := RevStrHL('0010'); // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で書き込む
cmd := cmd + RevStrHL('1401'); // コマンド
cmd := cmd + RevStrHL('0001'); // サブコマンド
// ASCII交信と順序が異なる
// 2016/11/03 修正
cmd := cmd + RevStrHL3(IntToHex(0, 6)); // 先頭デバイス名(6文字)、16進
cmd := cmd + '9D'; // 'M*'='90', 'Y*'='9D' デバイスコード
cmd := cmd + RevStrHL('0008'); // デバイス点数
// 書き込みデータ 0=ON, 1=OFF(デバイス点数分の文字数)
// 文字列の左が、若い番号
// 奇数の時は、ダミーを追加して偶数にする (Ex: '1' -> '10')
cmd := cmd + '10000000';
snd := head;
// 要求データ長(16進)バイナリに変えるので、文字列長さの1/2
snd := snd + RevStrHL(IntToHex(cmd.Length div 2 , 4));
snd := snd + cmd;
// 送信データ数
sndLen := snd.Length div 2;
SetLength(buf, sndLen);
// 2文字ずつバイナリに変換し、バッファに格納
for i := 0 to snd.Length div 2 -1 do
buf[i] := StrToInt('$' + Copy(snd, i * 2 + 1, 2));
// 確認のためバッファを文字列として表示
s := '';
for i := 0 to Length(buf) -1 do
s := s + IntToHex(buf[i], 2);
Edit1.Text := s;
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
IOHandler.Write(buf, sndLen);
// レスポンス待ち
while IOHandler.CheckForDataOnSource(10) do ;
// 受信のため、バッファをクリア
SetLength(buf, 0);
// レスポンス受信
IOHandler.ReadBytes(buf, -1);
res := '';
for i := 0 to Length(buf) -1 do
res := res + IntToHex(buf[i], 2);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// バイナリ交信で、書き込み
// Y0 ~ Y7
procedure TForm1.Button5Click(Sender: TObject);
var
head, cmd, snd, res : string;
sndLen : integer;
i : integer;
StrText : string;
buf: TIdBytes;
s : string;
begin
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + RevStrHL('03FF'); // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := RevStrHL('0010'); // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で書き込む
cmd := cmd + RevStrHL('1401'); // コマンド
cmd := cmd + RevStrHL('0001'); // サブコマンド
// ASCII交信と順序が異なる
// 2016/11/03 修正
cmd := cmd + RevStrHL3(IntToHex(0, 6)); // 先頭デバイス名(6文字)、16進
cmd := cmd + '9D'; // 'M*='90'、'Y*'='9D'デバイスコード
cmd := cmd + RevStrHL('0008'); // デバイス点数
// 書き込みデータ 0=ON, 1=OFF(デバイス点数分の文字数)
// 文字列の左が、若い番号
// 奇数の時は、ダミーを追加し偶数にする (ex: '1' -> '10')
cmd := cmd + '00000000';
snd := head;
// 要求データ長(16進)バイナリに変えるので、文字列長さの1/2
snd := snd + RevStrHL(IntToHex(cmd.Length div 2 , 4));
snd := snd + cmd;
// 送信データ数
sndLen := snd.Length div 2;
SetLength(buf, sndLen);
// 2文字ずつバイナリに変換し、バッファに格納
for i := 0 to snd.Length div 2 -1 do
buf[i] := StrToInt('$' + Copy(snd, i * 2 + 1, 2));
// 確認のためバッファを文字列として表示
s := '';
for i := 0 to Length(buf) -1 do
s := s + IntToHex(buf[i], 2);
Edit1.Text := s;
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
IOHandler.Write(buf, sndLen);
// レスポンス待ち
while IOHandler.CheckForDataOnSource(10) do ;
// 受信のため、バッファをクリア
SetLength(buf, 0);
// レスポンス受信
IOHandler.ReadBytes(buf, -1);
res := '';
for i := 0 to Length(buf) -1 do
res := res + IntToHex(buf[i], 2);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// バイナリ交信で、読み込み
// Y0 ~ Y7
procedure TForm1.Button6Click(Sender: TObject);
var
head, cmd, snd, res : string;
sndLen : integer;
i : integer;
StrText : string;
buf: TIdBytes;
s : string;
iBits : integer;
begin
// ビット単位読み出し数
iBits := 8;
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + RevStrHL('03FF'); // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := RevStrHL('0010'); // CPU監視タイマ(16進)
//ビットデバイス(X,Y,M...など)を1点単位で読み込む
cmd := cmd + RevStrHL('0401'); // コマンド
cmd := cmd + RevStrHL('0001'); // サブコマンド
// ASCII交信と順序が異なる
// 2016/11/03 修正
cmd := cmd + RevStrHL3(IntTiHex(0, 6)); // 先頭デバイス名(6文字) 16進表記
cmd := cmd + '9D'; // 'M*'='90'、'Y*'='9D'デバイスコード
cmd := cmd + RevStrHL(IntToHex(iBits, 4)); // デバイス点数
snd := head;
// 要求データ長(16進)バイナリに変えるので、文字列長さの1/2
snd := snd + RevStrHL(IntToHex(cmd.Length div 2 , 4));
snd := snd + cmd;
// 送信データ数
sndLen := snd.Length div 2;
SetLength(buf, sndLen);
// 2文字ずつバイナリに変換し、バッファに格納
for i := 0 to snd.Length div 2 -1 do
buf[i] := StrToInt('$' + Copy(snd, i * 2 + 1, 2));
// 確認のためバッファを文字列として表示
s := '';
for i := 0 to Length(buf) -1 do
s := s + IntToHex(buf[i], 2);
Edit1.Text := s;
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
IOHandler.Write(buf, sndLen);
// レスポンス待ち
while IOHandler.CheckForDataOnSource(10) do ;
// 受信のため、バッファをクリア
SetLength(buf, 0);
// レスポンス受信
IOHandler.ReadBytes(buf, -1);
res := '';
for i := 0 to Length(buf) -1 do
res := res + IntToHex(buf[i], 2);
// 受信文字列
Edit2.Text := res;
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (res.Length = 22 + iBits) and (Copy(res, 19, 4) = '0000') then
// 正常取得(ビット単位で表示)
// オンオフを文字列で表す
// 文字列の左が先頭
Edit3.Text := Copy(res, 23, iBits)
else
// エラーコード表示
Edit3.Text := Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
StrText := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(StrText), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
end.
// *************************
// 以下、2016/10/24 追加分
// *************************
// ASCII 文字列書き込み
procedure TForm1.Button12Click(Sender: TObject);
var
head, cmd, snd, res : string;
strTExt : string;
srcText, sndText : string;
wordsCount : integer;
i : integer;
s : string;
n : integer;
B : TBytes;
begin
// 2文字ずつ入れ替え
s := Edit12.Text;
n := s.Length;
for i := 0 to n div 2 -1 do
srcText := srcText + Copy(s, i * 2 + 2, 1) + Copy(s, i * 2 + 1, 1);
if n mod 2 > 0 then
srcText := srcText + #00 + Copy(s, n, 1);
// 文字列をASCIIコードに変換し、それを16進2桁の文字列にする
// 文字列は、上位、下位で格納される
for i := 1 to srcText.Length do
sndText := sndText + IntToHex(Ord(srcText[i]), 2);
// 書き込みワード数=必要ワード数
wordsCount := srcText.Length div 2;
if srcText.Length mod 2 > 0 then begin
// 1文字余った時
sndText := sndText + '00';
Inc(wordsCount);
end;
Edit1.Text := '';
Edit2.Text := '';
Edit3.Text := '';
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + '03FF'; // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := '0010'; // CPU監視タイマ(16進)
//ワードデバイス(D...など)を1ワード単位で書き込む
cmd := cmd + '1401'; // コマンド
cmd := cmd + '0000'; // サブコマンド
cmd := cmd + 'D*'; // デバイスコード
cmd := cmd + '000000'; // 先頭デバイス名(6文字)
cmd := cmd + IntToHex(wordsCount, 4); // ワードデバイス点数
cmd := cmd + sndText; // 書き込みデータ
snd := head;
snd := snd + IntToHex(cmd.Length, 4); // 要求データ長(16進)
snd := snd + cmd;
// 送信文字列
Edit1.Text := snd;
// Indy Version 10.6.2.5341
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
B := TEncoding.ANSI.GetBytes(snd);
IOHandler.Write(TIdBytes(B), snd.Length);
// レスポンス受信
SetLength(B, 0);
IOHandler.ReadBytes(TIdBytes(B), -1);
res := TEncoding.ANSI.GetString(B);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := 'ErrorCode = ' + Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
strTExt := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(strTExt), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// ASCII 文字列読込
procedure TForm1.Button13Click(Sender: TObject);
var
head, snd, cmd, res : string;
strTExt : string;
wordsCount : integer;
readLen : integer;
readText : string;
src : string;
i : integer;
n : integer;
s : string;
B : TBytes;
begin
Edit1.Text := '';
Edit2.Text := '';
EDit3.Text := '';
// 読み込み文字列数
readLen := Length(Edit12.Text);
// 読み込みワード数
wordsCount := readLen div 2;
if readLen mod 2 > 0 then Inc(wordsCount);
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + '03FF'; // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
cmd := '0010'; // CPU監視タイマ(16進)
//ワードデバイス(D...など)を1ワード単位で読みだす
cmd := cmd + '0401'; // コマンド
cmd := cmd + '0000'; // サブコマンド
cmd := cmd + 'D*000000'; // 先頭デバイス名(8文字)
cmd := cmd + IntToHex(wordsCount, 4); // 読み出しワード数(16進4桁)
snd := head;
snd := snd + IntToHex(cmd.Length, 4);
snd := snd + cmd;
// 送信文字列
Edit1.Text := snd;
// Indy Version 10.6.2.5341
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
B := TEncoding.ANSI.GetBytes(snd);
IOHandler.Write(TIdBytes(B), snd.Length);
// レスポンス受信
SetLength(B, 0);
IOHandler.ReadBytes(TIdBytes(B), -1);
res := TEncoding.ANSI.GetString(B);
// 受信文字列
Edit2.Text := res;
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (res.Length = 22 + wordsCount * 4) and (Copy(res, 19, 4) = '0000') then begin
// 正常取得(ビット単位で表示)
// 文字列の左が先頭
src := Copy(res, 23, wordsCount*4);
for i := 1 to src.Length div 2 do
// ASCIIコードを文字列に変換
readText := readText + Char(StrToInt('$' + src[i * 2 - 1] + src[i * 2]));
n := readText.Length;
s := '';
// 2文字ずつ入れ替え
for i := 0 to n div 2 -1 do
s := s + Copy(readText, i * 2 + 2, 1) + Copy(readText, i * 2 + 1, 1);
if n mod 2 > 0 then
s := s + Copy(readText, n, 1);
Edit3.Text := s;
end
else
// エラーコード表示
Edit3.Text := 'ErrorCode = ' + Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
strTExt := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(strTExt), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// Binary 文字列書込
procedure TForm1.Button14Click(Sender: TObject);
var
head, cmd, snd, res : string;
sndLen : integer;
i : integer;
strTExt : string;
buf: TIdBytes;
s : string;
srcText, sndText : string;
wordsCount : integer;
begin
srcText := Edit12.Text;
// 文字列をASCIIコードに変換し、それを16進2桁の文字列にする
// 文字列は、上位、下位で格納される
for i := 1 to srcText.Length do
sndText := sndText + IntToHex(Ord(srcText[i]), 2);
// 書き込みワード数=必要ワード数
wordsCount := srcText.Length div 2;
if srcText.Length mod 2 > 0 then begin
// 1文字余った時
sndText := sndText + '00';
Inc(wordsCount);
end;
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号
head := head + 'FF'; // PC番号
head := head + RevStrHL('03FF'); // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号
// 送信データには、これ以降の文字列数が必要
cmd := RevStrHL('0010'); // CPU監視タイマ(16進)
//ワードデバイス(D...など)を1ワード点単位で書き込む
cmd := cmd + RevStrHL('1401'); // コマンド
cmd := cmd + RevStrHL('0000'); // サブコマンド
// ASCII交信と順序が異なる
// 2016/11/03 修正
cmd := cmd + RevStrHL3(IntToHex(0, 6)); // 先頭デバイス名(6文字) 16進表記
cmd := cmd + 'A8'; // 'D*'='A8'デバイスコード
cmd := cmd + RevStrHL(IntToHex(wordsCount, 4)); // デバイス点数
cmd := cmd + sndText;
snd := head;
// 要求データ長(16進)バイナリに変えるので、文字列長さの1/2
snd := snd + RevStrHL(IntToHex(cmd.Length div 2 , 4));
snd := snd + cmd;
// 送信データ数
sndLen := snd.Length div 2;
SetLength(buf, sndLen);
// 2文字ずつバイナリに変換し、バッファに格納
for i := 0 to snd.Length div 2 -1 do
buf[i] := StrToInt('$' + Copy(snd, i * 2 + 1, 2));
// 確認のためバッファを文字列として表示
s := '';
for i := 0 to Length(buf) -1 do
s := s + IntToHex(buf[i], 2);
Edit1.Text := s;
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
IOHandler.Write(buf, sndLen);
// レスポンス待ち
while IOHandler.CheckForDataOnSource(10) do ;
// 受信のため、バッファをクリア
SetLength(buf, 0);
// レスポンス受信
IOHandler.ReadBytes(buf, -1);
res := '';
for i := 0 to Length(buf) -1 do
res := res + IntToHex(buf[i], 2);
// 受信文字列
Edit2.Text := res;
// 正常終了時:'D00000FF03FF0000040000'
// レスポンスの判断
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (Copy(res, 19, 4) = '0000') then begin
// 正常終了
Edit3.Text := 'OK';
end
else
// エラーコード表示
Edit3.Text := 'ErrorCode = ' + Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
strTExt := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(strTExt), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;
// Binary 文字列読込
procedure TForm1.Button15Click(Sender: TObject);
var
head, cmd, snd, res : string;
sndLen : integer;
i : integer;
strTExt : string;
buf: TIdBytes;
s : string;
wordsCount : integer;
readLen : integer;
readText : string;
begin
// 読み込み文字列数
readLen := Length(Edit12.Text);
// 読み込みワード数
wordsCount := readLen div 2;
if readLen mod 2 > 0 then Inc(wordsCount);
// 送信文字列
// QnA互換3Eフレーム
head := '5000'; // サブヘッダ(PC->PLCへの伝文)
head := head + '00'; // ネットワーク番号(PLC側の設定による)
head := head + 'FF'; // PC番号(固定)
head := head + RevStrHL('03FF'); // 要求先ユニットI/O番号
head := head + '00'; // 要求先ユニット局番号(PLC側の設定による)
// 送信データには、これ以降の文字列数が必要
cmd := RevStrHL('0010'); // CPU監視タイマ(16進)
//ワードデバイス(D...など)を1ワード単位で読み込む
cmd := cmd + RevStrHL('0401'); // コマンド
cmd := cmd + RevStrHL('0000'); // サブコマンド
// ASCII交信と順序が異なる
// 2016/11/03 修正
cmd := cmd + RevStrHL3(IntToHex(0, 6)); // 先頭デバイス名(6文字)
cmd := cmd + 'A8'; // 'D*'='A8'デバイスコード
cmd := cmd + RevStrHL(IntToHex(wordsCount, 4)); // デバイス点数
snd := head;
// 要求データ長(16進)バイナリに変えるので、文字列長さの1/2
snd := snd + RevStrHL(IntToHex(cmd.Length div 2 , 4));
snd := snd + cmd;
// 送信データ数
sndLen := snd.Length div 2;
SetLength(buf, sndLen);
// 2文字ずつバイナリに変換し、バッファに格納
for i := 0 to snd.Length div 2 -1 do
buf[i] := StrToInt('$' + Copy(snd, i * 2 + 1, 2));
// 確認のためバッファを文字列として表示
s := '';
for i := 0 to Length(buf) -1 do
s := s + IntToHex(buf[i], 2);
Edit1.Text := s;
with IdTCPClient1 do begin
// タイムアウトを設定
ConnectTimeout := 1000;
ReadTimeout := 200;
// PLC の設定に合わせる
// IPアドレス
Host := Edit4.Text; //'169.254.17.243';
// ポート番号
Port := StrToIntDef(Edit5.Text, 1025);
try
// 接続
if not Connected then
Connect;
if Connected then begin
// コマンド送信
IOHandler.Write(buf, sndLen);
// レスポンス待ち
while IOHandler.CheckForDataOnSource(10) do ;
// 受信のため、バッファをクリア
SetLength(buf, 0);
// レスポンス受信
IOHandler.ReadBytes(buf, -1);
res := '';
for i := 0 to Length(buf) -1 do
res := res + IntToHex(buf[i], 2);
// 受信文字列
Edit2.Text := res;
if (res.Length >= 22) and (Copy(res, 1, 4) = 'D000') then begin
if (res.Length = 22 + wordsCount * 4) and (Copy(res, 19, 4) = '0000') then begin
// 正常取得
s := Copy(res, 23, wordsCount * 4);
for i := 1 to s.Length div 2 do
// ASCIIコードを文字列に変換
readText := readText + Char(StrToInt('$' + s[i * 2 - 1] + s[i * 2]));
Edit3.Text := readText;
end
else
// エラーコード表示
Edit3.Text := 'ErrorCode = ' + Copy(res, 19, 4);
end;
end;
// 切断
Disconnect;
except
// エラーメッセージ
on E: Exception do begin
strTExt := E.ClassName + sLineBreak + E.Message;
Application.MessageBox(PChar(strTExt), '情報', MB_ICONINFORMATION);
end;
end;
end;
end;