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.
// 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.
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.
// 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.