Read the List of an ADS Device's Declared Variables

System requirements:

Task

The sample program illustrates how the AdsReadSymbolInfo and AdsEnumSymbols methods can be used to read the list of declared variables of an ADS device. By clicking on the Read Symbol Info button, the symbol information of the first PLC runtime system (port 801), or of an additional task in the TwinCAT System Manager (port 301), is read and displayed in a table.

Description

Symbol Configuration for the PLC Runtime System

In order to be able to access the symbol information for a PLC runtime system, it is necessary to activate the symbol generation for the PLC variables or structures, and for the symbol information to be loaded into the PLC runtime system during the project download. The settings necessary for the symbol download can be made in the option dialog for the TwinCAT category in TwinCAT PLC Control. The first PLC runtime system is addressed via port number 801. 

Symbol Configuration of the Additional Task in the TwinCAT System Manager

An additional task can be inserted and configured in the TwinCAT System Manager. The variables of the additional task can be linked to other variables (e.g. with the PLC variables, or the I/O variables of a Bus Terminal Controller). In order to be able to access the additional task's symbol information, the checkbox for symbol generation must be activated in the Task settings configuration dialog. The additional task is addressed via port number 301. 

Delphi 5 program

The connection to the first runtime system of the PLC (port 801) on the local PC is established in the OnFormCreate event function. At the same time the ListView component and the necessary variables are initialized. The ReadSymInfoButtonClick method is called by clicking the Read Symbol Info button. In this method, the AdsReadSymbolInfo method is first called to determine the number of available symbols, after which a for-loop is used to read the symbol information for each individual symbol variable. The values are then added to the ListView component by means of the supplementary AddListViewItem procedure. The AdsEnumSymbols method possesses a boolean flag, bNext. If this flag is set to FALSE, the symbol information of the first symbol is read, but if bNext=TRUE then all the other symbols are read. In order to be able to read the symbol information of the additional task in the TwinCAT System Manager, the AdsAmsServerPort property of the AdsOcx component must be set to 301. The port number can be set at runtime using the AdsOcx component's properties page. The properties page can be called in the sample application via the AdsOcx->Properties menu. 

unit SampleUnit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, OleCtrls, ADSOCXLib_TLB, ExtCtrls, ComCtrls, Menus;

type
  TForm1 = class(TForm)
    AdsOcx1: TAdsOcx;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Exit1: TMenuItem;
    AdsOcx2: TMenuItem;
    Properties1: TMenuItem;
    About1: TMenuItem;
    ReadSymInfoButton: TButton;
    ListView1: TListView;
    StatusBar1: TStatusBar;
    procedure OnFormCreate(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure Properties1Click(Sender: TObject);
    procedure About1Click(Sender: TObject);
    procedure ReadSymInfoButtonClick(Sender: TObject);
  private
    { Private declarations }
    procedure CreateColumns(Sender: TObject);
    procedure AddListViewItem(Sender: TObject; strSymbolName, strComment :WideString; nSymbolType, cbSymbolSize , nIndexGroup, nIndexOffset : integer);
  public
    { Public declarations }
  end;

var
  Form1         : TForm1;
  adsResult     : integer;       {Ads result}
  nSymbols      : integer;
  nSymByteSize      : integer;

implementation

{$R *.DFM}

procedure TForm1.CreateColumns(Sender: TObject);
var ListColumn :TListColumn;
begin
     ListView1.ViewStyle := vsReport;
     ListView1.Align := alBottom;
     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 50;
     ListColumn.Caption := 'No';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 200;
     ListColumn.Caption := 'Symbol name';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 100;
     ListColumn.Caption := 'Type';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 100;
     ListColumn.Caption := 'Size';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 100;
     ListColumn.Caption := 'Comment';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 100;
     ListColumn.Caption := 'Index Group';
     ListColumn.Alignment := taLeftJustify;

     ListColumn := ListView1.Columns.Add();
     ListColumn.Width := 100;
     ListColumn.Caption := 'Index Offset';
     ListColumn.Alignment := taLeftJustify;
end;


procedure TForm1.OnFormCreate(Sender: TObject);
begin
     nSymbols := 0;
     nSymByteSize := 0;
     StatusBar1.SimplePanel := true;

     AdsOcx1.AdsAmsServerNetId := AdsOcx1.AdsAmsClientNetId;    {Sets PLC server network adress}
     AdsOcx1.AdsAmsServerPort := 801;               {Sets the PLC run time system}
     StatusBar1.SimpleText := AdsOcx1.AdsServerAdsState;

     CreateColumns(Sender);
end;



procedure TForm1.ReadSymInfoButtonClick(Sender: TObject);
var
   strSymbolName : WideString;
   nSymbolType : Integer;
   cbSymbolSize : Integer;
   strComment : WideString;
   nIndexGroup : Integer;
   nIndexOffset : Integer;

   bNext : WordBool;
   nSymNo      :Integer;
begin
     ListView1.Items.Clear();      {clear old items}

     adsResult := AdsOcx1.AdsReadSymbolInfo( nSymbols, nSymByteSize );
     StatusBar1.SimpleText := Format('AdsReadSymbolInfo result:%d, nSymbols:%d, nSymByteSize:%d', [adsResult, nSymbols, nSymByteSize]);

     if ( ( adsResult = 0 ) And ( nSymbols > 0 ) ) then
     begin

      bNext := false;      {read first symbol info}
      adsResult := AdsOcx1.AdsEnumSymbols( strSymbolName, nSymbolType, cbSymbolSize, strComment, nIndexGroup, nIndexOffset, bNext);
      AddListViewItem(Sender, strSymbolName, strComment, nSymbolType, cbSymbolSize, nIndexGroup, nIndexOffset);

      if adsResult > 0 then
         StatusBar1.SimpleText := Format('AdsEnumSymbols result:%d', [adsResult]);

      for nSymNo := 1 to nSymbols-1 do
      begin
           bNext := true;
           adsResult := AdsOcx1.AdsEnumSymbols( strSymbolName, nSymbolType, cbSymbolSize, strComment, nIndexGroup, nIndexOffset, bNext);
           AddListViewItem(Sender, strSymbolName, strComment, nSymbolType, cbSymbolSize, nIndexGroup, nIndexOffset);

           if (adsResult > 0) then
          StatusBar1.SimpleText := Format('AdsEnumSymbols result:%d', [adsResult]);
     end;
     end;
end;

procedure TForm1.AddListViewItem(Sender: TObject; strSymbolName, strComment :WideString; nSymbolType, cbSymbolSize , nIndexGroup, nIndexOffset : integer);
var   ListItem     :TListItem;
      strAdsType   :String;
begin
     ListItem := ListView1.Items.Add();
     ListItem.Caption :=  Format('%d',[ListView1.Items.Count]);

     ListItem.SubItems.Add(strSymbolName);

     case  nSymbolType of
       0:  strAdsType := 'ADST_VOID';
       16:  strAdsType := 'ADST_INT8';
       17:  strAdsType := 'ADST_UINT8';
       2:  strAdsType := 'ADST_INT16';
       18:  strAdsType := 'ADST_UINT16';
       3:  strAdsType := 'ADST_INT32';
       19:  strAdsType := 'ADST_UINT32';
       20:  strAdsType := 'ADST_INT64';
       21:  strAdsType := 'ADST_UINT64';
       4:  strAdsType := 'ADST_REAL32';
       5:  strAdsType := 'ADST_REAL64';
       65:  strAdsType := 'ADST_BIGTYPE';
       30:  strAdsType := 'ADST_STRING';
       31:  strAdsType := 'ADST_WSTRING';
       32:  strAdsType := 'ADST_REAL80';
       33:  strAdsType := 'ADST_BIT';
       34:  strAdsType := 'ADST_MAXTYPES';
     end;

     ListItem.SubItems.Add(Format('%s',[strAdsType]));
     ListItem.SubItems.Add(Format('0x%x (%d)',[cbSymbolSize, cbSymbolSize]));
     ListItem.SubItems.Add(strComment);
     ListItem.SubItems.Add(Format('0x%x (%d)',[nIndexGroup, nIndexGroup]));
     ListItem.SubItems.Add(Format('0x%x (%d)',[nIndexOffset, nIndexOffset]));
end;


procedure TForm1.Exit1Click(Sender: TObject);
begin
    Close();
end;

procedure TForm1.Properties1Click(Sender: TObject);
begin
    AdsOcx1.BrowseProperties();
    StatusBar1.SimpleText := AdsOcx1.AdsServerAdsState;
end;

procedure TForm1.About1Click(Sender: TObject);
begin
    AdsOcx1.AboutBox();
end;

Initialization
    IsMultiThread := True;// Setting this system variable makes Delphi's memory manager thread-safe


end.

PLC program

PROGRAM MAIN
VAR
    REAL32_1 AT %MB0 : REAL;  (* 1 *)
    REAL32_2 AT %MB4 : REAL;  (* 2 *)
    REAL32_3 AT %MB8 : REAL;  (* 3 *)
    REAL32_4 AT %MB12: REAL;  (* 4 *)
    REAL32_5 AT %MB16: REAL;  (* 5 *)

    REAL64_1 AT %MB20 : LREAL;  (* 6 *)
    REAL64_2 AT %MB28 : LREAL;  (* 7 *)
    REAL64_3 AT %MB36 : LREAL;  (* 8 *)
    REAL64_4 AT %MB44 : LREAL;  (* 9 *)
    REAL64_5 AT %MB52 : LREAL;  (* 10 *)

    INT32_1 AT %MB60 : DINT;  (* 11 *)
    INT32_2 AT %MB64 : DINT;  (* 12 *)
    INT32_3 AT %MB68 : DINT;  (* 13 *)
    INT32_4 AT %MB72 : DINT;  (* 14 *)
    INT32_5 AT %MB76 : DINT;  (* 15 *)

    UINT32_1 AT %MB80 : UDINT;  (* 16 *)
    UINT32_2 AT %MB84 : UDINT;  (* 17 *)
    UINT32_3 AT %MB88 : UDINT;  (* 18 *)
    UINT32_4 AT %MB92 : UDINT;  (* 19 *)
    UINT32_5 AT %MB96 : UDINT;  (* 20 *)

    INT16_1 AT %MB100 : INT;  (* 21 *)
    INT16_2 AT %MB102 : INT;  (* 22 *)
    INT16_3 AT %MB104 : INT;  (* 23 *)
    INT16_4 AT %MB106 : INT;  (* 24 *)
    INT16_5 AT %MB108 : INT;  (* 25 *)

    UINT16_1 AT %MB110 : UINT;  (* 26 *)
    UINT16_2 AT %MB112 : UINT;  (* 27 *)
    UINT16_3 AT %MB114 : UINT;  (* 28 *)
    UINT16_4 AT %MB116 : UINT;  (* 29 *)
    UINT16_5 AT %MB118 : UINT;  (* 30 *)

    INT8_1 AT %MB120 : SINT;  (* 31 *)
    INT8_2 AT %MB121 : SINT;  (* 32 *)
    INT8_3 AT %MB122 : SINT;  (* 33 *)
    INT8_4 AT %MB123 : SINT;  (* 34 *)
    INT8_5 AT %MB124 : SINT;  (* 35 *)

    UINT8_1 AT %MB125 : USINT;  (* 36 *)
    UINT8_2 AT %MB126 : USINT;  (* 37 *)
    UINT8_3 AT %MB128 : USINT;  (* 38 *)
    UINT8_4 AT %MB129 : USINT;  (* 39 *)
    UINT8_5 AT %MB130 : USINT;  (* 40 *)

    BOOL_1 AT %MX131.0 : BOOL;  (* 41 *)
    BOOL_2 AT %MX131.1 : BOOL;  (* 42 *)
    BOOL_3 AT %MX131.2 : BOOL;  (* 43 *)
    BOOL_4 AT %MX131.3 : BOOL;  (* 44 *)
    BOOL_5 AT %MX131.4 : BOOL;  (* 45 *)

    ARRAY_1 : ARRAY[1 .. 10] OF SINT; (* 46 *)
    ARRAY_2 : ARRAY[1 .. 10] OF INT;  (* 47 *)
    ARRAY_3 : ARRAY[1 .. 10] OF DINT; (* 48 *)
    ARRAY_4 : ARRAY[1 .. 10] OF LREAL;(* 49 *)
    ARRAY_5 : ARRAY[1 .. 10] OF BOOL; (* 50 *)
END_VAR

Language / IDE

Unpack sample program

Delphi XE2

Sample02.exe

Delphi 5 or higher (classic)