Can I use twincat-ads to query a Beckhoff PLC for the variables (and their types) that are exposed on ADS.
Yes you can.
This example comes directly from the Beckhoff ads documentation which you should study a bit in order to understand the basics of the ads protocol.
/// <summary>
/// Defines the entry point of the application.
/// </summary>
/// <param name="args">The arguments.</param>
static void Main(string[] args)
{
Console.WriteLine("");
Console.WriteLine("Press [Enter] for start:");
Console.ReadLine();
// Parse the command-line arguments
AmsAddress address = ArgParser.Parse(args);
using (TcAdsClient client = new TcAdsClient())
{
// Connect the AdsClient to the device target.
client.Connect(address);
// Load symbolic information
ISymbolLoader loader = SymbolLoaderFactory.Create(client, SymbolLoaderSettings.Default);
ReadOnlySymbolCollection allSymbols = loader.Symbols;
ISymbol bVar1 = allSymbols["GVL.bVar1"];
ISymbol bVar2 = allSymbols["GVL.iCount"];
ISymbol projectName = allSymbols["TwinCAT_SystemInfoVarList._AppInfo.ProjectName"];
SymbolCollection symbols = new SymbolCollection() {bVar1, bVar2, projectName};
// Sum Command Read
SumSymbolRead readCommand = new SumSymbolRead(client,symbols);
object[] values = readCommand.Read();
for (int i = 0; i < symbols.Count; i++)
{
Console.WriteLine("Symbol: {0} (Value: {1}, Type: {2})",symbols[i].InstancePath,values[i].ToString(),values[i].GetType().Name);
}
// Sum Command Write
SumSymbolWrite writeCommand = new SumSymbolWrite(client,symbols);
object[] writeValues = new object[] {true, (short) 42, "MyNewProjectName"};
writeCommand.Write(writeValues);
}
Console.WriteLine("");
Console.WriteLine("Press [Enter] for leave:");
Console.ReadLine();
}
In C++ you need to use the AdsSyncReadReq function:
#include <iostream.h>
#include <windows.h>
#include <conio.h>
#include <assert.h>
// ADS headers for TwinCAT 3
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsAPI.h"
void main()
{
long nErr, nPort;
char *pchSymbols = NULL;
UINT uiIndex;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
AdsSymbolUploadInfo tAdsSymbolUploadInfo;
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;
// Read the length of the variable declaration
nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOADINFO, 0x0, sizeof(tAdsSymbolUploadInfo), &tAdsSymbolUploadInfo);
if (nErr) cerr << "Error: AdsSyncReadReq: " << nErr << '\n';
pchSymbols = new char[tAdsSymbolUploadInfo.nSymSize];
assert(pchSymbols);
// Read information about the PLC variables
nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOAD, 0, tAdsSymbolUploadInfo.nSymSize, pchSymbols);
if (nErr) cerr << "Error: AdsSyncReadReq: " << nErr << '\n';
// Output information about the PLC variables
pAdsSymbolEntry = (PAdsSymbolEntry)pchSymbols;
for (uiIndex = 0; uiIndex < tAdsSymbolUploadInfo.nSymbols; uiIndex++)
{
cout << PADSSYMBOLNAME(pAdsSymbolEntry) << "\t\t"
<< pAdsSymbolEntry->iGroup << '\t'
<< pAdsSymbolEntry->iOffs << '\t'
<< pAdsSymbolEntry->size << '\t'
<< PADSSYMBOLTYPE(pAdsSymbolEntry) << '\t'
<< PADSSYMBOLCOMMENT(pAdsSymbolEntry) << '\n';
pAdsSymbolEntry = PADSNEXTSYMBOLENTRY(pAdsSymbolEntry); cout.flush();
}
getch();
// Close communication port
nErr = AdsPortClose();
if (nErr) cerr << "Fehler: AdsPortClose: " << nErr << '\n';
// Release memory
if (pchSymbols) delete(pchSymbols);
}
For more info: