S7协议 大版本合并
This commit is contained in:
parent
81dd41be60
commit
0ad4d2b3e3
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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: ""
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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 西门子200smart、1200、1500默认的 机架号=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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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 西门子200smart、1200、1500默认的 机架号=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
|
||||
}
|
||||
}
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user