Ads In Java
- 依赖包
TcJavaToAds.jar, 可以直接在TwinCAT的安装目录下找到,路径(我这里装在C盘):C:\TwinCAT\AdsApi\AdsToJava,对应的DLL(adstojava.dll)也在这个目录下,DLL不用管,只要安装了TwinCAT XAE,TcJavaToAds.jar 使用时会自己按默认路径装载这个DLL,我们只需要在Java项目中加入TcJavaToAds.jar这个外部包就行。 - 示例
Java中ADS通信的流程比C#中复杂些,底层机制都一样,只是C#封装的相对好一些,这里为了更清晰的说明使用方式,将分成几段进行描述;项目中,我们通常只对发布的变量进行读写,即使用了AT指定段地址和偏移地址的,此时group和offset可以直接从PLC中获取到,这里我们描述的更为通用的方式,通过变量名自动获取段地址和偏移地址,进而对变量进行读、写、监听;当然也可以通过变量名获取变量句柄,然后通过句柄对变量进行读写,但所提供的API中没有通过句柄进行变量监听的操作,要监听必须提供段地址和偏移地址。另外,这里读写监听示例主要针对单线程环境,如果需要在多线程环境下使用,需要使用相应的Ex结尾的API函数,函数名和参数均类似单线程的。- 建立Ads连接
AmsAddr addr = new AmsAddr(); AdsCallDllFunction.adsPortOpen(); addr.setNetIdStringEx("*.*.*.*.*.*"); addr.setPort(851);
- 读取变量地址信息
long err; String PLC_VAR = "MAIN.sTest"; //JNIByteBuffer handleBuff = new JNIByteBuffer(16); JNIByteBuffer symbolInfoBuff = new JNIByteBuffer(BUFF_LENGTH_MAX); //BUFF_LENGTH_MAX:16 JNIByteBuffer symbolBuff = new JNIByteBuffer(PLC_VAR.getBytes()); err = AdsCallDllFunction.adsSyncReadWriteReq(addr, AdsCallDllFunction.ADSIGRP_SYM_INFOBYNAME, 0x0, symbolInfoBuff.getUsedBytesCount(), symbolInfoBuff, symbolBuff.getUsedBytesCount(), symbolBuff);//err处理略 byte[] bArr = symbolInfoBuff.getByteArray(); System.out.println(bArr.length); ByteBuffer wrapped = ByteBuffer.wrap(bArr); wrapped.order(ByteOrder.LITTLE_ENDIAN); int group = wrapped.getInt(); System.out.println("group: "+group); int offset = wrapped.getInt(); System.out.println("offset: "+offset); int len = wrapped.getInt(); System.out.println("len: "+len);
- 根据Group+Offset读取变量
JNIByteBuffer dataBuff = new JNIByteBuffer(BUFF_LENGTH_MAX); err = AdsCallDllFunction.adsSyncReadReq(addr, group, offset, len, dataBuff);//err处理略 ByteBuffer wrapped2 = ByteBuffer.wrap(dataBuff.getByteArray()); wrapped2.order(ByteOrder.LITTLE_ENDIAN);
- 读取INT变量
System.out.println("val: " + wrapped2.getShort());
- 读取DINT变量
wrapped2.getInt();
- 读取LREAL变量
wrapped2.getDouble();
- 读取字符串
new String(dataBuff.getByteArray());
- 读取数组
for(int i=0; i<len/2; i++) { System.out.println("val: [" + i + "]: " + wrapped2.getShort()); }
- 读取结构体
其中,PLC中对应的结构体定义为:System.out.println(wrapped2.getShort()); System.out.println(wrapped2.get()); System.out.println(wrapped2.getDouble(8));
注意结构体中变量的字节对齐问题TYPE S_Test : STRUCT i: INT; b: BOOL; q: LREAL; END_STRUCT END_TYPE
- 读取INT变量
- 根据Group+Offset写变量
AdsCallDllFunction.adsSyncWriteReq(addr, group, offset, dataBuff.getUsedBytesCount(), dataBuff);
- 写INT变量
dataBuff.setByteArray(ByteBuffer.allocate(Short.SIZE/Byte.SIZE) .order(ByteOrder.LITTLE_ENDIAN).putShort((short) 99).array(), true);
- 写DINT变量
dataBuff.setByteArray(ByteBuffer.allocate(Integer.SIZE/Byte.SIZE) .order(ByteOrder.LITTLE_ENDIAN).putInt((short) 99).array(), true);
- 写LREAL变量
dataBuff.setByteArray(ByteBuffer.allocate(Double.SIZE/Byte.SIZE) .order(ByteOrder.LITTLE_ENDIAN).putDouble((short) 99).array(), true);
- 写字符串
dataBuff.setByteArray("Hi\0".getBytes(), true);
- 写数组
ByteBuffer buf = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN); for(int i=1; i<=32; i++) { buf.putShort((short) i); } dataBuff.setByteArray(buf.array(), true);
- 写结构体
ByteBuffer buf = ByteBuffer.allocate(len).order(ByteOrder.LITTLE_ENDIAN); buf.putShort((short)19); buf.put((byte)1); buf.putDouble(8, 9.99); dataBuff.setByteArray(buf.array(), true);
- 写INT变量
- 事件触发读取变量
-
注册变量监听
JNILong notification = new JNILong(); AdsNotificationAttrib attr = new AdsNotificationAttrib(); attr.setCbLength(Short.SIZE / Byte.SIZE); attr.setNTransMode(AdsConstants.ADSTRANS_SERVERONCHA); attr.setDwChangeFilter(10000000); // 1 sec attr.setNMaxDelay(20000000); // 2 sec AdsListener listener = new AdsListener(); AdsCallbackObject callObject = new AdsCallbackObject(); callObject.addListenerCallbackAdsState(listener); err = AdsCallDllFunction.adsSyncAddDeviceNotificationReq( addr, group, offset, attr, 99, notification);
-
监听器实现
public class AdsListener implements CallbackListenerAdsState { private final static long SPAN = 1929293939399L; //回调函数 public void onEvent(AmsAddr addr, AdsNotificationHeader notification, long user) { long dateInMillis = notification.getNTimeStamp(); Date notificationDate = new Date(dateInMillis / 10000 - SPAN); System.out.println("Value: " + notification.getData()); System.out.println("Notification: " + notification.getHNotification()); System.out.println("Time: " + notificationDate.toString()); System.out.println("User: " + user); System.out.println("ServerNetID: " + addr.getNetIdString() + "\n"); } }
-
取消变量监听
AdsCallDllFunction.adsSyncDelDeviceNotificationReq(addr, notification);
-