S7 更新了一个大版本,待测试
This commit is contained in:
parent
5b2c38770d
commit
829c9ce9ca
14
pom.xml
14
pom.xml
@ -80,11 +80,19 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<!-- websocket 结束 -->
|
<!-- websocket 结束 -->
|
||||||
|
|
||||||
|
<!-- retry 结束 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
<version>1.2.2.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- retry 结束 -->
|
||||||
|
|
||||||
<!-- fastjson 开始 -->
|
<!-- fastjson 开始 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>1.2.78</version>
|
<version>2.0.21</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- fastjson 结束 -->
|
<!-- fastjson 结束 -->
|
||||||
<!-- hutool 开始 -->
|
<!-- hutool 开始 -->
|
||||||
@ -201,6 +209,10 @@
|
|||||||
<artifactId>influxdb-client-java</artifactId>
|
<artifactId>influxdb-client-java</artifactId>
|
||||||
<version>6.7.0</version>
|
<version>6.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- influx end -->
|
<!-- influx end -->
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public interface S7Connector extends Closeable {
|
|||||||
* @param offset
|
* @param offset
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset) throws Exception;
|
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads an area 读需要bit 位置的 变量(其实就是 read bool变量的时候调用这个方法。)
|
* Reads an area 读需要bit 位置的 变量(其实就是 read bool变量的时候调用这个方法。)
|
||||||
@ -41,7 +41,7 @@ public interface S7Connector extends Closeable {
|
|||||||
* @param offset
|
* @param offset
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize) throws Exception;
|
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize);
|
||||||
/**
|
/**
|
||||||
* Writes an area
|
* Writes an area
|
||||||
* desc : 只要未抛出异常,都是 操作成功的
|
* desc : 只要未抛出异常,都是 操作成功的
|
||||||
@ -50,9 +50,9 @@ public interface S7Connector extends Closeable {
|
|||||||
* @param offset
|
* @param offset
|
||||||
* @param buffer
|
* @param buffer
|
||||||
*/
|
*/
|
||||||
public void write(DaveArea area, int areaNumber, int offset, byte[] buffer) throws Exception;
|
public void write(DaveArea area, int areaNumber, int offset, byte[] buffer);
|
||||||
|
|
||||||
//如果 bitOffset 没有 那么就填0
|
//如果 bitOffset 没有 那么就填0
|
||||||
public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var) throws Exception;
|
public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package com.qgs.dc.s7.my.s7connector.api.utils;
|
|||||||
* @DATE: 2021/12/16 9:08
|
* @DATE: 2021/12/16 9:08
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7ParseDataException;
|
||||||
import com.qgs.dc.s7.my.s7connector.utils.CommonFunctions;
|
import com.qgs.dc.s7.my.s7connector.utils.CommonFunctions;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
@ -47,9 +48,14 @@ public class ByteUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String addDate(String timeParam, Long day) throws ParseException {
|
public static String addDate(String timeParam, Long day) {
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式
|
||||||
Date date = dateFormat.parse(timeParam); // 指定日期
|
Date date = null;
|
||||||
|
try {
|
||||||
|
date = dateFormat.parse(timeParam); // 指定日期
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new S7ParseDataException("ByteUtils.addDate error:", e);
|
||||||
|
}
|
||||||
|
|
||||||
long time = date.getTime(); // 得到指定日期的毫秒数
|
long time = date.getTime(); // 得到指定日期的毫秒数
|
||||||
day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数
|
day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数
|
||||||
@ -175,13 +181,13 @@ public class ByteUtils {
|
|||||||
// String ascii = new String(b, Charset.forName("UTF-8"));
|
// String ascii = new String(b, Charset.forName("UTF-8"));
|
||||||
// return ascii;
|
// return ascii;
|
||||||
// }
|
// }
|
||||||
public static Character toChar(byte[] b) throws UnsupportedEncodingException {
|
public static Character toChar(byte[] b) {
|
||||||
if(b.length==1){
|
if(b.length==1){
|
||||||
return toChar(b[0]);
|
return toChar(b[0]);
|
||||||
}
|
}
|
||||||
return byteToChar(b);
|
return byteToChar(b);
|
||||||
}
|
}
|
||||||
public static Character toChar(byte b) throws UnsupportedEncodingException {
|
public static Character toChar(byte b){
|
||||||
return byteToChar(b);
|
return byteToChar(b);
|
||||||
}
|
}
|
||||||
// public static String toChar(byte b) throws UnsupportedEncodingException {
|
// public static String toChar(byte b) throws UnsupportedEncodingException {
|
||||||
@ -194,7 +200,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* return null 代表返回传入参数不正确str 取的length太小
|
* return null 代表返回传入参数不正确str 取的length太小
|
||||||
* */
|
* */
|
||||||
public static String toStr(byte[] b) throws UnsupportedEncodingException {
|
public static String toStr(byte[] b) {
|
||||||
Integer length = Byte.toUnsignedInt(b[1]);
|
Integer length = Byte.toUnsignedInt(b[1]);
|
||||||
if(length>(b.length-2)){
|
if(length>(b.length-2)){
|
||||||
return null;
|
return null;
|
||||||
@ -207,7 +213,7 @@ public class ByteUtils {
|
|||||||
// String s = new String(content);
|
// String s = new String(content);
|
||||||
return ascii;
|
return ascii;
|
||||||
}
|
}
|
||||||
public static String[] toStrArray(byte[] b,Integer length,Integer strSize) throws UnsupportedEncodingException {
|
public static String[] toStrArray(byte[] b,Integer length,Integer strSize) {
|
||||||
String[] res = new String[length];
|
String[] res = new String[length];
|
||||||
strSize+=2;
|
strSize+=2;
|
||||||
for(int i=0;i<length;i++){
|
for(int i=0;i<length;i++){
|
||||||
@ -275,7 +281,7 @@ public class ByteUtils {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Boolean> toBoolArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Boolean> toBoolArray(byte[] b) {
|
||||||
List<Boolean> res = new ArrayList<>();
|
List<Boolean> res = new ArrayList<>();
|
||||||
for(int i=0;i<b.length;i++){
|
for(int i=0;i<b.length;i++){
|
||||||
boolean[] booleanArray = getBooleanArray(b[i], true);
|
boolean[] booleanArray = getBooleanArray(b[i], true);
|
||||||
@ -301,7 +307,7 @@ public class ByteUtils {
|
|||||||
|
|
||||||
|
|
||||||
//bool array to byte array
|
//bool array to byte array
|
||||||
public static byte[] toByteArray(boolean[] b) throws UnsupportedEncodingException {
|
public static byte[] toByteArray(boolean[] b){
|
||||||
Integer byteLength = CommonFunctions.exactDivision(b.length, 8);
|
Integer byteLength = CommonFunctions.exactDivision(b.length, 8);
|
||||||
byte[] res = new byte[byteLength];
|
byte[] res = new byte[byteLength];
|
||||||
Queue<Boolean> queue = new LinkedList<Boolean>();
|
Queue<Boolean> queue = new LinkedList<Boolean>();
|
||||||
@ -347,7 +353,7 @@ public class ByteUtils {
|
|||||||
// return res;
|
// return res;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static List<Byte> toByteArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Byte> toByteArray(byte[] b) {
|
||||||
List<Byte> res = new ArrayList<>();
|
List<Byte> res = new ArrayList<>();
|
||||||
for(int i=0;i<b.length;i++){
|
for(int i=0;i<b.length;i++){
|
||||||
res.add((b[i]));
|
res.add((b[i]));
|
||||||
@ -355,7 +361,7 @@ public class ByteUtils {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Character> toCharArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Character> toCharArray(byte[] b) {
|
||||||
List<Character> res = new ArrayList<>();
|
List<Character> res = new ArrayList<>();
|
||||||
for(int i=0;i<b.length;i++){
|
for(int i=0;i<b.length;i++){
|
||||||
res.add(toChar(b[i]));
|
res.add(toChar(b[i]));
|
||||||
@ -367,7 +373,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* 默认:word => 有符号的整形
|
* 默认:word => 有符号的整形
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toWordArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toWordArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+2)<=b.length){
|
while ((i+2)<=b.length){
|
||||||
@ -383,7 +389,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* 默认:dword => 有符号的整形
|
* 默认:dword => 有符号的整形
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toDWordArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toDWordArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+4)<=b.length){
|
while ((i+4)<=b.length){
|
||||||
@ -444,7 +450,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* USInt 无符号整形 1个字节 =》 Integer
|
* USInt 无符号整形 1个字节 =》 Integer
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toUSIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toUSIntArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
for(int i=0;i<b.length;i++){
|
for(int i=0;i<b.length;i++){
|
||||||
res.add(toUInt(b[i]));
|
res.add(toUInt(b[i]));
|
||||||
@ -454,7 +460,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* UInt 无符号整形 2个字节 =》 Integer
|
* UInt 无符号整形 2个字节 =》 Integer
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toUIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toUIntArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+2)<=b.length){
|
while ((i+2)<=b.length){
|
||||||
@ -468,7 +474,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* UDInt 无符号整形 4个字节 =》 Long
|
* UDInt 无符号整形 4个字节 =》 Long
|
||||||
* */
|
* */
|
||||||
public static List<Long> toUDIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Long> toUDIntArray(byte[] b) {
|
||||||
List<Long> res = new ArrayList<>();
|
List<Long> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+4)<=b.length){
|
while ((i+4)<=b.length){
|
||||||
@ -483,7 +489,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* SInt 无符号整形 1个字节 =》 Integer
|
* SInt 无符号整形 1个字节 =》 Integer
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toSIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toSIntArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
for(int i=0;i<b.length;i++){
|
for(int i=0;i<b.length;i++){
|
||||||
res.add(toInt(b[i]));
|
res.add(toInt(b[i]));
|
||||||
@ -493,7 +499,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* Int 无符号整形 2个字节 =》 Integer
|
* Int 无符号整形 2个字节 =》 Integer
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toIntArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+2)<=b.length){
|
while ((i+2)<=b.length){
|
||||||
@ -507,7 +513,7 @@ public class ByteUtils {
|
|||||||
/**
|
/**
|
||||||
* DInt 无符号整形 4个字节 =》 Integer
|
* DInt 无符号整形 4个字节 =》 Integer
|
||||||
* */
|
* */
|
||||||
public static List<Integer> toDIntArray(byte[] b) throws UnsupportedEncodingException {
|
public static List<Integer> toDIntArray(byte[] b) {
|
||||||
List<Integer> res = new ArrayList<>();
|
List<Integer> res = new ArrayList<>();
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((i+4)<=b.length){
|
while ((i+4)<=b.length){
|
||||||
|
@ -0,0 +1,355 @@
|
|||||||
|
package com.qgs.dc.s7.my.s7connector.enmuc;
|
||||||
|
|
||||||
|
|
||||||
|
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.exception.S7Exception;
|
||||||
|
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
|
||||||
|
import com.qgs.dc.s7.my.s7connector.utils.CommonFunctions;
|
||||||
|
import com.qgs.dc.s7.retry.S7RetryTemplate;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/1/15 13:01
|
||||||
|
*/
|
||||||
|
public enum S7ClientNew {
|
||||||
|
//TODO 步骤1 这里是配置多PLC 的,,,有多个plc 就在这里配置一个枚举类
|
||||||
|
//1500 西门子200smart、1200、1500默认的 机架号=0 槽位号=1; 300/400 默认的 机架-0 插槽-2
|
||||||
|
S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200),
|
||||||
|
|
||||||
|
S7_1500("192.168.0.51",0,1,1,PlcVarActual.HeartBeat),
|
||||||
|
//1500 机架-0 插槽-1
|
||||||
|
//后续 在这里扩展 多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(S7ClientNew.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//coreSize 是线程池的数量
|
||||||
|
S7ClientNew(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;
|
||||||
|
|
||||||
|
connections = new ArrayList<>();
|
||||||
|
connectionPool();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost(){
|
||||||
|
return this.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* StringArray ===> String[] (特殊)
|
||||||
|
*
|
||||||
|
* 如果返回null,就代表出现了异常,并且尝试了 retryMax 次数,并且尝试重置连接
|
||||||
|
* */
|
||||||
|
public Object read(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset, Integer length, Integer strSizes, PlcVar type) {
|
||||||
|
S7Connector connector = getConnector();
|
||||||
|
return S7RetryTemplate.getInstance().execute(
|
||||||
|
context -> {
|
||||||
|
//String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。
|
||||||
|
if(type.equals(PlcVar.STRING)){
|
||||||
|
Integer readBytes = 2;
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
readBytes,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
|
||||||
|
Integer allLength = Integer.valueOf(read[1])+2;
|
||||||
|
byte[] readF = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
allLength,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return type.toObject(readF);
|
||||||
|
}else if(type.equals(PlcVar.BOOL_Array)){
|
||||||
|
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
CommonFunctions.exactDivision(length,8),
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
List<Boolean> booleans = ByteUtils.toBoolArray(read);
|
||||||
|
List<Boolean> res = new ArrayList<Boolean>();
|
||||||
|
for(int i=0;i<length;i++){
|
||||||
|
res.add(i,booleans.get(i));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}else if(type.equals(PlcVar.STRING_Array)){
|
||||||
|
Integer arrayLength = length;
|
||||||
|
Integer strSize = strSizes;
|
||||||
|
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
arrayLength*(strSize+2),
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return ByteUtils.toStrArray(read, arrayLength, strSize);
|
||||||
|
}else {
|
||||||
|
Integer readBytes = type.getTransportSize().getSizeInBytes() * length;
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
readBytes,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return type.toObject(read);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
context -> {
|
||||||
|
logger.info("S7-Retry : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接");
|
||||||
|
if(replaceConnector(connector)==1){
|
||||||
|
logger.info("S7-Retry-Read 现在恢复成功,创建新connection成功");
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
logger.info("S7-Retry-Read 现在恢复失败,创建新connection失败");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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];
|
||||||
|
* StringArray ===> String[] stringArrays_content = new String[3];
|
||||||
|
* //如果有其他数据类型 这里没有找我扩展
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public void write(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize, PlcVar type, Object newValue) throws Exception {
|
||||||
|
S7Connector connector = getConnector();
|
||||||
|
|
||||||
|
S7RetryTemplate.getInstance().execute(
|
||||||
|
context -> {
|
||||||
|
//String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。
|
||||||
|
if(type.equals(PlcVar.STRING)){
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.strToBytes(newValue.toString(), strSize),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else if(type.equals(PlcVar.BOOL_Array)){
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.toByteArray((boolean[])newValue),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else if(type.equals(PlcVar.STRING_Array)){
|
||||||
|
//todo here 检查 read write service
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.strArrayToBytes((String[])newValue, strSize),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else {
|
||||||
|
byte[] bytes = type.toBytes(newValue);
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
bytes,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
context -> {
|
||||||
|
logger.info("S7-Retry-Write : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接");
|
||||||
|
if( replaceConnector(connector) == 1 ){
|
||||||
|
logger.info("S7-Retry-Write 现在恢复成功,创建新connection成功");
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
logger.info("S7-Retry-Write 现在恢复失败,创建新connection失败");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desc: 传入的connection 是需要被替换的
|
||||||
|
* return:
|
||||||
|
* 1 代表替换成功
|
||||||
|
* -1 代表替换失败(创建connection失败,原因:出现异常.原来的connection也被舍弃掉了)
|
||||||
|
* */
|
||||||
|
private Integer replaceConnector(S7Connector oldOne){
|
||||||
|
connections.remove(oldOne);
|
||||||
|
S7Connector connect = connect(host, rack, slot);
|
||||||
|
if(connect == null){
|
||||||
|
return -1;
|
||||||
|
}else {
|
||||||
|
connections.add(connect);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public S7Connector getConnector() {
|
||||||
|
int size = connections.size();
|
||||||
|
S7Connector s7Connector = connections.get((pickOne + size) % size);
|
||||||
|
pickOne+=1;
|
||||||
|
pickOne = (pickOne)%size;
|
||||||
|
return s7Connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 (S7Exception e){
|
||||||
|
// logger.info("创建S7Connector 连接失败,原因:"+e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetConnetctions(){
|
||||||
|
this.connections = new ArrayList<S7Connector>();
|
||||||
|
connectionPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectionPool(){
|
||||||
|
for(int i=0;i<coreSize;i++){
|
||||||
|
S7Connector connect = connect(host, rack, slot);
|
||||||
|
if(connect!=null){
|
||||||
|
connections.add(connect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//todo 在plc上新增一个 变量来解决 心跳问题 okok
|
||||||
|
}
|
||||||
|
}
|
@ -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 S7CheckResultException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7CheckResultException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.exception;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7IOException is an exception related to S7 Communication
|
||||||
|
*/
|
||||||
|
public final class S7IOException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7IOException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7IOException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7IOException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7IOException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 S7ParseDataException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7ParseDataException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,6 +17,8 @@ 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.DaveArea;
|
||||||
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
import com.qgs.dc.s7.my.s7connector.api.S7Connector;
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7CheckResultException;
|
||||||
|
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.Nodave;
|
||||||
import com.qgs.dc.s7.my.s7connector.impl.nodave.S7Connection;
|
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.PlcVar;
|
||||||
@ -32,7 +34,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
|
|
||||||
/** The Constant MAX_SIZE. */
|
/** The Constant MAX_SIZE. */
|
||||||
//private static final int MAX_SIZE = 96; //原版96 ;; ioserver 127 ;;
|
//private static final int MAX_SIZE = 96; //原版96 ;; ioserver 127 ;;
|
||||||
private static final int MAX_SIZE = 212; //S7-1200-maxReadBytes = 212 ;; S7-1200-maxReadBytes = 452
|
private static final int MAX_SIZE = 212; //S7-1200-maxReadBytes = 212 ;; S7-1500-maxReadBytes = 452
|
||||||
|
|
||||||
/** The Constant PROPERTY_AREA. */
|
/** The Constant PROPERTY_AREA. */
|
||||||
public static final String PROPERTY_AREA = "area";
|
public static final String PROPERTY_AREA = "area";
|
||||||
@ -52,11 +54,11 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
* @param libnodaveResult
|
* @param libnodaveResult
|
||||||
* the libnodave result
|
* the libnodave result
|
||||||
*/
|
*/
|
||||||
public static void checkResult(final int libnodaveResult) throws Exception {
|
public static void checkResult(final int libnodaveResult) {
|
||||||
if (libnodaveResult != Nodave.RESULT_OK) {
|
if (libnodaveResult != Nodave.RESULT_OK) {
|
||||||
final String msg = Nodave.strerror(libnodaveResult);
|
final String msg = Nodave.strerror(libnodaveResult);
|
||||||
// throw new IllegalArgumentException("Result: " + msg);
|
// throw new IllegalArgumentException("Result: " + msg);
|
||||||
throw new Exception(msg);
|
throw new S7CheckResultException("errMsg : "+msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +89,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) throws Exception {
|
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) {
|
||||||
if (bytes > MAX_SIZE) {
|
if (bytes > MAX_SIZE) {
|
||||||
final byte[] ret = new byte[bytes];
|
final byte[] ret = new byte[bytes];
|
||||||
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
||||||
@ -108,7 +110,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) throws Exception {
|
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) {
|
||||||
if(bitOffset==0){
|
if(bitOffset==0){
|
||||||
return read(area,areaNumber,bytes,offset);
|
return read(area,areaNumber,bytes,offset);
|
||||||
}
|
}
|
||||||
@ -128,6 +130,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
final byte[] buffer = new byte[bytes];
|
final byte[] buffer = new byte[bytes];
|
||||||
final int ret = this.dc.readBytes(area, areaNumber, offset,bitOffset, bytes, buffer,transportSize);
|
final int ret = this.dc.readBytes(area, areaNumber, offset,bitOffset, bytes, buffer,transportSize);
|
||||||
|
|
||||||
|
//thr resultException
|
||||||
checkResult(ret);
|
checkResult(ret);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -135,7 +138,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) throws Exception {
|
public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) {
|
||||||
if (buffer.length > MAX_SIZE) {
|
if (buffer.length > MAX_SIZE) {
|
||||||
// Split buffer
|
// Split buffer
|
||||||
final byte[] subBuffer = new byte[MAX_SIZE];
|
final byte[] subBuffer = new byte[MAX_SIZE];
|
||||||
@ -155,7 +158,7 @@ public abstract class S7BaseConnection implements S7Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) throws Exception {
|
public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) {
|
||||||
if(bitOffset==0){
|
if(bitOffset==0){
|
||||||
write(area,areaNumber,byteOffset,buffer);
|
write(area,areaNumber,byteOffset,buffer);
|
||||||
return;
|
return;
|
||||||
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7IOException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -67,8 +68,9 @@ public final class PLCinterface {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
logger.info("Socket read字节流失败: "+e);
|
String errMsg = "Socket read字节流失败: "+e.getMessage();
|
||||||
return 0;
|
logger.info(errMsg);
|
||||||
|
throw new S7IOException(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +79,9 @@ public final class PLCinterface {
|
|||||||
this.out.write(b, start, len);
|
this.out.write(b, start, len);
|
||||||
return 1;
|
return 1;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
logger.info("Socket write字节流失败: "+e);
|
String errMsg = "Socket write字节流失败: "+e.getMessage();
|
||||||
return 0;
|
logger.info(errMsg);
|
||||||
|
throw new S7IOException(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public abstract class S7Connection {
|
|||||||
* it's NULL you can get your data from the resultPointer in daveConnection
|
* it's NULL you can get your data from the resultPointer in daveConnection
|
||||||
* long as you do not send further requests.
|
* long as you do not send further requests.
|
||||||
*/
|
*/
|
||||||
public ResultSet execReadRequest(final PDU p) {
|
public ResultSet execReadRequest(final PDU p) throws Exception {
|
||||||
PDU p2;
|
PDU p2;
|
||||||
int errorState;
|
int errorState;
|
||||||
errorState = this.exchange(p);
|
errorState = this.exchange(p);
|
||||||
@ -269,7 +269,7 @@ public abstract class S7Connection {
|
|||||||
* build the PDU for a PDU length negotiation
|
* build the PDU for a PDU length negotiation
|
||||||
* 构建第二次握手
|
* 构建第二次握手
|
||||||
*/
|
*/
|
||||||
public int negPDUlengthRequest() {
|
public int negPDUlengthRequest() throws Exception {
|
||||||
int res;
|
int res;
|
||||||
final PDU p = new PDU(this.msgOut, this.PDUstartOut);
|
final PDU p = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
//S7-Param 构造
|
//S7-Param 构造
|
||||||
@ -320,7 +320,7 @@ public abstract class S7Connection {
|
|||||||
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
p1.initReadRequest();
|
p1.initReadRequest();
|
||||||
p1.addVarToReadRequest(area, DBnum, start, len);
|
p1.addVarToReadRequest(area, DBnum, start, len);
|
||||||
//发送read var request
|
//通过tcp链接 发送read var request,thr S7IOException
|
||||||
res = this.exchange(p1);
|
res = this.exchange(p1);
|
||||||
if (res != Nodave.RESULT_OK) {
|
if (res != Nodave.RESULT_OK) {
|
||||||
this.semaphore.release();
|
this.semaphore.release();
|
||||||
|
@ -17,6 +17,7 @@ package com.qgs.dc.s7.my.s7connector.impl.nodave;
|
|||||||
|
|
||||||
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
import com.qgs.dc.s7.my.s7connector.api.utils.ByteUtils;
|
||||||
import com.qgs.dc.s7.my.s7connector.enmuc.S7Client;
|
import com.qgs.dc.s7.my.s7connector.enmuc.S7Client;
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7IOException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ public final class TCPConnection extends S7Connection {
|
|||||||
*
|
*
|
||||||
* @return the int
|
* @return the int
|
||||||
*/
|
*/
|
||||||
public int connectPLC() {
|
public int connectPLC() throws Exception {
|
||||||
//COTP包 字节流(是上位机 和plc进行的第一次握手)
|
//COTP包 字节流(是上位机 和plc进行的第一次握手)
|
||||||
final byte[] b4 = { //b4.length = 18
|
final byte[] b4 = { //b4.length = 18
|
||||||
(byte) 0x11, //(16进制)当前字节以后的字节数
|
(byte) 0x11, //(16进制)当前字节以后的字节数
|
||||||
@ -123,9 +124,9 @@ public final class TCPConnection extends S7Connection {
|
|||||||
if(writeRes!=0 && readRes!=0){
|
if(writeRes!=0 && readRes!=0){
|
||||||
return 0;
|
return 0;
|
||||||
}else {
|
}else {
|
||||||
|
String errMsg = "exchange 出现了问题:① writeRes:"+(writeRes==0?"writeISOPacket成功":"writeISOPacket失败")+"② readRes:"+(readRes==0?"readISOPacket成功":"readISOPacket失败");
|
||||||
logger.info("exchange 出现了问题:① writeRes:"+(writeRes==0?"writeISOPacket成功":"writeISOPacket失败")+"② readRes:"+(readRes==0?"readISOPacket成功":"readISOPacket失败"));
|
logger.info(errMsg);
|
||||||
return 1 ;
|
throw new S7IOException(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ public final class TCPConnection extends S7Connection {
|
|||||||
* Read iso packet.
|
* Read iso packet.
|
||||||
*
|
*
|
||||||
* @return the int
|
* @return the int
|
||||||
* 0 ==> 不成功
|
* 0 ==> 不成功(异常)
|
||||||
* -1 ==> 读到一个空的字节流 (这种情况很少)
|
* -1 ==> 读到一个空的字节流 (这种情况很少)
|
||||||
* 其他 ==> 成功
|
* 其他 ==> 成功
|
||||||
*/
|
*/
|
||||||
@ -141,7 +142,6 @@ public final class TCPConnection extends S7Connection {
|
|||||||
//read return 为0 就是异常
|
//read return 为0 就是异常
|
||||||
int res = this.iface.read(this.msgIn, 0, 4);
|
int res = this.iface.read(this.msgIn, 0, 4);
|
||||||
if (res == 4) {
|
if (res == 4) {
|
||||||
// final int len = (0x100 * this.msgIn[2]) + this.msgIn[3]; //读取字节数 这串是bug代码
|
|
||||||
final int len = (0x100 * ByteUtils.toUInt(this.msgIn[2])) + ByteUtils.toUInt(this.msgIn[3]);
|
final int len = (0x100 * ByteUtils.toUInt(this.msgIn[2])) + ByteUtils.toUInt(this.msgIn[3]);
|
||||||
res += this.iface.read(this.msgIn, 4, len);
|
res += this.iface.read(this.msgIn, 4, len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,7 +330,7 @@ public enum PlcVar {
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
public Object toObject(byte[] value) throws ParseException, UnsupportedEncodingException {
|
public Object toObject(byte[] value) {
|
||||||
if(!isArray){
|
if(!isArray){
|
||||||
Object res = null;
|
Object res = null;
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
|
60
src/main/java/com/qgs/dc/s7/retry/S7RetryTemplate.java
Normal file
60
src/main/java/com/qgs/dc/s7/retry/S7RetryTemplate.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package com.qgs.dc.s7.retry;
|
||||||
|
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.qgs.dc.s7.my.s7connector.exception.S7IOException;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caixiang
|
||||||
|
* @description 重试模板和重试策略
|
||||||
|
*/
|
||||||
|
public class S7RetryTemplate extends RetryTemplate {
|
||||||
|
|
||||||
|
private volatile static S7RetryTemplate instance = null;
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
private static long fixedPeriodTime = 500L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
private static int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
private static Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
private S7RetryTemplate() {
|
||||||
|
// 代表S7IOException 这个异常是需要重试的(true), 如果你想设置这个异常不去重试,那么可以把它设置为false。
|
||||||
|
exceptionMap.put(S7IOException.class,true);
|
||||||
|
exceptionMap.put(S7CheckResultException.class,true);
|
||||||
|
|
||||||
|
}
|
||||||
|
public static int getMaxRetryTimes() {
|
||||||
|
return maxRetryTimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static S7RetryTemplate getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (S7RetryTemplate.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
// 定义重试间隔-间隔 fixedPeriodTime ms再重试,总共重试3次
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
instance = new S7RetryTemplate();
|
||||||
|
// 定义重试次数- maxRetryTimes
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
instance.setRetryPolicy(retryPolicy);
|
||||||
|
|
||||||
|
instance.setBackOffPolicy(backOffPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
39
src/main/java/com/qgs/dc/s7/retrydemo/RetryDemoTask.java
Normal file
39
src/main/java/com/qgs/dc/s7/retrydemo/RetryDemoTask.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.qgs.dc.s7.retrydemo;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: cx
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
public class RetryDemoTask {
|
||||||
|
/**
|
||||||
|
* 重试方法
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean retryTask(String param) {
|
||||||
|
System.out.println("retry-task : 收到请求参数:"+param);
|
||||||
|
|
||||||
|
int i = RandomUtils.nextInt(0,11);
|
||||||
|
System.out.println("retry-task : 随机生成的数:"+i);
|
||||||
|
if (i == 0) {
|
||||||
|
System.out.println("retry-task : 为0,抛出参数异常.");
|
||||||
|
//因为Illeague这个异常我们没有在exceptionMap里面配置,所以 抛出这个异常后
|
||||||
|
//spring-retry不会进行重试,而是会直接进入recovery函数
|
||||||
|
throw new IllegalArgumentException("retry-task : 参数异常");
|
||||||
|
}else if (i == 1){
|
||||||
|
System.out.println("retry-task : 为1,返回true.");
|
||||||
|
return true;
|
||||||
|
}else if (i == 2){
|
||||||
|
System.out.println("retry-task : 为2,返回false.");
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
//因为RemoteAccessExcep这个异常我们在exceptionMap里面配置了,所以 抛出这个异常后
|
||||||
|
//spring-retry会进行重试
|
||||||
|
System.out.println("retry-task : 大于2,抛出自定义异常.");
|
||||||
|
throw new RemoteAccessException("retry-task : 大于2,抛出远程访问异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/main/java/com/qgs/dc/s7/retrydemo/RetryMain.java
Normal file
58
src/main/java/com/qgs/dc/s7/retrydemo/RetryMain.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package com.qgs.dc.s7.retrydemo;
|
||||||
|
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RetryMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
long fixedPeriodTime = 1000L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
exceptionMap.put(RemoteAccessException.class,true);
|
||||||
|
|
||||||
|
// 构建重试模板实例
|
||||||
|
RetryTemplate retryTemplate = new RetryTemplate();
|
||||||
|
|
||||||
|
// 设置重试回退操作策略,主要设置重试间隔时间
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
|
||||||
|
// 设置重试策略,主要设置重试次数
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
|
||||||
|
retryTemplate.setRetryPolicy(retryPolicy);
|
||||||
|
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
Boolean execute = retryTemplate.execute(
|
||||||
|
//RetryCallback
|
||||||
|
retryContext -> {
|
||||||
|
boolean b = RetryDemoTask.retryTask("abc");
|
||||||
|
System.err.println("retry-main : 调用的结果:"+b+",times:"+retryContext.getRetryCount());
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
retryContext -> {
|
||||||
|
//RecoveryCallback
|
||||||
|
System.err.println("retry-main : 已达到最大重试次数或抛出了不重试的异常~~~");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
System.err.println("retry-main : 执行结果:"+execute);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.qgs.dc.s7.retrydemo;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: zgd
|
||||||
|
* @Description: spring-retry 重试框架
|
||||||
|
*/
|
||||||
|
public class SpringS7RetryTemplateTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
private long fixedPeriodTime = 1000L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
private int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
private Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
//文档:https://blog.csdn.net/minghao0508/article/details/123972703
|
||||||
|
exceptionMap.put(RemoteAccessException.class,true);
|
||||||
|
|
||||||
|
// 构建重试模板实例
|
||||||
|
RetryTemplate retryTemplate = new RetryTemplate();
|
||||||
|
|
||||||
|
// 设置重试回退操作策略,主要设置重试间隔时间
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
|
||||||
|
// 设置重试策略,主要设置重试次数
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
|
||||||
|
retryTemplate.setRetryPolicy(retryPolicy);
|
||||||
|
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
Boolean execute = retryTemplate.execute(
|
||||||
|
//RetryCallback
|
||||||
|
retryContext -> {
|
||||||
|
boolean b = RetryDemoTask.retryTask("abc");
|
||||||
|
System.out.println("调用的结果:"+b);
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
retryContext -> {
|
||||||
|
//RecoveryCallback
|
||||||
|
System.out.println("已达到最大重试次数或抛出了不重试的异常~~~");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
System.out.println("执行结果:"+execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
src/main/java/com/qgs/dc/s7/retrydemo/TestMain.java
Normal file
20
src/main/java/com/qgs/dc/s7/retrydemo/TestMain.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.qgs.dc.s7.retrydemo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TestMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Integer a = 1;
|
||||||
|
Integer a1 = 2;
|
||||||
|
Integer a2 = 3;
|
||||||
|
List<Integer> list = new ArrayList<Integer>();
|
||||||
|
list.add(a);
|
||||||
|
list.add(a1);
|
||||||
|
list.add(a2);
|
||||||
|
Integer integer = list.get(0);
|
||||||
|
list.remove(integer);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user