S7协议 大版本合并

This commit is contained in:
caixiang 2023-01-03 09:19:08 +08:00
parent 81dd41be60
commit 0ad4d2b3e3
9 changed files with 201 additions and 644 deletions

View File

@ -1,16 +1,13 @@
package com.qgs.dc.s7.controller;
import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.client.write.Point;
import com.qgs.dc.opcua.controller.R;
import com.qgs.dc.s7.entity.AGVInfoCallBack;
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 org.slf4j.Logger;
@ -154,7 +151,7 @@ public class S7DemoController {
public R testForString1200() throws Exception {
//测试结果 l => 66ms
long l = System.currentTimeMillis();
String[] subs = (String[])read(S7Client.S7_1200,PlcVarActual.SubIdArrays1200); //65ms
String[] subs = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays1200); //65ms
long l1 = System.currentTimeMillis();
//System.out.println(Arrays.toString(subs));
@ -165,10 +162,10 @@ public class S7DemoController {
}
////测试结果 c => 57ms
long c1 = System.currentTimeMillis();
write(S7Client.S7_1200,PlcVarActual.SubIdArrays1200,toWrite);
write(S7Client.S7_1500,PlcVarActual.SubIdArrays1200,toWrite);
long c2 = System.currentTimeMillis();
String[] subs2 = (String[])read(S7Client.S7_1200,PlcVarActual.SubIdArrays1200);
String[] subs2 = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays1200);
logger.info("正常测试: l:"+(l1-l)+"c:"+(c2-c1)+";;read1:"+Arrays.toString(subs)+";;read2:"+Arrays.toString(subs2));
return R.ok().put("l",(l1-l)).put("c",(c2-c1));
@ -202,17 +199,17 @@ public class S7DemoController {
@PostMapping("/testFor1200")
public R testFor1200() throws Exception {
//Object subs = read(PlcVarActual.INT1200, S7Client.S7_1200);
Object read = read(S7Client.S7_1200, PlcVarActual.SubIdArrays1200);
//Object subs = read(PlcVarActual.INT1200, S7Client.S7_1500);
Object read = read(S7Client.S7_1500, PlcVarActual.SubIdArrays1200);
String[] toWrite = new String[60];
for(int i=0;i<60;i++){
int i1 = new Random().nextInt(100);
toWrite[i] = "2212"+ i1;
}
write(S7Client.S7_1200,PlcVarActual.SubIdArrays1200,toWrite);
write(S7Client.S7_1500,PlcVarActual.SubIdArrays1200,toWrite);
Object read2 = read(S7Client.S7_1200, PlcVarActual.SubIdArrays1200);
Object read2 = read(S7Client.S7_1500, PlcVarActual.SubIdArrays1200);
return R.ok();
}

View File

@ -1,15 +1,6 @@
package com.qgs.dc.s7.my.s7connector;
import com.qgs.dc.common.utils.CommonFunction;
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.S7Client;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
/**
* @Desc: ""

View File

@ -4,11 +4,6 @@ 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.S7Client;
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
import java.io.UnsupportedEncodingException;
import java.util.List;
/**

View File

@ -23,7 +23,7 @@ import java.io.Closeable;
public interface S7Connector extends Closeable {
/**
* Reads an area
* desc : 只要未抛出异常都是 操作成功的
* desc : 只要未抛出异常都是 操作成功的 ( )
* @param area
* @param areaNumber
* @param bytes
@ -34,7 +34,7 @@ public interface S7Connector extends Closeable {
/**
* Reads an area 读需要bit 位置的 变量其实就是 read bool变量的时候调用这个方法
* desc : 只要未抛出异常都是 操作成功的
* desc : 只要未抛出异常都是 操作成功的 ( )
* @param area
* @param areaNumber
* @param bytes
@ -44,7 +44,7 @@ public interface S7Connector extends Closeable {
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize);
/**
* Writes an area
* desc : 只要未抛出异常都是 操作成功的
* desc : 只要未抛出异常都是 操作成功的 ( )
* @param area
* @param areaNumber
* @param offset
@ -52,7 +52,7 @@ public interface S7Connector extends Closeable {
*/
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);
}

View File

@ -8,12 +8,11 @@ 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;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
@ -24,14 +23,11 @@ import java.util.concurrent.ScheduledExecutorService;
public enum S7Client {
//TODO 步骤1 这里是配置多PLC 有多个plc 就在这里配置一个枚举类
//1500 西门子200smart12001500默认的 机架号=0 槽位号=1; 300/400 默认的 机架-0 插槽-2
S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200),
// S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200),
S7_15001("192.168.0.51",0,1,1,PlcVarActual.HeartBeat),
S7_1500("192.168.0.51",0,1,1,PlcVarActual.HeartBeat),
//1500 机架-0 插槽-1
//后续 在这里扩展 多PLC应用
;
private String host;
//默认 0 机架号
@ -49,27 +45,21 @@ public enum S7Client {
private int pickOne;
private static final Logger logger = LoggerFactory.getLogger(S7Client.class);
private ScheduledExecutorService executor;
private ScheduledExecutorService ping_fail_check;
//coreSize 是线程池的数量
S7Client(String host, Integer rack, Integer slot,Integer coreSize,PlcVarActual heartBeat){
S7Client(String host, Integer rack, Integer slot, Integer coreSize, PlcVarActual heartBeat){
this.host = host;
this.rack = rack;
this.slot = slot;
this.pickOne = 0;
this.executor = Executors.newScheduledThreadPool(1);
this.ping_fail_check = Executors.newScheduledThreadPool(1);
this.coreSize = coreSize;
this.heartBeat = heartBeat;
connections = new ArrayList<>();
connectionPool();
ping();
//
check_ping();
}
public String getHost(){
@ -112,73 +102,87 @@ public enum S7Client {
* UDIntArray ===> List<Long>
* StringArray ===> String[] 特殊
*
*
* 如果返回null就代表出现了异常并且尝试了 retryMax 次数并且尝试重置连接
* */
public Object read(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset, Integer length, Integer strSizes, PlcVar type) throws Exception {
public Object read(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset, Integer length, Integer strSizes, PlcVar type) {
S7Connector connector = getConnector();
//String 类型比较特殊 String[] 也是同理Sring数组里面的子项 也是有两个字节的 readBytes
if(type.equals(PlcVar.STRING)){
Integer readBytes = 2;
byte[] read = connector.read(
area,
areaNumber,
readBytes,
byteOffset,
bitOffset,
type.getTransportSize()
);
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)){
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,
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);
}
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()+", 现在尝试重新连接"+" ; 异常原因 : "+context.getLastThrowable().getMessage());
if(replaceConnector(connector)==1){
logger.info("S7-Retry-Read 现在恢复成功创建新connection成功");
return null;
}else {
logger.info("S7-Retry-Read 现在恢复失败创建新connection失败");
return null;
}
}
);
}
@ -228,53 +232,103 @@ public enum S7Client {
*
*
* */
public void write(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize, PlcVar type, Object newValue) throws Exception {
public void write(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize, PlcVar type, Object newValue) {
S7Connector connector = getConnector();
//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
);
}
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;
}
}
);
}
// public void retry1() throws InterruptedException {
// S7RetryTemplate instance = S7RetryTemplate.getInstance();
// System.out.println(instance.hashCode()+ ", "+Thread.currentThread().getName());
// instance.execute(
// retryContext -> {
// System.out.println("retry1 : " + Thread.currentThread().getName() );
// Thread.sleep(10000);
// System.out.println("retry1 sleepdown : " + Thread.currentThread().getName() );
// return true;
// },
// retryContext -> {
// System.out.println("retry1 err: " + Thread.currentThread().getName() );
// return false;
// }
// );
// }
public S7Connector getConnector() {
/**
* desc: 传入的connection 是需要被替换的
* return:
* 1 代表替换成功
* -1 代表替换失败创建connection失败原因出现异常.原来的connection也被舍弃掉了
* */
private synchronized 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 synchronized S7Connector getConnector() {
int size = connections.size();
S7Connector s7Connector = connections.get((pickOne + size) % size);
pickOne+=1;
@ -282,7 +336,9 @@ public enum S7Client {
return s7Connector;
}
private S7Connector connect(String host,Integer rack,Integer slot ){
private synchronized S7Connector connect(String host,Integer rack,Integer slot ){
try {
S7Connector connector = S7ConnectorFactory
.buildTCPConnector()
@ -303,7 +359,7 @@ public enum S7Client {
connectionPool();
}
private void connectionPool(){
private synchronized void connectionPool(){
for(int i=0;i<coreSize;i++){
S7Connector connect = connect(host, rack, slot);
if(connect!=null){
@ -312,101 +368,4 @@ public enum S7Client {
}
//todo 在plc上新增一个 变量来解决 心跳问题 okok
}
private void check_ping(){
ping_fail_check.execute(new Runnable() {
@Override
public void run() {
while (true){
try {
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){
logger.info("host:"+host +" ;;(check_ping()) 检测到有断线 ==》 现在断线恢复成功");
connections.add(connect);
}else {
logger.info("host:"+host +" ;;(check_ping()) 检测到有断线 ==》 现在断线恢复失败");
}
}
}
}catch (Exception e){
logger.info(" ( outside check_ping catched ) host:"+host +" ;;(check_ping()) Thread.sleep 异常,异常原因:"+e.getMessage());
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
}
//todo 当网络断开之后下面这个ping() 循环不生效 可能是read = connector.read( 出来是null但还是继续通过了也可能是 当连接全部断开后 getConnector(); 应该是取不到数据的也就会报null这个明天再看看
private void ping(){
executor.execute(new Runnable() {
@Override
public void run() {
while (true){
try {
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("host:"+host +" ;; "+connector.hashCode()+" : ping");
Thread.sleep(100);
}catch (Exception e){
logger.info("host:"+host +" ;;(ping) "+connector.hashCode()+" : connection error"+"errMessage is : "+e.getMessage());
//先把 socket close掉
try {
connector.close();
connections.remove(connector);
//如果是网络波动照成的socket断开 等个1S 再重连试试
Thread.sleep(100);
}catch (Exception ee){
logger.info("host:"+host +" ;;(ping) "+"connector.close() 出现异常errMessage is : "+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){
logger.info("host:"+host +" ;;(ping) "+"ping时候出现异常尝试重连 重连成功!!");
connections.add(connect);
}else {
logger.info("host:"+host +" ;;(ping) "+"ping时候出现异常尝试重连 重连时候还是 出现异常。。");
}
}
}
}
}catch (Exception e){
e.printStackTrace();
logger.info(" ( outside ping catched ) host:"+host +" ;;(ping) "+e.getMessage());
}
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
}
}

View File

@ -1,371 +0,0 @@
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 西门子200smart12001500默认的 机架号=0 槽位号=1; 300/400 默认的 机架-0 插槽-2
// S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200),
S7_15001("192.168.0.51",0,1,1,PlcVarActual.HeartBeat),
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) {
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;
}
}
);
}
// public void retry1() throws InterruptedException {
// S7RetryTemplate instance = S7RetryTemplate.getInstance();
// System.out.println(instance.hashCode()+ ", "+Thread.currentThread().getName());
// instance.execute(
// retryContext -> {
// System.out.println("retry1 : " + Thread.currentThread().getName() );
// Thread.sleep(10000);
// System.out.println("retry1 sleepdown : " + Thread.currentThread().getName() );
// return true;
// },
// retryContext -> {
// System.out.println("retry1 err: " + Thread.currentThread().getName() );
// return false;
// }
// );
// }
/**
* desc: 传入的connection 是需要被替换的
* return:
* 1 代表替换成功
* -1 代表替换失败创建connection失败原因出现异常.原来的connection也被舍弃掉了
* */
private synchronized 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 synchronized S7Connector getConnector() {
int size = connections.size();
S7Connector s7Connector = connections.get((pickOne + size) % size);
pickOne+=1;
pickOne = (pickOne)%size;
return s7Connector;
}
private synchronized 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 synchronized void connectionPool(){
for(int i=0;i<coreSize;i++){
S7Connector connect = connect(host, rack, slot);
if(connect!=null){
connections.add(connect);
}
}
//todo 在plc上新增一个 变量来解决 心跳问题 okok
}
}

View File

@ -16,13 +16,10 @@ limitations under the License.
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.enmuc.S7Client;
import com.qgs.dc.s7.my.s7connector.exception.S7IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
/**
* The Class TCPConnection.
*/

View File

@ -1,9 +1,7 @@
package com.qgs.dc.s7.retrydemo.forTest;
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.enmuc.S7ClientNew;
import com.qgs.dc.s7.my.s7connector.exception.S7ParseDataException;
import com.qgs.dc.s7.my.s7connector.type.PlcVar;
import org.apache.commons.lang3.RandomStringUtils;
@ -15,7 +13,6 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -35,7 +32,7 @@ public class InitialS7Thread implements ApplicationRunner {
private ScheduledExecutorService executor;
private void write(S7ClientNew s7Client,PlcVarActual var,Object newValue) {
private void write(S7Client s7Client, PlcVarActual var, Object newValue) {
if(var.getType().equals(PlcVar.STRING_Array)){
String[] s = (String[])newValue;
String[] ss = (String[])newValue;
@ -50,14 +47,8 @@ public class InitialS7Thread implements ApplicationRunner {
s7Client.write(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getStrSize(), var.getType(),newValue);
}
}
private Object read(S7ClientNew s7Client,PlcVarActual var) {
try {
return s7Client.read(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getLength(), var.getStrSize(), var.getType());
}catch (Exception e){
logger.error("host:"+s7Client.getHost()+" ; read 操作出现问题: "+e.getMessage());
e.printStackTrace();
return null;
}
private Object read(S7Client s7Client, PlcVarActual var) {
return s7Client.read(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getLength(), var.getStrSize(), var.getType());
}
@Override
@ -68,7 +59,7 @@ public class InitialS7Thread implements ApplicationRunner {
public void run() {
while (true){
//read one
logger.info(Thread.currentThread().getName()+" , subId : "+Arrays.toString((String[])read(S7ClientNew.S7_1500,PlcVarActual.SubIdArrays)));
logger.info(Thread.currentThread().getName()+" , subId : "+Arrays.toString((String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays)));
try {
Thread.sleep(300);
} catch (InterruptedException e) {
@ -83,7 +74,7 @@ public class InitialS7Thread implements ApplicationRunner {
}
try {
write(S7ClientNew.S7_1500,PlcVarActual.SubIdArrays,toWrite);
write(S7Client.S7_1500,PlcVarActual.SubIdArrays,toWrite);
} catch (Exception e) {
throw new S7ParseDataException(e);
}
@ -95,7 +86,7 @@ public class InitialS7Thread implements ApplicationRunner {
@Override
public void run() {
while (true){
logger.info(Thread.currentThread().getName()+" , subId : "+Arrays.toString((String[])read(S7ClientNew.S7_1500,PlcVarActual.SubIdArrays)));
logger.info(Thread.currentThread().getName()+" , subId : "+Arrays.toString((String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays)));
try {
Thread.sleep(300);
@ -110,7 +101,7 @@ public class InitialS7Thread implements ApplicationRunner {
}
try {
write(S7ClientNew.S7_15001,PlcVarActual.SubIdArrays,toWrite);
write(S7Client.S7_15001,PlcVarActual.SubIdArrays,toWrite);
} catch (Exception e) {
throw new S7ParseDataException(e);
}

View File

@ -1,7 +1,5 @@
package com.qgs.dc.s7.retrydemo.lock;
import com.qgs.dc.s7.my.s7connector.enmuc.S7ClientNew;
/**
* @Desc: ""
* @Author: caixiang
@ -9,7 +7,7 @@ import com.qgs.dc.s7.my.s7connector.enmuc.S7ClientNew;
*/
public class LockDemo {
//对象
//对象
public synchronized void func1() {
System.out.println("func1!");
try {
@ -25,7 +23,7 @@ public class LockDemo {
}
public static void main(String[] args) {
LockDemo test = new LockDemo();
LockDemo test2 = new LockDemo();
Thread t1 = new Thread(() -> {
// test.func1();