Twincat ADS事件驱动的读取在一段时间后停止工作(Java)

Int*_*_TS 5 java twincat twincat-ads

我们开发了一个Java应用程序,该应用程序使用TwinCat ADS库(DLL)从Beckhoff PLC(CX5120)读取,写入和处理事件。我们已经成功地在多台机器上运行了该程序,但是不幸的是,当前遇到了一个事件处理突然停止的问题。这是我们经历的确切场景:

  • 读取,写入和事件得到正确处理。
  • 突然我们再也没有任何事件了,尽管读写仍然可以正常工作。
  • 将PLC替换为另一个PLC,再次成功开始工作。当时我们认为这是一个许可问题。
  • 经过一周的无人值守运行后,同样的问题再次出现,PLC / ADS库似乎不再触发事件,我们似乎也无法以任何方式使其再次正常工作。读/写仍然可以正常工作。

使用另一台带有Java应用程序的PC进行测试,同样的问题。因此,PLC中的某些内容似乎冻结/停止工作。

这是我们设置事件处理的方式:

// Implementation of the CallbackListenerAdsState interface
public class ADSEventController implements CallbackListenerAdsState {

......

// Register itself as listener for the ADS events (in constructor)
callObject = new AdsCallbackObject();
callObject.addListenerCallbackAdsState(this);

....

// Event handling
public void onEvent(AmsAddr addr, AdsNotificationHeader notification, long user) {
    log.info("Got ADS event for handle[{}] and with raw data[{}]", user, notification.getData());

......

// Registering notification handles for PLC variables
// If we already assigned a notification, delete it first (while reconnecting)
    JNILong notification = new JNILong();
if(var.getNotification() != null) {
    notification = var.getNotification();
    AdsCallDllFunction.adsSyncDelDeviceNotificationReq(addr,notification);
}

// Specify attributes of the notificationRequest
AdsNotificationAttrib attr = new AdsNotificationAttrib();
attr.setCbLength(var.getSize());
attr.setNTransMode(AdsConstants.ADSTRANS_SERVERONCHA);
attr.setDwChangeFilter(1000);   // 0.01 sec
attr.setNMaxDelay(2000);        // 0.02 sec

// Create notificationHandle
long err = AdsCallDllFunction.adsSyncAddDeviceNotificationReq(
    addr,
    AdsCallDllFunction.ADSIGRP_SYM_VALBYHND, // IndexGroup
    var.getHandle(), // IndexOffset
    attr, // The defined AdsNotificationAttrib object
    var.getHandle(), // Choose arbitrary number
    notification);
var.setNotification(notification);

if (err != 0) {
    log.error("Error: Add notification: 0x{} for var[{}]", Long.toHexString(err), var.getId());
}
Run Code Online (Sandbox Code Playgroud)

Int*_*_TS 5

我们设法找到了原因。当我们注册一个变量时,我们会从 PLC 获得一个句柄(long),在我们的例子中,它在一段时间后意外地开始为负值。我们还使用这个 long 值作为通知的用户引用,但是,我们发现用户引用在 ADS 库中是一个 unsigned long。

因此,如果我们在 adsSyncAddDeviceNotificationReq 调用中将一个负值(例如 -1258290964)设置为“任意数字”,则 CallbackListenerAdsState onEvent 方法的参数“user”(Long)将获得我们有符号长用户引用的无符号长表示,即 3036676332。在我们的Java 应用程序我们使用此用户引用通过此句柄将事件与特定 plc 变量进行匹配。由于在我们的示例中,我们期望 -1258290964 但得到 3036676332,因此我们从未处理过任何事件。