更新 S7 部分
This commit is contained in:
parent
9b6cd65daf
commit
0d326d95a7
@ -1,21 +1,23 @@
|
||||
package com.qgs.dc.s7.controller;
|
||||
|
||||
import com.qgs.dc.opcua.arg.*;
|
||||
import com.qgs.dc.opcua.controller.R;
|
||||
import com.qgs.dc.s7.service.S7Service;
|
||||
import org.apache.plc4x.java.PlcDriverManager;
|
||||
import org.apache.plc4x.java.api.PlcConnection;
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
||||
import com.qgs.dc.s7.my.s7connector.enmuc.PlcVarActual;
|
||||
import com.qgs.dc.s7.my.s7connector.enmuc.S7Client;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.service.S7Service;
|
||||
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
|
||||
import org.apache.plc4x.java.api.messages.PlcReadRequest;
|
||||
import org.apache.plc4x.java.api.messages.PlcReadResponse;
|
||||
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
||||
import org.apache.plc4x.java.api.value.PlcValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/s7")
|
||||
@ -25,18 +27,47 @@ public class S7Controller {
|
||||
@Autowired
|
||||
S7Service s7Service;
|
||||
|
||||
|
||||
@PostMapping("/addThisPlc")
|
||||
public R addThisPlc() throws PlcConnectionException {
|
||||
//s7://192.168.1.51?remote-rack=0&remote-slot=3&controller-type=S7_400,如果参数不是默认的 要向这样往url 后面加。
|
||||
return R.ok().put("res",s7Service.addPlc("s7://192.168.0.100"));
|
||||
//demo1
|
||||
@PostMapping("/testReadAll")
|
||||
public R testReadAll() throws UnsupportedEncodingException, ParseException {
|
||||
for(PlcVarActual actual:PlcVarActual.values()){
|
||||
System.out.println(s7Service.read(actual,S7Client.S7_1200));;
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
@PostMapping("/getValue")
|
||||
public R getValue() throws PlcConnectionException {
|
||||
|
||||
//demo2
|
||||
@PostMapping("/readTest")
|
||||
public R getTestForS7() throws UnsupportedEncodingException, ParseException {
|
||||
Boolean heartBeat = (Boolean)s7Service.read(PlcVarActual.HeartBeat,S7Client.S7_1200);
|
||||
String ddtl = (String)s7Service.read(PlcVarActual.DTL,S7Client.S7_1200);
|
||||
List<Character> characters = (List<Character>)s7Service.read(PlcVarActual.CharArrays,S7Client.S7_1200);
|
||||
|
||||
List<Boolean> booleans = (List<Boolean>)s7Service.read(PlcVarActual.BooleanArrays,S7Client.S7_1200);
|
||||
String stri = (String)s7Service.read(PlcVarActual.STRING1,S7Client.S7_1200);
|
||||
|
||||
return R.ok().put("res",1);
|
||||
return R.ok().put("res",heartBeat).put("characters",characters).put("ddtl",ddtl).put("bools",booleans).put("str",stri);
|
||||
}
|
||||
|
||||
//demo3
|
||||
@PostMapping("/writeTest")
|
||||
public R writeTest() throws PlcConnectionException, UnsupportedEncodingException {
|
||||
s7Service.write(PlcVarActual.HeartBeat, false, S7Client.S7_1200);
|
||||
|
||||
char[] charArrays_content = new char[2];
|
||||
charArrays_content[0] = '1';
|
||||
charArrays_content[1] = 'c';
|
||||
s7Service.write(PlcVarActual.CharArrays, charArrays_content, S7Client.S7_1200);
|
||||
|
||||
boolean[] boolArrays_content = new boolean[2];
|
||||
boolArrays_content[0] = true;
|
||||
boolArrays_content[1] = false;
|
||||
s7Service.write(PlcVarActual.BooleanArrays, boolArrays_content, S7Client.S7_1200);
|
||||
|
||||
String str = "你好啊aa";
|
||||
//todo string 的读写有问题 待会看看
|
||||
s7Service.write(PlcVarActual.STRING1, str, S7Client.S7_1200);
|
||||
return R.ok().put("res",true);
|
||||
}
|
||||
|
||||
}
|
||||
|
16
src/main/java/com/qgs/dc/s7/entity/ReadedBack.java
Normal file
16
src/main/java/com/qgs/dc/s7/entity/ReadedBack.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.qgs.dc.s7.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/12/6 13:42
|
||||
*/
|
||||
@Data
|
||||
public class ReadedBack {
|
||||
private Integer size;
|
||||
private List<Object> content;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.qgs.dc.s7.my.s7connector.Constant;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2022/1/17 15:16
|
||||
*/
|
||||
public class S7ClientArg {
|
||||
public static final Integer S7ClientPoolCore = 3;
|
||||
private static final Integer pickOne = 0;
|
||||
|
||||
public synchronized Integer getPickOne(){
|
||||
return pickOne;
|
||||
}
|
||||
|
||||
|
||||
}
|
233
src/main/java/com/qgs/dc/s7/my/s7connector/Main2.java
Normal file
233
src/main/java/com/qgs/dc/s7/my/s7connector/Main2.java
Normal file
@ -0,0 +1,233 @@
|
||||
package com.qgs.dc.s7.my.s7connector;
|
||||
|
||||
import cn.hutool.core.util.ByteUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/12/10 11:22
|
||||
*/
|
||||
public class Main2 {
|
||||
public static byte[] double2Bytes(double d) {
|
||||
long value = Double.doubleToRawLongBits(d);
|
||||
byte[] byteRet = new byte[8];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
|
||||
}
|
||||
return byteRet;
|
||||
}
|
||||
/**
|
||||
* 1个字节byte[] 转成有符号的short
|
||||
* */
|
||||
public static Integer toInt(byte bytes) {
|
||||
return Integer.valueOf(Byte.toString(bytes));
|
||||
}
|
||||
public static Integer toUInt(byte bytes) {
|
||||
return Integer.valueOf(Byte.toUnsignedInt(bytes));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = -1; //内部是 补码形式存在 //todo 搞清楚 补码和原码什么时候转化
|
||||
bytes[1] = -111;
|
||||
//-1 原码 1000 0001 ;;-1 补码 1111 1111
|
||||
//1000 0001 1110 1111 //原码形式
|
||||
//1111 1111 1001 0001 //补码形式,在计算机内部是以补码形式存储的,当赋值给2个字节后是无符号整形的 要强制转化成short类型后,如果之前首位是1 就会被java强制转化成补码
|
||||
//1000 0000 0110 1111 //
|
||||
//1+16+128+256+512+1024+2048+4096+4096*2+4096*3+4096*4
|
||||
//1024*(63)
|
||||
|
||||
//1000 0000 0110 1111 //-111
|
||||
System.out.println(toInt(bytes[0]));
|
||||
System.out.println(toUInt(bytes[0]));
|
||||
System.out.println(toInt(bytes[1]));
|
||||
System.out.println(toUInt(bytes[1]));
|
||||
|
||||
System.out.println("无符号 "+(bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE));
|
||||
System.out.println("有符号 "+(short)(bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE));
|
||||
|
||||
// //byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保持二进制补码的一致性。 0xff 其实就是0000 0000 0000 0000 0000 0000 1111 0100
|
||||
short l = 0;
|
||||
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
//注意: 移位并不会增加原来字节长度,被挤掉的数据就没了,而且是以补码的形式移动的。
|
||||
l |= (bytes[0] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff) // 255 补码 1111 1111
|
||||
|
||||
l<<=7;
|
||||
l<<=1;
|
||||
//l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
l |= (bytes[1] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||
|
||||
|
||||
short c = 0;
|
||||
c<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
//注意: 移位并不会增加原来字节长度,被挤掉的数据就没了,而且是以补码的形式移动的。
|
||||
c |= ((byte)1 & 0xff); //和上面也是一样的 l = l | (b[i]&0xff) // 255 补码 1111 1111
|
||||
|
||||
c<<=7;
|
||||
c<<=1;
|
||||
//l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
c |= ((byte)2 & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||
|
||||
|
||||
byte bb = -1;
|
||||
bb<<=8;
|
||||
System.out.println(bb);
|
||||
System.out.println(l);
|
||||
System.out.println(Byte.valueOf((byte) 0x81)); //有符号 因为0x81 会自动被java 转成byte,而byte会以补码 有符号的形式存在
|
||||
System.out.println(0x81); //无符号
|
||||
|
||||
|
||||
byte[] lrealBuffer = new byte[8];
|
||||
Number lrealNumber = new Double(-12.1);
|
||||
byte[] bytesss = ByteUtil.numberToBytes(lrealNumber);
|
||||
Number intNumber = new Integer(-12);
|
||||
byte[] bytessss = ByteUtil.numberToBytes(intNumber);
|
||||
|
||||
Integer s = new Integer(-999);
|
||||
byte b = s.byteValue();
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public static double bytes2Double(byte[] arr) {
|
||||
long value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
value |= ((long) (arr[i] & 0xff)) << (8 * i);
|
||||
}
|
||||
return Double.longBitsToDouble(value);
|
||||
}
|
||||
|
||||
public static byte[] short2byte(short s){
|
||||
byte[] b = new byte[2];
|
||||
for(int i = 0; i < 2; i++){
|
||||
int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量
|
||||
b[i] = (byte)((s >> offset)&0xff); //把16位分为2个8位进行分别存储
|
||||
}
|
||||
return b;
|
||||
}
|
||||
/**
|
||||
* 将byte[]转为各种进制的字符串
|
||||
* @param bytes byte[]
|
||||
* @param radix 基数可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
public static String binary(byte[] bytes, int radix){
|
||||
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
|
||||
}
|
||||
|
||||
public static String byteToBit(byte b) {
|
||||
return ""
|
||||
+ (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
|
||||
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1) +","
|
||||
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
|
||||
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
|
||||
}
|
||||
|
||||
public static short byte2short(byte[] b){
|
||||
short l = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
public static byte[] int2byte(int s){
|
||||
byte[] b = new byte[2];
|
||||
for(int i = 0; i < 4; i++){
|
||||
int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量
|
||||
b[i] = (byte)((s >> offset)&0xff); //把32位分为4个8位进行分别存储
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
public static int byte2int(byte[] b){
|
||||
int l = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* int到byte[](byte数组4个字节)
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
public static byte[] intToByteArray(int i) {
|
||||
byte[] result = new byte[4];
|
||||
//由高位到低位
|
||||
result[0] = (byte)((i >> 24) & 0xFF);
|
||||
result[1] = (byte)((i >> 16) & 0xFF); //如果查过128 那么会被java自动转成负数
|
||||
result[2] = (byte)((i >> 8) & 0xFF);
|
||||
result[3] = (byte)(i & 0xFF);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 4个字节的byte[]转int
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static Integer byteArrayToInt(byte[] in) {
|
||||
byte[] bytes = new byte[4];
|
||||
|
||||
//如果传进来数组不满足4个字节,自动填充
|
||||
if(in.length>4){
|
||||
return null;
|
||||
}else if(in.length!=4){
|
||||
Stack<Byte> st = new Stack<Byte>();
|
||||
int c = 4-in.length;
|
||||
in = invert(in);
|
||||
for(int i=0;i<in.length;i++){
|
||||
st.push(in[i]);
|
||||
}
|
||||
for(int i=0;i<c;i++){
|
||||
st.push(Byte.valueOf((byte) 0));
|
||||
}
|
||||
for(int i=0;i<4;i++){
|
||||
bytes[i] = st.pop();
|
||||
}
|
||||
}else {
|
||||
bytes = in;
|
||||
}
|
||||
|
||||
int value=0;
|
||||
//由高位到低位
|
||||
for(int i = 0; i < 4; i++) {
|
||||
int shift= (4-1-i) * 8;
|
||||
value +=(bytes[i] & 0x000000FF) << shift;//往高位游
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Integer byteToUSInt(byte bytes) {
|
||||
int value=0;
|
||||
value +=(bytes & 0xFF);
|
||||
return value;
|
||||
}
|
||||
public static Integer byteToSInt(byte bytes) {
|
||||
return Byte.valueOf(bytes).intValue();
|
||||
}
|
||||
|
||||
public static byte[] invert(byte[] a){
|
||||
byte[] b = new byte[a.length];
|
||||
Stack<Byte> st = new Stack<Byte>();
|
||||
for(int i=0;i<a.length;i++){
|
||||
st.push(a[i]);
|
||||
}
|
||||
for(int i=0;i<a.length;i++){
|
||||
b[i] = st.pop();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
248
src/main/java/com/qgs/dc/s7/my/s7connector/MainForRead.java
Normal file
248
src/main/java/com/qgs/dc/s7/my/s7connector/MainForRead.java
Normal file
@ -0,0 +1,248 @@
|
||||
package com.qgs.dc.s7.my.s7connector;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.factory.S7ConnectorFactory;
|
||||
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/12/10 10:17
|
||||
*/
|
||||
public class MainForRead {
|
||||
public static void main(String[] args) {
|
||||
//前言:
|
||||
//DB3.1.1 中间那个1是byte区,后面那个1 是bit
|
||||
//缺陷: 不支持 DB3.1.1
|
||||
|
||||
//Create connection
|
||||
S7Connector connector =
|
||||
S7ConnectorFactory
|
||||
.buildTCPConnector()
|
||||
.withHost("192.168.0.51")
|
||||
.withRack(0) //optional rack 是机架号
|
||||
.withSlot(0) //optional slot 是插槽号
|
||||
.build();
|
||||
|
||||
|
||||
// // [0]
|
||||
// byte[] bool = connector.read(DaveArea.DB, 3, 1, 3266,0);
|
||||
// byte[] bool2 = connector.read(DaveArea.DB, 3, 1, 3266,1);
|
||||
// System.out.println("DB3.0-bool : " + ByteUtils.toBoolean(bool));
|
||||
// System.out.println("DB3.0-bool2 : " + ByteUtils.toBoolean(bool2));
|
||||
|
||||
|
||||
|
||||
//bool3 => [1] 0000 0001 ==> 1000 0000 10.......
|
||||
//bool3 => [3] 0000 0011 ==> 1100 0000 11.......
|
||||
//bool3 => [10] 0000 1010 ==> 0101 0000 0101.....
|
||||
//bool3 => [25] 0001 1001 ==> 1001 1000 10011....
|
||||
byte[] bool3 = connector.read(DaveArea.DB, 3, 1, 3267);
|
||||
System.out.println("DB3.0-bool3 : " + ByteUtils.toBoolean(bool3));
|
||||
|
||||
|
||||
//
|
||||
// byte[] bool4 = connector.read(DaveArea.DB, 3, 1, 0);
|
||||
// System.out.println("DB3.0-bool3 : " + ByteUtils.toBoolean(bool3));
|
||||
|
||||
//
|
||||
//
|
||||
// //非常规
|
||||
// {
|
||||
// //注意1:
|
||||
// //lreal 要小端(拿到字节流要翻转一下)
|
||||
// //参数一:读取方式,一般默认是DB区域块
|
||||
// //参数二:区域块编号
|
||||
// //参数三:区域数据类型大小,int 2字节,real 4字节
|
||||
// //参数四:区域偏移量
|
||||
// //[-64, 40, 51, 51, 51, 51, 51, 51] -64==0xc0(要翻转一下才能用)
|
||||
// //1100 0000 0010 1000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
|
||||
//
|
||||
// byte[] lreal = connector.read(DaveArea.DB, 3, 8, 26,0);
|
||||
// System.out.println("DB3.26-lreal : "+ ByteUtils.forLReal(lreal));
|
||||
//
|
||||
// byte[] real = connector.read(DaveArea.DB, 3, 4, 22,0);
|
||||
// System.out.println("DB3.22-real : "+ ByteUtils.forReal(real));
|
||||
//
|
||||
// }
|
||||
|
||||
// {
|
||||
// //data 是有符号的双字节
|
||||
// //注意2:
|
||||
// //[2, -38] 就就代表1990-1-1 因为这就是其实位置。 后续位置要1990+n的 D#1992-01-01
|
||||
// //[4, 72] 1993-1-1
|
||||
// //0000 0100 0100 1000 72+1024=1096 1990-1-1 + 1096(天) = 1993-1-1
|
||||
// byte[] date = connector.read(DaveArea.DB, 3, 2, 42);
|
||||
//// System.out.println("DB3.42-DATE : "+addDate("1990-01-01",byte2short(date)));
|
||||
// Long aLong = Long.valueOf(ByteUtils.toInt(date[0], date[1]).toString());
|
||||
// System.out.println("DB3.42-DATE : "+ByteUtils.addDate("1990-01-01",aLong));
|
||||
// }
|
||||
//
|
||||
{
|
||||
//[7, -78, 1, 1, 5, 0, 0, 0, 0, 0, 0, 0] DTL#1970-01-01-00:00:00 1998-1-1 星期五 0.0.0.0
|
||||
//0000 0111 (1100 1110)=>(1011 0010 178) 178+256+512+1024=1970
|
||||
//(注意:第二个字节是负数要转成补码形式表示(因为在通行传输中 字节是原码形式传输的,但是java中long int byte... 都是以补码形式保存的 java帮你自动保存了其实这是不对的所以你要转换一下) 参考https://blog.csdn.net/csdn_ds/article/details/79106006)
|
||||
//[7, -68, 1, 21, 2, 0, 0, 0, 0, 0, 0, 0]
|
||||
//0000 0111 (1100 0100)=>(1011 1100 188) 188+256+512+1024=1980
|
||||
byte[] dtl = connector.read(DaveArea.DB, 3, 12, 44);
|
||||
byte[] year = new byte[2];
|
||||
year[0] = dtl[0];
|
||||
year[1] = dtl[1];
|
||||
byte[] month = new byte[1];
|
||||
month[0] = dtl[2];
|
||||
// System.out.println("DB3.12-DTL : " + byteArrayByteUtils.toUInt(year)+"-"+byteArrayByteUtils.toUInt(month));
|
||||
System.out.println("DB3.44-DTL : " + ByteUtils.toInt(year[0],year[1])+"-"+ByteUtils.toInt(month[0]));
|
||||
}
|
||||
//
|
||||
// {
|
||||
// //[59, -102, -55, -1] T#11D_13H_46M_39S_999MS
|
||||
// //0011 1011
|
||||
// byte[] time = connector.read(DaveArea.DB, 3, 4, 34);
|
||||
// System.out.println("DB3.34-time : " + ByteUtils.toInt(time[0],time[1],time[2],time[3]) +" ms");
|
||||
// }
|
||||
//
|
||||
// //常规
|
||||
// {
|
||||
// // [0]
|
||||
// byte[] bool = connector.read(DaveArea.DB, 3, 1, 0);
|
||||
// System.out.println("DB3.0-bool : " + ByteUtils.toBoolean(bool));
|
||||
//
|
||||
// //todo 就像这种情况的话,这个工具就无法读取了。。。。 这个后续可以改他的源码 就是addrees(Byte/Bit)那里 后续再说好了。
|
||||
// byte[] bool2 = connector.read(DaveArea.DB, 3, 1, 3266);
|
||||
// System.out.println("DB3.3266-bool : " + ByteUtils.toBoolean(bool2));
|
||||
//
|
||||
//
|
||||
// //byte 目前读取以 有符号的十进制
|
||||
// //[8]
|
||||
// //[-63]
|
||||
// //1011 1111
|
||||
// byte[] byteOne = connector.read(DaveArea.DB, 3, 1, 1);
|
||||
// System.out.println("DB3.1-byteOne-有符号 : " + ByteUtils.toInt(byteOne[0])); //有符号 整形
|
||||
//
|
||||
// System.out.println("DB3.1-byteOne-无符号 : " + ByteUtils.toUInt(byteOne[0])); //无符号 整形
|
||||
//
|
||||
//
|
||||
// // [0, 5] word 可 2/8/16进制 可无符号 可有符号,就看你真没用
|
||||
// byte[] word = connector.read(DaveArea.DB, 3, 2, 2);
|
||||
// System.out.println("DB3.2-word : " + ByteUtils.toInt(word[0],word[1]));
|
||||
//
|
||||
// // [-1, -1, -1, -4] 把java自动转换成byte类型 的补码形式 ,如果电控变量是这个要问下他是无符号还是有符号的。
|
||||
// // [FF, FF, FF, FC] 原码
|
||||
// byte[] dword = connector.read(DaveArea.DB, 3, 4, 4);
|
||||
// System.out.println("DB3.4-dword : " + ByteUtils.toInt(dword[0],dword[1],dword[2],dword[3])); //带符号的 整形
|
||||
//
|
||||
// //[11]
|
||||
// byte[] usint = connector.read(DaveArea.DB, 3, 1, 8);
|
||||
// System.out.println("DB3.8-usint : " + ByteUtils.toUInt(usint[0]));
|
||||
//
|
||||
// byte[] sint = connector.read(DaveArea.DB, 3, 1, 9);
|
||||
// System.out.println("DB3.9-sint : " + ByteUtils.toInt(sint[0]));
|
||||
//
|
||||
// byte[] uint = connector.read(DaveArea.DB, 3, 2, 10);
|
||||
// System.out.println("DB3.10-uint : " + ByteUtils.toUInt(uint[0],uint[1]));
|
||||
//
|
||||
// //[-1, -111] -111
|
||||
// //[-1, -64] -64
|
||||
// //[-4, 25] -999
|
||||
// byte[] ints = connector.read(DaveArea.DB, 3, 2, 12);
|
||||
// System.out.println("DB3.12-ints : " + ByteUtils.toInt(ints[0],ints[1]));
|
||||
//
|
||||
// byte[] dint = connector.read(DaveArea.DB, 3, 4, 14);
|
||||
// System.out.println("DB3.14-dint : " + ByteUtils.toInt(dint[0],dint[1],dint[2],dint[3]));
|
||||
//
|
||||
// byte[] udint = connector.read(DaveArea.DB, 3, 4, 18);
|
||||
// System.out.println("DB3.18-udint : " + ByteUtils.toUInt(udint[0],udint[1],udint[2],udint[3]));
|
||||
//
|
||||
// //plc 中char 是1个字节 注意char 和 wchar 都是ascii码格式的。
|
||||
// byte[] chars = connector.read(DaveArea.DB, 3, 1, 58);
|
||||
// Character charss = ByteUtils.toChar(chars);
|
||||
// System.out.println("DB3.58-char : " + charss);
|
||||
// //plc 中wchar 是2个字节
|
||||
// byte[] wchar = connector.read(DaveArea.DB, 3, 2, 60);
|
||||
// Character wchars =ByteUtils.toChar(wchar);
|
||||
// System.out.println("DB3.60-wchar : " + wchars);
|
||||
//
|
||||
// //n+2 个字节 (这里的n 就是实际content的字节数 如 "123"=> n=3 ;; "@123" ==> n=4)
|
||||
// //[-2, 4, 64, 65, 83, 68] @ASD 前面-2 4两个字节就是上面的2字节 是无用的
|
||||
// //-2 代表 字符串中存储最大的总字节数 ; 4代表字符数 后面跟着的 是内容(最多256个字节)
|
||||
// byte[] str = connector.read(DaveArea.DB, 3, 6, 62);
|
||||
// String string = ByteUtils.toStr(str);
|
||||
// System.out.println("DB3.62-str : " +string );
|
||||
//
|
||||
// }
|
||||
//
|
||||
{
|
||||
try {
|
||||
//byte 占用一个字节,如果是数组的话,就读取2个(要事先知道,点表规定数组长度),实际就是读取 DB3.830
|
||||
//bytes = byteLength * arrayLength 举例:1(byteLength) * 2(arrayLength) =2(bytes)
|
||||
byte[] boolArrays = connector.read(DaveArea.DB, 3, 2, 830);
|
||||
List<Boolean> booleans = ByteUtils.toBoolArray(boolArrays);
|
||||
System.out.println("DB3.830-boolArrays : " +booleans );
|
||||
|
||||
byte[] byteArrays = connector.read(DaveArea.DB, 3, 2, 832);
|
||||
List<Byte> bytes = ByteUtils.toByteArray(byteArrays);
|
||||
System.out.println("DB3.832-byteArrays : " +bytes );
|
||||
|
||||
byte[] charArrays = connector.read(DaveArea.DB, 3, 2, 834);
|
||||
List<Character> chars = ByteUtils.toCharArray(charArrays);
|
||||
System.out.println("DB3.834-charArrays : " +chars );
|
||||
|
||||
byte[] wordArrays = connector.read(DaveArea.DB, 3, 4, 836);
|
||||
List<Integer> words = ByteUtils.toWordArray(wordArrays);
|
||||
System.out.println("DB3.836-wordArrays : " +words );
|
||||
|
||||
byte[] dwordArrays = connector.read(DaveArea.DB, 3, 8, 840);
|
||||
List<Integer> dwords = ByteUtils.toDWordArray(dwordArrays);
|
||||
System.out.println("DB3.840-dwordArrays : " +dwords );
|
||||
|
||||
byte[] sintArrays = connector.read(DaveArea.DB, 3, 2, 852);
|
||||
List<Integer> sints = ByteUtils.toSIntArray(sintArrays);
|
||||
System.out.println("DB3.852-sintArrays : " +sints );
|
||||
|
||||
byte[] intArrays = connector.read(DaveArea.DB, 3, 4, 848);
|
||||
List<Integer> ints = ByteUtils.toIntArray(intArrays);
|
||||
System.out.println("DB3.848-intArrays : " +ints );
|
||||
|
||||
byte[] dintArrays = connector.read(DaveArea.DB, 3, 8, 854);
|
||||
List<Integer> dints = ByteUtils.toDIntArray(dintArrays);
|
||||
System.out.println("DB3.852-dintArrays : " +dints);
|
||||
|
||||
|
||||
byte[] usintArrays = connector.read(DaveArea.DB, 3, 3, 3240);
|
||||
List<Integer> usints = ByteUtils.toUSIntArray(usintArrays);
|
||||
System.out.println("DB3.3240-usintArrays : " +usints );
|
||||
|
||||
byte[] uintArrays = connector.read(DaveArea.DB, 3, 6, 3256);
|
||||
List<Integer> uints = ByteUtils.toUIntArray(uintArrays);
|
||||
System.out.println("DB3.3256-uintArrays : " +uints );
|
||||
|
||||
byte[] udintArrays = connector.read(DaveArea.DB, 3, 12, 3244);
|
||||
List<Long> udints = ByteUtils.toUDIntArray(udintArrays);
|
||||
System.out.println("DB3.852-udintArrays : " +udints);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Write to DB100 10 bytes
|
||||
|
||||
|
||||
|
||||
//connector.write(DaveArea.DB, 3, 830, byteArrays);
|
||||
|
||||
//Close connection
|
||||
|
||||
//connector.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
391
src/main/java/com/qgs/dc/s7/my/s7connector/MainForWrite.java
Normal file
391
src/main/java/com/qgs/dc/s7/my/s7connector/MainForWrite.java
Normal file
@ -0,0 +1,391 @@
|
||||
package com.qgs.dc.s7.my.s7connector;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.factory.S7ConnectorFactory;
|
||||
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/12/10 10:17
|
||||
*/
|
||||
public class MainForWrite {
|
||||
public static void main(String[] args) throws IOException, ParseException {
|
||||
//Create connection
|
||||
S7Connector connector =
|
||||
S7ConnectorFactory
|
||||
.buildTCPConnector()
|
||||
.withHost("192.168.0.51")
|
||||
.withRack(0) //optional rack 是机架号
|
||||
.withSlot(0) //optional slot 是插槽号
|
||||
.build();
|
||||
|
||||
|
||||
{
|
||||
connector.write(DaveArea.DB, 3, 3266,1,ByteUtils.boolToBytes(true), PlcVar.BOOL);
|
||||
// byte[] bool = connector.read(DaveArea.DB, 3, 1, 3266,1);
|
||||
// Boolean b = (Boolean)PlcVar.BOOL.toObject(bool);
|
||||
// System.out.println("DB3.3266.1-boolean : " + b);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//非常规
|
||||
{
|
||||
//注意1:
|
||||
//lreal 要小端(拿到字节流要翻转一下)
|
||||
//参数一:读取方式,一般默认是DB区域块
|
||||
//参数二:区域块编号
|
||||
//参数三:区域数据类型大小,int 2字节,real 4字节
|
||||
//参数四:区域偏移量
|
||||
//[-64, 40, 51, 51, 51, 51, 51, 51] -64==0xc0(要翻转一下才能用)
|
||||
//1100 0000 0010 1000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
|
||||
|
||||
|
||||
|
||||
// byte[] lreal_content = ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
|
||||
byte[] lreal_content = PlcVar.LREAL.toBytes(-121.1);
|
||||
connector.write(DaveArea.DB, 3, 26,lreal_content);
|
||||
byte[] lreal = connector.read(DaveArea.DB, 3, 8, 26);
|
||||
// Double aDouble = ByteUtils.lrealbytesToDouble(lreal);
|
||||
Double ad = (Double)PlcVar.LREAL.toObject(lreal);
|
||||
System.out.println("DB3.26-lreal : "+ ad);
|
||||
|
||||
//byte[] real_content = ByteUtils.realToBytes(Float.valueOf("-11.2"));
|
||||
byte[] real_content = PlcVar.REAL.toBytes(-12.1);
|
||||
connector.write(DaveArea.DB, 3, 22,real_content);
|
||||
byte[] real = connector.read(DaveArea.DB, 3, 4, 22);
|
||||
//ByteUtils.realbytesToFloat(real)
|
||||
Float o = (Float)PlcVar.REAL.toObject(real);
|
||||
System.out.println("DB3.22-real : "+ o);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
//data 是有符号的双字节
|
||||
//注意2:
|
||||
//[2, -38] 就就代表1990-1-1 因为这就是其实位置。 后续位置要1990+n的 D#1992-01-01
|
||||
//[4, 72] 1993-1-1
|
||||
//0000 0100 0100 1000 72+1024=1096 1990-1-1 + 1096(天) = 1993-1-1
|
||||
byte[] date = connector.read(DaveArea.DB, 3, 2, 42);
|
||||
// System.out.println("DB3.42-DATE : "+addDate("1990-01-01",byte2short(date)));
|
||||
// Long aLong = Long.valueOf(ByteUtils.toInt(date[0], date[1]).toString());
|
||||
// String s = ByteUtils.addDate("1990-01-01", aLong);
|
||||
String s = (String) PlcVar.DATE.toObject(date);
|
||||
System.out.println("DB3.42-DATE : "+s);
|
||||
}
|
||||
|
||||
{
|
||||
//[7, -78, 1, 1, 5, 0, 0, 0, 0, 0, 0, 0] DTL#1970-01-01-00:00:00 1998-1-1 星期五 0.0.0.0
|
||||
//0000 0111 (1100 1110)=>(1011 0010 178) 178+256+512+1024=1970
|
||||
//(注意:第二个字节是负数要转成补码形式表示(因为在通行传输中 字节是原码形式传输的,但是java中long int byte... 都是以补码形式保存的 java帮你自动保存了其实这是不对的所以你要转换一下) 参考https://blog.csdn.net/csdn_ds/article/details/79106006)
|
||||
//[7, -68, 1, 21, 2, 0, 0, 0, 0, 0, 0, 0]
|
||||
//0000 0111 (1100 0100)=>(1011 1100 188) 188+256+512+1024=1980
|
||||
byte[] dtl = connector.read(DaveArea.DB, 3, 12, 44);
|
||||
// byte[] year = new byte[2];
|
||||
// year[0] = dtl[0];
|
||||
// year[1] = dtl[1];
|
||||
// Integer yearInt = ByteUtils.toInt(year[0], year[1]);
|
||||
// Integer monthInt = ByteUtils.toInt(dtl[2]);
|
||||
// Integer dayInt = ByteUtils.toInt(dtl[3]);
|
||||
// Integer worddayInt = ByteUtils.toInt(dtl[4]);
|
||||
// Integer hourInt = ByteUtils.toInt(dtl[5]);
|
||||
// Integer minuInt = ByteUtils.toInt(dtl[6]);
|
||||
// Integer secondInt = ByteUtils.toInt(dtl[7]);
|
||||
|
||||
|
||||
// System.out.println("DB3.12-DTL : " + byteArrayByteUtils.toUInt(year)+"-"+byteArrayByteUtils.toUInt(month));
|
||||
String o = (String)PlcVar.DTL.toObject(dtl);
|
||||
System.out.println("DB3.44-DTL : " + o );
|
||||
}
|
||||
|
||||
{
|
||||
//[59, -102, -55, -1] T#11D_13H_46M_39S_999MS
|
||||
//0011 1011
|
||||
byte[] time = connector.read(DaveArea.DB, 3, 4, 34);
|
||||
// Integer integer = ByteUtils.toInt(time[0], time[1], time[2], time[3]);
|
||||
Integer i = (Integer) PlcVar.TIME.toObject(time);
|
||||
System.out.println("DB3.34-time : " + i +" ms");
|
||||
}
|
||||
|
||||
//常规
|
||||
|
||||
//int 相关(sint、int、dint 。。 usint、uint、udint)
|
||||
{
|
||||
//[11] //[9] ==>2304
|
||||
// byte[] usint_content = ByteUtils.usintToBytes(9);
|
||||
|
||||
byte[] usint_content = PlcVar.USINT.toBytes(9);
|
||||
connector.write(DaveArea.DB, 3, 8,usint_content);
|
||||
byte[] usint = connector.read(DaveArea.DB, 3, 1, 8);
|
||||
// Integer integer = ByteUtils.toUInt(usint[0]);
|
||||
Integer integer = (Integer) PlcVar.USINT.toObject(usint);
|
||||
System.out.println("DB3.8-usint : " + integer);
|
||||
|
||||
// byte[] bytes = ByteUtils.sintToBytes(-9);
|
||||
byte[] bytes = PlcVar.SINT.toBytes(-9);
|
||||
connector.write(DaveArea.DB, 3, 9,bytes);
|
||||
byte[] sint = connector.read(DaveArea.DB, 3, 1, 9);
|
||||
// Integer integer1 = ByteUtils.toInt(sint[0]);
|
||||
Integer integer1 = (Integer) PlcVar.SINT.toObject(usint);
|
||||
System.out.println("DB3.9-sint : " + integer1);
|
||||
|
||||
// byte[] unit_content = ByteUtils.uintToBytes(9);
|
||||
byte[] unit_content = PlcVar.UINT.toBytes(9);
|
||||
connector.write(DaveArea.DB, 3, 10,unit_content);
|
||||
byte[] uint = connector.read(DaveArea.DB, 3, 2, 10);
|
||||
System.out.println("DB3.10-uint : " + ByteUtils.toUInt(uint[0],uint[1]));
|
||||
|
||||
//[-1, -111] -111
|
||||
//[-1, -64] -64
|
||||
//[-4, 25] -999
|
||||
//byte[] bytes1 = ByteUtils.intToBytes(-99);
|
||||
byte[] bytes1 = PlcVar.INT.toBytes(-99);
|
||||
connector.write(DaveArea.DB, 3, 12,bytes1);
|
||||
byte[] ints = connector.read(DaveArea.DB, 3, 2, 12);
|
||||
System.out.println("DB3.12-ints : " + ByteUtils.toInt(ints[0],ints[1]));
|
||||
|
||||
|
||||
// byte[] bytes2 = ByteUtils.dintToBytes(-999);
|
||||
byte[] bytes2 = PlcVar.DINT.toBytes(-999);
|
||||
connector.write(DaveArea.DB, 3, 14,bytes2);
|
||||
byte[] dint = connector.read(DaveArea.DB, 3, 4, 14);
|
||||
System.out.println("DB3.14-dint : " + ByteUtils.toInt(dint[0],dint[1],dint[2],dint[3]));
|
||||
|
||||
// byte[] bytes3 = ByteUtils.udintToBytes(99);
|
||||
|
||||
byte[] bytes3 = PlcVar.UDINT.toBytes(99);
|
||||
connector.write(DaveArea.DB, 3, 18,bytes3);
|
||||
byte[] udint = connector.read(DaveArea.DB, 3, 4, 18);
|
||||
System.out.println("DB3.18-udint : " + ByteUtils.toUInt(udint[0],udint[1],udint[2],udint[3]));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// [0]
|
||||
// byte[] bytes = ByteUtils.boolToBytes(false);
|
||||
byte[] bytes = PlcVar.BOOL.toBytes(false);
|
||||
connector.write(DaveArea.DB, 3, 0,bytes);
|
||||
byte[] bool = connector.read(DaveArea.DB, 3, 1, 0);
|
||||
System.out.println("DB3.0-boolean : " + ByteUtils.toBoolean(bool));
|
||||
|
||||
//byte 目前读取以 有符号的十进制
|
||||
//[8]
|
||||
//[-63]
|
||||
//1011 1111
|
||||
// byte[] setbytes = ByteUtils.setbytes(Byte.valueOf((byte) 0xFF));
|
||||
byte[] setbytes = PlcVar.BYTE.toBytes((byte)0xFF);
|
||||
connector.write(DaveArea.DB, 3, 1,setbytes);
|
||||
byte[] byteOne = connector.read(DaveArea.DB, 3, 1, 1);
|
||||
System.out.println("DB3.1-byteOne-有符号 : " + ByteUtils.toInt(byteOne[0])); //有符号 整形
|
||||
System.out.println("DB3.1-byteOne-无符号 : " + ByteUtils.toUInt(byteOne[0])); //无符号 整形
|
||||
|
||||
|
||||
// [0, 5] word 可 2/8/16进制 可无符号 可有符号,就看你真没用
|
||||
// byte[] bytes1 = ByteUtils.wordToBytes(Short.valueOf("-55"));
|
||||
byte[] bytes1 = PlcVar.WORD.toBytes(-55);
|
||||
connector.write(DaveArea.DB, 3, 2,bytes1);
|
||||
byte[] word = connector.read(DaveArea.DB, 3, 2, 2);
|
||||
System.out.println("DB3.2-word : " + ByteUtils.toInt(word[0],word[1]));
|
||||
|
||||
// [-1, -1, -1, -4] 把java自动转换成byte类型 的补码形式 ,如果电控变量是这个要问下他是无符号还是有符号的。
|
||||
// [FF, FF, FF, FC] 原码
|
||||
byte[] bytes2 = PlcVar.DWORD.toBytes(-99);
|
||||
connector.write(DaveArea.DB, 3, 4,bytes2);
|
||||
byte[] dword = connector.read(DaveArea.DB, 3, 4, 4);
|
||||
System.out.println("DB3.4-dword : " + ByteUtils.toInt(dword[0],dword[1],dword[2],dword[3])); //带符号的 整形
|
||||
|
||||
|
||||
//plc 中char 是1个字节 注意char 和 wchar 都是ascii码格式的。
|
||||
// byte[] bytes3 = ByteUtils.charToBytes('b');
|
||||
byte[] bytes3 = PlcVar.CHAR.toBytes('b');
|
||||
connector.write(DaveArea.DB, 3, 58,bytes3);
|
||||
byte[] chars = connector.read(DaveArea.DB, 3, 1, 58);
|
||||
System.out.println("DB3.58-char : " + ByteUtils.toChar(chars));
|
||||
|
||||
//plc 中wchar 是2个字节 '菜' =》[-125, -36]
|
||||
// byte[] bytes4 = ByteUtils.wcharToBytes('菜');
|
||||
byte[] bytes4 = PlcVar.WCHAR.toBytes('翔');
|
||||
connector.write(DaveArea.DB, 3, 60,bytes4);
|
||||
byte[] wchar = connector.read(DaveArea.DB, 3, 2, 60);
|
||||
System.out.println("DB3.60-wchar : " + ByteUtils.toChar(wchar));
|
||||
|
||||
//n+2 个字节 (这里的n 就是实际content的字节数 如 "123"=> n=3 ;; "@123" ==> n=4)
|
||||
//[-2, 4, 64, 65, 83, 68] @ASD 前面-2 4两个字节就是上面的2字节 是无用的
|
||||
//-2 代表 字符串中存储最大的总字节数 ; 4代表字符数 后面跟着的 是内容(最多256个字节)
|
||||
|
||||
//[-2, 4, 64, 65, 83, 68] @ASD
|
||||
//[-2, 4, 64, 64, 64, 64] @ASD
|
||||
//读取字符串 要事先知道长度,否则可能读取的字符串长度不完整
|
||||
String s = "你好啊呢";
|
||||
// byte[] str_content = ByteUtils.strToBytes(s);
|
||||
// byte[] str_content = PlcVar.STRING.toBytes(s);
|
||||
// connector.write(DaveArea.DB, 3, 62 , str_content);
|
||||
//byte[] str = connector.read(DaveArea.DB, 3, str_content.length, 62);
|
||||
//[-2, 6, -60, -29, -70, -61]
|
||||
//[-2, 8, -53, -58, -75, -60]
|
||||
byte[] str = connector.read(DaveArea.DB, 3, 10, 62);
|
||||
String string = ByteUtils.toStr(str);
|
||||
System.out.println("DB3.62-str : " +string );
|
||||
//下面这种方式读取字符串,,是指定长度的,
|
||||
//byte[] str2 = connector.read(DaveArea.DB, 3, 7, 62);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
//byte 占用一个字节,如果是数组的话,就读取2个(要事先知道,点表规定数组长度),实际就是读取 DB3.830
|
||||
//bytes = byteLength * arrayLength 举例:1(byteLength) * 2(arrayLength) =2(bytes)
|
||||
boolean[] booleanArray = new boolean[2];
|
||||
booleanArray[0] = true;
|
||||
booleanArray[1] = true;
|
||||
// byte[] bytes1 = ByteUtils.booleanArrayToBytes(booleanArray);
|
||||
byte[] bytes1 = PlcVar.BOOL_Array.toBytes(booleanArray);
|
||||
connector.write(DaveArea.DB, 3, 830 , bytes1);
|
||||
byte[] boolArrays = connector.read(DaveArea.DB, 3, 2, 830);
|
||||
// List<Boolean> booleans = ByteUtils.toBoolArray(boolArrays);
|
||||
List<Boolean> booleans = (List<Boolean>) PlcVar.BOOL_Array.toObject(boolArrays);
|
||||
System.out.println("DB3.830-boolArrays : " +booleans );
|
||||
|
||||
|
||||
//注意 write的长度,要和plc中定义的长度要一致
|
||||
byte[] write_byteArrays = new byte[2];
|
||||
write_byteArrays[0] = 1;
|
||||
write_byteArrays[1] = 2;
|
||||
byte[] bytes2 = PlcVar.BYTE_Array.toBytes(write_byteArrays);
|
||||
connector.write(DaveArea.DB, 3, 832 , bytes2);
|
||||
byte[] byteArrays = connector.read(DaveArea.DB, 3, 2, 832);
|
||||
// List<Byte> bytes = ByteUtils.toByteArray(byteArrays);
|
||||
List<Byte> bytes = (List<Byte>) PlcVar.BYTE_Array.toObject(boolArrays);
|
||||
System.out.println("DB3.832-byteArrays : " +bytes );
|
||||
|
||||
|
||||
short[] shortArrays_content = new short[2];
|
||||
shortArrays_content[0] = 1;
|
||||
shortArrays_content[1] = -1;
|
||||
// byte[] bytes4 = ByteUtils.wordArrayToBytes(shortArrays_content);
|
||||
byte[] bytes4 = PlcVar.WORD_Array.toBytes(shortArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 836 ,bytes4);
|
||||
byte[] wordArrays = connector.read(DaveArea.DB, 3, 4, 836);
|
||||
List<Integer> words = ByteUtils.toWordArray(wordArrays);
|
||||
System.out.println("DB3.836-wordArrays : " +words );
|
||||
|
||||
int[] intArrays_content = new int[2];
|
||||
intArrays_content[0] = 1;
|
||||
intArrays_content[1] = -1;
|
||||
// byte[] bytes5 = ByteUtils.dwordArrayToBytes(intArrays_content);
|
||||
byte[] bytes5 = PlcVar.DWORD_Array.toBytes(intArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 840 ,bytes5);
|
||||
byte[] dwordArrays = connector.read(DaveArea.DB, 3, 8, 840);
|
||||
List<Integer> dwords = ByteUtils.toDWordArray(dwordArrays);
|
||||
System.out.println("DB3.840-dwordArrays : " +dwords );
|
||||
|
||||
|
||||
char[] charArrays_content = new char[2];
|
||||
charArrays_content[0] = '1';
|
||||
charArrays_content[1] = 'b';
|
||||
// byte[] bytes3 = ByteUtils.charArrayToBytes(charArrays_content);
|
||||
byte[] bytes3 = PlcVar.CHAR_Array.toBytes(charArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 834 ,bytes3);
|
||||
byte[] charArrays = connector.read(DaveArea.DB, 3, 2, 834);
|
||||
List<Character> chars = ByteUtils.toCharArray(charArrays);
|
||||
System.out.println("DB3.834-charArrays : " +chars );
|
||||
|
||||
|
||||
int[] sintArrays_content = new int[2];
|
||||
sintArrays_content[0] = 1;
|
||||
sintArrays_content[1] = -1;
|
||||
// byte[] bytes6 = ByteUtils.sintArrayToBytes(sintArrays_content);
|
||||
byte[] bytes6 = PlcVar.SINT_Array.toBytes(sintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 852 ,bytes6);
|
||||
byte[] sintArrays = connector.read(DaveArea.DB, 3, 2, 852);
|
||||
List<Integer> sints = ByteUtils.toSIntArray(sintArrays);
|
||||
System.out.println("DB3.852-sintArrays : " +sints );
|
||||
|
||||
|
||||
int[] iintArrays_content = new int[2];
|
||||
iintArrays_content[0] = 12;
|
||||
iintArrays_content[1] = -21;
|
||||
// byte[] bytes7 = ByteUtils.intArrayToBytes(iintArrays_content);
|
||||
byte[] bytes7 = PlcVar.INT_Array.toBytes(iintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 848 ,bytes7);
|
||||
byte[] intArrays = connector.read(DaveArea.DB, 3, 4, 848);
|
||||
List<Integer> ints = ByteUtils.toIntArray(intArrays);
|
||||
System.out.println("DB3.848-intArrays : " +ints );
|
||||
|
||||
|
||||
//todo here
|
||||
int[] dintArrays_content = new int[2];
|
||||
dintArrays_content[0] = 12;
|
||||
dintArrays_content[1] = -21;
|
||||
//ByteUtils.dintArrayToBytes(dintArrays_content)
|
||||
byte[] bytes11 =PlcVar.DINT_Array.toBytes(dintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 854 ,bytes11);
|
||||
byte[] dintArrays = connector.read(DaveArea.DB, 3, 8, 854);
|
||||
List<Integer> dints = ByteUtils.toDIntArray(dintArrays);
|
||||
System.out.println("DB3.852-dintArrays : " +dints);
|
||||
|
||||
|
||||
int[] uintArrays_content = new int[3];
|
||||
uintArrays_content[0] = 12;
|
||||
uintArrays_content[1] = 99;
|
||||
uintArrays_content[2] = 1;
|
||||
//byte[] bytes9 = ByteUtils.uintArrayToBytes(uintArrays_content);
|
||||
byte[] bytes9 = PlcVar.UINT_Array.toBytes(uintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 3256 ,bytes9);
|
||||
byte[] uintArrays = connector.read(DaveArea.DB, 3, 6, 3256);
|
||||
List<Integer> uints = ByteUtils.toUIntArray(uintArrays);
|
||||
System.out.println("DB3.3256-uintArrays : " +uints );
|
||||
|
||||
|
||||
|
||||
int[] usintArrays_content = new int[3];
|
||||
usintArrays_content[0] = 12;
|
||||
usintArrays_content[1] = 99;
|
||||
usintArrays_content[2] = 1;
|
||||
// byte[] bytes8 = ByteUtils.usintArrayToBytes(usintArrays_content);
|
||||
byte[] bytes8 = PlcVar.USINT_Array.toBytes(usintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 3240 ,bytes8);
|
||||
byte[] usintArrays = connector.read(DaveArea.DB, 3, 3, 3240);
|
||||
List<Integer> usints = ByteUtils.toUSIntArray(usintArrays);
|
||||
System.out.println("DB3.3240-usintArrays : " +usints );
|
||||
|
||||
|
||||
int[] udintArrays_content = new int[3];
|
||||
udintArrays_content[0] = 12;
|
||||
udintArrays_content[1] = 99;
|
||||
udintArrays_content[2] = 1;
|
||||
// byte[] bytes10 = ByteUtils.udintArrayToBytes(udintArrays_content);
|
||||
byte[] bytes10 = PlcVar.UDINT_Array.toBytes(udintArrays_content);
|
||||
connector.write(DaveArea.DB, 3, 3244 ,bytes10);
|
||||
byte[] udintArrays = connector.read(DaveArea.DB, 3, 12, 3244);
|
||||
List<Long> udints = ByteUtils.toUDIntArray(udintArrays);
|
||||
System.out.println("DB3.852-udintArrays : " +udints);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Write to DB100 10 bytes
|
||||
|
||||
|
||||
|
||||
//connector.write(DaveArea.DB, 3, 830, byteArrays);
|
||||
|
||||
//Close connection
|
||||
connector.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
47
src/main/java/com/qgs/dc/s7/my/s7connector/api/DaveArea.java
Normal file
47
src/main/java/com/qgs/dc/s7/my/s7connector/api/DaveArea.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api;
|
||||
|
||||
public enum DaveArea {
|
||||
ANALOGINPUTS200(6), // System info of 200 family
|
||||
ANALOGOUTPUTS200(7), // System flags of 200 family
|
||||
COUNTER(28), // analog inputs of 200 family
|
||||
COUNTER200(30), // analog outputs of 200 family
|
||||
DB(0x84), // Peripheral I/O //这个是plc中的不同区,有V区,input区,output区
|
||||
DI(0x85), FLAGS(0x83), INPUTS(0x81), LOCAL(0x86), // data blocks
|
||||
OUTPUTS(0x82), // instance data blocks
|
||||
P(0x80), // not tested
|
||||
SYSINFO(3), // local of caller
|
||||
SYSTEMFLAGS(5), // S7 counters
|
||||
TIMER(29), // S7 timers
|
||||
TIMER200(31), // IEC counters (200 family)
|
||||
V(0x87); // IEC timers (200 family)
|
||||
|
||||
/** Function Code */
|
||||
int code;
|
||||
|
||||
/** Constructor */
|
||||
DaveArea(final int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function code as associated
|
||||
*/
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
public interface S7Connector extends Closeable {
|
||||
/**
|
||||
* Reads an area
|
||||
*
|
||||
* @param area
|
||||
* @param areaNumber
|
||||
* @param bytes
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset);
|
||||
|
||||
/**
|
||||
* Reads an area 读需要bit 位置的 变量(其实就是 read bool变量的时候调用这个方法。)
|
||||
*
|
||||
* @param area
|
||||
* @param areaNumber
|
||||
* @param bytes
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize);
|
||||
/**
|
||||
* Writes an area
|
||||
*
|
||||
* @param area
|
||||
* @param areaNumber
|
||||
* @param offset
|
||||
* @param buffer
|
||||
*/
|
||||
public void write(DaveArea area, int areaNumber, int offset, byte[] buffer);
|
||||
|
||||
//如果 bitOffset 没有 那么就填0
|
||||
public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var);
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
/**
|
||||
* The Interface S7Serializable API
|
||||
*/
|
||||
public interface S7Serializable {
|
||||
|
||||
/**
|
||||
* Extracts a java type from a byte buffer.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
* @param targetClass
|
||||
* the target class
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
* @param bitOffset
|
||||
* the bit offset
|
||||
* @return the t
|
||||
*/
|
||||
public <T> T extract(Class<T> targetClass, byte[] buffer, int byteOffset, int bitOffset);
|
||||
|
||||
/**
|
||||
* Returns the S7-Type.
|
||||
*
|
||||
* @return the s7 type
|
||||
*/
|
||||
public S7Type getS7Type();
|
||||
|
||||
/**
|
||||
* Returns the size of the s7 type bytes.
|
||||
*
|
||||
* @return the size in bits
|
||||
*/
|
||||
public int getSizeInBits();
|
||||
|
||||
/**
|
||||
* Returns the size of the s7 type bytes.
|
||||
*
|
||||
* @return the size in bytes
|
||||
*/
|
||||
public int getSizeInBytes();
|
||||
|
||||
/**
|
||||
* Inserts a Java Object to the byte buffer.
|
||||
*
|
||||
* @param javaType
|
||||
* the java type
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
* @param bitOffset
|
||||
* the bit offset
|
||||
* @param size
|
||||
* the size
|
||||
*/
|
||||
public void insert(Object javaType, byte[] buffer, int byteOffset, int bitOffset, int size);
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.exception.S7Exception;
|
||||
|
||||
public interface S7Serializer {
|
||||
|
||||
/**
|
||||
* Dispenses an Object from the mapping of the Datablock.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
* @param beanClass
|
||||
* the bean class
|
||||
* @param dbNum
|
||||
* the db num
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
* @return the t
|
||||
* @throws S7Exception
|
||||
* the s7 exception
|
||||
*/
|
||||
<T> T dispense(Class<T> beanClass, int dbNum, int byteOffset) throws S7Exception;
|
||||
|
||||
/**
|
||||
* Dispense.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
* @param beanClass
|
||||
* the bean class
|
||||
* @param dbNum
|
||||
* the db num
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
* @param blockSize
|
||||
* the block size
|
||||
* @return the t
|
||||
* @throws S7Exception
|
||||
* the s7 exception
|
||||
*/
|
||||
<T> T dispense(Class<T> beanClass, int dbNum, int byteOffset, int blockSize) throws S7Exception;
|
||||
|
||||
/**
|
||||
* Stores an Object to the Datablock.
|
||||
*
|
||||
* @param bean
|
||||
* the bean
|
||||
* @param dbNum
|
||||
* the db num
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
*/
|
||||
void store(Object bean, int dbNum, int byteOffset);
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation for array-declaration
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*/
|
||||
@Target(value = { ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Array {
|
||||
int size();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation for a datablock
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*/
|
||||
@Target(value = { ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Datablock {
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api.annotation;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Defines an Offset in a DB
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*/
|
||||
@Target(value = { ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface S7Variable {
|
||||
/**
|
||||
* The size of the array
|
||||
*/
|
||||
int arraySize() default 1;
|
||||
|
||||
/**
|
||||
* The bit offset, if any
|
||||
*/
|
||||
int bitOffset() default 0;
|
||||
|
||||
/**
|
||||
* The Byte Offset
|
||||
*/
|
||||
int byteOffset();
|
||||
|
||||
/**
|
||||
* The specified size (for String)
|
||||
*/
|
||||
int size() default 0;
|
||||
|
||||
/**
|
||||
* The corresponding S7 Type
|
||||
*/
|
||||
S7Type type();
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api.factory;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.S7TCPConnection;
|
||||
|
||||
/**
|
||||
* S7 connector factory, currently only for TCP connections
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*
|
||||
*/
|
||||
public class S7ConnectorFactory {
|
||||
|
||||
/**
|
||||
* TCP Connection builder
|
||||
*
|
||||
*/
|
||||
public static class TCPConnectionBuilder {
|
||||
|
||||
private String host;
|
||||
|
||||
//rack 和 slot 都是指的是 remote-rack 和 remote-slot
|
||||
private int rack = 0, slot = 0, port = 102;
|
||||
|
||||
/**
|
||||
* Builds a connection with given params
|
||||
*/
|
||||
public S7Connector build() {
|
||||
return new S7TCPConnection(this.host, this.rack, this.slot, this.port);
|
||||
}
|
||||
|
||||
/**
|
||||
* use hostname/ip
|
||||
*/
|
||||
public TCPConnectionBuilder withHost(final String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* use port, default is 102
|
||||
*/
|
||||
public TCPConnectionBuilder withPort(final int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* use rack, default is 0
|
||||
*/
|
||||
public TCPConnectionBuilder withRack(final int rack) {
|
||||
this.rack = rack;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* use slot, default is 2
|
||||
*/
|
||||
public TCPConnectionBuilder withSlot(final int slot) {
|
||||
this.slot = slot;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a new TCP connection builder
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TCPConnectionBuilder buildTCPConnector() {
|
||||
return new TCPConnectionBuilder();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.api.factory;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializer;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.S7SerializerImpl;
|
||||
|
||||
/**
|
||||
* S7 Serializer factory
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*
|
||||
*/
|
||||
public class S7SerializerFactory {
|
||||
|
||||
/**
|
||||
* Builds a new serializer with given connector
|
||||
*
|
||||
* @param connector
|
||||
* the connector to use
|
||||
* @return a serializer instance
|
||||
*/
|
||||
public static S7Serializer buildSerializer(final S7Connector connector) {
|
||||
return new S7SerializerImpl(connector);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,689 @@
|
||||
package com.qgs.dc.s7.my.s7connector.api.utils;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/12/16 9:08
|
||||
*/
|
||||
|
||||
import cn.hutool.core.util.ByteUtil;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class ByteUtils {
|
||||
|
||||
|
||||
public static double bytes2Double(byte[] arr) {
|
||||
long value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
value |= ((long) (arr[i] & 0xff)) << (8 * i);
|
||||
}
|
||||
|
||||
return Double.longBitsToDouble(value);
|
||||
}
|
||||
|
||||
public static Boolean toBoolean(byte[] bytes){
|
||||
if(bytes.length ==0){
|
||||
return null;
|
||||
}
|
||||
if(bytes[0] == 1){
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static Boolean toBoolean(byte bytes){
|
||||
if(bytes == 1){
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String addDate(String timeParam, Long day) throws ParseException {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式
|
||||
Date date = dateFormat.parse(timeParam); // 指定日期
|
||||
|
||||
long time = date.getTime(); // 得到指定日期的毫秒数
|
||||
day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数
|
||||
time += day; // 相加得到新的毫秒数
|
||||
Date newDate = new Date(time);
|
||||
return dateFormat.format(newDate); // 将毫秒数转换成日期
|
||||
}
|
||||
|
||||
|
||||
public static byte[] invert(byte[] a){
|
||||
byte[] b = new byte[a.length];
|
||||
Stack<Byte> st = new Stack<Byte>();
|
||||
for(int i=0;i<a.length;i++){
|
||||
st.push(a[i]);
|
||||
}
|
||||
for(int i=0;i<a.length;i++){
|
||||
b[i] = st.pop();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 1个字节byte[] 转成有符号的Integer
|
||||
* */
|
||||
public static Integer toInt(byte bytes) {
|
||||
return Integer.valueOf(Byte.toString(bytes));
|
||||
}
|
||||
/**
|
||||
* 1个字节byte[] 转成无符号的Integer
|
||||
* */
|
||||
public static Integer toUInt(byte bytes) {
|
||||
int i = Byte.toUnsignedInt(bytes);
|
||||
return Integer.valueOf(i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 2个字节byte[] 转成有符号的Integer
|
||||
* 默认大端
|
||||
* */
|
||||
public static Integer toInt(byte byte1,byte byte2) {
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = byte1;
|
||||
bytes[1] = byte2;
|
||||
|
||||
return Integer.valueOf(Short.toString(ByteUtil.bytesToShort(bytes, ByteOrder.BIG_ENDIAN)));
|
||||
}
|
||||
/**
|
||||
* 2个字节byte[] 转成无符号的Integer
|
||||
* 默认大端
|
||||
* */
|
||||
public static Integer toUInt(byte byte1,byte byte2) {
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = byte1;
|
||||
bytes[1] = byte2;
|
||||
short i = ByteUtil.bytesToShort(bytes, ByteOrder.BIG_ENDIAN);
|
||||
return Short.toUnsignedInt(i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 4个字节byte[] 转成有符号的Integer
|
||||
* 默认大端
|
||||
* */
|
||||
public static Integer toInt(byte byte1,byte byte2,byte byte3,byte byte4) {
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = byte1;
|
||||
bytes[1] = byte2;
|
||||
bytes[2] = byte3;
|
||||
bytes[3] = byte4;
|
||||
return ByteUtil.bytesToInt(bytes, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
/**
|
||||
* 4个字节byte[] 转成无符号的Long(因为如果首位为1 Integer就不满足长度了)
|
||||
* 默认大端
|
||||
* */
|
||||
public static Long toUInt(byte byte1,byte byte2,byte byte3,byte byte4) {
|
||||
byte[] bytes = new byte[8];
|
||||
bytes[0] = 0;
|
||||
bytes[1] = 0;
|
||||
bytes[2] = 0;
|
||||
bytes[3] = 0;
|
||||
bytes[4] = byte1;
|
||||
bytes[5] = byte2;
|
||||
bytes[6] = byte3;
|
||||
bytes[7] = byte4;
|
||||
long l = ByteUtil.bytesToLong(bytes, ByteOrder.BIG_ENDIAN);
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 4个字节byte[] 转成有符号的Double
|
||||
* 默认大端
|
||||
* */
|
||||
public static Float forReal(byte[] bytes) {
|
||||
return Float.intBitsToFloat(toInt(bytes[0],bytes[1],bytes[2],bytes[3]));
|
||||
}
|
||||
/**
|
||||
*
|
||||
* 8个字节byte[] 转成有符号的Double
|
||||
* 默认大端
|
||||
* */
|
||||
public static Double forLReal(byte[] bytes) {
|
||||
return ByteUtil.bytesToDouble(bytes, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 8个字节byte[] 转成有符号的Double
|
||||
* 默认大端
|
||||
* */
|
||||
public static Double lrealbytesToDouble(byte[] bytes) {
|
||||
return ByteUtil.bytesToDouble(bytes, ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
public static byte[] lrealToBytes(double doubleValue) {
|
||||
return ByteUtil.doubleToBytes(doubleValue, ByteOrder.BIG_ENDIAN);
|
||||
//return double2Bytes(doubleValue);
|
||||
}
|
||||
|
||||
// public static String toChar(byte[] b) throws UnsupportedEncodingException {
|
||||
// String ascii = new String(b, Charset.forName("UTF-8"));
|
||||
// return ascii;
|
||||
// }
|
||||
public static Character toChar(byte[] b) throws UnsupportedEncodingException {
|
||||
if(b.length==1){
|
||||
return toChar(b[0]);
|
||||
}
|
||||
return byteToChar(b);
|
||||
}
|
||||
public static Character toChar(byte b) throws UnsupportedEncodingException {
|
||||
return byteToChar(b);
|
||||
}
|
||||
// public static String toChar(byte b) throws UnsupportedEncodingException {
|
||||
// byte[] bs = new byte[1];
|
||||
// bs[0] = b;
|
||||
// String ascii = new String(bs, "ascii");
|
||||
// return ascii;
|
||||
// }
|
||||
|
||||
/**
|
||||
* return null 代表返回传入参数不正确str 取的length太小
|
||||
* */
|
||||
public static String toStr(byte[] b) throws UnsupportedEncodingException {
|
||||
Integer length = Byte.toUnsignedInt(b[1]);
|
||||
if(length>(b.length-2)){
|
||||
return null;
|
||||
}
|
||||
byte[] content = new byte[b.length-2];
|
||||
for(int i=0;i<length;i++){
|
||||
content[i] = b[i+2];
|
||||
}
|
||||
String ascii = new String(content, StandardCharsets.UTF_8);
|
||||
// String s = new String(content);
|
||||
return ascii;
|
||||
}
|
||||
|
||||
public static List<Boolean> toBoolArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Boolean> res = new ArrayList<>();
|
||||
for(int i=0;i<b.length;i++){
|
||||
res.add(toBoolean(b[i]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Byte> toByteArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Byte> res = new ArrayList<>();
|
||||
for(int i=0;i<b.length;i++){
|
||||
res.add((b[i]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Character> toCharArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Character> res = new ArrayList<>();
|
||||
for(int i=0;i<b.length;i++){
|
||||
res.add(toChar(b[i]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//toWord
|
||||
/**
|
||||
* 默认:word => 有符号的整形
|
||||
* */
|
||||
public static List<Integer> toWordArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+2)<=b.length){
|
||||
res.add(
|
||||
toInt(b[i],b[i+1])
|
||||
);
|
||||
i+=2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//toDWord
|
||||
/**
|
||||
* 默认:dword => 有符号的整形
|
||||
* */
|
||||
public static List<Integer> toDWordArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+4)<=b.length){
|
||||
res.add(
|
||||
toInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||
);
|
||||
i+=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* 4个字节byte[] 转成有符号的Double
|
||||
* 默认大端
|
||||
* */
|
||||
public static Float realbytesToFloat(byte[] bytes) {
|
||||
|
||||
return Float.intBitsToFloat(toInt(bytes[0],bytes[1],bytes[2],bytes[3]));
|
||||
}
|
||||
public static byte[] realToBytes(Float f) {
|
||||
return invert(float2byte(f));
|
||||
}
|
||||
/**
|
||||
* 浮点转换为字节
|
||||
*
|
||||
* @param f
|
||||
* @return
|
||||
*/
|
||||
private static byte[] float2byte(float f) {
|
||||
|
||||
// 把float转换为byte[]
|
||||
int fbit = Float.floatToIntBits(f);
|
||||
|
||||
byte[] b = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
b[i] = (byte) (fbit >> (24 - i * 8));
|
||||
}
|
||||
|
||||
// 翻转数组
|
||||
int len = b.length;
|
||||
// 建立一个与源数组元素类型相同的数组
|
||||
byte[] dest = new byte[len];
|
||||
// 为了防止修改源数组,将源数组拷贝一份副本
|
||||
System.arraycopy(b, 0, dest, 0, len);
|
||||
byte temp;
|
||||
// 将顺位第i个与倒数第i个交换
|
||||
for (int i = 0; i < len / 2; ++i) {
|
||||
temp = dest[i];
|
||||
dest[i] = dest[len - i - 1];
|
||||
dest[len - i - 1] = temp;
|
||||
}
|
||||
|
||||
return dest;
|
||||
|
||||
}
|
||||
|
||||
//toUInt
|
||||
/**
|
||||
* USInt 无符号整形 1个字节 =》 Integer
|
||||
* */
|
||||
public static List<Integer> toUSIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
for(int i=0;i<b.length;i++){
|
||||
res.add(toUInt(b[i]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* UInt 无符号整形 2个字节 =》 Integer
|
||||
* */
|
||||
public static List<Integer> toUIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+2)<=b.length){
|
||||
res.add(
|
||||
toUInt(b[i],b[i+1])
|
||||
);
|
||||
i+=2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* UDInt 无符号整形 4个字节 =》 Long
|
||||
* */
|
||||
public static List<Long> toUDIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Long> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+4)<=b.length){
|
||||
res.add(
|
||||
toUInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||
);
|
||||
i+=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* SInt 无符号整形 1个字节 =》 Integer
|
||||
* */
|
||||
public static List<Integer> toSIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
for(int i=0;i<b.length;i++){
|
||||
res.add(toInt(b[i]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Int 无符号整形 2个字节 =》 Integer
|
||||
* */
|
||||
public static List<Integer> toIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+2)<=b.length){
|
||||
res.add(
|
||||
toInt(b[i],b[i+1])
|
||||
);
|
||||
i+=2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* DInt 无符号整形 4个字节 =》 Integer
|
||||
* */
|
||||
public static List<Integer> toDIntArray(byte[] b) throws UnsupportedEncodingException {
|
||||
List<Integer> res = new ArrayList<>();
|
||||
int i=0;
|
||||
while ((i+4)<=b.length){
|
||||
res.add(
|
||||
toInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||
);
|
||||
i+=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* sint(1个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] sintToBytes(Integer i){
|
||||
byte[] res = new byte[1];
|
||||
res[0] = Byte.valueOf(i.toString());
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* sintArray(1个字节) =》 byte[]
|
||||
*
|
||||
* */
|
||||
public static byte[] sintArrayToBytes(int[] sintArray) {
|
||||
byte[] res = new byte[sintArray.length];
|
||||
for(int i=0;i<sintArray.length;i++){
|
||||
int i1 = sintArray[i];
|
||||
res[i] = sintToBytes(i1)[0];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* int(2个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] intToBytes(Integer i) {
|
||||
Number shortNumber = Short.valueOf(i.toString());
|
||||
return ByteUtil.numberToBytes(shortNumber,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
/**
|
||||
* intArray(2个字节) =》 byte[]
|
||||
*
|
||||
* */
|
||||
public static byte[] intArrayToBytes(int[] intArray) {
|
||||
byte[] res = new byte[intArray.length*2];
|
||||
for(int i=0 ; i< intArray.length ; i++){
|
||||
byte[] bytes = intToBytes(intArray[i]);
|
||||
res[i*2] = bytes[0];
|
||||
res[i*2+1] = bytes[1];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* int(2个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] dintToBytes(Integer i) {
|
||||
Number intNumber = i;
|
||||
return ByteUtil.numberToBytes(intNumber,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
/**
|
||||
* intArray(2个字节) =》 byte[]
|
||||
*
|
||||
* */
|
||||
public static byte[] dintArrayToBytes(int[] dintArray) {
|
||||
byte[] res = new byte[dintArray.length*4];
|
||||
for(int i=0 ; i< dintArray.length ; i++){
|
||||
byte[] bytes = dintToBytes(dintArray[i]);
|
||||
res[i*4] = bytes[0];
|
||||
res[i*4+1] = bytes[1];
|
||||
res[i*4+2] = bytes[2];
|
||||
res[i*4+3] = bytes[3];
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* sint(1个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] usintToBytes(Integer i){
|
||||
if(i<0){
|
||||
return null;
|
||||
}
|
||||
byte[] res = new byte[1];
|
||||
res[0] = Byte.valueOf(i.toString());
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* usintArrayToBytes =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] usintArrayToBytes(int[] usintArray) {
|
||||
byte[] res = new byte[usintArray.length];
|
||||
for(int i=0 ; i< usintArray.length ; i++){
|
||||
byte[] bytes = usintToBytes(usintArray[i]);
|
||||
if(bytes == null){
|
||||
return null;
|
||||
}
|
||||
res[i] = bytes[0];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* int(2个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] uintToBytes(Integer i) {
|
||||
if(i<0){
|
||||
return null;
|
||||
}
|
||||
Number shortNumber = Short.valueOf(i.toString());
|
||||
return ByteUtil.numberToBytes(shortNumber,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
public static byte[] uintArrayToBytes(int[] uintArray) {
|
||||
byte[] res = new byte[uintArray.length*2];
|
||||
for(int i=0 ; i< uintArray.length ; i++){
|
||||
byte[] bytes = uintToBytes(uintArray[i]);
|
||||
if(bytes == null){
|
||||
return null;
|
||||
}
|
||||
res[i*2] = bytes[0];
|
||||
res[i*2+1] = bytes[1];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* int(2个字节) =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] udintToBytes(Integer i) {
|
||||
if(i<0){
|
||||
return null;
|
||||
}
|
||||
Number intNumber = i;
|
||||
return ByteUtil.numberToBytes(intNumber,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
public static byte[] udintArrayToBytes(int[] udintArray) {
|
||||
byte[] res = new byte[udintArray.length*4];
|
||||
for(int i=0 ; i< udintArray.length ; i++){
|
||||
byte[] bytes = udintToBytes(udintArray[i]);
|
||||
if(bytes == null){
|
||||
return null;
|
||||
}
|
||||
res[i*4] = bytes[0];
|
||||
res[i*4+1] = bytes[1];
|
||||
res[i*4+2] = bytes[2];
|
||||
res[i*4+3] = bytes[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* boolean =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] boolToBytes(Boolean bool) {
|
||||
byte[] res = new byte[1];
|
||||
if(bool){
|
||||
res[0] = 1;
|
||||
return res;
|
||||
}else {
|
||||
res[0] = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* booleanArray =》 byte[]
|
||||
* */
|
||||
public static byte[] booleanArrayToBytes(boolean[] boolArray) {
|
||||
byte[] res = new byte[boolArray.length];
|
||||
for(int i=0 ; i<boolArray.length ; i++){
|
||||
boolean b = boolArray[i];
|
||||
if(b){
|
||||
res[i] = 1;
|
||||
}else {
|
||||
res[i] = 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* charArray =》 byte[]
|
||||
* */
|
||||
public static byte[] charArrayToBytes(char[] charArray) {
|
||||
byte[] res = new byte[charArray.length];
|
||||
for(int i=0 ; i< charArray.length ; i++){
|
||||
byte[] bytes = charToByte(charArray[i]);
|
||||
if(bytes[0] != 0){
|
||||
return null;
|
||||
}else {
|
||||
res[i] = bytes[1];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* byte =》 byte[]
|
||||
* 默认大端模式
|
||||
* */
|
||||
public static byte[] setbytes(Byte bytes) {
|
||||
byte[] res = new byte[1];
|
||||
res[0] = bytes;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* word =》 byte[]
|
||||
* 默认大端模式
|
||||
* tip: 目前只支持 带符号的十进制 ==》 word(2个字节)
|
||||
* */
|
||||
public static byte[] wordToBytes(Short word) {
|
||||
return ByteUtil.shortToBytes(word,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* wordArray =》 byte[]
|
||||
* */
|
||||
public static byte[] wordArrayToBytes(short[] shortArray) {
|
||||
byte[] res = new byte[shortArray.length*2];
|
||||
for(int i=0 ; i< shortArray.length ; i++){
|
||||
byte[] bytes = wordToBytes(shortArray[i]);
|
||||
res[i*2] = bytes[0];
|
||||
res[i*2+1] = bytes[1];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* dword =》 byte[]
|
||||
* 默认大端模式
|
||||
* tip: 目前只支持 带符号的十进制 ==》 word(4个字节)
|
||||
* */
|
||||
public static byte[] dwordToBytes(Integer dword) {
|
||||
return ByteUtil.intToBytes(dword,ByteOrder.BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwordArray =》 byte[]
|
||||
* */
|
||||
public static byte[] dwordArrayToBytes(int[] intArray) {
|
||||
byte[] res = new byte[intArray.length*4];
|
||||
for(int i=0 ; i< intArray.length ; i++){
|
||||
byte[] bytes = dwordToBytes(intArray[i]);
|
||||
res[i*4] = bytes[0];
|
||||
res[i*4+1] = bytes[1];
|
||||
res[i*4+2] = bytes[2];
|
||||
res[i*4+3] = bytes[3];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* char(1字节) =》 byte[]
|
||||
*
|
||||
* */
|
||||
public static byte[] charToBytes(Character c) {
|
||||
return String.valueOf(c).getBytes();
|
||||
}
|
||||
public static byte[] wcharToBytes(Character c) {
|
||||
return charToByte(c);
|
||||
}
|
||||
|
||||
public static byte[] strToBytes(String s) {
|
||||
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] res = new byte[bytes.length+2];
|
||||
res[0] = -2;
|
||||
res[1] = Integer.valueOf(bytes.length).byteValue();
|
||||
for(int i=0;i<bytes.length;i++){
|
||||
res[i+2] = bytes[i];
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for private
|
||||
|
||||
private static byte[] charToByte(char c) {
|
||||
byte[] b = new byte[2];
|
||||
b[0] = (byte) ((c & 0xFF00) >> 8);
|
||||
b[1] = (byte) (c & 0xFF);
|
||||
return b;
|
||||
}
|
||||
private static char byteToChar(byte[] b) {
|
||||
char c = (char) (((b[0] & 0xFF) << 8) | (b[1] & 0xFF));
|
||||
return c;
|
||||
}
|
||||
private static char byteToChar(byte b) {
|
||||
char c = (char) (b & 0xFF);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.blocks;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.annotation.S7Variable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
/**
|
||||
* PID Control block representation
|
||||
*
|
||||
* @author Thomas Rudin (thomas@rudin-informatik.ch)
|
||||
*
|
||||
*/
|
||||
public class CONT_C {
|
||||
|
||||
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 6)
|
||||
public boolean D_SEL;
|
||||
|
||||
@S7Variable(type = S7Type.REAL, byteOffset = 20)
|
||||
public double GAIN;
|
||||
|
||||
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 3)
|
||||
public boolean I_SEL;
|
||||
|
||||
@S7Variable(type = S7Type.REAL, byteOffset = 72)
|
||||
public double LMN;
|
||||
|
||||
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 0)
|
||||
public boolean MAN_ON;
|
||||
|
||||
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 2)
|
||||
public boolean P_SEL;
|
||||
|
||||
@S7Variable(type = S7Type.REAL, byteOffset = 10)
|
||||
public double PV_IN;
|
||||
|
||||
@S7Variable(type = S7Type.REAL, byteOffset = 6)
|
||||
public double SP_INT;
|
||||
|
||||
@S7Variable(type = S7Type.TIME, byteOffset = 24)
|
||||
public long TN;
|
||||
|
||||
@S7Variable(type = S7Type.TIME, byteOffset = 28)
|
||||
public long TV;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CONT_C [MAN_ON=" + this.MAN_ON + ", P_SEL=" + this.P_SEL + ", I_SEL=" + this.I_SEL + ", D_SEL="
|
||||
+ this.D_SEL + ", SP_INT=" + this.SP_INT + ", PV_IN=" + this.PV_IN + ", GAIN=" + this.GAIN + ", TN="
|
||||
+ this.TN + ", TV=" + this.TV + ", LMN=" + this.LMN + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.qgs.dc.s7.my.s7connector.enmuc;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
import org.omg.CORBA.PRIVATE_MEMBER;
|
||||
|
||||
//实际 Plc中的变量。。。 要实现录入到这个枚举类中。。。 为后续做准备。
|
||||
public enum PlcVarActual {
|
||||
HeartBeat("HeartBeat",PlcVar.BOOL,1,DaveArea.DB,3,3267,5),
|
||||
//bitOffset 是针对Bool 来说的,
|
||||
DB54("DB54",PlcVar.BYTE,1,DaveArea.DB,3,3268,0),
|
||||
DTL("DTL",PlcVar.DTL,1,DaveArea.DB,3,44,0),
|
||||
STRING1("STRING",PlcVar.STRING,1,DaveArea.DB,3,62,0),
|
||||
|
||||
CharArrays("CharArrays",PlcVar.CHAR_Array,2,DaveArea.DB,3,834,0),
|
||||
BooleanArrays("BooleanArrays",PlcVar.BOOL_Array,2,DaveArea.DB,3,830,0)
|
||||
|
||||
|
||||
|
||||
;
|
||||
|
||||
private String name;
|
||||
private DaveArea area;
|
||||
private Integer areaNumber;
|
||||
private Integer byteOffset;
|
||||
private Integer bitOffset;
|
||||
private PlcVar type;
|
||||
//length = 1代表 非数组;;; length > 1 代表数组 ;; 注意 length这个参数 是实际plc中 数据的长度,和read操作相关
|
||||
//如果是String 类型不用填length 只需要填string类型的起始位置就行了,我会自己去取数据长度(也就是说这里的length并不是string 的长度)。
|
||||
private Integer length;
|
||||
|
||||
PlcVarActual(String name, PlcVar type,Integer length, DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset){
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.length = length;
|
||||
this.area = area;
|
||||
this.areaNumber = areaNumber;
|
||||
this.byteOffset = byteOffset;
|
||||
this.bitOffset = bitOffset;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public DaveArea getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
public Integer getAreaNumber() {
|
||||
return areaNumber;
|
||||
}
|
||||
|
||||
public Integer getBitOffset() {
|
||||
return bitOffset;
|
||||
}
|
||||
|
||||
public Integer getByteOffset() {
|
||||
return byteOffset;
|
||||
}
|
||||
|
||||
public PlcVar getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Integer getLength() {
|
||||
return length;
|
||||
}
|
||||
}
|
181
src/main/java/com/qgs/dc/s7/my/s7connector/enmuc/S7Client.java
Normal file
181
src/main/java/com/qgs/dc/s7/my/s7connector/enmuc/S7Client.java
Normal file
@ -0,0 +1,181 @@
|
||||
package com.qgs.dc.s7.my.s7connector.enmuc;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.factory.S7ConnectorFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2022/1/15 13:01
|
||||
*/
|
||||
public enum S7Client {
|
||||
//TODO 步骤1 这里是配置多PLC 的,,,有多个plc 就在这里配置一个枚举类
|
||||
S7_1200("192.168.0.51",0,0,3,PlcVarActual.HeartBeat)
|
||||
//后续 在这里扩展 多PLC应用。
|
||||
|
||||
|
||||
|
||||
|
||||
;
|
||||
private String host;
|
||||
//默认 0 机架号
|
||||
private Integer rack;
|
||||
//默认 0
|
||||
private Integer slot;
|
||||
|
||||
//心跳变量,如果plc没有让电控的人加一个,这个是必填的
|
||||
private PlcVarActual heartBeat;
|
||||
|
||||
private List<S7Connector> connections;
|
||||
//coreSize 是线程池的大小
|
||||
private Integer coreSize;
|
||||
//pickOne 就是一个初始化 的轮询取余值
|
||||
private int pickOne;
|
||||
private static final Logger logger = LoggerFactory.getLogger(S7Client.class);
|
||||
//coreSize 是线程池的数量
|
||||
S7Client(String host, Integer rack, Integer slot,Integer coreSize,PlcVarActual heartBeat){
|
||||
this.host = host;
|
||||
this.rack = rack;
|
||||
this.slot = slot;
|
||||
this.pickOne = 0;
|
||||
|
||||
this.coreSize = coreSize;
|
||||
this.heartBeat = heartBeat;
|
||||
connections = new ArrayList<>();
|
||||
connectionPool();
|
||||
|
||||
ping();
|
||||
|
||||
check_ping();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
|
||||
private ScheduledExecutorService ping_fail_check = Executors.newScheduledThreadPool(1);
|
||||
|
||||
|
||||
public S7Connector getConnector() {
|
||||
int size = connections.size();
|
||||
S7Connector s7Connector = connections.get((pickOne + size) % size);
|
||||
pickOne+=1;
|
||||
pickOne = (pickOne)%size;
|
||||
return s7Connector;
|
||||
}
|
||||
public S7Connector connect(String host,Integer rack,Integer slot ){
|
||||
try {
|
||||
S7Connector connector = S7ConnectorFactory
|
||||
.buildTCPConnector()
|
||||
.withHost(host)
|
||||
.withRack(rack) //optional rack 是机架号
|
||||
.withSlot(slot) //optional slot 是插槽号
|
||||
.build();
|
||||
return connector;
|
||||
}catch (Exception e){
|
||||
logger.info("创建S7Connector 连接失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void connectionPool(){
|
||||
for(int i=0;i<coreSize;i++){
|
||||
connections.add(connect(host,rack,slot));
|
||||
}
|
||||
//todo 在plc上新增一个 变量来解决 心跳问题 okok
|
||||
}
|
||||
|
||||
private void check_ping(){
|
||||
ping_fail_check.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true){
|
||||
if(connections.size()!=coreSize){
|
||||
int c = coreSize-connections.size();
|
||||
for(int z=0;z<c;z++){
|
||||
S7Connector connect = connect(host, rack, slot);
|
||||
if(connect!=null){
|
||||
connections.add(connect);
|
||||
}else {
|
||||
logger.info("check_ping 断线重连出现异常。。");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
}catch (Exception e){
|
||||
logger.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ping(){
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true){
|
||||
for(int i=0;i<coreSize;i++){
|
||||
S7Connector connector = getConnector();
|
||||
try {
|
||||
//只要没有报异常 都是通讯正常的。
|
||||
byte[] read = connector.read(
|
||||
heartBeat.getArea(),
|
||||
heartBeat.getAreaNumber(),
|
||||
heartBeat.getType().getTransportSize().getSizeInBytes(),
|
||||
heartBeat.getByteOffset(),
|
||||
heartBeat.getBitOffset(),
|
||||
heartBeat.getType().getTransportSize());
|
||||
System.out.println(connector.hashCode()+" : ping");
|
||||
Thread.sleep(100);
|
||||
}catch (Exception e){
|
||||
System.out.println(connector.hashCode()+" : connection error");
|
||||
logger.info(e.getMessage());
|
||||
//先把 socket close掉
|
||||
try {
|
||||
connector.close();
|
||||
connections.remove(connector);
|
||||
//如果是网络波动照成的socket断开。 等个1S 再重连试试
|
||||
Thread.sleep(100);
|
||||
}catch (Exception ee){
|
||||
logger.info(ee.getMessage());
|
||||
}
|
||||
|
||||
|
||||
//todo 把之前的连接close 掉,然后新增一个连接到connections
|
||||
|
||||
if(connections.size()!=coreSize){
|
||||
int c = coreSize-connections.size();
|
||||
for(int z=0;z<c;z++){
|
||||
S7Connector connect = connect(host, rack, slot);
|
||||
if(connect!=null){
|
||||
connections.add(connect);
|
||||
}else {
|
||||
logger.info("断线重连出现异常。。");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(30000);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
logger.info(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.exception;
|
||||
|
||||
/**
|
||||
* The Class S7Exception is an exception related to S7 Communication
|
||||
*/
|
||||
public final class S7Exception extends RuntimeException {
|
||||
|
||||
/** The Constant serialVersionUID. */
|
||||
private static final long serialVersionUID = -4761415733559374116L;
|
||||
|
||||
/**
|
||||
* Instantiates a new s7 exception.
|
||||
*/
|
||||
public S7Exception() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new s7 exception.
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*/
|
||||
public S7Exception(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new s7 exception.
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public S7Exception(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new s7 exception.
|
||||
*
|
||||
* @param cause
|
||||
* the cause
|
||||
*/
|
||||
public S7Exception(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.Nodave;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.S7Connection;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
|
||||
/**
|
||||
* Base-Connection for the S7-PLC Connection Libnodave:
|
||||
* http://libnodave.sourceforge.net/
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*/
|
||||
public abstract class S7BaseConnection implements S7Connector {
|
||||
|
||||
/** The Constant MAX_SIZE. */
|
||||
private static final int MAX_SIZE = 96;
|
||||
|
||||
/** The Constant PROPERTY_AREA. */
|
||||
public static final String PROPERTY_AREA = "area";
|
||||
|
||||
/** The Constant PROPERTY_AREANUMBER. */
|
||||
public static final String PROPERTY_AREANUMBER = "areanumber";
|
||||
|
||||
/** The Constant PROPERTY_BYTES. */
|
||||
public static final String PROPERTY_BYTES = "bytes";
|
||||
|
||||
/** The Constant PROPERTY_OFFSET. */
|
||||
public static final String PROPERTY_OFFSET = "offset";
|
||||
|
||||
/**
|
||||
* Checks the Result.
|
||||
*
|
||||
* @param libnodaveResult
|
||||
* the libnodave result
|
||||
*/
|
||||
public static void checkResult(final int libnodaveResult) {
|
||||
if (libnodaveResult != Nodave.RESULT_OK) {
|
||||
final String msg = Nodave.strerror(libnodaveResult);
|
||||
throw new IllegalArgumentException("Result: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump data
|
||||
*
|
||||
* @param b
|
||||
* the byte stream
|
||||
*/
|
||||
protected static void dump(final byte[] b) {
|
||||
for (final byte element : b) {
|
||||
System.out.print(Integer.toHexString(element & 0xFF) + ",");
|
||||
}
|
||||
}
|
||||
|
||||
/** The dc. */
|
||||
private S7Connection dc;
|
||||
|
||||
/**
|
||||
* Initialize the connection
|
||||
*
|
||||
* @param dc
|
||||
* the connection instance
|
||||
*/
|
||||
protected void init(final S7Connection dc) {
|
||||
this.dc = dc;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) {
|
||||
if (bytes > MAX_SIZE) {
|
||||
final byte[] ret = new byte[bytes];
|
||||
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
||||
final byte[] currentBuffer = this.read(area, areaNumber, MAX_SIZE, offset);
|
||||
System.arraycopy(currentBuffer, 0, ret, 0, currentBuffer.length);
|
||||
|
||||
final byte[] nextBuffer = this.read(area, areaNumber, bytes - MAX_SIZE, offset + MAX_SIZE);
|
||||
System.arraycopy(nextBuffer, 0, ret, currentBuffer.length, nextBuffer.length);
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
//接收结果的 容器,传进去指针
|
||||
final byte[] buffer = new byte[bytes];
|
||||
final int ret = this.dc.readBytes(area, areaNumber, offset, bytes, buffer);
|
||||
|
||||
checkResult(ret);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) {
|
||||
if(bitOffset==0){
|
||||
return read(area,areaNumber,bytes,offset);
|
||||
}
|
||||
|
||||
if (bytes > MAX_SIZE) {
|
||||
final byte[] ret = new byte[bytes];
|
||||
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
||||
final byte[] currentBuffer = this.read(area, areaNumber, MAX_SIZE, offset,bitOffset,transportSize);
|
||||
System.arraycopy(currentBuffer, 0, ret, 0, currentBuffer.length);
|
||||
|
||||
final byte[] nextBuffer = this.read(area, areaNumber, bytes - MAX_SIZE, offset + MAX_SIZE,bitOffset,transportSize);
|
||||
System.arraycopy(nextBuffer, 0, ret, currentBuffer.length, nextBuffer.length);
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
//接收结果的 容器,传进去指针
|
||||
final byte[] buffer = new byte[bytes];
|
||||
final int ret = this.dc.readBytes(area, areaNumber, offset,bitOffset, bytes, buffer,transportSize);
|
||||
|
||||
checkResult(ret);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) {
|
||||
if (buffer.length > MAX_SIZE) {
|
||||
// Split buffer
|
||||
final byte[] subBuffer = new byte[MAX_SIZE];
|
||||
final byte[] nextBuffer = new byte[buffer.length - subBuffer.length];
|
||||
|
||||
System.arraycopy(buffer, 0, subBuffer, 0, subBuffer.length);
|
||||
System.arraycopy(buffer, MAX_SIZE, nextBuffer, 0, nextBuffer.length);
|
||||
|
||||
this.write(area, areaNumber, offset, subBuffer);
|
||||
this.write(area, areaNumber, offset + subBuffer.length, nextBuffer);
|
||||
} else {
|
||||
// Size fits
|
||||
final int ret = this.dc.writeBytes(area, areaNumber, offset, buffer.length, buffer);
|
||||
// Check return-value
|
||||
checkResult(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) {
|
||||
if(bitOffset==0){
|
||||
write(area,areaNumber,byteOffset,buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (buffer.length > MAX_SIZE) {
|
||||
// Split buffer
|
||||
final byte[] subBuffer = new byte[MAX_SIZE];
|
||||
final byte[] nextBuffer = new byte[buffer.length - subBuffer.length];
|
||||
|
||||
System.arraycopy(buffer, 0, subBuffer, 0, subBuffer.length);
|
||||
System.arraycopy(buffer, MAX_SIZE, nextBuffer, 0, nextBuffer.length);
|
||||
|
||||
this.write(area, areaNumber, byteOffset,bitOffset, subBuffer,var);
|
||||
this.write(area, areaNumber, byteOffset + subBuffer.length,bitOffset, nextBuffer,var);
|
||||
} else {
|
||||
// Size fits
|
||||
final int ret = this.dc.writeBytes(area, areaNumber, byteOffset,bitOffset, buffer.length, buffer,var);
|
||||
// Check return-value
|
||||
checkResult(ret);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.exception.S7Exception;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.Nodave;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.PLCinterface;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.TCPConnection;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* TCP_Connection to a S7 PLC
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
* @href http://libnodave.sourceforge.net/
|
||||
*
|
||||
*/
|
||||
public final class S7TCPConnection extends S7BaseConnection {
|
||||
|
||||
/**
|
||||
* The Connection
|
||||
*/
|
||||
private TCPConnection dc;
|
||||
|
||||
/**
|
||||
* The Interface
|
||||
*/
|
||||
private PLCinterface di;
|
||||
|
||||
/**
|
||||
* The Host to connect to
|
||||
*/
|
||||
private final String host;
|
||||
|
||||
/**
|
||||
* The port to connect to
|
||||
*/
|
||||
private final int port;
|
||||
|
||||
/**
|
||||
* Rack and slot number
|
||||
*/
|
||||
private final int rack, slot;
|
||||
|
||||
/**
|
||||
* The Socket
|
||||
*/
|
||||
private Socket socket;
|
||||
|
||||
/**
|
||||
* Creates a new Instance to the given host, rack, slot and port
|
||||
*
|
||||
* @param host
|
||||
* @throws
|
||||
*/
|
||||
public S7TCPConnection(final String host, final int rack, final int slot, final int port) throws S7Exception {
|
||||
this.host = host;
|
||||
this.rack = rack;
|
||||
this.slot = slot;
|
||||
this.port = port;
|
||||
this.setupSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.socket.close();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
this.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the socket
|
||||
*/
|
||||
private void setupSocket() {
|
||||
try {
|
||||
this.socket = new Socket();
|
||||
this.socket.setSoTimeout(2000);
|
||||
//先socket 建立好连接
|
||||
this.socket.connect(new InetSocketAddress(this.host, this.port));
|
||||
|
||||
|
||||
this.di = new PLCinterface(this.socket.getOutputStream(), this.socket.getInputStream(), "IF1",
|
||||
DaveArea.LOCAL.getCode(), // TODO Local MPI-Address?
|
||||
Nodave.PROTOCOL_ISOTCP);
|
||||
|
||||
this.dc = new TCPConnection(this.di, this.rack, this.slot);
|
||||
|
||||
final int res = this.dc.connectPLC();
|
||||
checkResult(res);
|
||||
|
||||
super.init(this.dc);
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception("constructor", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
public final class Nodave {
|
||||
public final static int MAX_RAW_LEN = 2048;
|
||||
public final static int MPIReachable = 0x30;
|
||||
public final static int MPIunused = 0x10;
|
||||
public final static int OrderCodeSize = 21;
|
||||
|
||||
public final static int PartnerListSize = 126;
|
||||
|
||||
public final static int PROTOCOL_ISOTCP = 4;
|
||||
public final static int PROTOCOL_ISOTCP243 = 5;
|
||||
public final static int PROTOCOL_MPI_IBH = 223; // MPI with IBH NetLink MPI
|
||||
// to ethernet gateway
|
||||
public final static int PROTOCOL_MPI_NLPRO = 230; // MPI with IBH NetLink
|
||||
// MPI to ethernet
|
||||
// gateway
|
||||
public final static int PROTOCOL_NLPRO = 230; // MPI with IBH NetLink MPI to
|
||||
// ethernet gateway
|
||||
// to ethernet gateway
|
||||
public final static int PROTOCOL_PPI_IBH = 224; // PPI with IBH NetLink MPI
|
||||
|
||||
public final static int RESULT_ADDRESS_OUT_OF_RANGE = 5;
|
||||
/* means the write data size doesn't fit item size */
|
||||
public final static int RESULT_CANNOT_EVALUATE_PDU = -123;
|
||||
public final static int RESULT_CPU_RETURNED_NO_DATA = -124;
|
||||
public final static int RESULT_EMPTY_RESULT_ERROR = -126;
|
||||
|
||||
public final static int RESULT_EMPTY_RESULT_SET_ERROR = -127;
|
||||
|
||||
public final static int RESULT_ITEM_NOT_AVAILABLE = 10;
|
||||
/* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB */
|
||||
/* CPU tells it does not support to read a bit block with a */
|
||||
/* length other than 1 bit. */
|
||||
public final static int RESULT_ITEM_NOT_AVAILABLE200 = 3;
|
||||
/* means a a piece of data is not available in the CPU, e.g. */
|
||||
/* when trying to read a non existing DB or bit bloc of length<>1 */
|
||||
/* This code seems to be specific to 200 family. */
|
||||
/* CPU tells there is no peripheral at address */
|
||||
public final static int RESULT_MULTIPLE_BITS_NOT_SUPPORTED = 6;
|
||||
public final static int RESULT_NO_PERIPHERAL_AT_ADDRESS = 1;
|
||||
|
||||
public final static int RESULT_OK = 0; /* means all ok */
|
||||
public final static int RESULT_SHORT_PACKET = -1024;
|
||||
public final static int RESULT_TIMEOUT = -1025;
|
||||
public final static int RESULT_UNEXPECTED_FUNC = -128;
|
||||
public final static int RESULT_UNKNOWN_DATA_UNIT_SIZE = -129;
|
||||
|
||||
public final static int RESULT_UNKNOWN_ERROR = -125;
|
||||
/* means the data address is beyond the CPUs address range */
|
||||
public final static int RESULT_WRITE_DATA_SIZE_MISMATCH = 7;
|
||||
|
||||
public static float BEFloat(final byte[] b, final int pos) {
|
||||
int i = 0;
|
||||
// System.out.println("pos" + pos);
|
||||
|
||||
i |= Nodave.USByte(b, pos);
|
||||
i <<= 8;
|
||||
i |= Nodave.USByte(b, pos + 1);
|
||||
i <<= 8;
|
||||
i |= Nodave.USByte(b, pos + 2);
|
||||
i <<= 8;
|
||||
i |= Nodave.USByte(b, pos + 3);
|
||||
final float f = Float.intBitsToFloat(i);
|
||||
return (f);
|
||||
}
|
||||
|
||||
public static byte[] bswap_16(int a) {
|
||||
final byte[] b = new byte[2];
|
||||
b[1] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[0] = (byte) (a & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
public static byte[] bswap_32(int a) {
|
||||
final byte[] b = new byte[4];
|
||||
b[3] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[2] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[1] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[0] = (byte) (a & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
public static byte[] bswap_32(long a) {
|
||||
final byte[] b = new byte[4];
|
||||
b[3] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[2] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[1] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[0] = (byte) (a & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* This doesn't swap anything, but the name fits into the series
|
||||
*
|
||||
* @param a
|
||||
* @return
|
||||
*/
|
||||
public static byte[] bswap_8(final int a) {
|
||||
final byte[] b = new byte[1];
|
||||
b[0] = (byte) (a & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps len hex codes from byte array mem beginning at index start.
|
||||
*
|
||||
*/
|
||||
public static void dump(final String text, final byte[] mem, final int start, final int len) {
|
||||
System.out.print(text + " ");
|
||||
for (int i = start; i < (start + len); i++) {
|
||||
int j = mem[i];
|
||||
if (j < 0) {
|
||||
j += 256;
|
||||
}
|
||||
String s = Integer.toHexString(j);
|
||||
if (s.length() < 2) {
|
||||
s = "0" + s;
|
||||
}
|
||||
System.out.print(s + ",");
|
||||
}
|
||||
System.out.println(" ");
|
||||
}
|
||||
|
||||
public static long SBELong(final byte[] b, final int pos) {
|
||||
final int i = b[pos];
|
||||
int j = b[pos + 1];
|
||||
int k = b[pos + 2];
|
||||
int l = b[pos + 3];
|
||||
// if (i < 0)
|
||||
// i += 256;
|
||||
if (j < 0) {
|
||||
j += 256;
|
||||
}
|
||||
if (k < 0) {
|
||||
k += 256;
|
||||
}
|
||||
if (l < 0) {
|
||||
l += 256;
|
||||
}
|
||||
return ((256 * k) + l) + (65536L * ((256 * i) + j));
|
||||
}
|
||||
|
||||
public static int SBEWord(final byte[] b, final int pos) {
|
||||
final int i = b[pos];
|
||||
int k = b[pos + 1];
|
||||
// if (i < 0)
|
||||
// i += 256;
|
||||
if (k < 0) {
|
||||
k += 256;
|
||||
}
|
||||
return ((256 * i) + k);
|
||||
}
|
||||
|
||||
public static int SByte(final byte[] b, final int pos) {
|
||||
final int i = b[pos];
|
||||
return (i);
|
||||
}
|
||||
|
||||
public static void setBEFloat(final byte[] b, final int pos, final float f) {
|
||||
int a = Float.floatToIntBits(f);
|
||||
b[pos + 3] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos + 2] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos + 1] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos] = (byte) (a & 0xff);
|
||||
}
|
||||
|
||||
public static void setUSBELong(final byte[] b, final int pos, long a) {
|
||||
b[pos + 3] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos + 2] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos + 1] = (byte) (a & 0xff);
|
||||
a = a >> 8;
|
||||
b[pos] = (byte) (a & 0xff);
|
||||
}
|
||||
|
||||
public static void setUSBEWord(final byte[] b, final int pos, final int val) {
|
||||
b[pos] = ((byte) (val / 0x100));
|
||||
b[pos + 1] = ((byte) (val % 0x100));
|
||||
}
|
||||
|
||||
public static void setUSByte(final byte[] b, final int pos, final int val) {
|
||||
b[pos] = ((byte) (val & 0xff));
|
||||
}
|
||||
|
||||
public static String strerror(final int code) {
|
||||
switch (code) {
|
||||
case RESULT_OK:
|
||||
return "ok";
|
||||
case RESULT_MULTIPLE_BITS_NOT_SUPPORTED:
|
||||
return "the CPU does not support reading a bit block of length<>1";
|
||||
case RESULT_ITEM_NOT_AVAILABLE:
|
||||
return "the desired item is not available in the PLC";
|
||||
case RESULT_ITEM_NOT_AVAILABLE200:
|
||||
return "the desired item is not available in the PLC (200 family)";
|
||||
case RESULT_ADDRESS_OUT_OF_RANGE:
|
||||
return "the desired address is beyond limit for this PLC";
|
||||
case RESULT_CPU_RETURNED_NO_DATA:
|
||||
return "the PLC returned a packet with no result data";
|
||||
case Nodave.RESULT_UNKNOWN_ERROR:
|
||||
return "the PLC returned an error code not understood by this library";
|
||||
case Nodave.RESULT_EMPTY_RESULT_ERROR:
|
||||
return "this result contains no data";
|
||||
case Nodave.RESULT_EMPTY_RESULT_SET_ERROR:
|
||||
return "cannot work with an undefined result set";
|
||||
case Nodave.RESULT_CANNOT_EVALUATE_PDU:
|
||||
return "cannot evaluate the received PDU";
|
||||
case Nodave.RESULT_WRITE_DATA_SIZE_MISMATCH:
|
||||
return "Write data size error";
|
||||
case Nodave.RESULT_NO_PERIPHERAL_AT_ADDRESS:
|
||||
return "No data from I/O module";
|
||||
case Nodave.RESULT_UNEXPECTED_FUNC:
|
||||
return "Unexpected function code in answer";
|
||||
case Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE:
|
||||
return "PLC responds wit an unknown data type";
|
||||
case Nodave.RESULT_SHORT_PACKET:
|
||||
return "Short packet from PLC";
|
||||
case Nodave.RESULT_TIMEOUT:
|
||||
return "Timeout when waiting for PLC response";
|
||||
case 0x8000:
|
||||
return "function already occupied.";
|
||||
case 0x8001:
|
||||
return "not allowed in current operating status.";
|
||||
case 0x8101:
|
||||
return "hardware fault.";
|
||||
case 0x8103:
|
||||
return "object access not allowed.";
|
||||
case 0x8104:
|
||||
return "context is not supported.";
|
||||
case 0x8105:
|
||||
return "invalid address.";
|
||||
case 0x8106:
|
||||
return "data type not supported.";
|
||||
case 0x8107:
|
||||
return "data type not consistent.";
|
||||
case 0x810A:
|
||||
return "object does not exist.";
|
||||
case 0x8500:
|
||||
return "incorrect PDU size.";
|
||||
case 0x8702:
|
||||
return "address invalid.";
|
||||
case 0xd201:
|
||||
return "block name syntax error.";
|
||||
case 0xd202:
|
||||
return "syntax error function parameter.";
|
||||
case 0xd203:
|
||||
return "syntax error block type.";
|
||||
case 0xd204:
|
||||
return "no linked block in storage medium.";
|
||||
case 0xd205:
|
||||
return "object already exists.";
|
||||
case 0xd206:
|
||||
return "object already exists.";
|
||||
case 0xd207:
|
||||
return "block exists in EPROM.";
|
||||
case 0xd209:
|
||||
return "block does not exist.";
|
||||
case 0xd20e:
|
||||
return "no block does not exist.";
|
||||
case 0xd210:
|
||||
return "block number too big.";
|
||||
case 0xd240:
|
||||
return "unfinished block transfer in progress?";
|
||||
case 0xd241:
|
||||
return "protected by password.";
|
||||
default:
|
||||
return "no message defined for code: " + code + "!";
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toPLCfloat(final double d) {
|
||||
final float f = (float) d;
|
||||
return toPLCfloat(f);
|
||||
}
|
||||
|
||||
public static byte[] toPLCfloat(final float f) {
|
||||
final int i = Float.floatToIntBits(f);
|
||||
return bswap_32(i);
|
||||
}
|
||||
|
||||
public static long USBELong(final byte[] b, final int pos) {
|
||||
int i = b[pos];
|
||||
int j = b[pos + 1];
|
||||
int k = b[pos + 2];
|
||||
int l = b[pos + 3];
|
||||
// System.out.println(
|
||||
// pos + " 0:" + i + " 1:" + j + " 2:" + k + " 3:" + l);
|
||||
if (i < 0) {
|
||||
i += 256;
|
||||
}
|
||||
if (j < 0) {
|
||||
j += 256;
|
||||
}
|
||||
if (k < 0) {
|
||||
k += 256;
|
||||
}
|
||||
if (l < 0) {
|
||||
l += 256;
|
||||
}
|
||||
return ((256 * k) + l) + (65536L * ((256 * i) + j));
|
||||
}
|
||||
|
||||
public static int USBEWord(final byte[] b, final int pos) {
|
||||
int i = b[pos];
|
||||
int k = b[pos + 1];
|
||||
if (i < 0) {
|
||||
i += 256;
|
||||
}
|
||||
if (k < 0) {
|
||||
k += 256;
|
||||
}
|
||||
return ((256 * i) + k);
|
||||
}
|
||||
|
||||
public static int USByte(final byte[] b, final int pos) {
|
||||
int i = b[pos];
|
||||
if (i < 0) {
|
||||
i += 256;
|
||||
}
|
||||
return (i);
|
||||
}
|
||||
|
||||
private Nodave() {
|
||||
// Not needed because of utility class
|
||||
}
|
||||
|
||||
}
|
621
src/main/java/com/qgs/dc/s7/my/s7connector/impl/nodave/PDU.java
Normal file
621
src/main/java/com/qgs/dc/s7/my/s7connector/impl/nodave/PDU.java
Normal file
@ -0,0 +1,621 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
|
||||
public final class PDU {
|
||||
/**
|
||||
* known function codes
|
||||
*/
|
||||
public final static byte FUNC_READ = 4;
|
||||
|
||||
public final static byte FUNC_WRITE = 5;
|
||||
|
||||
public int data;
|
||||
|
||||
int dlen;
|
||||
int error;
|
||||
|
||||
int header; // the position of the header;
|
||||
int hlen;
|
||||
byte[] mem; //msgOut 也就是 上位机==》plc 的channel
|
||||
public int param; // the position of the parameters;
|
||||
public int plen;
|
||||
public int udata;
|
||||
public int udlen;
|
||||
|
||||
/**
|
||||
* set up the PDU information
|
||||
*
|
||||
* mem =》 msgOut、msgIn
|
||||
* pos =》 pdu在整个request请求 的起始位置(起始都是7,第7个字节)
|
||||
*/
|
||||
public PDU(final byte[] mem, final int pos) {
|
||||
this.mem = mem;
|
||||
this.header = pos;
|
||||
}
|
||||
|
||||
public int addBitVarToReadRequest(final int area, final int DBnum, final int start, final int len) {
|
||||
final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bits */
|
||||
0x00, 0x1A, /* insert length in bytes here */
|
||||
0x00, 0x0B, /* insert DB number here */
|
||||
(byte) 0x84, /* change this to real area code */
|
||||
0x00, 0x00, (byte) 0xC0 /* insert start address in bits */
|
||||
};
|
||||
Nodave.setUSBEWord(pa, 4, len);
|
||||
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||
Nodave.setUSBELong(pa, 8, start);
|
||||
Nodave.setUSByte(pa, 8, area);
|
||||
|
||||
this.mem[this.param + 1]++;
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public void addBitVarToWriteRequest(final DaveArea area, final int DBnum, final int start, final int byteCount,
|
||||
final byte[] buffer) {
|
||||
final byte da[] = { 0, 3, 0, 0, };
|
||||
final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bit */
|
||||
0, 0, /* insert length in bytes here */
|
||||
0, 0, /* insert DB number here */
|
||||
0, /* change this to real area code */
|
||||
0, 0, 0 /* insert start address in bits */
|
||||
};
|
||||
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||
|| (area == DaveArea.COUNTER200)) {
|
||||
pa[3] = (byte) area.getCode();
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||
pa[3] = 4;
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else {
|
||||
pa[4] = (byte) (byteCount / 0x100);
|
||||
pa[5] = (byte) (byteCount & 0xff);
|
||||
}
|
||||
pa[6] = (byte) (DBnum / 256);
|
||||
pa[7] = (byte) (DBnum & 0xff);
|
||||
pa[8] = (byte) area.getCode();
|
||||
pa[11] = (byte) (start & 0xff);
|
||||
pa[10] = (byte) ((start / 0x100) & 0xff);
|
||||
pa[9] = (byte) (start / 0x10000);
|
||||
|
||||
if ((this.dlen % 2) != 0) {
|
||||
this.addData(da, 1);
|
||||
}
|
||||
|
||||
this.mem[this.param + 1]++;
|
||||
if (this.dlen > 0) {
|
||||
final byte[] saveData = new byte[this.dlen];
|
||||
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||
}
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
this.data = this.param + this.plen;
|
||||
|
||||
this.addData(da);
|
||||
this.addValue(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data after parameters, set dlen as needed. Needs valid header and
|
||||
* parameters
|
||||
*/
|
||||
void addData(final byte[] newData) {
|
||||
final int appPos = this.data + this.dlen; // append to this position
|
||||
this.dlen += newData.length;
|
||||
System.arraycopy(newData, 0, this.mem, appPos, newData.length);
|
||||
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add len bytes of len after parameters from a maybe longer block of bytes.
|
||||
* Set dlen as needed. Needs valid header and parameters
|
||||
*/
|
||||
public void addData(final byte[] newData, final int len) {
|
||||
final int appPos = this.data + this.dlen; // append to this position
|
||||
this.dlen += len;
|
||||
System.arraycopy(newData, 0, this.mem, appPos, len);
|
||||
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
|
||||
}
|
||||
|
||||
public void addParam(final byte[] pa) {
|
||||
this.plen = pa.length;
|
||||
System.arraycopy(pa, 0, this.mem, this.param, this.plen);
|
||||
//设置S7-Header 里的Parameter Length
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
// mem[header + 6] = (byte) (pa.length / 256);
|
||||
// mem[header + 7] = (byte) (pa.length % 256);
|
||||
//this.data = 17+2 = 19 ( data 其实就是item项 )
|
||||
this.data = this.param + this.plen;
|
||||
this.dlen = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add data in user data. Add a user data header, if not yet present.
|
||||
*/
|
||||
public void addUserData(final byte[] da) {
|
||||
final byte udh[] = { (byte) 0xff, 9, 0, 0 };
|
||||
if (this.dlen == 0) {
|
||||
this.addData(udh);
|
||||
}
|
||||
this.addValue(da);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values after value header in data, adjust dlen and data count. Needs
|
||||
* valid header,parameters,data,dlen
|
||||
*/
|
||||
void addValue(final byte[] values) {
|
||||
int valCount = (0x100 * this.mem[this.data + 2]) + this.mem[this.data + 3];
|
||||
|
||||
if (this.mem[this.data + 1] == 4) { // bit data, length is in bits
|
||||
valCount += 8 * values.length;
|
||||
} else if (this.mem[this.data + 1] == 9) { // byte data, length is in
|
||||
// bytes
|
||||
valCount += values.length;
|
||||
} else if(this.mem[this.data+1] == 3){
|
||||
// for bool
|
||||
valCount += values.length;
|
||||
|
||||
|
||||
}else {
|
||||
// for other
|
||||
}
|
||||
if (this.udata == 0) {
|
||||
this.udata = this.data + 4;
|
||||
}
|
||||
|
||||
|
||||
this.udlen += values.length;
|
||||
Nodave.setUSBEWord(this.mem, this.data + 2, valCount);
|
||||
this.addData(values);
|
||||
}
|
||||
|
||||
public int addVarToReadRequest(final DaveArea area, final int DBnum, int start, final int len) {
|
||||
final byte[] pa = {
|
||||
0x12, //结构表示,一般默认 0x12
|
||||
0x0a, //此字节往后的字节数
|
||||
0x10, //Syntax id:S7ANY (0X10) (决定寻址方式,0x10表示any-type)
|
||||
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||
0x00, 0x1A, /* length of data in bytes ( 2 bytes ),就是读几个长度 如有些变量是数组 ,这里就是数组长度,如果是非数组变量那么这里都是1 */
|
||||
0x00, 0x0B, /* DB块编号 */
|
||||
(byte) 0x84, // * area code ,也就是 DaveArea.DB数据区 */
|
||||
0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address,3-18bit 是Byte Address */
|
||||
};
|
||||
|
||||
if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||
pa[3] = 4;
|
||||
start *= 8; /* bits */
|
||||
} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||
|| (area == DaveArea.COUNTER200)) {
|
||||
pa[3] = (byte) area.getCode();
|
||||
} else {
|
||||
start *= 8; /* 乘以8 相当于把这个偏移量向左移动了 3位 */
|
||||
}
|
||||
//把len =》 2个字节 并且填充到 pa数组 对应位置(pa[4]、pa[5])。
|
||||
Nodave.setUSBEWord(pa, 4, len);
|
||||
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||
//start 是这个db块的偏移量。。。。 //todo 其实这里简单处理了 ,是分Byte address 和 Bit address的
|
||||
Nodave.setUSBELong(pa, 8, start);
|
||||
Nodave.setUSByte(pa, 8, area.getCode());
|
||||
|
||||
//因为add了 Var 所以要 ,item count ++ ;;this.param + 1 位置就是Item count位置
|
||||
this.mem[this.param + 1]++;
|
||||
|
||||
//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
//要读的 var item 也算 参数的 所以也算在param length里面。
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
/**
|
||||
* TODO calc length of result. Do not add variable if it would exceed
|
||||
* max. result length.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
public int addVarToReadRequest(final DaveArea area, final int DBnum, int byteAddress,int bitAddress, final int len,final TransportSize transportSize) {
|
||||
final byte[] pa = {
|
||||
0x12, //结构表示,一般默认 0x12
|
||||
0x0a, //此字节往后的字节数
|
||||
0x10, //Syntax id:S7ANY (0X10) (决定寻址方式,0x10表示any-type)(把这个认为是固定就行了)
|
||||
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||
0x00, 0x1A, /* length of data in bytes ( 2 bytes ),就是读几个长度 如有些变量是数组 ,这里就是数组长度,如果是非数组变量那么这里都是1 */
|
||||
0x00, 0x0B, /* DB块编号 */
|
||||
(byte) 0x84, // * area code ,也就是 DaveArea.DB数据区 */
|
||||
0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address,3-18bit 是Byte Address */
|
||||
};
|
||||
|
||||
if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||
pa[3] = 4;
|
||||
byteAddress *= 8; /* bits */
|
||||
} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||
|| (area == DaveArea.COUNTER200)) {
|
||||
pa[3] = (byte) area.getCode();
|
||||
} else {
|
||||
///* 乘以8 相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
|
||||
byteAddress *= 8;
|
||||
//把 bitAddress 赋予后三位
|
||||
byteAddress += bitAddress;
|
||||
}
|
||||
pa[3] = Byte.valueOf(Short.toString(transportSize.getCode()));
|
||||
|
||||
//把len =》 2个字节 并且填充到 pa数组 对应位置(pa[4]、pa[5])。
|
||||
Nodave.setUSBEWord(pa, 4, len);
|
||||
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||
//start 是这个db块的偏移量。。。。 //todo 其实这里简单处理了 ,是分Byte address 和 Bit address的
|
||||
Nodave.setUSBELong(pa, 8, byteAddress);
|
||||
Nodave.setUSByte(pa, 8, area.getCode());
|
||||
|
||||
//因为add了 Var 所以要 ,item count ++ ;;this.param + 1 位置就是Item count位置
|
||||
this.mem[this.param + 1]++;
|
||||
|
||||
//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
//要读的 var item 也算 参数的 所以也算在param length里面。
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
/**
|
||||
* TODO calc length of result. Do not add variable if it would exceed
|
||||
* max. result length.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public void addVarToWriteRequest(final DaveArea area, final int DBnum, int byteOffset, int bitOffset, final int byteCount,
|
||||
final byte[] buffer, PlcVar var) {
|
||||
final byte da[] = { 0, 4, 0, 0, };
|
||||
final byte pa[] = {
|
||||
0x12,
|
||||
0x0a,
|
||||
0x10,
|
||||
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||
/* unit (for count?, for consistency?) byte */
|
||||
0, 0, /* length in bytes */
|
||||
0, 0, /* DB number */
|
||||
0, /* area code */
|
||||
0, 0, 0 /* start address in bits */
|
||||
};
|
||||
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||
|| (area == DaveArea.COUNTER200)) {
|
||||
pa[3] = (byte) area.getCode();
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||
pa[3] = 4;
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else {
|
||||
pa[4] = (byte) (byteCount / 0x100);
|
||||
pa[5] = (byte) (byteCount & 0xff);
|
||||
}
|
||||
pa[6] = (byte) (DBnum / 256);
|
||||
pa[7] = (byte) (DBnum & 0xff);
|
||||
pa[8] = (byte) (area.getCode());
|
||||
|
||||
//设置parameter item 的 transportsize
|
||||
pa[3] = (byte) var.getTransportSize().getCode();
|
||||
|
||||
///* 乘以8 相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
|
||||
byteOffset *= 8;
|
||||
//把 bitAddress 赋予后三位
|
||||
byteOffset += bitOffset;
|
||||
pa[11] = (byte) (byteOffset & 0xff);
|
||||
pa[10] = (byte) ((byteOffset / 0x100) & 0xff);
|
||||
pa[9] = (byte) (byteOffset / 0x10000);
|
||||
if ((this.dlen % 2) != 0) {
|
||||
this.addData(da, 1);
|
||||
}
|
||||
this.mem[this.param + 1]++;
|
||||
if (this.dlen > 0) {
|
||||
final byte[] saveData = new byte[this.dlen];
|
||||
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||
}
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
this.data = this.param + this.plen;
|
||||
this.addData(da);
|
||||
//给 keyItem 的transportsize 赋值
|
||||
this.mem[this.data + 1] = (byte) var.getTransportSize().getDataTransportSize().getValue();
|
||||
this.addValue(buffer);
|
||||
}
|
||||
|
||||
public void addVarToWriteRequest(final DaveArea area, final int DBnum, int start, final int byteCount,
|
||||
final byte[] buffer) {
|
||||
final byte da[] = { 0, 4, 0, 0, };
|
||||
final byte pa[] = { 0x12, 0x0a, 0x10, 0x02,
|
||||
/* unit (for count?, for consistency?) byte */
|
||||
0, 0, /* length in bytes */
|
||||
0, 0, /* DB number */
|
||||
0, /* area code */
|
||||
0, 0, 0 /* start address in bits */
|
||||
};
|
||||
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||
|| (area == DaveArea.COUNTER200)) {
|
||||
pa[3] = (byte) area.getCode();
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||
pa[3] = 4;
|
||||
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||
} else {
|
||||
pa[4] = (byte) (byteCount / 0x100);
|
||||
pa[5] = (byte) (byteCount & 0xff);
|
||||
}
|
||||
pa[6] = (byte) (DBnum / 256);
|
||||
pa[7] = (byte) (DBnum & 0xff);
|
||||
pa[8] = (byte) (area.getCode());
|
||||
start *= 8; /* number of bits */
|
||||
pa[11] = (byte) (start & 0xff);
|
||||
pa[10] = (byte) ((start / 0x100) & 0xff);
|
||||
pa[9] = (byte) (start / 0x10000);
|
||||
if ((this.dlen % 2) != 0) {
|
||||
this.addData(da, 1);
|
||||
}
|
||||
this.mem[this.param + 1]++;
|
||||
if (this.dlen > 0) {
|
||||
final byte[] saveData = new byte[this.dlen];
|
||||
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||
}
|
||||
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||
this.plen += pa.length;
|
||||
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||
this.data = this.param + this.plen;
|
||||
|
||||
//下面两个方法,是拼接 keyItem、valueItem
|
||||
this.addData(da);
|
||||
|
||||
this.addValue(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct a write request for a single item in PLC memory.
|
||||
*/
|
||||
/*
|
||||
* void constructWriteRequest( int area, int DBnum, int start, int len,
|
||||
* byte[] buffer) { byte pa[] = new byte[14]; byte da[] = { 0, 4, 0, 0 };
|
||||
* pa[0] = PDU.FUNC_WRITE; pa[1] = (byte) 0x01; pa[2] = (byte) 0x12; pa[3] =
|
||||
* (byte) 0x0a; pa[4] = (byte) 0x10; pa[5] = (byte) 0x02;
|
||||
*
|
||||
* Nodave.setUSBEWord(pa, 6, len); Nodave.setUSBEWord(pa, 8, DBnum);
|
||||
* Nodave.setUSBELong(pa, 10, 8 * start); // the bit address
|
||||
* Nodave.setUSByte(pa, 10, area); initHeader(1); addParam(pa); addData(da);
|
||||
* addValue(buffer); if ((Nodave.Debug & Nodave.DEBUG_PDU) != 0) { dump(); }
|
||||
* }
|
||||
*/
|
||||
/**
|
||||
* display information about a PDU
|
||||
*/
|
||||
public void dump() {
|
||||
Nodave.dump("PDU header ", this.mem, this.header, this.hlen);
|
||||
System.out.println("plen: " + this.plen + " dlen: " + this.dlen);
|
||||
Nodave.dump("Parameter", this.mem, this.param, this.plen);
|
||||
if (this.dlen > 0) {
|
||||
Nodave.dump("Data ", this.mem, this.data, this.dlen);
|
||||
}
|
||||
if (this.udlen > 0) {
|
||||
Nodave.dump("result Data ", this.mem, this.udata, this.udlen);
|
||||
}
|
||||
}
|
||||
|
||||
public int getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the function code of the PDU
|
||||
*/
|
||||
public int getFunc() {
|
||||
return Nodave.USByte(this.mem, this.param + 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef struct { uc P; // allways 0x32 uc type; // a type? type 2 and 3
|
||||
* headers are two bytes longer. uc a,b; // currently unknown us number; //
|
||||
* Number, can be used to identify answers corresponding to requests us
|
||||
* plen; // length of parameters which follow this header us dlen; // length
|
||||
* of data which follows the parameters uc x[2]; // only present in type 2
|
||||
* and 3 headers. This may contain error information. } PDUHeader;
|
||||
*/
|
||||
/**
|
||||
* return the number of the PDU
|
||||
*/
|
||||
public int getNumber() {
|
||||
return Nodave.USBEWord(this.mem, this.header + 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* reserve space for the header of a new PDU
|
||||
*/
|
||||
public void initHeader(final int type) {
|
||||
//注意 这里的type 就是下面的 MSG Type(消息类型)
|
||||
if ((type == 2) || (type == 3)) {
|
||||
this.hlen = 12;
|
||||
} else {
|
||||
this.hlen = 10;
|
||||
}
|
||||
|
||||
//给S7-Header 初始化 全部初始化为0
|
||||
for (int i = 0; i < this.hlen; i++) {
|
||||
//mem 代表msgOut
|
||||
this.mem[this.header + i] = 0;
|
||||
}
|
||||
|
||||
//this.param 是 param的起始位置,是在 initHeader 被初始化的,(7+10) = 17= this.param (因为数组从0开始,所以17这个位置刚好是param的起始位置)
|
||||
this.param = this.header + this.hlen;
|
||||
//protocol id 协议id ,默认0x32
|
||||
this.mem[this.header] = (byte) 0x32;
|
||||
//MSG Type(1byte): 消息类型 :
|
||||
//0x01:工作请求(Job Request);
|
||||
//0x02:确认(Ack),主要是由设备请求,不携带数据;
|
||||
//0x03:响应数据(Ack-Data),响应0x01的请求;
|
||||
//0x07:自定义数据(Userdata),扩展协议类型
|
||||
this.mem[this.header + 1] = (byte) type;
|
||||
//dlen = data length ( 报文中存在两个字节 )
|
||||
this.dlen = 0;
|
||||
//plen = param length ( 报文中存在两个字节 )
|
||||
this.plen = 0;
|
||||
//udlen = protocol data unit reference length
|
||||
this.udlen = 0;
|
||||
this.data = 0;
|
||||
//udata = protocol data unit reference
|
||||
this.udata = 0;
|
||||
}
|
||||
|
||||
public void initReadRequest() {
|
||||
final byte pa[] = new byte[2];
|
||||
pa[0] = PDU.FUNC_READ;
|
||||
pa[1] = (byte) 0x00;
|
||||
this.initHeader(1);
|
||||
this.addParam(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare a read request with no item.
|
||||
*/
|
||||
public void prepareReadRequest() {
|
||||
final byte pa[] = new byte[2];
|
||||
pa[0] = PDU.FUNC_READ;
|
||||
pa[1] = (byte) 0x00;
|
||||
this.initHeader(1);
|
||||
this.addParam(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare a write request with no item.
|
||||
*/
|
||||
public void prepareWriteRequest() {
|
||||
final byte pa[] = new byte[2];
|
||||
pa[0] = PDU.FUNC_WRITE;
|
||||
pa[1] = (byte) 0x00;
|
||||
this.initHeader(1);
|
||||
this.addParam(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the number of the PDU
|
||||
*/
|
||||
public void setNumber(final int n) {
|
||||
Nodave.setUSBEWord(this.mem, this.header + 4, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a PDU instance to reflect the structure of data present in the
|
||||
* memory area given to initHeader. Needs valid header.
|
||||
*/
|
||||
|
||||
public int setupReceivedPDU() {
|
||||
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
|
||||
//this.mem[this.header + 1]( ROSCTR ) 就是MSG TYPE =2 (确认(Ack),主要是由设备请求,不携带数据) ;;MSG TYPE =3 (响应数据(Ack-Data),响应0x01的请求)
|
||||
if ((this.mem[this.header + 1] == 2) || (this.mem[this.header + 1] == 3)) {
|
||||
this.hlen = 12;
|
||||
//this.header + 10 就是 Error class(看附录3)/code(看附录4)
|
||||
//todo this.header + 10 其实是一个字节一个字节的 不能像下面这样读两个字节。(其实这种也行的,因为这样就能够 同时判断两个信息 是否同时为0,如果同时为0 有一个不为0 就代表都不ok)
|
||||
res = Nodave.USBEWord(this.mem, this.header + 10);
|
||||
} else {
|
||||
this.error = 0;
|
||||
this.hlen = 10;
|
||||
res = 0;
|
||||
}
|
||||
//外部初始化的 header == 7(4字节TPKT + 3个字节COTP)
|
||||
//this.param = 7+12 = 19;
|
||||
this.param = this.header + this.hlen;
|
||||
//读取S7-Header 里面的Param-length(2个字节转为word ok)
|
||||
this.plen = Nodave.USBEWord(this.mem, this.header + 6);
|
||||
//this.param(19 固定的如果是ACK) + this.plen(2 是固定的应为就两个参数)
|
||||
this.data = this.param + this.plen;
|
||||
|
||||
//读取S7-Header 里面的Data-length(2个字节转为word ok)
|
||||
this.dlen = Nodave.USBEWord(this.mem, this.header + 8);
|
||||
this.udlen = 0;
|
||||
this.udata = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int testResultData() {
|
||||
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
|
||||
//当响应成功的情况 //todo here read
|
||||
if ((this.mem[this.data] == (byte) 255) && (this.dlen > 4)) {
|
||||
res = Nodave.RESULT_OK;
|
||||
//udata 代表的是read response 里面 Data=>Item=>n个字节的实际数据bytes
|
||||
this.udata = this.data + 4;
|
||||
// udlen=data[2]*0x100+data[3];
|
||||
//udlen = udata length 就是实际承载value 的byte[] 长度
|
||||
this.udlen = Nodave.USBEWord(this.mem, this.data + 2);
|
||||
|
||||
// ==4 是走byte流,通过转义字节来 来解码真是value。。 看附录8
|
||||
if (this.mem[this.data + 1] == 4) {
|
||||
//注意 这里的数据响应长度 单位 是bit 不是 byte,因为 用bit 表示才准确,比如像bit类型 他并不需要一个字节
|
||||
//往右移3位,就相当于 除以8 ,把 bit 转成 byte //todo 这个需要和read request关联的,后续如果要开发点位的功能 再说。
|
||||
this.udlen >>= 3; /* len is in bits, adjust */
|
||||
} else if (this.mem[this.data + 1] == 9) {
|
||||
/* len is already in bytes, ok */
|
||||
} else if (this.mem[this.data + 1] == 3) {
|
||||
/* len is in bits, but there is a byte per result bit, ok */
|
||||
} else {
|
||||
res = Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE;
|
||||
}
|
||||
} else {
|
||||
//当响应不成功的情况
|
||||
//this.mem[this.data] 是return code (成功或者失败)
|
||||
res = this.mem[this.data];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public int testPGReadResult() {
|
||||
if (this.mem[this.param] != 0) {
|
||||
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||
}
|
||||
return this.testResultData();
|
||||
};
|
||||
|
||||
int testReadResult() {
|
||||
if (this.mem[this.param] != FUNC_READ) {
|
||||
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||
}
|
||||
return this.testResultData();
|
||||
}
|
||||
|
||||
int testWriteResult() {
|
||||
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU;
|
||||
if (this.mem[this.param] != FUNC_WRITE) {
|
||||
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||
}
|
||||
if ((this.mem[this.data] == 255)) {
|
||||
res = Nodave.RESULT_OK;
|
||||
} else {
|
||||
res = this.mem[this.data];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public final class PLCinterface {
|
||||
InputStream in;
|
||||
int localMPI; // the adapter's MPI address
|
||||
String name;
|
||||
|
||||
OutputStream out;
|
||||
int protocol; // The kind of transport used on this interface.
|
||||
int wp, rp;
|
||||
|
||||
public PLCinterface(final OutputStream out, final InputStream in, final String name, final int localMPI,
|
||||
final int protocol) {
|
||||
this.init(out, in, name, localMPI, protocol);
|
||||
}
|
||||
|
||||
public void init(final OutputStream oStream, final InputStream iStream, final String name, final int localMPI,
|
||||
final int protocol) {
|
||||
this.out = oStream;
|
||||
this.in = iStream;
|
||||
this.name = name;
|
||||
this.localMPI = localMPI;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public int read(final byte[] b, int start, int len) {
|
||||
int res;
|
||||
try {
|
||||
int retry = 0;
|
||||
while ((this.in.available() <= 0) && (retry < 500)) {
|
||||
try {
|
||||
if (retry > 0) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
retry++;
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
res = 0;
|
||||
while ((this.in.available() > 0) && (len > 0)) {
|
||||
res = this.in.read(b, start, len);
|
||||
start += res;
|
||||
len -= res;
|
||||
}
|
||||
return res;
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int write(final byte[] b, final int start, final int len) {
|
||||
try {
|
||||
this.out.write(b, start, len);
|
||||
return 1;
|
||||
} catch (final IOException e) {
|
||||
System.err.println("Interface.write: " + e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
/**
|
||||
* @author Thomas Hergenhahn
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||
*/
|
||||
public final class Result {
|
||||
public int bufferStart;
|
||||
public int error;
|
||||
public int length;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
/**
|
||||
* @author Thomas Hergenhahn
|
||||
*
|
||||
*/
|
||||
public final class ResultSet {
|
||||
private int errorState, numResults;
|
||||
public Result[] results;
|
||||
|
||||
public int getErrorState() {
|
||||
return this.errorState;
|
||||
}
|
||||
|
||||
public int getNumResults() {
|
||||
return this.numResults;
|
||||
};
|
||||
|
||||
public void setErrorState(final int error) {
|
||||
this.errorState = error;
|
||||
}
|
||||
|
||||
public void setNumResults(final int nr) {
|
||||
this.numResults = nr;
|
||||
};
|
||||
}
|
@ -0,0 +1,498 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
/**
|
||||
* This class comprises the variables and methods common to connections to an S7
|
||||
* PLC regardless of the type of transport.
|
||||
*
|
||||
* @author Thomas Hergenhahn
|
||||
*/
|
||||
public abstract class S7Connection {
|
||||
static int tmo_normal = 150;
|
||||
int answLen; // length of last message
|
||||
/**
|
||||
* position in result data, incremented when variables are extracted without
|
||||
* position
|
||||
*/
|
||||
int dataPointer;
|
||||
PLCinterface iface; // pointer to used interface
|
||||
public int maxPDUlength; //第二次握手里 的 PDU Length(2个字节)
|
||||
public byte messageNumber = 0;
|
||||
|
||||
//msgIn 和 msgOut 同理
|
||||
public byte[] msgIn;
|
||||
//msgOut 确实是当前TcpConnection共用的,但不影响每次write,因为每次发送都会修改msgOut
|
||||
public byte[] msgOut;
|
||||
|
||||
public int packetNumber = 0; // packetNumber in transport layer
|
||||
public int PDUstartIn;
|
||||
public int PDUstartOut;
|
||||
PDU rcvdPDU;
|
||||
public Semaphore semaphore;
|
||||
|
||||
/**
|
||||
* absolute begin of result data
|
||||
*/
|
||||
int udata;
|
||||
|
||||
public S7Connection(final PLCinterface ifa) {
|
||||
this.iface = ifa;
|
||||
this.msgIn = new byte[Nodave.MAX_RAW_LEN];
|
||||
this.msgOut = new byte[Nodave.MAX_RAW_LEN];
|
||||
this.PDUstartIn = 0;
|
||||
this.PDUstartOut = 0;
|
||||
this.semaphore = new Semaphore(1);
|
||||
}
|
||||
|
||||
abstract public int exchange(PDU p1);
|
||||
|
||||
// int numResults;
|
||||
/*
|
||||
* class Result { int error; byte[] data; }
|
||||
*/
|
||||
/*
|
||||
* Read a predefined set of values from the PLC. Return ok or an error state
|
||||
* If a buffer pointer is provided, data will be copied into this buffer. If
|
||||
* it's NULL you can get your data from the resultPointer in daveConnection
|
||||
* long as you do not send further requests.
|
||||
*/
|
||||
public ResultSet execReadRequest(final PDU p) {
|
||||
PDU p2;
|
||||
int errorState;
|
||||
errorState = this.exchange(p);
|
||||
|
||||
p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
p2.setupReceivedPDU();
|
||||
/*
|
||||
* if (p2.udlen == 0) { dataPointer = 0; answLen = 0; return
|
||||
* Nodave.RESULT_CPU_RETURNED_NO_DATA; }
|
||||
*/
|
||||
final ResultSet rs = new ResultSet();
|
||||
if (p2.mem[p2.param + 0] == PDU.FUNC_READ) {
|
||||
int numResults = p2.mem[p2.param + 1];
|
||||
// System.out.println("Results " + numResults);
|
||||
rs.results = new Result[numResults];
|
||||
int pos = p2.data;
|
||||
for (int i = 0; i < numResults; i++) {
|
||||
final Result r = new Result();
|
||||
r.error = Nodave.USByte(p2.mem, pos);
|
||||
if (r.error == 255) {
|
||||
|
||||
final int type = Nodave.USByte(p2.mem, pos + 1);
|
||||
int len = Nodave.USBEWord(p2.mem, pos + 2);
|
||||
r.error = 0;
|
||||
// System.out.println("Raw length " + len);
|
||||
if (type == 4) {
|
||||
len /= 8;
|
||||
} else if (type == 3) {
|
||||
; // length is ok
|
||||
}
|
||||
|
||||
// System.out.println("Byte length " + len);
|
||||
// r.data = new byte[len];
|
||||
|
||||
// System.arraycopy(p2.mem, pos + 4, r.data, 0, len);
|
||||
// Nodave.dump("Result " + i + ":", r.data, 0, len);
|
||||
r.bufferStart = pos + 4;
|
||||
pos += len;
|
||||
if ((len % 2) == 1) {
|
||||
pos++;
|
||||
}
|
||||
} else {
|
||||
System.out.println("Error " + r.error);
|
||||
}
|
||||
pos += 4;
|
||||
rs.results[i] = r;
|
||||
}
|
||||
numResults = p2.mem[p2.param + 1];
|
||||
rs.setNumResults(numResults);
|
||||
this.dataPointer = p2.udata;
|
||||
this.answLen = p2.udlen;
|
||||
// }
|
||||
} else {
|
||||
errorState |= 2048;
|
||||
}
|
||||
this.semaphore.release();
|
||||
rs.setErrorState(errorState);
|
||||
return rs;
|
||||
}
|
||||
|
||||
public int getBYTE() {
|
||||
this.dataPointer += 1;
|
||||
return Nodave.SByte(this.msgIn, this.dataPointer - 1);
|
||||
}
|
||||
|
||||
public int getBYTE(final int pos) {
|
||||
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public int getCHAR() {
|
||||
this.dataPointer += 1;
|
||||
return Nodave.SByte(this.msgIn, this.dataPointer - 1);
|
||||
}
|
||||
|
||||
public int getCHAR(final int pos) {
|
||||
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an signed 32bit value from the current position in result bytes
|
||||
*/
|
||||
public long getDINT() {
|
||||
this.dataPointer += 4;
|
||||
return Nodave.SBELong(this.msgIn, this.dataPointer - 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an signed 32bit value from the specified position in result bytes
|
||||
*/
|
||||
public long getDINT(final int pos) {
|
||||
return Nodave.SBELong(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an unsigned 32bit value from the specified position in result bytes
|
||||
*/
|
||||
public long getDWORD(final int pos) {
|
||||
// System.out.println("getDWORD pos " + pos);
|
||||
return Nodave.USBELong(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a float value from the current position in result bytes
|
||||
*/
|
||||
public float getFloat() {
|
||||
this.dataPointer += 4;
|
||||
return Nodave.BEFloat(this.msgIn, this.dataPointer - 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods are here to give Siemens users their usual data
|
||||
* types:
|
||||
*/
|
||||
/**
|
||||
* get a float value from the specified position in result bytes
|
||||
*/
|
||||
public float getFloat(final int pos) {
|
||||
// System.out.println("getFloat pos " + pos);
|
||||
return Nodave.BEFloat(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public int getINT() {
|
||||
this.dataPointer += 2;
|
||||
return Nodave.SBEWord(this.msgIn, this.dataPointer - 2);
|
||||
}
|
||||
|
||||
public int getINT(final int pos) {
|
||||
return Nodave.SBEWord(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public int getPPIresponse() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* public void sendYOURTURN() { }
|
||||
*/
|
||||
public int getResponse() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getS16(final int pos) {
|
||||
return Nodave.SBEWord(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public long getS32(final int pos) {
|
||||
return Nodave.SBELong(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public int getS8(final int pos) {
|
||||
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an unsigned 32bit value from the current position in result bytes
|
||||
*/
|
||||
public long getU32() {
|
||||
this.dataPointer += 4;
|
||||
return Nodave.USBELong(this.msgIn, this.dataPointer - 4);
|
||||
}
|
||||
|
||||
public int getUS16(final int pos) {
|
||||
return Nodave.USBEWord(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public long getUS32(final int pos) {
|
||||
return Nodave.USBELong(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
public int getUS8(final int pos) {
|
||||
return Nodave.USByte(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an unsigned 16bit value from the current position in result bytes
|
||||
*/
|
||||
public int getWORD() {
|
||||
this.dataPointer += 2;
|
||||
return Nodave.USBEWord(this.msgIn, this.dataPointer - 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* get an unsigned 16bit value from the specified position in result bytes
|
||||
*/
|
||||
public int getWORD(final int pos) {
|
||||
return Nodave.USBEWord(this.msgIn, this.udata + pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* build the PDU for a PDU length negotiation
|
||||
* 构建第二次握手
|
||||
*/
|
||||
public int negPDUlengthRequest() {
|
||||
int res;
|
||||
final PDU p = new PDU(this.msgOut, this.PDUstartOut);
|
||||
//S7-Param 构造
|
||||
final byte pa[] = {
|
||||
(byte) 0xF0, //Function:step Communication
|
||||
0, //Reserved
|
||||
0x00, //Max AmQ (parallel jobs with ack) calling,也就是说这个connection每次只能调用1次 ;;2个字节
|
||||
0x01,
|
||||
0x00, //Max AmQ (parallel jobs with ack) called,也就是说这个connection每次只能被调用1次 ;; 2个字节
|
||||
0x01,
|
||||
0x03, //PDU Length (2个字节) //这里是960 ,,一般是240/480/960 主要是和CPU型号有关的。
|
||||
(byte) 0xC0,
|
||||
};
|
||||
//初始化 S7 Header长度
|
||||
p.initHeader(1);
|
||||
//加载 param 参数到 请求里面去
|
||||
p.addParam(pa);
|
||||
//构建第二次握手cotp 部分
|
||||
res = this.exchange(p);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
//构建第二次握手 S7COMM 的接收容器。
|
||||
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
res = p2.setupReceivedPDU();
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
this.maxPDUlength = Nodave.USBEWord(this.msgIn, p2.param +6);
|
||||
return res;
|
||||
}
|
||||
|
||||
//reutrn
|
||||
// 0 代表成功
|
||||
// 1 代表失败
|
||||
// 异常 就会抛出异常
|
||||
public int readBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
|
||||
int res = 0;
|
||||
try {
|
||||
//信号量 ,加锁,,防止多处并发访问
|
||||
this.semaphore.acquire();
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//构建 request PDU
|
||||
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||
p1.initReadRequest();
|
||||
p1.addVarToReadRequest(area, DBnum, start, len);
|
||||
//发送read var request
|
||||
res = this.exchange(p1);
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
//构建 response PDU ,, 注意这里的msgIn 就是接收到的 plc=》上位机 的字节流
|
||||
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
// 这里配置received PUD参数。
|
||||
res = p2.setupReceivedPDU();
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
res = p2.testReadResult();
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
if (p2.udlen == 0) {
|
||||
this.semaphore.release();
|
||||
return Nodave.RESULT_CPU_RETURNED_NO_DATA;
|
||||
}
|
||||
/*
|
||||
* copy to user buffer and setup internal buffer pointers:
|
||||
* 判断外部确实 外部是否真实传 buffer 这个字节容器进来。
|
||||
*/
|
||||
if (buffer != null) {
|
||||
System.arraycopy(p2.mem, p2.udata, buffer, 0, p2.udlen);
|
||||
}
|
||||
|
||||
this.dataPointer = p2.udata;
|
||||
this.udata = p2.udata;
|
||||
this.answLen = p2.udlen;
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
//reutrn
|
||||
// 0 代表成功
|
||||
// 1 代表失败
|
||||
// 异常 就会抛出异常
|
||||
//start == byteAddress ;; bitStart ==
|
||||
public int readBytes(final DaveArea area, final int DBnum, final int byteAddress, final int bitAddress, final int len, final byte[] buffer, TransportSize transportSize) {
|
||||
int res = 0;
|
||||
try {
|
||||
//信号量 ,加锁,,防止多处并发访问
|
||||
this.semaphore.acquire();
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//构建 request PDU
|
||||
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||
p1.initReadRequest();
|
||||
p1.addVarToReadRequest(area, DBnum, byteAddress,bitAddress, len,transportSize);
|
||||
//发送read var request
|
||||
res = this.exchange(p1);
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
//构建 response PDU ,, 注意这里的msgIn 就是接收到的 plc=》上位机 的字节流
|
||||
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
// 这里配置received PUD参数。
|
||||
res = p2.setupReceivedPDU();
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
res = p2.testReadResult();
|
||||
if (res != Nodave.RESULT_OK) {
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
if (p2.udlen == 0) {
|
||||
this.semaphore.release();
|
||||
return Nodave.RESULT_CPU_RETURNED_NO_DATA;
|
||||
}
|
||||
/*
|
||||
* copy to user buffer and setup internal buffer pointers:
|
||||
* 判断外部确实 外部是否真实传 buffer 这个字节容器进来。
|
||||
*/
|
||||
if (buffer != null) {
|
||||
System.arraycopy(p2.mem, p2.udata, buffer, 0, p2.udlen);
|
||||
}
|
||||
|
||||
this.dataPointer = p2.udata;
|
||||
this.udata = p2.udata;
|
||||
this.answLen = p2.udlen;
|
||||
this.semaphore.release();
|
||||
return res;
|
||||
}
|
||||
|
||||
public int sendMsg(final PDU p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void sendRequestData(final int alt) {
|
||||
}
|
||||
|
||||
public int useResult(final ResultSet rs, final int number) {
|
||||
System.out.println("rs.getNumResults: " + rs.getNumResults() + " number: " + number);
|
||||
if (rs.getNumResults() > number) {
|
||||
this.dataPointer = rs.results[number].bufferStart;
|
||||
return 0;
|
||||
// udata=rs.results[number].bufferStart;
|
||||
}
|
||||
return -33;
|
||||
};
|
||||
|
||||
/*
|
||||
* Write len bytes to PLC memory area "area", data block DBnum.
|
||||
*/
|
||||
public int writeBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
|
||||
int errorState = 0;
|
||||
this.semaphore.release();
|
||||
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||
|
||||
// p1.constructWriteRequest(area, DBnum, start, len, buffer);
|
||||
p1.prepareWriteRequest();
|
||||
p1.addVarToWriteRequest(area, DBnum, start, len, buffer);
|
||||
|
||||
errorState = this.exchange(p1);
|
||||
|
||||
if (errorState == 0) {
|
||||
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
p2.setupReceivedPDU();
|
||||
|
||||
if (p2.mem[p2.param + 0] == PDU.FUNC_WRITE) {
|
||||
if (p2.mem[p2.data + 0] == (byte) 0xFF) {
|
||||
this.semaphore.release();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
errorState |= 4096;
|
||||
}
|
||||
}
|
||||
this.semaphore.release();
|
||||
return errorState;
|
||||
}
|
||||
|
||||
|
||||
public int writeBytes(final DaveArea area, final int DBnum, final int byteOffset, final int bitOffset, final int len, final byte[] buffer,final PlcVar var) {
|
||||
int errorState = 0;
|
||||
this.semaphore.release();
|
||||
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||
|
||||
// p1.constructWriteRequest(area, DBnum, start, len, buffer);
|
||||
p1.prepareWriteRequest();
|
||||
p1.addVarToWriteRequest(area, DBnum, byteOffset,bitOffset, len, buffer,var);
|
||||
|
||||
errorState = this.exchange(p1);
|
||||
|
||||
if (errorState == 0) {
|
||||
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||
p2.setupReceivedPDU();
|
||||
|
||||
if (p2.mem[p2.param + 0] == PDU.FUNC_WRITE) {
|
||||
if (p2.mem[p2.data + 0] == (byte) 0xFF) {
|
||||
this.semaphore.release();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
errorState |= 4096;
|
||||
}
|
||||
}
|
||||
this.semaphore.release();
|
||||
return errorState;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.enmuc.S7Client;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class TCPConnection.
|
||||
*/
|
||||
public final class TCPConnection extends S7Connection {
|
||||
|
||||
/** The rack. */
|
||||
int rack;
|
||||
|
||||
/** The slot. */
|
||||
int slot;
|
||||
private static final Logger logger = LoggerFactory.getLogger(TCPConnection.class);
|
||||
/**
|
||||
* Instantiates a new TCP connection.
|
||||
*
|
||||
* @param ifa
|
||||
* the plc interface
|
||||
* @param rack
|
||||
* the rack
|
||||
* @param slot
|
||||
* the slot
|
||||
*/
|
||||
public TCPConnection(final PLCinterface ifa, final int rack, final int slot) {
|
||||
super(ifa);
|
||||
this.rack = rack;
|
||||
this.slot = slot;
|
||||
this.PDUstartIn = 7;
|
||||
//PDUstartOut = 7 是因为在Header部分之前 还有TPKT+COTP报文,并且这两个报文长度加起来一共7个字节。
|
||||
this.PDUstartOut = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* We have our own connectPLC(), but no disconnect() Open connection to a
|
||||
* PLC. This assumes that dc is initialized by daveNewConnection and is not
|
||||
* yet used. (or reused for the same PLC ?)
|
||||
*
|
||||
* @return the int
|
||||
*/
|
||||
public int connectPLC() {
|
||||
//COTP包 字节流(是上位机 和plc进行的第一次握手)
|
||||
final byte[] b4 = { //b4.length = 18
|
||||
(byte) 0x11, //(16进制)当前字节以后的字节数
|
||||
(byte) 0xE0, //PDU type,连接请求【附录一】
|
||||
(byte) 0x00, (byte) 0x00, //DST reference
|
||||
(byte) 0x00, (byte) 0x01, //SRC reference
|
||||
(byte) 0x00, //固定(Class Extended formats No explilcti flow control)
|
||||
|
||||
(byte) 0xC1, //parameter-code:dst-tsap 上位机
|
||||
(byte) 0x02, //parameter-length
|
||||
(byte) 0x01, //Source rack 机架
|
||||
(byte) 0x00, //Source slot 槽位号
|
||||
|
||||
(byte) 0xC2, //parameter-code:dst-tsap PLC
|
||||
(byte) 0x02, //parameter-length
|
||||
(byte) 0x01, //Destination rack 机架 (Des rack 指的就是 plc rack) (msgOut[17])
|
||||
(byte) 0x02, //Destination slot 槽位号 (Des slot 指的就是 plc slot) (msgOut[18])
|
||||
|
||||
(byte) 0xC0, //parameter-code:tpdu-size
|
||||
(byte) 0x01, //parameter-length
|
||||
(byte) 0x09 //TPDU size
|
||||
};
|
||||
|
||||
//把 b4 这个数组从0开始位置 放到 this.msgOut 这个数组 第四个位置后面,放 b4.length 个长度
|
||||
//之所以目的位置4 是因为,前面4个字节是TPKT的内容(第一次握手)
|
||||
// msgOut 是这个socketChannel 往外写的 bytes(上位机 => plc 写) ;msgIn 是指这个socketChanne 外部往里写的bytes(上位机 <= plc 写)
|
||||
System.arraycopy(b4, 0, this.msgOut, 4, b4.length);
|
||||
this.msgOut[17] = (byte) (this.rack + 1);
|
||||
this.msgOut[18] = (byte) this.slot;
|
||||
this.sendISOPacket(b4.length);
|
||||
this.readISOPacket();
|
||||
/*
|
||||
* PDU p = new PDU(msgOut, 7); p.initHeader(1); p.addParam(b61);
|
||||
* exchange(p); return (0);
|
||||
*/
|
||||
return this.negPDUlengthRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建S7COMM 的COTP部分 3个字节(第二次握手)
|
||||
*
|
||||
* return
|
||||
* 1 代表失败
|
||||
* 0 代表成功
|
||||
* */
|
||||
@Override
|
||||
public int exchange(final PDU p1) {
|
||||
this.msgOut[4] = (byte) 0x02; //当前字节以后的字节数(也就是下面两个字节)
|
||||
this.msgOut[5] = (byte) 0xf0; //PDU Type
|
||||
this.msgOut[6] = (byte) 0x80; //TPDU number (如果这个字节首位为1 代表就是最后一个传输单元了 如1000 0000 ;; 如果首字母不为1 就代表这个Request是比较长的要分多个unit传输,后7位就代表传输单元序号)
|
||||
int writeRes = this.sendISOPacket(3 + p1.hlen + p1.plen + p1.dlen); //这里 TPKT 和 COTP字节一起发送的。。
|
||||
//这里读到的 ISO_Back_Packet 是暂存在msgIn 这暂存区的,后面可以直接拿里面的数据来构建 ISO_Back_Packet 的PDU
|
||||
int readRes = this.readISOPacket();
|
||||
if(writeRes!=0 && readRes!=0){
|
||||
return 0;
|
||||
}else {
|
||||
logger.info("exchange 出现了问题:① writeRes:"+writeRes+"② readRes:"+readRes);
|
||||
return 1 ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read iso packet.
|
||||
*
|
||||
* @return the int
|
||||
* 0 ==> 不成功
|
||||
* 其他 ==> 成功
|
||||
*/
|
||||
protected int readISOPacket() {
|
||||
//read return 为0 就是异常
|
||||
int res = this.iface.read(this.msgIn, 0, 4);
|
||||
if (res == 4) {
|
||||
final int len = (0x100 * this.msgIn[2]) + this.msgIn[3]; //读取字节数
|
||||
res += this.iface.read(this.msgIn, 4, len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// public static void main(String[] args) {
|
||||
// byte[] s = new byte[2];
|
||||
// List<Byte> a = new ArrayList<>();
|
||||
// a.add(Byte.valueOf("1"));
|
||||
// a.add(Byte.valueOf("2"));
|
||||
// read(a);
|
||||
// System.out.println(a.get(0));
|
||||
// System.out.println(a.get(1));
|
||||
// }
|
||||
// public static int read(byte[] ss){
|
||||
// ss[0] = 1;
|
||||
// ss[1] = 1;
|
||||
// return 0;
|
||||
// }
|
||||
// public static int read(List<Byte> ss){
|
||||
// ss.set(0,Byte.valueOf("3"));
|
||||
// ss.set(1,Byte.valueOf("4"));
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Send iso packet.
|
||||
*
|
||||
* @param size
|
||||
* the size
|
||||
* @return the int
|
||||
* 1 ==> 成功
|
||||
* 0 ==> 不成功
|
||||
*/
|
||||
protected int sendISOPacket(int size) {
|
||||
size += 4;
|
||||
//下面包装的 是TPKT 字节包(第一次握手)
|
||||
this.msgOut[0] = (byte) 0x03; //Version ,默认版本3
|
||||
this.msgOut[1] = (byte) 0x0; //保留字节 ,默认0
|
||||
|
||||
//这两个字节代表请求字节数,通常说都是固定的22,因为 TPKT字节数+COTP字节数 = 22
|
||||
this.msgOut[2] = (byte) (size / 0x100);//高位字节 除以8 取整 就放在高字节
|
||||
this.msgOut[3] = (byte) (size % 0x100);//低位字节 取余8 ,就放在低字节
|
||||
/*
|
||||
* if (messageNumber == 0) { messageNumber = 1; msgOut[11] = (byte)
|
||||
* ((messageNumber + 1) & 0xff); messageNumber++; messageNumber &= 0xff;
|
||||
* //!! }
|
||||
*/
|
||||
//像这种 write 和read 都是 传的是指针,里面数据消费掉了,外部就没了
|
||||
int writeRes = this.iface.write(this.msgOut, 0, size);
|
||||
return writeRes;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializer;
|
||||
import com.qgs.dc.s7.my.s7connector.exception.S7Exception;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.parser.BeanEntry;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.parser.BeanParseResult;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.parser.BeanParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/**
|
||||
* The Class S7Serializer is responsible for serializing S7 TCP Connection
|
||||
*/
|
||||
public final class S7SerializerImpl implements S7Serializer {
|
||||
|
||||
/** Local Logger. */
|
||||
private static final Logger logger = LoggerFactory.getLogger(S7SerializerImpl.class);
|
||||
|
||||
/**
|
||||
* Extracts bytes from a buffer.
|
||||
*
|
||||
* @param <T>
|
||||
* the generic type
|
||||
* @param beanClass
|
||||
* the bean class
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
* @return the t
|
||||
*/
|
||||
public static <T> T extractBytes(final Class<T> beanClass, final byte[] buffer, final int byteOffset) {
|
||||
logger.trace("Extracting type {} from buffer with size: {} at offset {}", beanClass.getName(), buffer.length,
|
||||
byteOffset);
|
||||
|
||||
try {
|
||||
final T obj = beanClass.newInstance();
|
||||
final BeanParseResult result = BeanParser.parse(beanClass);
|
||||
for (final BeanEntry entry : result.entries) {
|
||||
Object value = null;
|
||||
if (entry.isArray) {
|
||||
value = Array.newInstance(entry.type, entry.arraySize);
|
||||
for (int i = 0; i < entry.arraySize; i++) {
|
||||
final Object component = entry.serializer.extract(entry.type, buffer,
|
||||
entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
|
||||
entry.bitOffset + (i * entry.s7type.getBitSize()));
|
||||
Array.set(value, i, component);
|
||||
}
|
||||
} else {
|
||||
value = entry.serializer.extract(entry.type, buffer, entry.byteOffset + byteOffset,
|
||||
entry.bitOffset);
|
||||
}
|
||||
entry.field.set(obj, value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception("extractBytes", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the bytes to the buffer.
|
||||
*
|
||||
* @param bean
|
||||
* the bean
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param byteOffset
|
||||
* the byte offset
|
||||
*/
|
||||
public static void insertBytes(final Object bean, final byte[] buffer, final int byteOffset) {
|
||||
logger.trace("Inerting buffer with size: {} at offset {} into bean: {}", buffer.length, byteOffset, bean);
|
||||
|
||||
try {
|
||||
final BeanParseResult result = BeanParser.parse(bean);
|
||||
|
||||
for (final BeanEntry entry : result.entries) {
|
||||
final Object fieldValue = entry.field.get(bean);
|
||||
|
||||
if (fieldValue != null) {
|
||||
if (entry.isArray) {
|
||||
for (int i = 0; i < entry.arraySize; i++) {
|
||||
final Object arrayItem = Array.get(fieldValue, i);
|
||||
|
||||
if (arrayItem != null) {
|
||||
entry.serializer.insert(arrayItem, buffer,
|
||||
entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
|
||||
entry.bitOffset + (i * entry.s7type.getBitSize()), entry.size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entry.serializer.insert(fieldValue, buffer, entry.byteOffset + byteOffset, entry.bitOffset,
|
||||
entry.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception("insertBytes", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** The Connector. */
|
||||
private final S7Connector connector;
|
||||
|
||||
/**
|
||||
* Instantiates a new s7 serializer.
|
||||
*
|
||||
* @param connector
|
||||
* the connector
|
||||
*/
|
||||
public S7SerializerImpl(final S7Connector connector) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public synchronized <T> T dispense(final Class<T> beanClass, final int dbNum, final int byteOffset)
|
||||
throws S7Exception {
|
||||
try {
|
||||
final BeanParseResult result = BeanParser.parse(beanClass);
|
||||
final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, result.blockSize, byteOffset);
|
||||
return extractBytes(beanClass, buffer, 0);
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception("dispense", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public synchronized <T> T dispense(final Class<T> beanClass, final int dbNum, final int byteOffset,
|
||||
final int blockSize) throws S7Exception {
|
||||
try {
|
||||
final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, blockSize, byteOffset);
|
||||
return extractBytes(beanClass, buffer, 0);
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception(
|
||||
"dispense dbnum(" + dbNum + ") byteoffset(" + byteOffset + ") blocksize(" + blockSize + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public synchronized void store(final Object bean, final int dbNum, final int byteOffset) {
|
||||
try {
|
||||
final BeanParseResult result = BeanParser.parse(bean);
|
||||
|
||||
final byte[] buffer = new byte[result.blockSize];
|
||||
logger.trace("store-buffer-size: " + buffer.length);
|
||||
|
||||
insertBytes(bean, buffer, 0);
|
||||
|
||||
this.connector.write(DaveArea.DB, dbNum, byteOffset, buffer);
|
||||
} catch (final Exception e) {
|
||||
throw new S7Exception("store", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
/**
|
||||
* The Class BitConverter is responsible for converting bit values
|
||||
*/
|
||||
public final class BitConverter implements S7Serializable {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final byte bufValue = buffer[byteOffset];
|
||||
return targetClass.cast(bufValue == (bufValue | (0x01 << bitOffset)));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.BOOL;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Boolean value = (Boolean) javaType;
|
||||
|
||||
if (value) {
|
||||
byte bufValue = buffer[byteOffset];
|
||||
bufValue |= (0x01 << bitOffset);
|
||||
buffer[byteOffset] = bufValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public class ByteConverter implements S7Serializable {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
return targetClass.cast(buffer[byteOffset]);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.BYTE;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Byte value = (Byte) javaType;
|
||||
buffer[byteOffset] = value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public final class DateAndTimeConverter extends ByteConverter {
|
||||
|
||||
public static final int OFFSET_DAY = 2;
|
||||
public static final int OFFSET_HOUR = 3;
|
||||
public static final int OFFSET_MILLIS_1_AND_DOW = 7;
|
||||
public static final int OFFSET_MILLIS_100_10 = 6;
|
||||
public static final int OFFSET_MINUTE = 4;
|
||||
public static final int OFFSET_MONTH = 1;
|
||||
public static final int OFFSET_SECOND = 5;
|
||||
public static final int OFFSET_YEAR = 0;
|
||||
|
||||
// 18, 1,16,16, 5,80,0,3, (dec)
|
||||
// 12, 1,10,10, 5,50,0,3, (hex)
|
||||
// 12-01-10 10:05:50.000
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.clear();
|
||||
|
||||
int year = this.getFromPLC(buffer, OFFSET_YEAR + byteOffset);
|
||||
|
||||
if (year < 90) {
|
||||
// 1900 - 1989
|
||||
year += 2000;
|
||||
} else {
|
||||
// 2000 - 2090
|
||||
year += 1900;
|
||||
}
|
||||
|
||||
int month = this.getFromPLC(buffer, OFFSET_MONTH + byteOffset);
|
||||
|
||||
if (month > 0) {
|
||||
month--;
|
||||
}
|
||||
|
||||
c.set(Calendar.YEAR, year);
|
||||
c.set(Calendar.MONTH, month);
|
||||
c.set(Calendar.DAY_OF_MONTH, this.getFromPLC(buffer, OFFSET_DAY + byteOffset));
|
||||
c.set(Calendar.HOUR_OF_DAY, this.getFromPLC(buffer, OFFSET_HOUR + byteOffset));
|
||||
c.set(Calendar.MINUTE, this.getFromPLC(buffer, OFFSET_MINUTE + byteOffset));
|
||||
c.set(Calendar.SECOND, this.getFromPLC(buffer, OFFSET_SECOND + byteOffset));
|
||||
|
||||
/*
|
||||
* TODO byte upperMillis = super.extract(Byte.class, buffer,
|
||||
* OFFSET_MILLIS_100_10+byteOffset, bitOffset); byte lowerMillis =
|
||||
* super.extract(Byte.class, buffer, OFFSET_MILLIS_1_AND_DOW+byteOffset,
|
||||
* bitOffset);
|
||||
*
|
||||
* int ms100 = ( upperMillis >> 4 ); int ms10 = ( upperMillis & 0x0F );
|
||||
* int ms1 = ( lowerMillis >> 4 );
|
||||
*
|
||||
* int millis = ms1 + ( 10*ms10 ) + ( 100*ms100 );
|
||||
* c.set(Calendar.MILLISECOND, millis);
|
||||
*
|
||||
* int dow = ( lowerMillis & 0x0F ); c.set(Calendar.DAY_OF_WEEK, dow);
|
||||
*/
|
||||
|
||||
return targetClass.cast(c.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dec -> Hex 10 = 0a 16 = 0f 17 = 10
|
||||
*
|
||||
* @param buffer
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public byte getFromPLC(final byte[] buffer, final int offset) {
|
||||
try {
|
||||
final byte ret = super.extract(Byte.class, buffer, offset, 0);
|
||||
return (byte) Integer.parseInt(Integer.toHexString(ret & 0xFF));
|
||||
} catch (final NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.DATE_AND_TIME;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Date date = (Date) javaType;
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.setTime(date);
|
||||
|
||||
int year = c.get(Calendar.YEAR);
|
||||
|
||||
/*
|
||||
* if (year < 1990 || year > 2090) throw new
|
||||
* S7Exception("Invalid year: " + year + " @ offset: " + byteOffset);
|
||||
*/
|
||||
|
||||
if (year < 2000) {
|
||||
// 1990 -1999
|
||||
year -= 1900;
|
||||
} else {
|
||||
// 2000 - 2089
|
||||
year -= 2000;
|
||||
}
|
||||
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_YEAR, year);
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_MONTH, c.get(Calendar.MONTH) + 1);
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_DAY, c.get(Calendar.DAY_OF_MONTH));
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_HOUR, c.get(Calendar.HOUR_OF_DAY));
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_MINUTE, c.get(Calendar.MINUTE));
|
||||
this.putToPLC(buffer, byteOffset + OFFSET_SECOND, c.get(Calendar.SECOND));
|
||||
|
||||
/*
|
||||
* TODO int msec1 = 0, msec10 = 0, msec100 = 0; Integer millis =
|
||||
* c.get(Calendar.MILLISECOND); String mStr = millis.toString();
|
||||
*
|
||||
* if (mStr.length() > 2) { msec100 = Integer.parseInt(
|
||||
* mStr.substring(0, 1) ); msec10 = Integer.parseInt( mStr.substring(1,
|
||||
* 2) ); msec1 = Integer.parseInt( mStr.substring(2, 3) ); } else if
|
||||
* (mStr.length() > 1) { msec10 = Integer.parseInt( mStr.substring(0, 1)
|
||||
* ); msec1 = Integer.parseInt( mStr.substring(1, 2) ); } else { msec1 =
|
||||
* Integer.parseInt( mStr.substring(0, 1) ); }
|
||||
*
|
||||
* super.insert( (byte)( (byte)msec10 | (byte)(msec100 << 4) ), buffer,
|
||||
* OFFSET_MILLIS_100_10+byteOffset, 0, 1);
|
||||
*
|
||||
* int dow = c.get(Calendar.DAY_OF_WEEK);
|
||||
*
|
||||
* super.insert( (byte)( (byte)dow | (byte)(msec1 << 4) ), buffer,
|
||||
* OFFSET_MILLIS_1_AND_DOW+byteOffset, 0, 1);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex -> dec 0a = 10 0f = 16 10 = 17
|
||||
*
|
||||
* @param buffer
|
||||
* @param offset
|
||||
* @param i
|
||||
*/
|
||||
public void putToPLC(final byte[] buffer, final int offset, final int i) {
|
||||
try {
|
||||
final int ret = Integer.parseInt("" + i, 16);
|
||||
buffer[offset] = (byte) ret;
|
||||
} catch (final NumberFormatException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public final class DateConverter extends IntegerConverter {
|
||||
|
||||
private static final long MILLI_TO_DAY_FACTOR = 24 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* 1.1.1990
|
||||
*/
|
||||
private static final long OFFSET_1990;
|
||||
|
||||
static {
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.clear();
|
||||
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||
c.set(Calendar.YEAR, 1990);
|
||||
|
||||
OFFSET_1990 = c.getTime().getTime();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final long days = super.extract(Integer.class, buffer, byteOffset, bitOffset);
|
||||
|
||||
long millis = days * MILLI_TO_DAY_FACTOR;
|
||||
|
||||
millis += OFFSET_1990;
|
||||
|
||||
final Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(millis);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
c.set(Calendar.SECOND, 0);
|
||||
c.set(Calendar.MINUTE, 0);
|
||||
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||
|
||||
return targetClass.cast(c.getTime());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.DATE;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Date d = (Date) javaType;
|
||||
|
||||
long millis = d.getTime();
|
||||
|
||||
millis -= OFFSET_1990;
|
||||
|
||||
final double days = (double) millis / (double) MILLI_TO_DAY_FACTOR;
|
||||
|
||||
final long ROUND = 1000;
|
||||
|
||||
final long expected = (long) ((days * MILLI_TO_DAY_FACTOR) / ROUND);
|
||||
final long actual = millis / ROUND;
|
||||
|
||||
if (expected != actual) {
|
||||
throw new IllegalArgumentException("Expected: " + expected + " got: " + actual);
|
||||
}
|
||||
|
||||
if (millis < 0) {
|
||||
super.insert(0, buffer, byteOffset, bitOffset, 2);
|
||||
} else {
|
||||
super.insert((int) Math.round(days), buffer, byteOffset, bitOffset, 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public class IntegerConverter implements S7Serializable {
|
||||
|
||||
private static final int OFFSET_HIGH_BYTE = 0;
|
||||
private static final int OFFSET_LOW_BYTE = 1;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final byte lower = buffer[byteOffset + OFFSET_LOW_BYTE];
|
||||
final byte higher = buffer[byteOffset + OFFSET_HIGH_BYTE];
|
||||
|
||||
final Integer i = (lower & 0xFF) | ((higher << 8) & 0xFF00);
|
||||
|
||||
return targetClass.cast(i);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.WORD;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Integer value = (Integer) javaType;
|
||||
final byte lower = (byte) ((value >> 0) & 0xFF);
|
||||
final byte higher = (byte) ((value >> 8) & 0xFF);
|
||||
buffer[byteOffset + OFFSET_LOW_BYTE] = lower;
|
||||
buffer[byteOffset + OFFSET_HIGH_BYTE] = higher;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public final class LongConverter implements S7Serializable {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final byte b1 = buffer[byteOffset + 0];
|
||||
final byte b2 = buffer[byteOffset + 1];
|
||||
final byte b3 = buffer[byteOffset + 2];
|
||||
final byte b4 = buffer[byteOffset + 3];
|
||||
|
||||
final Integer i = ((b1 << 0) & 0x000000FF) | ((b2 << 8) & 0x0000FF00) | ((b3 << 16) & 0x00FF0000)
|
||||
| ((b4 << 24) & 0xFF000000);
|
||||
|
||||
return targetClass.cast(i);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.WORD;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final Long value = (Long) javaType;
|
||||
final byte b1 = (byte) ((value >> 0) & 0xFF);
|
||||
final byte b2 = (byte) ((value >> 8) & 0xFF);
|
||||
final byte b3 = (byte) ((value >> 16) & 0xFF);
|
||||
final byte b4 = (byte) ((value >> 24) & 0xFF);
|
||||
buffer[byteOffset + 0] = b1;
|
||||
buffer[byteOffset + 1] = b2;
|
||||
buffer[byteOffset + 2] = b3;
|
||||
buffer[byteOffset + 3] = b4;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public final class RealConverter implements S7Serializable {
|
||||
|
||||
private static final int OFFSET_POS1 = 0;
|
||||
private static final int OFFSET_POS2 = 1;
|
||||
private static final int OFFSET_POS3 = 2;
|
||||
private static final int OFFSET_POS4 = 3;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final int iValue = ((buffer[byteOffset + OFFSET_POS4] & 0xFF) << 0)
|
||||
| ((buffer[byteOffset + OFFSET_POS3] & 0xFF) << 8) | ((buffer[byteOffset + OFFSET_POS2] & 0xFF) << 16)
|
||||
| ((buffer[byteOffset + OFFSET_POS1] & 0xFF) << 24);
|
||||
|
||||
final Float fValue = Float.intBitsToFloat(iValue);
|
||||
|
||||
Object ret = fValue;
|
||||
|
||||
if (targetClass == Double.class) {
|
||||
ret = Double.parseDouble(fValue.toString());
|
||||
}
|
||||
|
||||
return targetClass.cast(ret);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.REAL;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final float fValue = Float.parseFloat(javaType.toString());
|
||||
|
||||
final int iValue = Float.floatToIntBits(fValue);
|
||||
|
||||
buffer[byteOffset + OFFSET_POS4] = (byte) ((iValue >> 0) & 0xFF);
|
||||
buffer[byteOffset + OFFSET_POS3] = (byte) ((iValue >> 8) & 0xFF);
|
||||
buffer[byteOffset + OFFSET_POS2] = (byte) ((iValue >> 16) & 0xFF);
|
||||
buffer[byteOffset + OFFSET_POS1] = (byte) ((iValue >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public final class StringConverter implements S7Serializable {
|
||||
|
||||
private static final int OFFSET_CURRENT_LENGTH = 1;
|
||||
private static final int OFFSET_OVERALL_LENGTH = 0;
|
||||
private static final int OFFSET_START = 2;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final int len = buffer[byteOffset + OFFSET_CURRENT_LENGTH];
|
||||
|
||||
final byte[] bytes = new byte[len];
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
bytes[i] = buffer[byteOffset + OFFSET_START + i];
|
||||
}
|
||||
|
||||
return targetClass.cast(new String(bytes));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.STRING;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
// Not static
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
// Not static
|
||||
return 2; // 2 bytes overhead
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final String value = (String) javaType;
|
||||
|
||||
final int len = value.length();
|
||||
|
||||
if (len > size) {
|
||||
throw new IllegalArgumentException("String to big: " + len);
|
||||
}
|
||||
|
||||
buffer[byteOffset + OFFSET_OVERALL_LENGTH] = (byte) size;
|
||||
buffer[byteOffset + OFFSET_CURRENT_LENGTH] = (byte) len;
|
||||
|
||||
final byte[] strBytes = value.getBytes();
|
||||
for (int i = 0; i < len; i++) {
|
||||
buffer[byteOffset + OFFSET_START + i] = (byte) (strBytes[i] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.S7SerializerImpl;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
|
||||
public final class StructConverter implements S7Serializable {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
return S7SerializerImpl.extractBytes(targetClass, buffer, byteOffset);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBits() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
S7SerializerImpl.insertBytes(javaType, buffer, byteOffset);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.converter;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
public final class TimeConverter extends ByteConverter {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||
final byte b1 = super.extract(Byte.class, buffer, byteOffset + 3, bitOffset);
|
||||
final byte b2 = super.extract(Byte.class, buffer, byteOffset + 2, bitOffset);
|
||||
final byte b3 = super.extract(Byte.class, buffer, byteOffset + 1, bitOffset);
|
||||
final byte b4 = super.extract(Byte.class, buffer, byteOffset + 0, bitOffset);
|
||||
|
||||
final long l = ((long) b1 & 0xFF) << 0 | ((long) b2 & 0xFF) << 8 | ((long) b3 & 0xFF) << 16
|
||||
| ((long) b4 & 0xFF) << 24;
|
||||
|
||||
return targetClass.cast(l);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public S7Type getS7Type() {
|
||||
return S7Type.TIME;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int getSizeInBytes() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||
final int size) {
|
||||
final long l = (Long) javaType;
|
||||
|
||||
final byte b1 = (byte) ((byte) (l >> 0) & 0xFF);
|
||||
final byte b2 = (byte) ((byte) (l >> 8) & 0xFF);
|
||||
final byte b3 = (byte) ((byte) (l >> 16) & 0xFF);
|
||||
final byte b4 = (byte) ((byte) (l >> 24) & 0xFF);
|
||||
|
||||
super.insert(b1, buffer, byteOffset + 3, bitOffset, 1);
|
||||
super.insert(b2, buffer, byteOffset + 2, bitOffset, 1);
|
||||
super.insert(b3, buffer, byteOffset + 1, bitOffset, 1);
|
||||
super.insert(b4, buffer, byteOffset + 0, bitOffset, 1);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.parser;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* A Bean-Entry
|
||||
*
|
||||
* @author Thomas Rudin
|
||||
*/
|
||||
public final class BeanEntry {
|
||||
/**
|
||||
* The Array size
|
||||
*/
|
||||
public int arraySize;
|
||||
|
||||
/**
|
||||
* Offsets and size
|
||||
*/
|
||||
public int byteOffset, bitOffset, size;
|
||||
|
||||
/**
|
||||
* The corresponding field
|
||||
*/
|
||||
public Field field;
|
||||
|
||||
/**
|
||||
* Array type
|
||||
*/
|
||||
public boolean isArray;
|
||||
|
||||
/**
|
||||
* The S7 Type
|
||||
*/
|
||||
public S7Type s7type;
|
||||
|
||||
/**
|
||||
* The corresponding serializer
|
||||
*/
|
||||
public S7Serializable serializer;
|
||||
|
||||
/**
|
||||
* The Java type
|
||||
*/
|
||||
public Class<?> type;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.parser;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public final class BeanParseResult {
|
||||
|
||||
/**
|
||||
* The needed blocksize
|
||||
*/
|
||||
public int blockSize;
|
||||
|
||||
/**
|
||||
* The Bean entries
|
||||
*/
|
||||
public Vector<BeanEntry> entries = new Vector<BeanEntry>();
|
||||
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.serializer.parser;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.api.annotation.S7Variable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.utils.S7Type;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public final class BeanParser {
|
||||
|
||||
/**
|
||||
* Local Logger
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanParser.class);
|
||||
|
||||
/**
|
||||
* Returns the wrapper for the primitive type
|
||||
*
|
||||
* @param primitiveType
|
||||
* @return
|
||||
*/
|
||||
private static Class<?> getWrapperForPrimitiveType(final Class<?> primitiveType) {
|
||||
if (primitiveType == boolean.class) {
|
||||
return Boolean.class;
|
||||
} else if (primitiveType == byte.class) {
|
||||
return Byte.class;
|
||||
} else if (primitiveType == int.class) {
|
||||
return Integer.class;
|
||||
} else if (primitiveType == float.class) {
|
||||
return Float.class;
|
||||
} else if (primitiveType == double.class) {
|
||||
return Double.class;
|
||||
} else if (primitiveType == long.class) {
|
||||
return Long.class;
|
||||
} else {
|
||||
// Fallback
|
||||
return primitiveType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Class
|
||||
*
|
||||
* @param jclass
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static BeanParseResult parse(final Class<?> jclass) throws Exception {
|
||||
final BeanParseResult res = new BeanParseResult();
|
||||
logger.trace("Parsing: " + jclass.getName());
|
||||
|
||||
for (final Field field : jclass.getFields()) {
|
||||
final S7Variable dataAnnotation = field.getAnnotation(S7Variable.class);
|
||||
|
||||
if (dataAnnotation != null) {
|
||||
logger.trace("Parsing field: " + field.getName());
|
||||
logger.trace(" type: " + dataAnnotation.type());
|
||||
logger.trace(" byteOffset: " + dataAnnotation.byteOffset());
|
||||
logger.trace(" bitOffset: " + dataAnnotation.bitOffset());
|
||||
logger.trace(" size: " + dataAnnotation.size());
|
||||
logger.trace(" arraySize: " + dataAnnotation.arraySize());
|
||||
|
||||
final int offset = dataAnnotation.byteOffset();
|
||||
|
||||
// update max offset
|
||||
if (offset > res.blockSize) {
|
||||
res.blockSize = offset;
|
||||
}
|
||||
|
||||
if (dataAnnotation.type() == S7Type.STRUCT) {
|
||||
// recurse
|
||||
logger.trace("Recursing...");
|
||||
final BeanParseResult subResult = parse(field.getType());
|
||||
res.blockSize += subResult.blockSize;
|
||||
logger.trace(" New blocksize: " + res.blockSize);
|
||||
}
|
||||
|
||||
logger.trace(" New blocksize (+offset): " + res.blockSize);
|
||||
|
||||
// Add dynamic size
|
||||
res.blockSize += dataAnnotation.size();
|
||||
|
||||
// Plain element
|
||||
final BeanEntry entry = new BeanEntry();
|
||||
entry.byteOffset = dataAnnotation.byteOffset();
|
||||
entry.bitOffset = dataAnnotation.bitOffset();
|
||||
entry.field = field;
|
||||
entry.type = getWrapperForPrimitiveType(field.getType());
|
||||
entry.size = dataAnnotation.size();
|
||||
entry.s7type = dataAnnotation.type();
|
||||
entry.isArray = field.getType().isArray();
|
||||
entry.arraySize = dataAnnotation.arraySize();
|
||||
|
||||
if (entry.isArray) {
|
||||
entry.type = getWrapperForPrimitiveType(entry.type.getComponentType());
|
||||
}
|
||||
|
||||
// Create new serializer
|
||||
final S7Serializable s = entry.s7type.getSerializer().newInstance();
|
||||
entry.serializer = s;
|
||||
|
||||
res.blockSize += (s.getSizeInBytes() * dataAnnotation.arraySize());
|
||||
logger.trace(" New blocksize (+array): " + res.blockSize);
|
||||
|
||||
if (s.getSizeInBits() > 0) {
|
||||
boolean offsetOfBitAlreadyKnown = false;
|
||||
for (final BeanEntry parsedEntry : res.entries) {
|
||||
if (parsedEntry.byteOffset == entry.byteOffset) {
|
||||
offsetOfBitAlreadyKnown = true;
|
||||
}
|
||||
}
|
||||
if (!offsetOfBitAlreadyKnown) {
|
||||
res.blockSize++;
|
||||
}
|
||||
}
|
||||
|
||||
res.entries.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
logger.trace("Parsing done, overall size: " + res.blockSize);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an Object
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static BeanParseResult parse(final Object obj) throws Exception {
|
||||
return parse(obj.getClass());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.utils;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Serializable;
|
||||
import com.qgs.dc.s7.my.s7connector.impl.serializer.converter.*;
|
||||
|
||||
/**
|
||||
* Type of the Address
|
||||
*
|
||||
* @author Thomas Rudin Libnodave: http://libnodave.sourceforge.net/
|
||||
*/
|
||||
public enum S7Type {
|
||||
/**
|
||||
* Boolean type
|
||||
*/
|
||||
BOOL(BitConverter.class, 0, 1),
|
||||
|
||||
/**
|
||||
* Byte type
|
||||
*/
|
||||
BYTE(ByteConverter.class, 1, 0),
|
||||
|
||||
/**
|
||||
* Simple Date with 2 bytes in length
|
||||
*/
|
||||
DATE(DateConverter.class, 2, 0),
|
||||
|
||||
/**
|
||||
* Full Date and time format with precision in milliseconds
|
||||
*/
|
||||
DATE_AND_TIME(DateAndTimeConverter.class, 8, 0),
|
||||
|
||||
/**
|
||||
* Double word
|
||||
*/
|
||||
DWORD(LongConverter.class, 4, 0),
|
||||
|
||||
/**
|
||||
* Real-type, corresponds to float or double
|
||||
*/
|
||||
REAL(RealConverter.class, 4, 0),
|
||||
|
||||
/**
|
||||
* String type, size must be specified manually
|
||||
*/
|
||||
STRING(StringConverter.class, 2, 0),
|
||||
|
||||
/**
|
||||
* Structure type
|
||||
*/
|
||||
STRUCT(StructConverter.class, 0, 0),
|
||||
|
||||
/**
|
||||
* Time-type, 4 bytes in length, number of millis
|
||||
*/
|
||||
TIME(TimeConverter.class, 4, 0),
|
||||
|
||||
/**
|
||||
* A Word-type (same as int-type)
|
||||
*/
|
||||
WORD(IntegerConverter.class, 2, 0);
|
||||
|
||||
private int byteSize, bitSize;
|
||||
|
||||
private Class<? extends S7Serializable> serializer;
|
||||
|
||||
/**
|
||||
* Enum Constructor
|
||||
*
|
||||
* @param serializer
|
||||
* @param byteSize
|
||||
* @param bitSize
|
||||
*/
|
||||
S7Type(final Class<? extends S7Serializable> serializer, final int byteSize, final int bitSize) {
|
||||
this.serializer = serializer;
|
||||
this.bitSize = bitSize;
|
||||
this.byteSize = byteSize;
|
||||
}
|
||||
|
||||
public int getBitSize() {
|
||||
return this.bitSize;
|
||||
}
|
||||
|
||||
public int getByteSize() {
|
||||
return this.byteSize;
|
||||
}
|
||||
|
||||
public Class<? extends S7Serializable> getSerializer() {
|
||||
return this.serializer;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2016 S7connector members (github.com/s7connector)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package com.qgs.dc.s7.my.s7connector.impl.utils;
|
||||
|
||||
/**
|
||||
* S7-Utility class
|
||||
*
|
||||
* @author Thomas Rudin Libnodave: http://libnodave.sourceforge.net/
|
||||
*
|
||||
*/
|
||||
public final class S7Utils {
|
||||
/**
|
||||
* Converts a byte to 8 bits
|
||||
*
|
||||
* @param buffer
|
||||
* The Input-Byte
|
||||
* @return The 8 bits
|
||||
*/
|
||||
public static boolean[] getBits(int buffer) {
|
||||
if (buffer < 0) {
|
||||
buffer += 256;
|
||||
}
|
||||
|
||||
final String binString = Integer.toBinaryString(buffer);
|
||||
/*
|
||||
* String-Pos: 0 1 2 3 4 5 6 7 Bit: 128 64 32 16 8 4 2 1
|
||||
*/
|
||||
final boolean[] ret = new boolean[8];
|
||||
for (int i = binString.length() - 1; i >= 0; i--) {
|
||||
// Check for the '1'-Char and mirror-set the result
|
||||
final int mirrorPos = (binString.length() - 1) - i;
|
||||
if (binString.charAt(i) == '1') {
|
||||
ret[mirrorPos] = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Constructor */
|
||||
private S7Utils() {
|
||||
// Not needed. Utility class.
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package com.qgs.dc.s7.my.s7connector.service;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||
import com.qgs.dc.s7.my.s7connector.enmuc.PlcVarActual;
|
||||
import com.qgs.dc.s7.my.s7connector.enmuc.S7Client;
|
||||
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||
import com.qgs.dc.s7.my.s7connector.type.TransportSize;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2022/1/17 14:20
|
||||
*/
|
||||
@Component
|
||||
public class S7Service {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
S7Service(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* PlcVar(byte[]) 转 java对象 对照表
|
||||
* 单体变量
|
||||
* Bool ===> Boolean
|
||||
* LREAL ===> Double
|
||||
* REAL ===> Float
|
||||
* DATE ===> String(yyyy-MM-dd 这种形式的类型)
|
||||
* DTL ===> String("年-月-日-工作日-时-分-秒" 这种格式)
|
||||
* TIME ===> Integer(单位 ms)
|
||||
* USINT ===> Integer
|
||||
* SINT ===> Integer
|
||||
* UINT ===> Integer
|
||||
* INT ===> Integer
|
||||
* DINT ===> Integer
|
||||
* UINT ===> Long
|
||||
* Byte ===> Integer(有符号)(默认)
|
||||
* Integer(无符号)(后续扩展)
|
||||
* Char ===> Character
|
||||
* WChar ===> Character
|
||||
* String ===> String
|
||||
|
||||
|
||||
* 数组变量
|
||||
* BoolArray ===> List<Boolean>
|
||||
* ByteArray ===> List<Byte>
|
||||
* WordArray ===> List<Integer>
|
||||
* DWordArray ===> List<Integer>
|
||||
* CharArray ===> List<Character>
|
||||
* SIntArray ===> List<Integer>
|
||||
* IntArray ===> List<Integer>
|
||||
* DIntArray ===> List<Integer>
|
||||
* UIntArray ===> List<Integer>
|
||||
* USIntArray ===> List<Integer>
|
||||
* UDIntArray ===> List<Long>
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
public Object read(PlcVarActual plcVarActual,S7Client s7Client) throws UnsupportedEncodingException, ParseException {
|
||||
S7Connector connector = s7Client.getConnector();
|
||||
if(plcVarActual.getType().equals(PlcVar.STRING)){
|
||||
Integer readBytes = 2;
|
||||
byte[] read = connector.read(
|
||||
plcVarActual.getArea(),
|
||||
plcVarActual.getAreaNumber(),
|
||||
readBytes,
|
||||
plcVarActual.getByteOffset(),
|
||||
plcVarActual.getBitOffset(),
|
||||
plcVarActual.getType().getTransportSize()
|
||||
);
|
||||
|
||||
Integer allLength = Integer.valueOf(read[1])+2;
|
||||
byte[] readF = connector.read(
|
||||
plcVarActual.getArea(),
|
||||
plcVarActual.getAreaNumber(),
|
||||
allLength,
|
||||
plcVarActual.getByteOffset(),
|
||||
plcVarActual.getBitOffset(),
|
||||
plcVarActual.getType().getTransportSize()
|
||||
);
|
||||
return plcVarActual.getType().toObject(readF);
|
||||
}else {
|
||||
Integer readBytes = plcVarActual.getType().getTransportSize().getSizeInBytes() * plcVarActual.getLength();
|
||||
byte[] read = connector.read(
|
||||
plcVarActual.getArea(),
|
||||
plcVarActual.getAreaNumber(),
|
||||
readBytes,
|
||||
plcVarActual.getByteOffset(),
|
||||
plcVarActual.getBitOffset(),
|
||||
plcVarActual.getType().getTransportSize()
|
||||
);
|
||||
return plcVarActual.getType().toObject(read);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* eg :
|
||||
* Object newValue = Boolean.FALSE
|
||||
* s7Service.write(PlcVarActual.HeartBeat, newValue, S7Client.S7_1200);
|
||||
*
|
||||
* PlcVar(byte[]) 转 java对象 对照表
|
||||
* 单体变量
|
||||
* Bool ===> Object newValue = Boolean.FALSE
|
||||
* LREAL ===> Object newValue = Boolean.FALSE
|
||||
* REAL ===> Object newValue = Boolean.FALSE
|
||||
* DATE ===> 暂时没需求(有问题找我)
|
||||
* DTL ===> 暂时没需求(有问题找我)
|
||||
* TIME ===> 暂时没需求(有问题找我)
|
||||
* USINT ===> Object newValue = new Integer(1)
|
||||
* SINT ===> Object newValue = new Integer(1)
|
||||
* UINT ===> Object newValue = new Integer(1)
|
||||
* INT ===> Object newValue = new Integer(1)
|
||||
* DINT ===> Object newValue = new Integer(1)
|
||||
* UINT ===> Object newValue = new Integer(1)
|
||||
* Byte ===> Object newValue = 0x11
|
||||
*
|
||||
* Char ===> Object newValue = 'a'
|
||||
* WChar ===> Object newValue = '菜'
|
||||
* String ===> Object newValue = '你好啊'
|
||||
|
||||
|
||||
* 数组变量
|
||||
* 注意:在write的时候,你write的数量 一定要和 plc中存在的数量一一对应
|
||||
* BoolArray ===> boolean[] booleanArray = new boolean[2]; .... 赋予值
|
||||
* ByteArray ===> byte[] write_byteArrays = new byte[2];
|
||||
* WordArray ===> short[] shortArrays_content = new short[2];
|
||||
* DWordArray ===> int[] intArrays_content = new int[2];
|
||||
* CharArray ===> char[] charArrays_content = new char[2];
|
||||
* SIntArray ===> int[] sintArrays_content = new int[2];
|
||||
* IntArray ===> int[] iintArrays_content = new int[2];
|
||||
* DIntArray ===> int[] dintArrays_content = new int[2];
|
||||
* UIntArray ===> int[] uintArrays_content = new int[3];
|
||||
* USIntArray ===> int[] usintArrays_content = new int[3];
|
||||
* UDIntArray ===> int[] udintArrays_content = new int[3];
|
||||
* //如果有其他数据类型 这里没有找我扩展
|
||||
*
|
||||
*
|
||||
* */
|
||||
public void write(PlcVarActual plcVarActual,Object newValue,S7Client s7Client){
|
||||
S7Connector connector = s7Client.getConnector();
|
||||
byte[] bytes = plcVarActual.getType().toBytes(newValue);
|
||||
connector.write(
|
||||
plcVarActual.getArea(),
|
||||
plcVarActual.getAreaNumber(),
|
||||
plcVarActual.getByteOffset(),
|
||||
plcVarActual.getBitOffset(),
|
||||
bytes,
|
||||
plcVarActual.getType()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.qgs.dc.s7.my.s7connector.type;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2022/1/7 14:41
|
||||
*/
|
||||
public enum DataTransportSize {
|
||||
|
||||
NULL((short) 0x00, (boolean) false),
|
||||
BIT((short) 0x03, (boolean) true),
|
||||
BYTE_WORD_DWORD((short) 0x04, (boolean) true),
|
||||
INTEGER((short) 0x05, (boolean) true),
|
||||
DINTEGER((short) 0x06, (boolean) false),
|
||||
REAL((short) 0x07, (boolean) false),
|
||||
OCTET_STRING((short) 0x09, (boolean) false);
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DataTransportSize.class);
|
||||
|
||||
private static final Map<Short, DataTransportSize> map;
|
||||
static {
|
||||
map = new HashMap<>();
|
||||
for (DataTransportSize value : DataTransportSize.values()) {
|
||||
map.put((short) value.getValue(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private short value;
|
||||
private boolean sizeInBits;
|
||||
|
||||
DataTransportSize(short value, boolean sizeInBits) {
|
||||
this.value = value;
|
||||
this.sizeInBits = sizeInBits;
|
||||
}
|
||||
|
||||
public short getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean getSizeInBits() {
|
||||
return sizeInBits;
|
||||
}
|
||||
|
||||
public static DataTransportSize firstEnumForFieldSizeInBits(boolean fieldValue) {
|
||||
for (DataTransportSize _val : DataTransportSize.values()) {
|
||||
if(_val.getSizeInBits() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<DataTransportSize> enumsForFieldSizeInBits(boolean fieldValue) {
|
||||
List<DataTransportSize> _values = new ArrayList();
|
||||
for (DataTransportSize _val : DataTransportSize.values()) {
|
||||
if(_val.getSizeInBits() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public static DataTransportSize enumForValue(short value) {
|
||||
if (!map.containsKey(value)) {
|
||||
logger.error("No DataTransportSize for value {}", value);
|
||||
}
|
||||
return map.get(value);
|
||||
}
|
||||
|
||||
public static Boolean isDefined(short value) {
|
||||
return map.containsKey(value);
|
||||
}
|
||||
|
||||
}
|
523
src/main/java/com/qgs/dc/s7/my/s7connector/type/PlcVar.java
Normal file
523
src/main/java/com/qgs/dc/s7/my/s7connector/type/PlcVar.java
Normal file
@ -0,0 +1,523 @@
|
||||
package com.qgs.dc.s7.my.s7connector.type;
|
||||
|
||||
import com.qgs.dc.s7.my.s7connector.api.DaveArea;
|
||||
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PlcVar {
|
||||
//单体变量
|
||||
BOOL("BOOL",TransportSize.BOOL,1,false),
|
||||
BYTE("BYTE",TransportSize.BYTE,2,false),
|
||||
WORD("WORD",TransportSize.WORD,3,false),
|
||||
DWORD("DWORD",TransportSize.DWORD,4,false),
|
||||
LWORD("LWORD",TransportSize.LWORD,5,false),
|
||||
INT("INT",TransportSize.INT,6,false),
|
||||
UINT("UINT",TransportSize.UINT,7,false),
|
||||
SINT("SINT",TransportSize.SINT,8,false),
|
||||
USINT("USINT",TransportSize.USINT,9,false),
|
||||
DINT("DINT",TransportSize.DINT,10,false),
|
||||
UDINT("UDINT",TransportSize.UDINT,11,false),
|
||||
LINT("LINT",TransportSize.LINT,12,false),
|
||||
ULINT("ULINT",TransportSize.ULINT,13,false),
|
||||
REAL("REAL",TransportSize.REAL,14,false),
|
||||
LREAL("LREAL",TransportSize.LREAL,15,false),
|
||||
CHAR("CHAR",TransportSize.CHAR,16,false),
|
||||
WCHAR("WCHAR",TransportSize.WCHAR,17,false),
|
||||
STRING("STRING",TransportSize.STRING,18,false),
|
||||
WSTRING("WSTRING",TransportSize.WSTRING,19,false),
|
||||
TIME("TIME",TransportSize.TIME,20,false),
|
||||
LTIME("LTIME",TransportSize.LTIME,21,false),
|
||||
DATE("DATE",TransportSize.DATE,22,false),
|
||||
TIME_OF_DAY("TIME_OF_DAY",TransportSize.TIME_OF_DAY,23,false),
|
||||
TOD("TOD",TransportSize.TOD,24,false),
|
||||
DATE_AND_TIME("DATE_AND_TIME",TransportSize.DATE_AND_TIME,25,false),
|
||||
DT("DT",TransportSize.DT,26,false),
|
||||
DTL("DTL",TransportSize.DTL,27,false),
|
||||
|
||||
//todo DTL 捋清 事件关系。。。
|
||||
//todo Array 再搞一搞。
|
||||
BOOL_Array("BOOL",TransportSize.BOOL,1,true),
|
||||
BYTE_Array("BYTE",TransportSize.BYTE,2,true),
|
||||
WORD_Array("WORD",TransportSize.WORD,3,true),
|
||||
DWORD_Array("DWORD",TransportSize.DWORD,4,true),
|
||||
CHAR_Array("CHAR",TransportSize.CHAR,5,true),
|
||||
SINT_Array("SINT",TransportSize.SINT,6,true),
|
||||
INT_Array("INT",TransportSize.INT,7,true),
|
||||
DINT_Array("DINT",TransportSize.DINT,8,true),
|
||||
UINT_Array("UINT",TransportSize.UINT,9,true),
|
||||
USINT_Array("USINT",TransportSize.USINT,10,true),
|
||||
UDINT_Array("UDINT",TransportSize.UDINT,11,true),
|
||||
;
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransportSize.class);
|
||||
|
||||
private static final Map<TransportSize, PlcVar> map;
|
||||
static {
|
||||
map = new HashMap<>();
|
||||
for (PlcVar value : PlcVar.values()) {
|
||||
if(!value.isArray){
|
||||
map.put(value.getTransportSize(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static PlcVar valueOf(TransportSize transportSize){
|
||||
return map.get(transportSize);
|
||||
}
|
||||
|
||||
|
||||
private String name;
|
||||
private TransportSize transportSize;
|
||||
private Integer dataType;
|
||||
private boolean isArray;
|
||||
PlcVar(String name , TransportSize transportSize, Integer dataType,Boolean isArray){
|
||||
this.name = name;
|
||||
this.transportSize = transportSize;
|
||||
this.dataType = dataType;
|
||||
this.isArray = isArray;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public TransportSize getTransportSize() {
|
||||
return transportSize;
|
||||
}
|
||||
|
||||
public boolean isArray() {
|
||||
return isArray;
|
||||
}
|
||||
|
||||
public byte[] toBytes(Object value){
|
||||
//todo here 扩展数组 toBytes
|
||||
if(!isArray){
|
||||
byte[] res = null;
|
||||
switch (dataType) {
|
||||
case 1:
|
||||
res = ByteUtils.boolToBytes((boolean)value);
|
||||
break;
|
||||
case 2:
|
||||
//ByteUtils.setbytes(Byte.valueOf((byte) 0xFF))
|
||||
res = ByteUtils.setbytes(Byte.valueOf((byte) value));
|
||||
break;
|
||||
case 3:
|
||||
//ByteUtils.wordToBytes(Short.valueOf("-55"))
|
||||
res = ByteUtils.wordToBytes(Short.valueOf(value.toString()));
|
||||
break;
|
||||
case 4:
|
||||
//ByteUtils.dwordToBytes(99)
|
||||
res = ByteUtils.dwordToBytes((int)value);
|
||||
break;
|
||||
case 5:
|
||||
//null
|
||||
break;
|
||||
case 6:
|
||||
//ByteUtils.intToBytes(-99)
|
||||
res = ByteUtils.intToBytes((int)value);
|
||||
break;
|
||||
case 7:
|
||||
//ByteUtils.uintToBytes(9)
|
||||
res = ByteUtils.uintToBytes((int)value);
|
||||
break;
|
||||
case 8:
|
||||
//ByteUtils.sintToBytes(-9)
|
||||
res =ByteUtils.sintToBytes((int)value);
|
||||
break;
|
||||
case 9:
|
||||
//ByteUtils.usintToBytes(9);
|
||||
res =ByteUtils.usintToBytes((int)value);
|
||||
break;
|
||||
case 10:
|
||||
//ByteUtils.dintToBytes(-999)
|
||||
res =ByteUtils.dintToBytes((int)value);
|
||||
break;
|
||||
case 11:
|
||||
//ByteUtils.udintToBytes(99)
|
||||
res =ByteUtils.udintToBytes((int)value);
|
||||
break;
|
||||
case 12:
|
||||
//待补充
|
||||
break;
|
||||
case 13:
|
||||
//待补充
|
||||
break;
|
||||
case 14:
|
||||
//ByteUtils.realToBytes(Float.valueOf("-11.2"))
|
||||
res =ByteUtils.realToBytes(Float.valueOf(value.toString()));
|
||||
break;
|
||||
case 15:
|
||||
//ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
|
||||
res =ByteUtils.lrealToBytes(Double.parseDouble(value.toString()));
|
||||
break;
|
||||
case 16:
|
||||
//ByteUtils.charToBytes('b')
|
||||
res =ByteUtils.charToBytes((char)value);
|
||||
break;
|
||||
case 17:
|
||||
//ByteUtils.wcharToBytes('菜')
|
||||
res =ByteUtils.wcharToBytes((char)value);
|
||||
break;
|
||||
case 18:
|
||||
//String s = "你好啊";
|
||||
//ByteUtils.strToBytes(s);
|
||||
res = ByteUtils.strToBytes(value.toString());
|
||||
break;
|
||||
case 19:
|
||||
//待补充
|
||||
break;
|
||||
case 20:
|
||||
//不常用 待补充
|
||||
break;
|
||||
case 21:
|
||||
//不常用
|
||||
break;
|
||||
case 22:
|
||||
//不常用
|
||||
break;
|
||||
case 23:
|
||||
////不常用
|
||||
break;
|
||||
case 24:
|
||||
////不常用
|
||||
break;
|
||||
case 25:
|
||||
//不常用
|
||||
break;
|
||||
case 26:
|
||||
//不常用
|
||||
break;
|
||||
case 27:
|
||||
//不常用
|
||||
break;
|
||||
default:
|
||||
//什么也不做
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}else {
|
||||
byte[] res = null;
|
||||
switch (dataType) {
|
||||
case 1:
|
||||
// boolean[] booleanArray = new boolean[2];
|
||||
// booleanArray[0] = true;
|
||||
// booleanArray[1] = true;
|
||||
// ByteUtils.booleanArrayToBytes(booleanArray)
|
||||
res = ByteUtils.booleanArrayToBytes((boolean[]) value);
|
||||
break;
|
||||
case 2:
|
||||
// byte[] write_byteArrays = new byte[2];
|
||||
// write_byteArrays[0] = 1;
|
||||
// write_byteArrays[1] = 2;
|
||||
//
|
||||
res = (byte[]) value;
|
||||
break;
|
||||
case 3:
|
||||
// short[] shortArrays_content = new short[2];
|
||||
// shortArrays_content[0] = 1;
|
||||
// shortArrays_content[1] = -1;
|
||||
//
|
||||
res = ByteUtils.wordArrayToBytes((short[]) value);
|
||||
break;
|
||||
case 4:
|
||||
// int[] intArrays_content = new int[2];
|
||||
// intArrays_content[0] = 1;
|
||||
// intArrays_content[1] = -1;
|
||||
//
|
||||
res = ByteUtils.dwordArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 5:
|
||||
// char[] charArrays_content = new char[2];
|
||||
// charArrays_content[0] = '1';
|
||||
// charArrays_content[1] = 'b';
|
||||
//
|
||||
res = ByteUtils.charArrayToBytes((char[]) value);
|
||||
break;
|
||||
case 6:
|
||||
// int[] sintArrays_content = new int[2];
|
||||
// sintArrays_content[0] = 1;
|
||||
// sintArrays_content[1] = -1;
|
||||
//
|
||||
res = ByteUtils.sintArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 7:
|
||||
// int[] iintArrays_content = new int[2];
|
||||
// iintArrays_content[0] = 12;
|
||||
// iintArrays_content[1] = -21;
|
||||
//
|
||||
res = ByteUtils.intArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 8:
|
||||
// int[] dintArrays_content = new int[2];
|
||||
// dintArrays_content[0] = 12;
|
||||
// dintArrays_content[1] = -21;
|
||||
//
|
||||
res = ByteUtils.dintArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 9:
|
||||
// int[] uintArrays_content = new int[3];
|
||||
// uintArrays_content[0] = 12;
|
||||
// uintArrays_content[1] = 99;
|
||||
// uintArrays_content[2] = 1;
|
||||
res = ByteUtils.uintArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 10:
|
||||
// int[] usintArrays_content = new int[3];
|
||||
// usintArrays_content[0] = 12;
|
||||
// usintArrays_content[1] = 99;
|
||||
// usintArrays_content[2] = 1;
|
||||
res = ByteUtils.usintArrayToBytes((int[]) value);
|
||||
break;
|
||||
case 11:
|
||||
// int[] udintArrays_content = new int[3];
|
||||
// udintArrays_content[0] = 12;
|
||||
// udintArrays_content[1] = 99;
|
||||
// udintArrays_content[2] = 1;
|
||||
res = ByteUtils.udintArrayToBytes((int[]) value);
|
||||
break;
|
||||
|
||||
default:
|
||||
//什么也不做
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
//todo here 把 read 和 write操作都封装一下 然后 和 toByte 和 toObject 整合
|
||||
/**
|
||||
* PlcVar(byte[]) 转 java对象 对照表
|
||||
* 单体变量
|
||||
* Bool ===> Boolean
|
||||
* LREAL ===> Double
|
||||
* REAL ===> Float
|
||||
* DATE ===> String(yyyy-MM-dd 这种形式的类型)
|
||||
* DTL ===> String("年-月-日-工作日-时-分-秒" 这种格式)
|
||||
* TIME ===> Integer(单位 ms)
|
||||
* USINT ===> Integer
|
||||
* SINT ===> Integer
|
||||
* UINT ===> Integer
|
||||
* INT ===> Integer
|
||||
* DINT ===> Integer
|
||||
* UINT ===> Long
|
||||
* Byte ===> Integer(有符号)(默认)
|
||||
* Integer(无符号)(后续扩展)
|
||||
* Char ===> Character
|
||||
* WChar ===> Character
|
||||
* String ===> String
|
||||
|
||||
|
||||
* 数组变量
|
||||
* BoolArray ===> List<Boolean>
|
||||
* ByteArray ===> List<Byte>
|
||||
* WordArray ===> List<Integer>
|
||||
* DWordArray ===> List<Integer>
|
||||
* CharArray ===> List<Character>
|
||||
* SIntArray ===> List<Integer>
|
||||
* IntArray ===> List<Integer>
|
||||
* DIntArray ===> List<Integer>
|
||||
* UIntArray ===> List<Integer>
|
||||
* USIntArray ===> List<Integer>
|
||||
* UDIntArray ===> List<Long>
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
public Object toObject(byte[] value) throws ParseException, UnsupportedEncodingException {
|
||||
if(!isArray){
|
||||
Object res = null;
|
||||
switch (dataType) {
|
||||
case 1:
|
||||
//
|
||||
res = ByteUtils.toBoolean(value);
|
||||
break;
|
||||
case 2:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0]);
|
||||
break;
|
||||
case 3:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0],value[1]);
|
||||
break;
|
||||
case 4:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||
break;
|
||||
case 5:
|
||||
//null
|
||||
break;
|
||||
case 6:
|
||||
//
|
||||
res = ByteUtils.toUInt(value[0],value[1]);
|
||||
break;
|
||||
case 7:
|
||||
//
|
||||
res = ByteUtils.toUInt(value[0],value[1]);
|
||||
break;
|
||||
case 8:
|
||||
//
|
||||
res = ByteUtils.toUInt(value[0]);
|
||||
break;
|
||||
case 9:
|
||||
//
|
||||
res = ByteUtils.toUInt(value[0]);
|
||||
break;
|
||||
case 10:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||
break;
|
||||
case 11:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||
|
||||
break;
|
||||
case 12:
|
||||
//
|
||||
|
||||
break;
|
||||
case 13:
|
||||
//
|
||||
|
||||
break;
|
||||
case 14:
|
||||
//
|
||||
res = ByteUtils.realbytesToFloat(value);
|
||||
break;
|
||||
case 15:
|
||||
//ByteUtils.lrealbytesToDouble(lreal)
|
||||
res = ByteUtils.lrealbytesToDouble(value);
|
||||
break;
|
||||
case 16:
|
||||
//
|
||||
res = ByteUtils.toChar(value);
|
||||
break;
|
||||
case 17:
|
||||
//
|
||||
res = ByteUtils.toChar(value);
|
||||
break;
|
||||
case 18:
|
||||
//
|
||||
res = ByteUtils.toStr(value);
|
||||
break;
|
||||
case 19:
|
||||
//
|
||||
|
||||
break;
|
||||
case 20:
|
||||
//
|
||||
res = ByteUtils.toInt(value[0], value[1], value[2], value[3]);
|
||||
break;
|
||||
case 21:
|
||||
//
|
||||
|
||||
break;
|
||||
case 22:
|
||||
//
|
||||
|
||||
Long aLong = Long.valueOf(ByteUtils.toInt(value[0], value[1]).toString());
|
||||
String s = ByteUtils.addDate("1990-01-01", aLong);
|
||||
res = s;
|
||||
break;
|
||||
case 23:
|
||||
//
|
||||
|
||||
break;
|
||||
case 24:
|
||||
//
|
||||
|
||||
break;
|
||||
case 25:
|
||||
//
|
||||
|
||||
break;
|
||||
case 26:
|
||||
//
|
||||
|
||||
break;
|
||||
case 27:
|
||||
//
|
||||
byte[] year = new byte[2];
|
||||
year[0] = value[0];
|
||||
year[1] = value[1];
|
||||
Integer yearInt = ByteUtils.toInt(year[0], year[1]);
|
||||
Integer monthInt = ByteUtils.toInt(value[2]);
|
||||
Integer dayInt = ByteUtils.toInt(value[3]);
|
||||
Integer worddayInt = ByteUtils.toInt(value[4]);
|
||||
Integer hourInt = ByteUtils.toInt(value[5]);
|
||||
Integer minuInt = ByteUtils.toInt(value[6]);
|
||||
Integer secondInt = ByteUtils.toInt(value[7]);
|
||||
res = yearInt+"-"+monthInt+"-"+dayInt+"-"+worddayInt+"-"+hourInt+"-"+minuInt+"-"+secondInt;
|
||||
break;
|
||||
default:
|
||||
//什么也不做
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}else {
|
||||
Object res = null;
|
||||
switch (dataType) {
|
||||
case 1:
|
||||
//
|
||||
res = ByteUtils.toBoolArray(value);
|
||||
break;
|
||||
case 2:
|
||||
//
|
||||
res = ByteUtils.toByteArray(value);
|
||||
break;
|
||||
case 3:
|
||||
//
|
||||
res = ByteUtils.toWordArray(value);
|
||||
break;
|
||||
case 4:
|
||||
//
|
||||
res = ByteUtils.toDWordArray(value);
|
||||
break;
|
||||
case 5:
|
||||
//
|
||||
res = ByteUtils.toCharArray(value);
|
||||
break;
|
||||
case 6:
|
||||
//
|
||||
res =ByteUtils.toSIntArray(value);
|
||||
break;
|
||||
case 7:
|
||||
res = ByteUtils.toIntArray(value);
|
||||
break;
|
||||
case 8:
|
||||
res = ByteUtils.toDIntArray(value);
|
||||
break;
|
||||
case 9:
|
||||
res = ByteUtils.toUIntArray(value);
|
||||
break;
|
||||
case 10:
|
||||
res = ByteUtils.toUSIntArray(value);
|
||||
break;
|
||||
case 11:
|
||||
res = ByteUtils.toUDIntArray(value);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
//后续有其他数组类型 ,再补充好了,先列出一些常用的。
|
||||
break;
|
||||
default:
|
||||
//什么也不做
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* area :DB块 或者其他块
|
||||
* areaNumber :数据块编号 DB3
|
||||
* byteOffset :字节偏移量
|
||||
* byteOffset :比特偏移量(不填就是0 ,差不多只有读bool类型才会用到)
|
||||
* length :长度(1 代表单个变量 ,2/3/4 代表读一个数组。)
|
||||
* */
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,350 @@
|
||||
package com.qgs.dc.s7.my.s7connector.type;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public enum TransportSize {
|
||||
|
||||
BOOL((byte) 0x01, (boolean) true, (boolean) true, (short) 0x01, (short) 1, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BIT, null, (String) "IEC61131_BOOL"),
|
||||
BYTE((byte) 0x02, (boolean) true, (boolean) true, (short) 0x02, (short) 1, (boolean) true, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_BYTE"),
|
||||
WORD((byte) 0x03, (boolean) true, (boolean) true, (short) 0x04, (short) 2, (boolean) true, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_WORD"),
|
||||
DWORD((byte) 0x04, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.WORD, (String) "IEC61131_DWORD"),
|
||||
LWORD((byte) 0x05, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_LWORD"),
|
||||
INT((byte) 0x06, (boolean) true, (boolean) true, (short) 0x05, (short) 2, (boolean) true, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.INTEGER, null, (String) "IEC61131_INT"),
|
||||
UINT((byte) 0x07, (boolean) false, (boolean) true, (short) 0x05, (short) 2, (boolean) false, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_UINT"),
|
||||
SINT((byte) 0x08, (boolean) false, (boolean) true, (short) 0x02, (short) 1, (boolean) false, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.INT, (String) "IEC61131_SINT"),
|
||||
USINT((byte) 0x09, (boolean) false, (boolean) true, (short) 0x02, (short) 1, (boolean) false, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.INT, (String) "IEC61131_USINT"),
|
||||
DINT((byte) 0x0A, (boolean) true, (boolean) true, (short) 0x07, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_DINT"),
|
||||
UDINT((byte) 0x0B, (boolean) false, (boolean) true, (short) 0x07, (short) 4, (boolean) false, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_UDINT"),
|
||||
LINT((byte) 0x0C, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.INT, (String) "IEC61131_LINT"),
|
||||
ULINT((byte) 0x0D, (boolean) false, (boolean) false, (short) 0x00, (short) 16, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.INT, (String) "IEC61131_ULINT"),
|
||||
REAL((byte) 0x0E, (boolean) true, (boolean) true, (short) 0x08, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.REAL, null, (String) "IEC61131_REAL"),
|
||||
LREAL((byte) 0x0F, (boolean) false, (boolean) false, (short) 0x30, (short) 8, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, TransportSize.REAL, (String) "IEC61131_LREAL"),
|
||||
CHAR((byte) 0x10, (boolean) true, (boolean) true, (short) 0x03, (short) 1, (boolean) true, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_CHAR"),
|
||||
WCHAR((byte) 0x11, (boolean) false, (boolean) true, (short) 0x13, (short) 2, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_WCHAR"),
|
||||
STRING((byte) 0x12, (boolean) true, (boolean) true, (short) 0x03, (short) 1, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_STRING"),
|
||||
WSTRING((byte) 0x13, (boolean) false, (boolean) true, (short) 0x00, (short) 2, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_WSTRING"),
|
||||
TIME((byte) 0x14, (boolean) true, (boolean) true, (short) 0x0B, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_TIME"),
|
||||
LTIME((byte) 0x16, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.TIME, (String) "IEC61131_LTIME"),
|
||||
DATE((byte) 0x17, (boolean) true, (boolean) true, (short) 0x09, (short) 2, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_DATE"),
|
||||
TIME_OF_DAY((byte) 0x18, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_TIME_OF_DAY"),
|
||||
TOD((byte) 0x19, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_TIME_OF_DAY"),
|
||||
DATE_AND_TIME((byte) 0x1A, (boolean) true, (boolean) false, (short) 0x0F, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME"),
|
||||
DT((byte) 0x1B, (boolean) true, (boolean) false, (short) 0x0F, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME"),
|
||||
DTL((byte) 0x1C, (boolean) true, (boolean) false, (short) 0x02, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransportSize.class);
|
||||
|
||||
private static final Map<Byte, TransportSize> map;
|
||||
static {
|
||||
map = new HashMap<>();
|
||||
for (TransportSize value : TransportSize.values()) {
|
||||
map.put((byte) value.getValue(), value);
|
||||
}
|
||||
}
|
||||
|
||||
//value 类似于TransportSize 的ID
|
||||
private byte value;
|
||||
private boolean supported_S7_300;
|
||||
private boolean supported_LOGO;
|
||||
private short code;
|
||||
private short sizeInBytes;
|
||||
private boolean supported_S7_400;
|
||||
private boolean supported_S7_1200;
|
||||
private short shortName;
|
||||
private boolean supported_S7_1500;
|
||||
private DataTransportSize dataTransportSize;
|
||||
private TransportSize baseType;
|
||||
private String dataProtocolId;
|
||||
|
||||
TransportSize(byte value, boolean supported_S7_300, boolean supported_LOGO, short code, short sizeInBytes, boolean supported_S7_400, boolean supported_S7_1200, short shortName, boolean supported_S7_1500, DataTransportSize dataTransportSize, TransportSize baseType, String dataProtocolId) {
|
||||
this.value = value;
|
||||
this.supported_S7_300 = supported_S7_300;
|
||||
this.supported_LOGO = supported_LOGO;
|
||||
//Parameter ITEM 的transportSize
|
||||
this.code = code;
|
||||
this.sizeInBytes = sizeInBytes;
|
||||
this.supported_S7_400 = supported_S7_400;
|
||||
this.supported_S7_1200 = supported_S7_1200;
|
||||
this.shortName = shortName;
|
||||
this.supported_S7_1500 = supported_S7_1500;
|
||||
//Data ITEM 的transportSize
|
||||
this.dataTransportSize = dataTransportSize;
|
||||
this.baseType = baseType;
|
||||
this.dataProtocolId = dataProtocolId;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean getSupported_S7_300() {
|
||||
return supported_S7_300;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSupported_S7_300(boolean fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_300() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSupported_S7_300(boolean fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_300() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public boolean getSupported_LOGO() {
|
||||
return supported_LOGO;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSupported_LOGO(boolean fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_LOGO() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSupported_LOGO(boolean fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_LOGO() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public short getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldCode(short fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getCode() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldCode(short fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getCode() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public short getSizeInBytes() {
|
||||
return sizeInBytes;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSizeInBytes(short fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSizeInBytes() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSizeInBytes(short fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSizeInBytes() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public boolean getSupported_S7_400() {
|
||||
return supported_S7_400;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSupported_S7_400(boolean fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_400() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSupported_S7_400(boolean fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_400() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public boolean getSupported_S7_1200() {
|
||||
return supported_S7_1200;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSupported_S7_1200(boolean fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_1200() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSupported_S7_1200(boolean fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_1200() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public short getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldShortName(short fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getShortName() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldShortName(short fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getShortName() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public boolean getSupported_S7_1500() {
|
||||
return supported_S7_1500;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldSupported_S7_1500(boolean fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_1500() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldSupported_S7_1500(boolean fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getSupported_S7_1500() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public DataTransportSize getDataTransportSize() {
|
||||
return dataTransportSize;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldDataTransportSize(DataTransportSize fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getDataTransportSize() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldDataTransportSize(DataTransportSize fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getDataTransportSize() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public TransportSize getBaseType() {
|
||||
return baseType;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldBaseType(TransportSize fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getBaseType() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldBaseType(TransportSize fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getBaseType() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public String getDataProtocolId() {
|
||||
return dataProtocolId;
|
||||
}
|
||||
|
||||
public static TransportSize firstEnumForFieldDataProtocolId(String fieldValue) {
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getDataProtocolId() == fieldValue) {
|
||||
return _val;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<TransportSize> enumsForFieldDataProtocolId(String fieldValue) {
|
||||
List<TransportSize> _values = new ArrayList();
|
||||
for (TransportSize _val : TransportSize.values()) {
|
||||
if(_val.getDataProtocolId() == fieldValue) {
|
||||
_values.add(_val);
|
||||
}
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
|
||||
public static TransportSize enumForValue(byte value) {
|
||||
if (!map.containsKey(value)) {
|
||||
logger.error("No TransportSize for value {}", value);
|
||||
}
|
||||
return map.get(value);
|
||||
}
|
||||
|
||||
public static Boolean isDefined(byte value) {
|
||||
return map.containsKey(value);
|
||||
}
|
||||
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package com.qgs.dc.s7.service;
|
||||
|
||||
import com.qgs.dc.s7.enums.S7DriveManage;
|
||||
import org.apache.plc4x.java.PlcDriverManager;
|
||||
import org.apache.plc4x.java.api.PlcConnection;
|
||||
import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
|
||||
import org.apache.plc4x.java.api.messages.PlcReadRequest;
|
||||
import org.apache.plc4x.java.api.messages.PlcReadResponse;
|
||||
import org.apache.plc4x.java.api.types.PlcResponseCode;
|
||||
import org.apache.plc4x.java.api.value.PlcValue;
|
||||
import org.apache.plc4x.java.utils.connectionpool.PooledPlcDriverManager;
|
||||
import org.apache.plc4x.java.utils.connectionpool2.CachedDriverManager;
|
||||
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* @Desc: ""
|
||||
* @Author: caixiang
|
||||
* @DATE: 2021/9/23 15:16
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class S7Service {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private HashMap<String, PlcConnection> plcConnections = new HashMap<>();
|
||||
private PlcDriverManager driverManager;
|
||||
|
||||
|
||||
public S7Service(){
|
||||
driverManager = S7DriveManage.INSTANCE.getInstance();
|
||||
}
|
||||
|
||||
public boolean addPlc(String url) throws PlcConnectionException {
|
||||
PlcConnection connection = driverManager.getConnection(url);
|
||||
return connection.isConnected();
|
||||
}
|
||||
|
||||
//url : s7://192.168.0.200
|
||||
//address : %DB10:10.0:STRING(20)
|
||||
//get 一个或者多个value
|
||||
public Object getValue(String url,HashMap<String,String> listAddress) throws PlcConnectionException {
|
||||
try(PlcConnection conn = driverManager.getConnection(url)) {
|
||||
if(conn.isConnected()){
|
||||
if(conn.getMetadata().canRead()){
|
||||
try {
|
||||
PlcReadRequest.Builder builder = conn.readRequestBuilder();
|
||||
for(String key:listAddress.keySet()){
|
||||
builder.addItem(key, listAddress.get(key));
|
||||
}
|
||||
|
||||
PlcReadRequest readRequest = builder.build();
|
||||
CompletableFuture<? extends PlcReadResponse> execute = readRequest.execute();
|
||||
|
||||
PlcReadResponse response = execute.get();
|
||||
|
||||
for (String fieldName : response.getFieldNames()) {
|
||||
if(response.getResponseCode(fieldName) == PlcResponseCode.OK) {
|
||||
int numValues = response.getNumberOfValues(fieldName);
|
||||
PlcValue asPlcValue = response.getAsPlcValue();
|
||||
if(numValues == 1) {
|
||||
Object obj = response.getObject(fieldName);
|
||||
logger.info("Value[" + fieldName + "]: " + response.getObject(fieldName));
|
||||
return obj;
|
||||
}
|
||||
else {
|
||||
logger.info("Value[" + fieldName + "]:");
|
||||
List<Object> res = new ArrayList<>();
|
||||
for(int i = 0; i < numValues; i++) {
|
||||
logger.info(" - " + response.getObject(fieldName, i));
|
||||
res.add(response.getObject(fieldName,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.error("Error[" + fieldName + "]: " + response.getResponseCode(fieldName).name());
|
||||
}
|
||||
}
|
||||
|
||||
}catch (Exception e){
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
}else {
|
||||
System.out.println("can not read");
|
||||
}
|
||||
}else {
|
||||
System.out.println("conn not connected");
|
||||
}
|
||||
|
||||
}catch (Exception e){
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
return driverManager.getConnection(url);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user