ADS-Sum Command: Reading or writing several variables

Requirement: TwinCAT 2.11 >= Build 1550

Download

Language / IDE

Extract the sample program

Visual C#

Sample09.zip

Visual Basic (for .NET Framework)

-

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

Sample09.exe

Delphi for .NET (Borland Developer Studio 2006)

-

 

Using the ADS Sum Command it is possible to read or write several variables in one command. Designed as TcAdsClient.ReadWrite it is used as a container, which transports all sub-commands in one ADS stream.



In the beginning it's important, binding 'TwinCAT.Ads.dll' to your project! To do so, open 'Solution Explorer' and choose 'Add References...' via'References'. 'Browse' for the DLL in the folder 'TwinCAT -> ADS API -> .NET' .

 

C# program


1. Read variables

First, define two structures:

namespace AdsBlockRead
{
// Structure declaration for values
  internal struct MyStruct
  {
    public ushort uintValue;
    public int dintValue;
    public bool boolValue;
  }

// Structure declaration for handles
  internal struct VariableInfo
  {
    public int indexGroup;
    public int indexOffset;
    public int length;
  }

and declare some global variables.

public classForm1 : System.Windows.Forms.Form
    {
    [...]
    
    privateTcAdsClient adsClient;
    private string[] variableNames;
    private int[] variableLengths;
    VariableInfo[] variables;

On applications start an ADS connection to PLC is established and Handle parameters are written into the structure.

private void Form1_Load(object sender, System.EventArgs e)
    {
        try
        {
        // Connect to PLC
        adsClient = newTcAdsClient();
        adsClient.Connect(801);

        // Fill structures with name and size of PLC variables
        variableNames = new string[] { "MAIN.uintValue", "MAIN.dintValue", "MAIN.boolValue" };
        variableLengths = new int[] { 2, 4, 1 };

        // Write handle parameter into structure
        variables = newVariableInfo[variableNames.Length];
        for (int i = 0; i < variables.Length; i++)
        {
            variables[i].indexGroup = (int)AdsReservedIndexGroups.SymbolValueByHandle;
            variables[i].indexOffset = adsClient.CreateVariableHandle(variableNames[i]);
            variables[i].length = variableLengths[i];
        }
        }
        catch (Exception err)
        {
        MessageBox.Show(err.Message);
        adsClient = null;
        }
    }

After clicking 'Read' Button, 'BlockRead' method returns an ADS Stream. Check for ADS return codes (Err) for error handling before data is read out of the stream und stored in the text boxes.

private void button1_Click(object sender, System.EventArgs e)
    {
        if (adsClient == null)
        return;

        try
        {
        // Get the ADS return codes and examine for errorsBinaryReader reader = newBinaryReader(BlockRead(variables));
        for (int i = 0; i < variables.Length; i++)
        {
            int error = reader.ReadInt32();
            if (error != (int)AdsErrorCode.NoError)
            System.Diagnostics.Debug.WriteLine(
                String.Format("Unable to read variable {0} (Error = {1})", i, error));
        }

        // Read the data from the ADS streamMyStruct myStruct;
        myStruct.uintValue = reader.ReadUInt16();
        myStruct.dintValue = reader.ReadInt32();
        myStruct.boolValue = reader.ReadBoolean();

        // Write data from the structure into the text boxes
        tbUint.Text = myStruct.uintValue.ToString();
        tbDint.Text = myStruct.dintValue.ToString();
        tbBool.Text = myStruct.boolValue.ToString();
        }
        catch (Exception err)
        {
        MessageBox.Show(err.Message);
        }
    }

'BlockRead' methode takes an object of type 'VariableInfo[]', where the handle parameters are strored. After reserving memory for the values to be read and write, an ADS stream is written with the parameters delivered by 'VariableInfo[]'. At the end the sum command transfers the commands, and an ADS stream is returned.

private AdsStream BlockRead(VariableInfo[] variables)
{
        // Allocate memoryint rdLength = variables.Length * 4;
        int wrLength = variables.Length * 12;

        // Write data for handles into the ADS StreamBinaryWriter writer = newBinaryWriter(newAdsStream(wrLength));
        for (int i = 0; i < variables.Length; i++)
        {
        writer.Write(variables[i].indexGroup);
        writer.Write(variables[i].indexOffset);
        writer.Write(variables[i].length);
        rdLength += variables[i].length;
        }

        // Sum command to read variables from the PLCAdsStream rdStream = newAdsStream(rdLength);
        adsClient.ReadWrite(0xF080, variables.Length, rdStream, (AdsStream)writer.BaseStream);

        // Return the ADS error codesreturn rdStream;
    }

Sum Command's Parameters consists of IndexGroup (0xF080) - sum command call, IndexOffset (variables.Length) - number of sub commands, rdDataStream (rdStream) - memory, taking the read values, wrDataStream (writer.BaseStream) - memory, containing values to be written.

sub commands in wrDataStream


response in rdDataStream


2. writing variablesAfter clicking 'Write' button, 'BlockRead2' methode returns an ADS stream. Following is a check of ADS return codes (Err) for error handlings.

private void button2_Click(object sender, EventArgs e)
{
        if (adsClient == null)
        return;

        try
        {
        // Get the ADS return codes and examine for errorsBinaryReader reader = newBinaryReader(BlockRead2(variables));
        for (int i = 0; i < variables.Length; i++)
        {
            int error = reader.ReadInt32();
            if (error != (int)AdsErrorCode.NoError)
            System.Diagnostics.Debug.WriteLine(
                String.Format("Unable to read variable {0} (Error = {1})", i, error));
        }
        }
        catch (Exception err)
        {
        MessageBox.Show(err.Message);
        }
}

'BlockRead2' methode takes an object of type 'VariableInfo[]', where handle parameters are stored. After reserving memory for the values to be read an write, 'MyStruct' object is filled with the values stored in the textboxes. Next, an ADS stream containing parameters from 'VariableInfo[]' objects an the values of 'MyStruct' object is written. At the end sum command transfers the commands and an ADS Stream is returned.

Private AdsStream BlockRead2(VariableInfo[] variables)
{
        // Allocate memoryint rdLength = variables.Length * 4;
        int wrLength = variables.Length * 12 + 7;

        BinaryWriter writer = newBinaryWriter(new AdsStream(wrLength));
        MyStruct myStruct;
        myStruct.uintValue = ushort.Parse(tbUint2.Text);
        myStruct.dintValue = int.Parse(tbDint2.Text);
        myStruct.boolValue = bool.Parse(tbBool2.Text);
        
        // Write data for handles into the ADS streamfor (int i = 0; i < variables.Length; i++)
        {
        writer.Write(variables[i].indexGroup);
        writer.Write(variables[i].indexOffset);
        writer.Write(variables[i].length);
        }

        // Write data to send to PLC behind the structure
        writer.Write(myStruct.uintValue);
        writer.Write(myStruct.dintValue);
        writer.Write(myStruct.boolValue);

        // Sum command to write the data into the PLCAdsStream rdStream = newAdsStream(rdLength);
        adsClient.ReadWrite(0xF081, variables.Length, rdStream, (AdsStream)writer.BaseStream);

        // Return the ADS error codesreturn rdStream;
}

Sum Command's Parameters consists of IndexGroup (0xF081) - sum command call, IndexOffset (variables.Length) - number of sub commands, rdDataStream (rdStream) - memory, taking the read values, wrDataStream (writer.BaseStream) - memory, containing values to be written.

sub commands in wrDataStream


response in rdDataStream