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.
Systemvoraussetzungen:
- TwinCAT v2.11 Build >= 1550
Beispielprogramm 'ADS-Summenkommando: Holen und Freigeben von mehreren Handles' entpacken: sample12.zip
- Um das *.jar Sample ausführen zu können, muss in der Konsole im korrekten Verzeichnis der Befehl 'java -classpath "Sample12.jar;[Pfad zu TcJavaToAds.jar] Main' ausgeführt werden (Beispielpfad: "C:TwinCAT\Ads Api\AdsToJava\*"). Dazu muss java in den Umgebungsvariablen eingetragen sein.
Handles holen
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import de.beckhoff.jni.Convert;
import de.beckhoff.jni.JNIByteBuffer;
import de.beckhoff.jni.tcads.AdsCallDllFunction;
import de.beckhoff.jni.tcads.AmsAddr;
public class Main {
private static final String VAR_NAME1 = ".bVar01";
private static final String VAR_NAME2 = ".bVar02";
public static void main (String[] args) {
long err = 0;
try {
AmsAddr addr = new AmsAddr();
// Create request and response buffer
JNIByteBuffer jniReqBuff;
JNIByteBuffer jniResBuff = new JNIByteBuffer(new byte[24]);
// Construct data objects
RequestData req1 = new RequestData();
req1.setIndexGroup(AdsCallDllFunction.ADSIGRP_SYM_HNDBYNAME);
req1.setIndexOffset(0x0);
req1.setReadLength(Integer.SIZE / Byte.SIZE);
req1.setWriteLength(VAR_NAME1.length());
RequestData req2 = new RequestData();
req2.setIndexGroup(AdsCallDllFunction.ADSIGRP_SYM_HNDBYNAME);
req2.setIndexOffset(0x0);
req2.setReadLength(Integer.SIZE / Byte.SIZE);
req2.setWriteLength(VAR_NAME2.length());
// Concatenate byte[] representations of RequestData objects and
// variable names (see picture 1)
int reqBuffSize = RequestData.SIZE * 2 / Byte.SIZE
+ req1.getWriteLength() + req2.getWriteLength();
ByteBuffer reqBuff = ByteBuffer.allocate(reqBuffSize);
reqBuff.order(ByteOrder.LITTLE_ENDIAN);
reqBuff.put(req1.toByteArray());
reqBuff.put(req2.toByteArray());
reqBuff.put(Convert.StringToByteArr(VAR_NAME1, false));
reqBuff.put(Convert.StringToByteArr(VAR_NAME2, false));
// Need to let a JNIByteBuffer wrap the byte[] to be able to send it
jniReqBuff = new JNIByteBuffer(reqBuff.array());
Die Namen der Variablen deren Handles wir erhalten wollen, werden an das Ende des Bytearrays gehängt.
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.
// Open communication
AdsCallDllFunction.adsPortOpen();
err = AdsCallDllFunction.getLocalAddress(addr);
addr.setPort(AdsCallDllFunction.AMSPORT_R0_PLC_RTS1);
if (err != 0) {
System.out.println("Error: Open communication: 0x"
+ Long.toHexString(err));
} else {
System.out.println("Success: Open communication!");
}
err = AdsCallDllFunction.adsSyncReadWriteReq(
addr,
0xf082, // ADS list-read-write command
0x2, // number of ADS-sub commands
jniResBuff.getUsedBytesCount(), // we expect an ADS error
// return-code for each ADS-sub command
jniResBuff, // provide space for the response
// containing the return codes
jniReqBuff.getUsedBytesCount(), // send 48 bytes(IG1,
// IO1, RLen1, WLen1, IG2, IO2, RLen2,
// WLen2, Data1, Data2)
jniReqBuff);
// Check return codes
ByteBuffer resBuff = ByteBuffer.wrap(jniResBuff.getByteArray());
resBuff.order(ByteOrder.LITTLE_ENDIAN);
if (err != 0) {
System.out.println("Error: Get handles: 0x"
+ Long.toHexString(err));
} else {
// Extract error codes from response (see picture 2)
// Pattern is: err1, len1, .., errN, lenN, data1, .., dataN
int req1Err = resBuff.getInt((Integer.SIZE / Byte.SIZE) * 0);
int req2Err = resBuff.getInt((Integer.SIZE / Byte.SIZE) * 2);
if (req1Err != 0) {
System.out.println("Error: Get handle1: 0x"
+ Integer.toHexString(req1Err));
} else if (req2Err != 0) {
System.out.println("Error: Get handle2: 0x"
+ Integer.toHexString(req2Err));
} else {
System.out.println("Success: Get handles!");
}
}
Nach dem Senden des Request, erwarten wir einen ADS Fehlercode und Länge für jeden Handle den wir versuchen zu bekommen. In diesem Fall wird die Länge immer 4 Bytes betragen.
Handles freigeben
// Extract handles from response(see picture 2)
int hnd1 = resBuff.getInt((Integer.SIZE / Byte.SIZE) * 4);
int hnd2 = resBuff.getInt((Integer.SIZE / Byte.SIZE) * 5);
//// Release handles
// Construct buffers
int relBuffSize =
(ReleaseData.SIZE * 2 / Byte.SIZE) + (Integer.SIZE * 2 / Byte.SIZE);
int relResBuffSize = Integer.SIZE * 2 / Byte.SIZE;
ByteBuffer relBuff = ByteBuffer.allocate(relBuffSize);
relBuff.order(ByteOrder.LITTLE_ENDIAN);
JNIByteBuffer jniRelBuff = new JNIByteBuffer(relBuffSize);
JNIByteBuffer jniRelResBuff = new JNIByteBuffer(relResBuffSize);
// Construct data objects
ReleaseData rel1 = new ReleaseData();
rel1.setIndexGroup(AdsCallDllFunction.ADSIGRP_SYM_RELEASEHND);
rel1.setIndexOffset(0);
rel1.setLength(Integer.SIZE / Byte.SIZE);
ReleaseData rel2 = new ReleaseData();
rel2.setIndexGroup(AdsCallDllFunction.ADSIGRP_SYM_RELEASEHND);
rel2.setIndexOffset(0);
rel2.setLength(Integer.SIZE / Byte.SIZE);
// Concatenate byte[] representations of ReleaseData objects and
// handles (see picture 3)
relBuff.put(rel1.toByteArray());
relBuff.put(rel2.toByteArray());
relBuff.putInt(hnd1);
relBuff.putInt(hnd2);
// Need to let a JNIByteBuffer wrap the byte[] to be able to send it
jniRelBuff.setByteArray(relBuff.array(), true);
Die zu den Kommandos zugehörigen Handles werden an das Ende des Bytearrays gehängt.
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 - Second task cleared
err = AdsCallDllFunction.adsSyncReadWriteReq(
addr,
0xf081, // ADS list-write command
0x2, // number of ADS-sub commands
relResBuffSize, // we expect an ADS-error-return-code for
// each ADS-sub command
jniRelResBuff, // provide space for the response containing
// the return codes
relBuffSize, // send 32 bytes (IG1, IO1, Len1, IG2, IO2,
// Len2, Data1, Data2)
jniRelBuff); // buffer with data
// Check return codes
if (err != 0) {
System.out.println("Error: Release handles: 0x"
+ Long.toHexString(err));
} else {
ByteBuffer relResBuff =
ByteBuffer.wrap(jniRelResBuff.getByteArray());
relResBuff.order(ByteOrder.LITTLE_ENDIAN);
// Extract error codes from response (see picture 4)
// Pattern is: err1, .., errN
int rel1Err = relResBuff.getInt((Integer.SIZE / Byte.SIZE) * 0);
int rel2Err = relResBuff.getInt((Integer.SIZE / Byte.SIZE) * 1);
if (rel1Err != 0) {
System.out.println("Error: Release handle1: 0x"
+ Integer.toHexString(rel1Err));
} else if (rel2Err != 0) {
System.out.println("Error: Release handle2: 0x"
+ Integer.toHexString(rel2Err));
} else {
System.out.println("Success: Release handles!");
}
}
System.out.println("\nPress enter to continue..");
System.in.read();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
// Close communication
err = AdsCallDllFunction.adsPortClose();
if (err != 0) {
System.out.println("Error: Close communication: 0x"
+ Long.toHexString(err));
} else {
System.out.println("Success: Close communication!");
}
}
}
}
Als Antwort erhalten wir einen ADS Fehlercode für jedes Handle das wir versuchen freizugeben.