package com.zy.acs.conveyor.core.thread;
|
|
import HslCommunication.Core.Types.OperateResultExOne;
|
import HslCommunication.Profinet.Siemens.SiemensS7Net;
|
import com.zy.acs.common.utils.News;
|
import com.zy.acs.conveyor.core.constant.DeviceField;
|
import com.zy.acs.conveyor.core.constant.PlcAlarmDefinition;
|
import com.zy.acs.conveyor.core.constant.SafeSignalField;
|
import com.zy.acs.conveyor.core.constant.StationStatusField;
|
import com.zy.acs.conveyor.core.model.StaProtocol;
|
import com.zy.acs.conveyor.core.properties.DevpSlave;
|
import com.zy.acs.conveyor.core.service.DevpS7Service;
|
import com.zy.acs.conveyor.core.service.StationService;
|
import com.zy.acs.conveyor.entity.Devp;
|
import com.zy.acs.conveyor.service.DevpService;
|
import com.zy.acs.conveyor.utils.SpringContextUtil;
|
import com.zy.acs.framework.common.Cools;
|
import lombok.Data;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
|
/**
|
* 输送线线程
|
* Created by vincent on 2020/8/4
|
*/
|
@Data
|
@Slf4j
|
public class SiemensDevpThread implements Runnable {
|
|
private DevpSlave slave;
|
|
private SiemensS7Net siemensS7Net;
|
|
private Map<Integer, StaProtocol> station;
|
|
private static final int WRITE_RETRY_MAX = 5;
|
|
private static final int WRITE_RETRY_INTERVAL_MS = 200;
|
|
private static final int READ_INTERVAL_MS = 100;
|
|
private static final int DB_UPDATE_INTERVAL_MS = 2000; // 数据库更新间隔
|
|
private long lastDbUpdateTime = 0;
|
|
|
public SiemensDevpThread(DevpSlave slave, SiemensS7Net siemensS7Net, Map<Integer, StaProtocol> station) {
|
this.slave = slave;
|
this.siemensS7Net = siemensS7Net;
|
this.station = station;
|
}
|
|
|
@Override
|
@SuppressWarnings("InfiniteLoopStatement")
|
public void run() {
|
while (!Thread.currentThread().isInterrupted()) {
|
try {
|
read();
|
Thread.sleep(READ_INTERVAL_MS);
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
log.warn("SiemensDevp线程被中断 [id:{}]", slave.getId());
|
break;
|
} catch (Exception e) {
|
log.error("SiemensDevp线程运行异常 [id:{}]", slave.getId(), e);
|
}
|
}
|
log.info("SiemensDevp读线程已退出 [id:{}]", slave.getId());
|
}
|
|
/**
|
* 读取状态 ====> 整块plc
|
*/
|
private void read() throws InterruptedException {
|
if (siemensS7Net == null) {
|
DevpS7Service devpS7Service = SpringContextUtil.getBean(DevpS7Service.class);
|
if (devpS7Service != null) {
|
siemensS7Net = devpS7Service.get(slave.getId());
|
}
|
log.warn("PLC未连接,跳过读取 [id:{}]", slave.getId());
|
return;
|
}
|
if (station == null) {
|
StationService stationService = SpringContextUtil.getBean(StationService.class);
|
if (stationService != null) {
|
station = stationService.getStationMap(slave.getId());
|
}
|
log.warn("站点未连接,跳过读取 [id:{}]", slave.getId());
|
return;
|
}
|
|
List<Integer> staNos = slave.getStaNos();
|
int staNoSize = staNos.size();
|
|
// 读取站点状态
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
StationStatusField.ALL.buildAddress(),
|
(short) (staNoSize * StationStatusField.ALL.getByteLength()));
|
|
if (!result.IsSuccess) {
|
log.error("读取站点状态失败 [id:{}] [error:{}]", slave.getId(), result.Message);
|
return;
|
}
|
|
byte[] content = result.Content;
|
for (int i = 0; i < staNoSize; i++) {
|
StaProtocol staProtocol = station.get(staNos.get(i));
|
parseStationStatus(content, i, staProtocol);
|
}
|
|
// 读取条码
|
readBarcodes();
|
|
// 称重
|
readWeight();
|
|
// 读取外形检测错误
|
readDimensionErrors();
|
|
// 读取PLC故障
|
readPlcAlarms(staNos, staNoSize);
|
|
// 读取安全交互信号
|
readSaleSingle(slave.getPutSta(), slave.getTakeSta());
|
|
|
// 定期更新数据库(降低频率)
|
updateDatabaseIfNeeded();
|
}
|
|
/**
|
* 解析单个站点状态
|
*/
|
private void parseStationStatus(byte[] content, int index, StaProtocol staProtocol) {
|
int offset = index * StationStatusField.ALL.getByteLength();
|
staProtocol.setWorkNo(siemensS7Net.getByteTransform().TransInt32(content, offset + StationStatusField.TASK_NUMBER.getOffset()));
|
staProtocol.setStaNo((int) siemensS7Net.getByteTransform().TransInt16(
|
content, offset + StationStatusField.FINAL_TARGET.getOffset()));
|
|
boolean[] status0 = siemensS7Net.getByteTransform().TransBool(
|
content, offset + StationStatusField.STATUS_WORD.getOffset(),
|
StationStatusField.STATUS_WORD.getByteLength());
|
|
boolean[] status = siemensS7Net.getByteTransform().TransBool(
|
content, offset + StationStatusField.STATUS_WORD.getOffset(),
|
1);
|
|
staProtocol.setAutoing(status[0]);
|
staProtocol.setLoading(status[1]);
|
staProtocol.setInEnable(status[2]);
|
staProtocol.setOutEnable(status[3]);
|
staProtocol.setEmptyMk(status[4]);
|
staProtocol.setFullPlt(status[5]);
|
staProtocol.setHigh(status[6]);
|
staProtocol.setLow(status[7]);
|
boolean[] status2 = siemensS7Net.getByteTransform().TransBool(
|
content, offset + StationStatusField.STATUS_WORD.getOffset() + 1,
|
1);
|
staProtocol.setMid(status2[0]);
|
staProtocol.setStartup(status2[1]);
|
staProtocol.setSegApply(status2[2]);
|
staProtocol.setApplyErr(status2[3]);
|
|
}
|
|
/**
|
* 读取条码信息
|
*/
|
private void readBarcodes() {
|
if (slave.getBarcode() == null || !slave.getBarcode()) {
|
return;
|
}
|
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
DeviceField.BARCODE.buildAddress(),
|
(short) (DeviceField.BARCODE.getByteLength() * DeviceField.BARCODE.getArrLength()));
|
|
if (!result.IsSuccess) {
|
log.warn("读取条码失败 [id:{}]", slave.getId());
|
return;
|
}
|
|
byte[] content = result.Content;
|
for (int i = 0; i < DeviceField.BARCODE.getArrLength(); i++) {
|
int[] seg = DeviceField.BARCODE.getSeg();
|
int staNo = siemensS7Net.getByteTransform().TransInt16(
|
content, seg[0] + i * DeviceField.BARCODE.getByteLength());
|
String barcode = siemensS7Net.getByteTransform().TransString(
|
content, seg[1] + i * DeviceField.BARCODE.getByteLength(),
|
DeviceField.BARCODE.getByteLength() - seg[1], "UTF-8");
|
|
if (!Cools.isEmpty(barcode) && staNo != 0) {
|
StaProtocol staProtocol = station.get(staNo);
|
if (staProtocol == null) {
|
log.warn("扫码站点不存在 [id:{}] [staNo:{}]", slave.getId(), staNo);
|
continue;
|
}
|
staProtocol.setBarcode(barcode);
|
News.info("料箱码:{}", barcode);
|
}
|
}
|
}
|
|
/**
|
* 读取重量信息
|
*/
|
private void readWeight() {
|
if (slave.getWeight() == null || !slave.getWeight()) {
|
return;
|
}
|
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
DeviceField.WEIGHT.buildAddress(),
|
(short) (DeviceField.WEIGHT.getArrLength() * DeviceField.WEIGHT.getByteLength()));
|
|
if (!result.IsSuccess) {
|
log.warn("读取重量失败 [id:{}]", slave.getId());
|
return;
|
}
|
byte[] content = result.Content;
|
for (int i = 0; i < DeviceField.WEIGHT.getArrLength(); i++) {
|
int[] seg = DeviceField.WEIGHT.getSeg();
|
int staNo = siemensS7Net.getByteTransform().TransInt16(
|
content, seg[0] + i * DeviceField.WEIGHT.getByteLength());
|
Double weight = (double) siemensS7Net.getByteTransform().TransSingle(
|
content, seg[1] + i * DeviceField.WEIGHT.getByteLength());
|
if (!Cools.isEmpty(weight) && staNo != 0) {
|
StaProtocol staProtocol = station.get(staNo);
|
if (staProtocol == null) {
|
log.warn("称重站点不存在 [id:{}] [staNo:{}]", slave.getId(), staNo);
|
continue;
|
}
|
staProtocol.setWeight(BigDecimal.valueOf(weight).setScale(4, RoundingMode.HALF_UP).doubleValue());
|
}
|
}
|
}
|
|
/**
|
* 读取外形检测错误
|
*/
|
private void readDimensionErrors() {
|
if (slave.getStaNosError() == null || !slave.getStaNosError()) {
|
return;
|
}
|
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
DeviceField.DIMENSION_WORD.buildAddress(),
|
(short) (DeviceField.DIMENSION_WORD.getArrLength() * DeviceField.DIMENSION_WORD.getByteLength()));
|
|
if (!result.IsSuccess) {
|
log.warn("读取外形检测错误失败 [id:{}]", slave.getId());
|
return;
|
}
|
|
byte[] content = result.Content;
|
for (int i = 0; i < DeviceField.DIMENSION_WORD.getArrLength(); i++) {
|
int[] seg = DeviceField.DIMENSION_WORD.getSeg();
|
int staNo = siemensS7Net.getByteTransform().TransInt16(
|
content, seg[0]);
|
if (staNo != 0) {
|
StaProtocol staProtocol = station.get(staNo);
|
if (staProtocol == null) {
|
log.warn("异常站点不存在 [id:{}] [staNo:{}]", slave.getId(), staNo);
|
continue;
|
}
|
boolean[] status = siemensS7Net.getByteTransform().TransBool(
|
content, seg[1] + i * DeviceField.DIMENSION_WORD.getByteLength(),
|
1);
|
//未使用,预留
|
// boolean[] status1 = siemensS7Net.getByteTransform().TransBool(
|
// content, seg[1]+i * DeviceField.DIMENSION_WORD.getByteLength()+1,
|
// 1);
|
|
staProtocol.setLeftErr(status[0]);
|
staProtocol.setRightErr(status[1]);
|
staProtocol.setFrontErr(status[2]);
|
staProtocol.setBackErr(status[3]);
|
staProtocol.setHighErr(status[4]);
|
staProtocol.setLoadErr(status[5]);
|
staProtocol.setWeightErr(status[6]);
|
staProtocol.setBarcodeErr(status[7]);
|
}
|
|
|
}
|
}
|
|
/**
|
* 读取PLC故障信息
|
*/
|
private void readPlcAlarms(List<Integer> staNos, int staNoSize) {
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
PlcAlarmDefinition.ALL.buildAddress(),
|
(short) (staNoSize * PlcAlarmDefinition.ALL.getByteLength()));
|
|
if (!result.IsSuccess) {
|
log.warn("读取PLC故障信息失败 [id:{}]", slave.getId());
|
return;
|
}
|
|
byte[] content = result.Content;
|
for (int i = 0; i < staNoSize; i++) {
|
Integer siteId = staNos.get(i);
|
StaProtocol staProtocol = station.get(siteId);
|
if (staProtocol == null) {
|
log.warn("站点不存在 [id:{}] [staNo:{}]", slave.getId(), siteId);
|
continue;
|
}
|
|
boolean[] status = siemensS7Net.getByteTransform().TransBool(
|
content, i * PlcAlarmDefinition.ALL.getByteLength(), 1);
|
|
staProtocol.setBreakerErr(status[0]);
|
staProtocol.setInfraredErr(status[1]);
|
staProtocol.setOutTimeErr(status[2]);
|
staProtocol.setSeizeSeatErr(status[3]);
|
staProtocol.setWrkYgoodsN(status[4]);
|
staProtocol.setInverterErr(status[5]);
|
staProtocol.setContactErr(status[6]);
|
staProtocol.setUpcontactErr(status[7]);
|
}
|
}
|
|
/**
|
* 读取安全交互信号
|
*/
|
private void readSaleSingle(List<DevpSlave.Sta> putSta, List<DevpSlave.Sta> takeSta) {
|
int staNoSize = putSta.size();
|
OperateResultExOne<byte[]> result = siemensS7Net.Read(
|
SafeSignalField.SAFE_SIGNAL_FROM_CONVEYOR.buildAddress(),
|
(short) (staNoSize * SafeSignalField.SAFE_SIGNAL_FROM_CONVEYOR.getByteLength()));
|
|
if (!result.IsSuccess) {
|
log.warn("读取PLC安全交互信息异常 [id:{}]", slave.getId());
|
return;
|
}
|
|
byte[] content = result.Content;
|
for (int i = 0; i < staNoSize; i++) {
|
Integer put = putSta.get(i).getStaNo();
|
Integer take = takeSta.get(i).getStaNo();
|
StaProtocol staProtocolPut = station.get(put);
|
StaProtocol staProtocolTake = station.get(take);
|
if (staProtocolPut == null || staProtocolTake == null) {
|
log.warn("站点不存在 [id:{}] [staNo:{},{}]", slave.getId(), put, take);
|
continue;
|
}
|
|
boolean[] status = siemensS7Net.getByteTransform().TransBool(
|
content, i * SafeSignalField.SAFE_SIGNAL_FROM_CONVEYOR.getByteLength(), 1);
|
|
boolean[] status2 = siemensS7Net.getByteTransform().TransBool(
|
content, i * SafeSignalField.SAFE_SIGNAL_FROM_CONVEYOR.getByteLength() + 2, 1);
|
|
staProtocolPut.setHeartbeat(status[0]);
|
staProtocolPut.setAllowTake(status[1]);
|
staProtocolPut.setAllowPut(status[2]);
|
staProtocolPut.setInComplete(status[3]);
|
staProtocolPut.setOutComplete(status[4]);
|
|
staProtocolTake.setHeartbeat(status2[0]);
|
staProtocolTake.setAllowTake(status2[1]);
|
staProtocolTake.setAllowPut(status2[2]);
|
staProtocolTake.setInComplete(status2[3]);
|
staProtocolTake.setOutComplete(status2[4]);
|
}
|
}
|
|
/**
|
* 按需更新数据库(降低更新频率)
|
*/
|
private void updateDatabaseIfNeeded() {
|
long currentTime = System.currentTimeMillis();
|
if (currentTime - lastDbUpdateTime < DB_UPDATE_INTERVAL_MS) {
|
return;
|
}
|
|
try {
|
List<Integer> staNos = slave.getStaNos();
|
List<Devp> devps = new ArrayList<>(staNos.size());
|
for (Integer siteId : staNos) {
|
StaProtocol staProtocol = station.get(siteId);
|
if (staProtocol != null) {
|
devps.add(staProtocol.toSqlModel());
|
}
|
}
|
|
if (devps.isEmpty()) {
|
return;
|
}
|
|
DevpService devpService = SpringContextUtil.getBean(DevpService.class);
|
if (devpService != null) {
|
devpService.updateBatchByDevpNo(devps);
|
lastDbUpdateTime = currentTime;
|
log.debug("批量更新数据库成功 [id:{}] [count:{}]", slave.getId(), devps.size());
|
} else {
|
log.error("DevpService未找到,无法更新数据库 [id:{}]", slave.getId());
|
}
|
} catch (Exception e) {
|
log.error("更新数据库数据失败 [id:{}]", slave.getId(), e);
|
News.error("SiemensDevp - 3 - 更新数据库数据失败 ===>> [id:{}]", slave.getId());
|
}
|
}
|
|
|
}
|