Reading the PLC variable declaration of an individual variable

Download: 'Read PLC Variable Declaration of an individual variable'

The following information is transferred when accessing the variable declaration:

The AdsSyncReadWriteReq() call is used to read the variable information. The variable name is transferred to the function via parameter pWriteData. After the call the requested information is contained in variable pAdsSymbolEntry . The individual information items in the PLC variables are stored in this structure. The macros PADSSYMBOLNAME, PADSSYMBOLTYPE and PADSSYMBOLCOMMENT simplify the evaluation of this data. In the next step, the data type of the variable is evaluated via pAdsSymbolEntry->dataType.
If the data type is UDINT or ARRAY OF UDINT, the value of this variable is also read.

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

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


typedef enum AdsDataTypeId
{
ADST_VOID = VT_EMPTY,
ADST_INT8 = VT_I1,
ADST_UINT8 = VT_UI1,
ADST_INT16 = VT_I2,
ADST_UINT16 = VT_UI2,
ADST_INT32 = VT_I4,
ADST_UINT32 = VT_UI4,
ADST_INT64 = VT_I8,
ADST_UINT64 = VT_UI8,
ADST_REAL32 = VT_R4,
ADST_REAL64 = VT_R8,
ADST_STRING = VT_LPSTR,
ADST_WSTRING = VT_LPWSTR,
ADST_REAL80 = VT_LPWSTR+1,
ADST_BIT = VT_LPWSTR+2,
ADST_BIGTYPE = VT_BLOB,
ADST_MAXTYPES = VT_STORAGE,
} ADS_DATATYPE;

typedef struct _ValueString
{
DWORD dwValue;
char* szLabel;
} ValueString;

ValueString AdsDatatypeString[] =
{
{ VT_EMPTY, "ADST_VOID", },
{ VT_I1, "ADST_INT8", },
{ VT_UI1, "ADST_UINT8", },
{ VT_I2, "ADST_INT16", },
{ VT_UI2, "ADST_UINT16", },
{ VT_I4, "ADST_INT32", },
{ VT_UI4, "ADST_UINT32", },
{ VT_I8, "ADST_INT64", },
{ VT_UI8, "ADST_UINT64", },
{ VT_R4, "ADST_REAL32", },
{ VT_R8, "ADST_REAL64", },
{ VT_LPSTR, "ADST_STRING", },
{ VT_LPWSTR, "ADST_WSTRING", },
{ VT_LPWSTR+2, "ADST_BIT", },
{ VT_BLOB, "ADST_BIGTYPE", },
{ VT_STORAGE, "ADST_MAXTYPES", },
};

void main()
{
long nErr, nPort;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
char szVariable[255];
BYTE buffer[0xFFFF];
PAdsSymbolEntry pAdsSymbolEntry;

// Open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';

// Select Port: TwinCAT 3 PLC1 = 851
pAddr->port = 851;

for(;;)
{
cout << "Enter variable Name: ";
cin >> szVariable;

nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_INFOBYNAMEEX, 0, sizeof(buffer), buffer, strlen(szVariable)+1, szVariable);
if (nErr)
{
cerr << "Error: AdsSyncReadReq: " << nErr << '\n';
}
else
{
pAdsSymbolEntry = (PAdsSymbolEntry)buffer;
cout << "Name: " << PADSSYMBOLNAME(pAdsSymbolEntry) << "\n"
<<"Index Group: "<< pAdsSymbolEntry->iGroup << '\n'
<<"Index Offset: "<< pAdsSymbolEntry->iOffs << '\n'
<<"Size: "<< pAdsSymbolEntry->size << '\n'
<<"Type: "<< (char*)PADSSYMBOLTYPE(pAdsSymbolEntry) << '\n'
<<"Comment: "<< (char*)PADSSYMBOLCOMMENT(pAdsSymbolEntry) << '\n';

switch( pAdsSymbolEntry->dataType )
{
case ADST_UINT32:
{
int nElements = pAdsSymbolEntry->size/sizeof(unsigned long);
unsigned long *pVal = new unsigned long[nElements];
cout << "Datatype: ADST_UINT32" <<'\n';
AdsSyncReadReq(pAddr, pAdsSymbolEntry->iGroup, pAdsSymbolEntry->iOffs, pAdsSymbolEntry->size, pVal);
if( nErr )
{
cerr << "Error: AdsSyncReadReq: Unable to read Value" << nErr << '\n';
}
else
{
cout << "Value: ";
for( int i=0; i<nElements; i++ )
{
cout << pVal[i] << '\t';
}
cout << '\n';
}
}
break;
default:
{
int nType = sizeof(AdsDatatypeString)/sizeof(ValueString);
for( int i=0; i< nType; i++ )
{
if( AdsDatatypeString[i].dwValue == pAdsSymbolEntry->dataType )
{
cout << "Datatype:" << AdsDatatypeString[i].szLabel <<'\n';
break;
}
}
if( i == nType )
cout << "Datatype:" << "Unknown datatype:" << pAdsSymbolEntry->dataType <<'\n';
}
break;
}
}
cout << "Exit(y/n)" << '\n';
cout.flush();

if( getch() == 'y' )
break;
}
// Close communication port
nErr = AdsPortClose();
if (nErr) cerr << "Fehler: AdsPortClose: " << nErr << '\n';
}