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.

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

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.

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