Event driven reading

If values from a PLC or NC are to be displayed continuously on a user interface, then it is very inefficient to use AdsSyncReadReq(), since this function must be called cyclically. By defining so-called notifications, a TwinCAT server can be caused to transfer values via ADS to another ADS device. A distinction is drawn between whether the TwinCAT server is to transmit the values cyclically, or only when the values change.

A notification is begun with the AdsSyncAddDeviceNotificationReq() function. After this, the callback function is automatically invoked by TwinCAT. AdsSyncDelDeviceNotificationReq() is used to halt the notification again. Since the number of notifications is limited, you should ensure the notifications no longer required by your program are deleted. You will find further information under the description of the AdsNotificationAttrib structure.

Unpack the sample program 'Event driven reading': sample09.zip

The following program starts a notification on flag double word 0 in the PLC. Each time the PLC variable changes, the callback function is invoked. The callback function receives a variable of type AdsNotificationHeader() as one of its parameters. This structure contains all the necessary information (value, timestamp, ...).

Event driven reading 1:

Time intensive actions

No time-intensive actions may be executed in the callback.

import de.beckhoff.jni.AdsConstants;
import de.beckhoff.jni.JNILong;
import de.beckhoff.jni.tcads.AdsCallDllFunction;
import de.beckhoff.jni.tcads.AdsNotificationAttrib;
import de.beckhoff.jni.tcads.AdsCallbackObject;
import de.beckhoff.jni.tcads.AmsAddr;

public class Main {  
    public static void main(String[] args) {
    try {
        long err;
        AmsAddr addr = new AmsAddr();
        JNILong notification = new JNILong();

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

        // Specify attributes of the notificationRequest
        AdsNotificationAttrib attr = new AdsNotificationAttrib();
        attr.setCbLength(Integer.SIZE / Byte.SIZE);
        attr.setNTransMode(AdsConstants.ADSTRANS_SERVERONCHA);
        attr.setDwChangeFilter(10000000);   // 1 sec
        attr.setNMaxDelay(20000000);    // 2 sec

        // Create and add listener
        AdsListener listener = new AdsListener();
        AdsCallbackObject callObject = new AdsCallbackObject();
        callObject.addListenerCallbackAdsState(listener);

        // Create notificationHandle
        err = AdsCallDllFunction.adsSyncAddDeviceNotificationReq(
        addr,
        0x4020,     // IndexGroup
        0x0,    // IndexOffset
        attr,       // The defined AdsNotificationAttrib object
        42,     // Choose arbitrary number
        notification);
        if(err!=0) { 
        System.out.println("Error: Add notification: 0x" 
            + Long.toHexString(err)); 
        }

        // Read as long as user does not press return
        System.out.println("Press enter to continue..");
        System.in.read();

        // Delete notificationHandle
        err = AdsCallDllFunction.adsSyncDelDeviceNotificationReq(
            addr,
            notification);
        if(err!=0) { 
        System.out.println("Error: Remove notification: 0x"
            + Long.toHexString(err)); 
        }

        // Delete listener
        callObject.removeListenerCallbackAdsState(listener);

        //Close communication
        err = AdsCallDllFunction.adsPortClose();
        if(err!=0) { 
        System.out.println("Error: Close Communication: 0x" 
            + Long.toHexString(err)); 
        }
    } catch(Exception ex) {
        System.out.println(ex.getMessage());
    }
    }
}


The implementation of the CallbackListenerAdsState interface:

import de.beckhoff.jni.Convert;
import de.beckhoff.jni.tcads.AdsNotificationHeader;
import de.beckhoff.jni.tcads.AmsAddr;
import de.beckhoff.jni.tcads.CallbackListenerAdsState;
import java.util.Date;

public class AdsListener implements CallbackListenerAdsState {
    private final static long SPAN = 11644473600000L;

    // Callback function
    public void onEvent(AmsAddr addr,
            AdsNotificationHeader notification,
            long user) {

    // The PLC timestamp is coded in Windows FILETIME.
    // Nano secs since 01.01.1601.
    long dateInMillis = notification.getNTimeStamp();

    // Date accepts millisecs since 01.01.1970.
    // Convert to millisecs and substract span.
    Date notificationDate = new Date(dateInMillis / 10000 - SPAN);

    System.out.println("Value:\t\t"
        + Convert.ByteArrToInt(notification.getData()));
    System.out.println("Notification:\t" + notification.getHNotification());
    System.out.println("Time:\t\t" + notificationDate.toString());
    System.out.println("User:\t\t" + user);
    System.out.println("ServerNetID:\t" + addr.getNetIdString() + "\n");
    }
}