Consumer in Delphi 8 for .NET to read and write PLC variables

The example explains how to create an ADS-Web Service consumer for reading and writing PLC variables via ADS-HTTP.

Requirements:

Consumer in Delphi 8 for .NET to read and write PLC variables 1:

Import into Delphi

The server interface description is published in a WSDL file (Web Service Definition Language). The WSDL description is imported into Delphi and converted by Delphi into Delphi units.

First of all create a new project (Windows Forms application Delphi .NET). Save the project. You can now import the WSDL file. In the Project Manager, right click with the mouse on the project name and select “Add Web Reference”.

Consumer in Delphi 8 for .NET to read and write PLC variables 2:

A dialog opens showing Web service directories from IBM, Microsoft etc. However, we want to open the WSDL file from the data storage device.

Consumer in Delphi 8 for .NET to read and write PLC variables 3:

The WSDL files from the TwinCAT ADS Web service can be found in the folder: ..TwinCAT\Ads API\TcAdsWebService\V100\... Navigate to the appropriate folder and select the WSDL file. In our case it is the WSDL file from the folder for the Windows CE (ARM) target platform.

There is no difference between the WSDL files for the XP/CE (X86 or ARM) platforms. I.e. it is always the same WSDL file. You can integrate the WSDL file from the CE/ARM folder in your consumer project and nonetheless still communicate with an ADS Web Service server on an XP platform.

Consumer in Delphi 8 for .NET to read and write PLC variables 4:

The contents of the WSDL file are displayed in a dialog box.

Consumer in Delphi 8 for .NET to read and write PLC variables 5:

Select “Add Web Reference”. The required units are generated automatically and added to the project.

Using the web service

In order to be able to use the web service you must integrate the web service unit in the main window unit. You can take the opportunity at the same time to integrate two further units that you will need in your project later: System.Text and System.Web.Services.Protocols

uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data,
 WebReference.TcAdsWebService, System.Text,System.Web.Services.Protocols;

Now you can create an ADS Web service instance.

 private
{ Private Declarations }
TcWebService : WebReference.TcAdsWebService.TcAdsWebService;

And in the TwinForm constructor:

TcWebService := WebReference.TcAdsWebService.TcAdsWebService.Create();

The code completion will help you further. Type in TcWebService with a dot and look at the methods which are available.

We use the following methods in our example:

type TArrayOfByte = array of Byte;

procedure Read(netId: string; nPort: Integer; indexGroup: Cardinal; indexOffset: Cardinal; cbLen: Integer; out ppData: TArrayOfByte);
procedure Write(netId: string; nPort: Integer; indexGroup: Cardinal; indexOffset: Cardinal; pData: TArrayOfByte);
procedure ReadState(netId: string; nPort: Integer; out pAdsState: Integer; out pDeviceState: Integer);
procedure WriteControl(netId: string; nPort: Integer; adsState: Integer; deviceState: Integer; pData: TArrayOfByte);

netId: String with the network address of the TwinCAT target system. In our case the TwinCAT AMS NetID of the PC with the PLC runtime system;

nPort: TwinCAT ADS port number of the PLC runtime system;

indexGroup: Index group of the PLC variables to be read;

indexOffset: Index offset (byte-/bit offset) of the PLC variables to be read;

cbLen: Number of bytes which are to be read;

ppData: Variable in which the read data is saved (dynamic byte array);

pData: Variable with the data to be written (dynamic array);

adsState / pAdsState: PLC server status.

deviceState / pDeviceState: PLC device status;

The PLC application

PROGRAM MAIN
VAR
    VarBool    AT %MX0.0:  BOOL := TRUE;
    VarInt     AT %MB1:    INT := 123;
    VarString  AT %MB3:    STRING := 'Hello Automation';
END_VAR

Read PLC variables

procedure TWinForm.ReadData();
var cbLen, nIG, nIO   : Integer;
    data    : TArrayOfByte;
begin
  try
    // read BOOL at adress AT%MX0.0
    nIG   := $4021;
    nIO   := 0;
    cbLen := SizeOf(varBool);
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varBool     := BitConverter.ToBoolean(data, 0);
    // read INT at adress AT%MB1
    nIG   := $4020;
    nIO   := 1;
    cbLen := SizeOf(varInt);
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varInt      := BitConverter.ToInt16(data, 0);
    // read STRING at adress AT%MB3
    nIG   := $4020;
    nIO   := 3;
    cbLen := 81;
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varString := System.Text.Encoding.Default.GetString(data,0, Length(data));
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Write PLC variables

procedure TWinForm.WriteData();
var data    : TArrayOfByte;
    cbLen, nIG, nIO : Integer;
begin
  try
    // write BOOL at adress AT%MX0.0
    nIG   := $4021;
    nIO   := 0;
    data  := BitConverter.GetBytes(varBool);
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
    // write INT at adress AT%MB1
    nIG   := $4020;
    nIO   := 1;
    data  := BitConverter.GetBytes(varInt);
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
    // write STRING at adress AT%MB3
    nIG   := $4020;
    nIO   := 3;
    cbLen := System.Text.Encoding.Default.GetByteCount(varString);
    // Allocate one byte more! We need it to write the string end delimiter!.
    SetLength(data, cbLen + 1);
    System.Text.Encoding.Default.GetBytes( varString, 0, cbLen, data, 0);
    data[cbLen] := 0;
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Read PLC status

procedure TWinForm.ReadState();
var adsState, deviceState : Integer;
sState : String;
begin
  try
    TcWebService.ReadState( sNetID, iPort, adsState, deviceState );
    case adsState of
      PLC_ADSSTATE_RUN:
    sState := 'RUN';
      PLC_ADSSTATE_STOP:
    sState := 'STOP';
    else
      sState := 'OTHER';
    end;
    StatusBar1.Panels.Item[0].Text := 'PLC server state: ' + sState;
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Start/stop PLC

procedure TWinForm.WriteControl(adsState : Integer);
begin
  try
    TcWebService.WriteControl( sNetID, iPort, adsState, 0, nil );
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Language / IDE

Extract the sample program

Delphi 8 for .NET

Sample01.exe