Search code examples
twincat-ads

Can I query the list of variables and types


Can I use twincat-ads to query a Beckhoff PLC for the variables (and their types) that are exposed on ADS.


Solution

  • 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:

    https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_ads_intro/9007199370899851.html&id=5869483416056481636