ADS-Summenkommando: Holen und Freigeben von mehreren Handles

Dieses Beispiel zeigt, wie man unter Zuhilfenahme des ADS-Summenkommandos, viele Handles holen und wieder freigeben kann. Aufgebaut als AdsSyncReadWriteRequest, dient es als Behälter, in dem die Unterkommandos transportiert werden.

Anforderung: TwinCAT 2.11 >= Build 1550

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

1. Handles holen

Als erstes, werden die benötigten Header eingebunden.

#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"

 

Es folgt das Definieren einer Struktur, Deklarieren von Variablen und Reservieren von Speicher.

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

 

Die zu übertragenden Werte werden hinter die letzte Struktur geschrieben.

ADS-Summenkommando: Holen und Freigeben von mehreren 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) );

 

Für die Kommunikation wird ein Port geöffnet und die lokale Adresse übergeben. Kommt es zur Übertragung wird vorher der Port vom Laufzeitsystem 1 der Adresse zugewiesen.

Die Parameter für das Summenkommando bestehen aus IndexGroup (0xf082) - Aufruf des Summenkommandos, IndexOffset (0x2) - Anzahl der Unterkommandos, ReadLength (0x18) - Größenangabe der zu lesenden Daten, ReadData (pBuffRes) - Speicher, der gelesene Daten entgegen nimmt, WriteLength (cbReq) - Größenangabe der zu sendenen Daten und WriteLength (pBuffReq) - Speicher, der zu sendende Daten enthält.

    // 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';};

 

Nach dem Senden des Request, erwarten wir einen ADS Fehlercode und Länge für jeden Handle den wir versuchen zu bekommen.

ADS-Summenkommando: Holen und Freigeben von mehreren Handles 2:

2. Handles freigeben

Es wird ein weiteres Mal eine Struktur definiert, Variablen deklariert und Speicher reserviert.

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

 

Die zu empfangenen Werte werden wieder hinter die letzte Struktur geschrieben.

ADS-Summenkommando: Holen und Freigeben von mehreren 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) );

 

Für die Freigabe der Handles wird die bestehende Verbindung benutzt.

Die Parameter für das Summenkommando bestehen aus IndexGroup (0xf081) - Aufruf des Summenkommandos, IndexOffset (0x2) - Anzahl der Unterkommandos, ReadLength (cbRelRes) - Größenangabe der zu lesenden Daten, ReadData (pBuffRelRes) - Speicher, der gelesene Daten entgegen nimmt, WriteLength (cbRel) - Größenangabe der zu sendenen Daten und WriteLength (pBuffRel) - Speicher, der zu sendene Daten enthält.Zum Schluss müssen die Handles freigegeben und der Port geschlossen werden.

// 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();
}

Als Antwort erhalten wir einen ADS Fehlercode für jeden Handle den wir versuchen freizugeben.

ADS-Summenkommando: Holen und Freigeben von mehreren Handles 4: