ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen

Systemvoraussetzungen:

  • TwinCAT v2.11 Build >= 1550

Dieses Beispiel zeigt, wie man unter Zuhilfenahme des ADS-Summenkommandos, viele Variablen lesen oder schreiben kann. Aufgebaut als TcAdsClient.ReadWrite dient es als Behälter, in dem die Unterkommandos in einem ADS-Stream transportiert werden.

1. Symbolinformationen der SPS-Variablen holen


import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import de.beckhoff.jni.JNIByteBuffer;
import de.beckhoff.jni.tcads.AdsCallDllFunction;
import de.beckhoff.jni.tcads.AmsAddr;

public class Main {

private final static RequestData[] REQ_DATA = new RequestData[]{
    new RequestData("uintValue", 0x4020, 0x0, 0x2),
    new RequestData("boolValue", 0x4020, 0x8, 0x1),
    new RequestData("dintValue", 0x4020, 0x10, 0x4)
};
// The data that is going to be written in the third step
private final static char CHAR_VAL = Character.MAX_VALUE;
private final static byte BOOL_VAL = 1;
private final static int INT_VAL = Integer.MIN_VALUE;
private final static int DATA_LEN = 7;
private final static int RESP_ERR_LEN = 4;

public static void main(String[] args) {

    long err;
    AmsAddr addr = new AmsAddr();
    
    try {
     // Open communication    
     AdsCallDllFunction.adsPortOpen();
     err = AdsCallDllFunction.getLocalAddress(addr);
     addr.setPort(851);

     if (err != 0) {
        System.out.println("Error: Open communication: 0x"
            + Long.toHexString(err));
     } else {
        System.out.println("Success: Open communication!");
     }

Wenn Variablen in der SPS beschrieben oder gelesen werden sollen, ohne dabei auf Handles zurückzugreifen, dann müssen IndexGroup und IndexOffset bekannt sein. Um diese Werte von allen relevanten Variablen zu erhalten, müssen üblicherweise die Symbolinformationen ausgelesen werden. In diesem Beispiel sind die Werte als konstant angenommen und in REQ_DATA definiert.

2. Werte lesen

Der RequestBuffer wird nun mit den Daten aus REQ_DATA nach unten stehendem Schema beschrieben. Dabei steht IG1 für die IndexGroup des ersten Subkommandos. IO2 für den IndexOffset des zweiten und L3 für die Länge der erwarteten Antwort des dritten Subkommandos.
RequestData objects

ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen 1:

Als Antwort des Summenkommandos erhalten wir pro Subkommando einen Ads-Fehlercode (Err), sowie den angeforderten Wert (Data). Entsprechend beträgt die Länge des Buffers in diesem Fall: 3 * 4Byte (Error) + 7Byte (Die Summe aller Längen der erwarteten Antworten).
RequestResponse object

ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen 2:

Das Summenkommando selbst wird mit den Parametern IndexGroup: 0xF080 (Summenkommando-Lesen), IndexOffset: 0x3 (Anzahl Subkommandos), ResponseBuffer-Länge, ResponseBuffer, RequestBuffer-Länge, RequestBuffer aufgerufen.


    // Create request buffer (see picture 1)
     JNIByteBuffer jniRequestBuffer = null;
     ByteBuffer requestBuffer =
         ByteBuffer.allocate(RequestData.SIZE * REQ_DATA.length);
     requestBuffer.order(ByteOrder.LITTLE_ENDIAN);

     for (int i = 0; i < REQ_DATA.length; i++) {
        requestBuffer.put(REQ_DATA[i].toByteArray());
     }
     // Need to let a JNIByteBuffer wrap the byte[] to be able to send it
     jniRequestBuffer = new JNIByteBuffer(requestBuffer.array());

     // Create response buffer (see picture 2)
     JNIByteBuffer jniResponseBuffer = new JNIByteBuffer(
         REQ_DATA.length * RESP_ERR_LEN + DATA_LEN);

     // Read the values via sum command
     err = AdsCallDllFunction.adsSyncReadWriteReq(
         addr,
         0xF080,
         REQ_DATA.length,
         jniResponseBuffer.getUsedBytesCount(),
         jniResponseBuffer,
         jniRequestBuffer.getUsedBytesCount(),
         jniRequestBuffer);

     if (err != 0) {
        System.out.println("Error: Get values: 0x"
            + Long.toHexString(err));
     } else {
        System.out.println("Success: Get values!");

        // Evaluate the sub commands error codes and response values
        // (see picture)
        ByteBuffer responseBuffer =
            ByteBuffer.wrap(jniResponseBuffer.getByteArray());
        responseBuffer.order(ByteOrder.LITTLE_ENDIAN);

        // In each loop the errPosition is increased by the Size of an
        // error (int) and the valPosition by the size of the
        // corresponding data type

        int[] respErrs = new int[REQ_DATA.length];
        for (int i = 0; i < respErrs.length; i++) {
          respErrs[i] = responseBuffer.getInt();
        }

        for (int i = 0; i < REQ_DATA.length; i++) {
         String varName = REQ_DATA[i].getVarName();
         int val = 0;

         if (respErrs[i] == 0) {
            switch (REQ_DATA[i].getLength()) {
             case 1:
                val = (int) responseBuffer.get();
                break;
             case 2:
                val = responseBuffer.getChar();
                break;
             case 4:
                val = responseBuffer.getInt();
                break;
             default:
                break;
            }

            System.out.println(varName + ": " + val + "\t");
         } else {
              System.out.println(varName + ": Error: 0x"
                + Long.toHexString(err) + "\t");
         }
        }
     }

3. Werte schreiben

Um Daten schreiben zu können müssen diese Daten lediglich an den RequestBuffer aus dem oberen Teil angehängt werden (siehe Bild). Alle anderen Parameter bleiben unverändert. Lediglich eine Anpassung des Summenkommandos ist nötig (siehe unten).
RequestData objects

ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen 3:

Als Antwort des Summenkommandos erhalten wir pro Subkommando einen Ads-Fehlercode (Err), allerdings dieses Mal keine Daten, da wir einen Schreibvorgang ausgeführt haben. Entsprechend beträgt die Länge des Buffers in diesem Fall: 3 * 4Byte (Error).
RequestResponse objects

ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen 4:

Beim Summenkommando muss nun noch der Wert für die IndexGroup auf 0xF081 (Summenkommando-Schreiben) geändert werden.


    //// Write values
     // Construct buffers. Fill request buffer with the data from above
     // and append the data that is going to be written (see picture 3)
     byte[] requestBufferCopy = requestBuffer.array();
     requestBuffer = ByteBuffer.allocate(
         requestBuffer.capacity()
         + DATA_LEN);
     requestBuffer.order(ByteOrder.LITTLE_ENDIAN);

     requestBuffer.put(requestBufferCopy);
     requestBuffer.putChar(CHAR_VAL);
     requestBuffer.put(BOOL_VAL);
     requestBuffer.putInt(INT_VAL);

     // Need to let a JNIByteBuffer wrap the byte[] to be able to send it
     jniRequestBuffer = new JNIByteBuffer(requestBuffer.array());

     // Adjust the length of the response buffer (compare pictures 2 & 4)
     jniResponseBuffer = new JNIByteBuffer(
                    new byte[(Integer.SIZE / Byte.SIZE) * REQ_DATA.length]);

     // Write the values via sum command
     err = AdsCallDllFunction.adsSyncReadWriteReq(
         addr,
         0xF081,
         REQ_DATA.length,
         jniResponseBuffer.getUsedBytesCount(),
         jniResponseBuffer,
         jniRequestBuffer.getUsedBytesCount(),
         jniRequestBuffer);

     if (err != 0) {
        System.out.println("Error: Write values: 0x"
            + Long.toHexString(err));
     } else {
        System.out.println("Success: Write values!");

        // Evaluate the sub command error codes
        ByteBuffer responseBuffer =
            ByteBuffer.wrap(jniResponseBuffer.getByteArray());
        responseBuffer.order(ByteOrder.LITTLE_ENDIAN);

        for (int i = 0; i < REQ_DATA.length; i++) {
         String varName = REQ_DATA[i].getVarName();
         err = responseBuffer.getInt();

          if (err == 0) {
            System.out.println(varName + ": Success\t");
         } else {
            System.out.println(varName + ": Error: 0x"
                + Long.toHexString(err) + "\t");
         }
        }
     }

     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!");
     }
    }
}
}

Beispielprogramm 'ADS-Summenkommando: Lesen und Schreiben von mehreren Variablen' entpacken.

Um das *.jar Sample ausführen zu können, muss in der Konsole im korrekten Verzeichnis der Befehl 'java -classpath "Sample13.jar;[Pfad zu TcJavaToAds.jar] Main' ausgeführt werden (Beispielpfad: "C:TwinCAT\Ads Api\AdsToJava\*"). Dazu muss Java in den Umgebungsvariablen eingetragen sein.

Voraussetzungen

Entwicklungsumgebung

Zielplattform

Einzubindende Java-Packages

TwinCAT v3.0 Build 3102, Java

PC or CX (x86)