Read PLC variable declaration with Delphi

From TwinCAT.Ads.NET version >= 1.0.0.12

Task

All variables that are declared in the PLC should be displayed in a tree view.

Description

In theMainForm_Loadmethod an instance of the TcAdsSymbolInfoLoader is created with a call to TcAdsClient.CreateSymbolInfoLoader. This class is responsible for loading the symbol information from the PLC. By clicking the Load Symbols button the symbols are loaded by means of the TcAdsSymbolInfoLoader.GetFirstSymbol method. This method returns the first loaded symbol as a TcAdsSymbolInfo object. The methods TcAdsSymbolInfo.NextSymbol und TcAdsSymbolInfo.FirstSubSymbol are  used to iterate over the symbols and to display the symbols hierarchically in the tree view. If the check box flat is checked, the symbols are displayed in a flat list. In this case the application enumerates over the symbols loaded by the TcAdsSymbolInfoLoader object. This includes the sub symbols.

By selecting a tree view item the edit boxes are filled with the symbol information. Additionally the value of the variable is read with the help of TcAdClient.ReadSymbol and is displayed in the value edit box. To write a value to a variable one has to click the  Write Value button, which leads to a call of TcAdsCient.WriteSymbol.

To read the symbol information for a specific variable, one can either click the Read Symbol Info or the Find Symbol button. In the first case the method TcAdsClient.ReadSymbolInfo is called. This leads to an ADS call, to load the information for this symbol from the PLC. In the second case the method TcAdsSymbolInfoLoader.FindSymbol is called, to search for the symbol in the list of the previous loaded symbols. If no symbols have been loaded before, all symbols are loaded from the PLC.

 

 

Delphi Prism (Embarcadero Prism XE2, Oxygene for .NET) program

namespace Sample06;

interface

uses
  System.Drawing,
  System.Collections,
  System.Collections.Generic,
  System.Windows.Forms,
  System.ComponentModel, System.IO, TwinCAt.Ads;

type
  /// <summary>
  /// Summary description for MainForm.
  /// </summary>
  MainForm = partial class(System.Windows.Forms.Form)
  private
    tcClient      : TcAdsClient;
    symbolLoader  : TcAdsSymbolInfoLoader;
    currentSymbol : ITcAdsSymbol;

    method CreateNewNode(var symbol: TcAdsSymbolInfo) : TreeNode;
    method SetSymbolInfo(symbol: ITcAdsSymbol);
    method MainForm_Load(sender: System.Object; e: System.EventArgs);
    method MainForm_FormClosing(sender: System.Object; e: System.Windows.Forms.FormClosingEventArgs);
    method btnLoad_Click(sender: System.Object; e: System.EventArgs);
    method btnWrite_Click(sender: System.Object; e: System.EventArgs);
    method btnFindSymbol_Click(sender: System.Object; e: System.EventArgs);
    method btnReadSymbolInfo_Click(sender: System.Object; e: System.EventArgs);
    method treeView1_AfterSelect(sender: System.Object; e: System.Windows.Forms.TreeViewEventArgs);
  protected
    method Dispose(disposing: Boolean); override;
  public
    constructor;
  end;

implementation

{$REGION Construction and Disposition}
constructor MainForm;
begin
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent();

  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

method MainForm.Dispose(disposing: Boolean);
begin
  if disposing then begin
    if assigned(components) then
      components.Dispose();

    //
    // TODO: Add custom disposition code here
    //
  end;
  inherited Dispose(disposing);
end;
{$ENDREGION}

method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);
begin
  tcClient := new TcAdsClient();
  tcClient.Connect(801);
  try
    symbolLoader := tcClient.CreateSymbolInfoLoader();
  except
    on err: Exception do
      MessageBox.Show(err.Message, err.Source);
  end;
end;

method MainForm.MainForm_FormClosing(sender: System.Object; e: System.Windows.Forms.FormClosingEventArgs);
begin
  try
  except
    on err: Exception do
      MessageBox.Show(err.Message, err.Source)
  end;
  tcClient.Dispose();
end;

method MainForm.btnLoad_Click(sender: System.Object; e: System.EventArgs);
var symbol  : TcAdsSymbolInfo;
    node    : TreeNode;  
begin
  treeViewSymbols.Nodes.Clear();

  if not cbFlat.Checked then
  begin
    symbol := symbolLoader.GetFirstSymbol(true);
    while ( symbol <> Nil )do
    begin
      treeViewSymbols.Nodes.Add(CreateNewNode(var symbol));
      symbol := symbol.NextSymbol;
    end;
  end
  else
  begin
    for symbol : TcAdsSymbolInfo in symbolLoader do
    begin
      node := new TreeNode(symbol.Name);
      node.Tag := symbol;
      treeViewSymbols.Nodes.Add(node);
    end;
  end;
end;

method MainForm.CreateNewNode(var symbol: TcAdsSymbolInfo) : TreeNode;
var node      : TreeNode;
  subSymbol : TcAdsSymbolInfo;
begin
  node := new TreeNode(symbol.Name);
  node.Tag := symbol;
  subSymbol := symbol.FirstSubSymbol;
  while( subSymbol <> Nil ) do
  begin
    node.Nodes.Add(CreateNewNode(var subSymbol));
    subSymbol := subSymbol.NextSymbol;
  end;
  result := node;
end;

method MainForm.SetSymbolInfo(symbol: ITcAdsSymbol);
begin
  currentSymbol := symbol;
  tbSymbolname.Text := symbol.Name;
  tbName.Text := symbol.Name.ToString();
  tbIndexGroup.Text := symbol.IndexGroup.ToString();
  tbIndexOffset.Text := symbol.IndexOffset.ToString();
  tbSize.Text := symbol.Size.ToString();

  tbDatatype.Text := symbol.Type;
  tbDatatypeId.Text := System.Object(symbol.Datatype).ToString();

  try
    tbValue.Text := tcClient.ReadSymbol(symbol).ToString();
  except
    on err: AdsDatatypeNotSupportedException do
      tbValue.Text := err.Message;
    on err: Exception do
      MessageBox.Show(err.Message, err.Source);
  end;
end;

method MainForm.btnWrite_Click(sender: System.Object; e: System.EventArgs);
begin
    try
      if( currentSymbol <> nil )then
    tcClient.WriteSymbol(currentSymbol, tbValue.Text);
    except
      on err: Exception do
    MessageBox.Show('Unable to write Value! ' + err.Message, err.Source);
    end;
end;

method MainForm.btnFindSymbol_Click(sender: System.Object; e: System.EventArgs);
var symbol : ITcAdsSymbol;
begin
  try
    symbol := symbolLoader.FindSymbol(tbSymbolname.Text);
    if( symbol = Nil ) then
      MessageBox.Show('Symbol ' + tbSymbolname.Text + ' not found!', 'TwinCAT.Ads')
    else
      SetSymbolInfo(symbol);
  except
    on err: Exception do
      MessageBox.Show(err.Message, err.Source);
  end;
end;

method MainForm.btnReadSymbolInfo_Click(sender: System.Object; e: System.EventArgs);
var symbol : ITcAdsSymbol;
begin
  try
    symbol := tcClient.ReadSymbolInfo(tbSymbolname.Text);
    if( symbol = Nil ) then
      MessageBox.Show('Symbol ' + tbSymbolname.Text + ' not found!', 'TwinCAT.Ads')
    else
      SetSymbolInfo(symbol);
  except
    on err: Exception do
      MessageBox.Show(err.Message, err.Source);
  end;
end;

method MainForm.treeView1_AfterSelect(sender: System.Object; e: System.Windows.Forms.TreeViewEventArgs);
begin
  if( e.Node.Text.Length > 0 ) then
  begin
    if( e.Node.Tag is TcAdsSymbolInfo ) then
    begin
      SetSymbolInfo(ITcAdsSymbol(e.Node.Tag));
    end;
  end;
end;

end.

 

PLC program

PROGRAM MAIN
VAR
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 *)
    STRING_1 : STRING(20);
END_VAR
;

 

 

Download

Language / IDE

Unpack the sample program

Delphi Prism (Embarcadero Prism XE2, Oxygene for .NET)

Sample06.exe

Delphi for .NET (Borland Developer Studio 2006)

Sample06.exe