OMRON 上位リンク通信 (2017/02/26)

上位リンク C コマンドと FINS コマンド で通信します。
C コマンドのほうが、シンプルで速いです。
Write-ReadBytes は、コメントアウトしていますが、WriteLn-ReadLn と同じ結果になります。
WriteLn の場合、CRLF (#13#10) が付加されるので、ターミネータの CR (#13) は不要です。


unit FINSUnit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Edit,
  FMX.Controls.Presentation, FMX.StdCtrls, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, IdGlobal;

type
  TForm1 = class(TForm)
    IdTCPClient1: TIdTCPClient;
    Button1: TButton;
    Edit1: TEdit;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

// FCS 計算
function FCS(const src: string):integer;
var
  i :integer;
begin
  result := 0;
  for i := 0 to Pred(src.Length) do
    result := Ord(src.Chars[i]) Xor result;
end;

// FINS コマンド
procedure TForm1.Button1Click(Sender: TObject);
// uses ... , IdGlobal;
var
  snd, res : string;
  //AData : TBytes;
  Ticks:Cardinal;
begin
  IdTCPClient1.Host := '1.2.3.4';
  IdTCPClient1.Port := 2000;
  IdTCPClient1.ConnectTimeout := 2000;

  snd := '@';
  snd := snd + '00';   // 上位リンク用ユニットNo
  snd := snd + 'FA';   // ヘッダーコード
  snd := snd + '0';    // レスポンスウェイト時間
  snd := snd + '00';   // ICF (ネットワーク上=80, でない時=00)
  snd := snd + '00';   // DA2
  snd := snd + '00';   // SA2
  snd := snd + '00';   // SID  (通常00)再送の場合のカウンタ
  snd := snd + '0101'; // 連続したI/O メモリエリアの内容を読み出し

  snd := snd + '30';     // CIO=30 (16進2桁)
  snd := snd + '000000'; // 読出し開始アドレス(16進4桁+16進2桁) 0000CH の00BIT
  snd := snd + '0010';   // 読出しビット数(BIN) (16 進 4 桁)$10=16個

  snd := snd + IntToHex(FCS(snd), 2); // FCS (16進 4桁)
  snd := snd + '*';// + #13; // ターミネーター

  IdTCPClient1.Connect;
  if IdTCPClient1.Connected then begin
    Ticks := TThread.GetTickCount;
    {
    AData := TEncoding.ANSI.GetBytes(snd);
    IdTCPClient1.IOHandler.Write(TIdBytes(AData), snd.Length);
    // レスポンス受信
    SetLength(AData, 0);
    IdTCPClient1.IOHandler.ReadBytes(TIdBytes(Adata), -1);
    res := TEncoding.ANSI.GetString(Adata);
    }

    IdTCPClient1.IOHandler.WriteLn(snd);
    res := IdTCPClient1.IOHandler.ReadLn(#13);

    if res.Substring(5, 2) = '00' then
      // ビットは、24文字目から2文字ずつ取得 00=OFF, 01=ON
      res := res.Substring(23, 32);
    Edit1.Text := res;
    ShowMessage(IntToStr(TThread.GetTickCount - Ticks));
    IdTCPClient1.Disconnect;
  end;
end;

// C コマンド
procedure TForm1.Button2Click(Sender: TObject);
// uses ... , IdGlobal;
var
  snd, res : string;
  //AData : TBytes;
  Ticks : Cardinal;
begin
  IdTCPClient1.Host := '1.2.3.4';
  IdTCPClient1.Port := 2000;
  IdTCPClient1.ConnectTimeout := 2000;

  snd := '@';
  // ユニットNo.(BCD 2文字)
  snd := snd + '00';
  // ヘッダコード
  snd := snd + 'RR';   //CIOエリア読出
  snd := snd + '0000'; // 読出開始チャネル:BCD 4桁
  // モード
  snd := snd + '0001'; // 読出チャネル数:BCD 4桁
  // FCS (HEX 2 桁)
  snd := snd + IntToHex(FCS(snd), 2);
  // ターミネーター
  snd := snd + '*';// + #13;
  AData := TEncoding.ANSI.GetBytes(snd);


  IdTCPClient1.Connect;
  if IdTCPClient1.Connected then begin
    Ticks := TThread.GetTickCount;
    {
    AData := TEncoding.ANSI.GetBytes(snd);
    IdTCPClient1.IOHandler.Write(TIdBytes(AData), snd.Length);
    // レスポンス受信
    SetLength(AData, 0);
    IdTCPClient1.IOHandler.ReadBytes(TIdBytes(Adata), -1);
    res := TEncoding.ANSI.GetString(Adata);
    }
    IdTCPClient1.IOHandler.WriteLn(snd);
    res := IdTCPClient1.IOHandler.ReadLn(#13);
    if res.Substring(5, 2) = '00' then
      // BCD 4桁
      res := res.Substring(7, 4);
    Edit1.Text := res;
    ShowMessage(IntToStr(TThread.GetTickCount - Ticks));
    IdTCPClient1.Disconnect;
  end;
end;

end.