ADS sum command: fetch and release multiple handles

This sample shows how to fetch and release many handles using the ADS sum command. Set up as AdsSyncReadWriteRequest, it serves as a container in which the subcommands are transported.

Requirement: TwinCAT 2.11 >= Build 1550

Download: sample18-c-ads-dll-sumgetreleasehandles.zip

1. Fetch handles

First, the required headers are included.

#include <iostream.h>
#include <windows.h>
#include <conio.h>

// ADS headers 
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsApi.h"

 

This is followed by defining a structure, declaring variables and reserving memory.

// Structure declaration for valuestypedef struct dataReq
    {
        unsigned long       indexGroup;     // index group in ADS server interfaceunsigned long       indexOffset;    // index offset in ADS server interfaceunsigned long       rlength;        // count of bytes to readunsigned long       wlength;        // count of bytes to write
    }TDataReq, *PTDataReq;


    // Variables declaration
    AmsAddr     Addr;
    LONG        nErr, nPort;
    PAmsAddr        pAddr = &Addr;

    char        szVar1[] = {".bVar01"};
    char        szVar2[] = {".bVar02"};

    // Allocate memory
    ULONG   cbReq   = ( sizeof(TDataReq)*2 ) + sizeof(szVar1) + sizeof(szVar2);
    BYTE*   pBuffReq    = new BYTE[cbReq];
    
    BYTE*   pBuffRes    = new BYTE[24];

    // Put structure over memory
    PTDataReq           pDataReq = (PTDataReq)pBuffReq;
    ULONG*      pDataRes = (ULONG*)pBuffRes;

 

The values to be transferred are written after the last structure.

ADS sum command: fetch and release multiple handles 1:
// pDataReq-> structure 1
    pDataReq->indexGroup    = ADSIGRP_SYM_HNDBYNAME;        
    pDataReq->indexOffset   = 0x0;  
    pDataReq->rlength           = sizeof(ULONG);        
    pDataReq->wlength           = sizeof(szVar1);       

    // Skip to next structure
    pDataReq = pDataReq+1;

    // pDataReq-> structure 2
    pDataReq->indexGroup    = ADSIGRP_SYM_HNDBYNAME;        
    pDataReq->indexOffset   = 0x0;  
    pDataReq->rlength           = sizeof(ULONG);        
    pDataReq->wlength           = sizeof(szVar2);

    // Skip to write data 1char*   szVarName = ( (char*)pDataReq ) + sizeof(TDataReq);
    strncpy( szVarName, szVar1, sizeof(szVar1) );

    // Skip to write data 2
    szVarName = szVarName + sizeof(szVar1);
    strncpy( szVarName, szVar2, sizeof(szVar2) );

 

For communication, a port is opened and the local address is passed. If a transmission takes place, the port is assigned to the address by runtime system 1 beforehand.

The parameters for the sum command consist of IndexGroup (0xf082) - call of the sum command, IndexOffset (0x2) - number of subcommands, ReadLength (0x18) - size specification of the data to be read, ReadData (pBuffRes) - memory that accepts read data, WriteLength (cbReq) - size specification of the data to be sent and WriteLength (pBuffReq) - memory that contains data to be sent.

    // Kommunikationsport auf dem ADS Router öffnen
    nPort = AdsPortOpen();
    nErr  = AdsGetLocalAddress(pAddr);

    cout << "open port:  ";
        if (nErr == 0)
        {
            cout << "OK" << '\n';

            // Get handles
            pAddr->port = AMSPORT_R0_PLC_RTS1;
            nErr = AdsSyncReadWriteReq(
                pAddr, 
                0xf082,     // ADS list-read-write command
                0x2,        // number of ADS-sub commands
                0x18,       // we expect an ADS-error-return-code for each ADS-sub command
                pBuffRes,           // provide space for the response containing the return codes
                cbReq,      // cbReq : send 48 bytes (IG1, IO1, RLen1, WLen1,// IG2, IO2, RLen2, WLen2, Data1, Data2)
                pBuffReq );     // buffer with data
        }
        else {cout << "ERROR [" << nErr << "]" << '\n';};

    cout << "connect:    ";
        if (nErr == 0)
        {
            cout << "OK" << '\n';
            
            // Skip to handle 1 and examine the value
            ULONG nVarHandle = *( (ULONG*)pBuffRes );
            if (nVarHandle != 0)
            {
                cout << " > handle1: ";
                cout << "ERROR [" << nVarHandle << "]" << '\n';
            }

            // Skip to handle 2 and examine the value
            nVarHandle = *( (ULONG*)pBuffRes + 2 );
            if (nVarHandle != 0)
            {
                cout << " > handle2: ";
                cout << "ERROR [" << nVarHandle << "]" << '\n';
            }
        }
        else {cout << "ERROR [" << nErr << "]" << '\n';};

 

After sending the request, we expect an ADS error code and length for each handle we try to fetch.

ADS sum command: fetch and release multiple handles 2:

2. Release handles

Once again, a structure is defined, variables are declared and memory is reserved.

// Structure declaration for valuestypedef struct dataRel
    {
        unsigned long       indexGroup;     // index group in ADS server interfaceunsigned long       indexOffset;    // index offset in ADS server interfaceunsigned long       length;     // count of bytes to write
    }TDataRel, *PTDataRel;


    // Variables declaration
    ULONG*  nVar1   = (ULONG*)pBuffRes+4;
    ULONG*  nVar2   = (ULONG*)pBuffRes+5;

    // Allocate memory
    ULONG   cbRel      = sizeof(TDataRel)*2 + sizeof(ULONG)*2;
    BYTE*   pBuffRel    = new BYTE[cbRel];

    ULONG   cbRelRes    = sizeof(ULONG)*2;
    BYTE*   pBuffRelRes = new BYTE[cbRelRes];
    
    // Put structure over memory
    PTDataRel  pDataRel    = (PTDataRel)pBuffRel;
    ULONG*    pDataRelRes = (ULONG*)pBuffRelRes;

 

The values to be received are again written after the last structure.

ADS sum command: fetch and release multiple handles 3:
// pDataRel-> structure 1
    pDataRel->indexGroup    = ADSIGRP_SYM_RELEASEHND;
    pDataRel->indexOffset   = 0x0;  
    pDataRel->length        = sizeof(ULONG);

    // Skip to next structure
    pDataRel++;

    // pDataReq-> structure 2
    pDataRel->indexGroup    = ADSIGRP_SYM_RELEASEHND;           
    pDataRel->indexOffset   = 0x0;  
    pDataRel->length        = sizeof(ULONG);
    
    // Skip to next structure
    pDataRel++;

    // Write handles into structure
    memcpy(    pDataRel,   nVar1, sizeof(ULONG) );
    memcpy( (ULONG*)pDataRel+1, nVar2, sizeof(ULONG) );

 

The existing connection is used to release the handles.

The parameters for the sum command consist of IndexGroup (0xf081) - call of the sum command, IndexOffset (0x2) - number of subcommands, ReadLength (cbRelRes) - size specification of the data to be read, ReadData (pBuffRelRes) - memory that accepts read data, WriteLength (cbRel) - size specification of the data to be sent and WriteLength (pBuffRel) - memory that contains data to be sent. Finally, the handles must be released and the port closed.

// Release handles
    nErr = AdsSyncReadWriteReq(
        pAddr, 
        0xf081,     // ADS list-write command
        0x2,        // number of ADS-sub commands
        cbRelRes,           // we expect an ADS-error-return-code for each ADS-sub command
        pBuffRelRes,    // provide space for the response containing the return codes
        cbRel,      // cbReq : send 40 bytes (IG1, IO1, Len1, IG2, IO2, Len2, Data1, Data2)
        pBuffRel );     // buffer with data
    
    cout << "disconnect: ";
        if (nErr == 0)
        {
            cout << "OK" << '\n';

            // Skip to handle 1 and examine the value
            ULONG nVarHandle = *( (ULONG*)pBuffRes );
            if (nVarHandle != 0)
            {
                cout << " > handle1: ";
                cout << "ERROR [" << nVarHandle << "]" << '\n';
            }

            // Skip to handle 2 and examine the value
            nVarHandle = *( (ULONG*)pBuffRes + 2 );
            if (nVarHandle != 0)
            {
                cout << " > handle2: ";
                cout << "ERROR [" << nVarHandle << "]" << '\n';
            }
        }
        else {cout << "ERROR [" << nErr << "]" << '\n';};

    // Close the communication port
    nErr = AdsPortClose();
    cout << "close port: ";
        if (nErr == 0) {cout << "OK" << '\n' << "-------------------" << '\n';}
        else {cout << "ERROR [" << nErr << "]" << '\n' << "-------------------" << '\n';}

    cout.flush();

    // Wait for key press
    getch();
}

In response we get an ADS error code for each handle we try to release.

ADS sum command: fetch and release multiple handles 4: