package com.zy.core.thread.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.core.common.DateUtils;
|
import com.core.common.SpringUtils;
|
import com.zy.asrs.entity.BasDualCrnp;
|
import com.zy.asrs.entity.BasDualCrnpOpt;
|
import com.zy.asrs.entity.DeviceConfig;
|
import com.zy.asrs.entity.DeviceDataLog;
|
import com.zy.asrs.service.BasDualCrnpOptService;
|
import com.zy.asrs.service.BasDualCrnpService;
|
import com.zy.asrs.utils.Utils;
|
import com.zy.common.utils.RedisUtil;
|
import com.zy.core.cache.MessageQueue;
|
import com.zy.core.cache.OutputQueue;
|
import com.zy.core.enums.CrnTaskModeType;
|
import com.zy.core.enums.RedisKeyType;
|
import com.zy.core.enums.SlaveType;
|
import com.zy.core.model.CommandResponse;
|
import com.zy.core.model.Task;
|
import com.zy.core.model.command.DualCrnCommand;
|
import com.zy.core.model.protocol.DualCrnProtocol;
|
import com.zy.core.network.DeviceConnectPool;
|
import com.zy.core.network.ZyDualCrnConnectDriver;
|
import com.zy.core.network.entity.ZyDualCrnStatusEntity;
|
import com.zy.core.thread.DualCrnThread;
|
import lombok.Data;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.text.MessageFormat;
|
import java.util.Date;
|
import java.util.concurrent.Executors;
|
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* 双工位堆垛机线程
|
*/
|
@Data
|
@Slf4j
|
public class ZySiemensDualCrnThread implements Runnable, DualCrnThread {
|
|
private DeviceConfig deviceConfig;
|
private RedisUtil redisUtil;
|
private ZyDualCrnConnectDriver zyDualCrnConnectDriver;
|
private DualCrnProtocol crnProtocol;
|
private int deviceLogCollectTime = 200;
|
private boolean resetFlag = false;
|
private volatile boolean closed = false;
|
private ScheduledExecutorService readExecutor;
|
private ScheduledExecutorService processExecutor;
|
|
public ZySiemensDualCrnThread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
|
this.deviceConfig = deviceConfig;
|
this.redisUtil = redisUtil;
|
}
|
|
@Override
|
@SuppressWarnings("InfiniteLoopStatement")
|
public void run() {
|
this.connect();
|
this.initCrn();
|
readExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
|
@Override
|
public Thread newThread(Runnable r) {
|
Thread t = new Thread(r);
|
t.setName("DualCrnReader-" + deviceConfig.getDeviceNo());
|
t.setDaemon(true);
|
return t;
|
}
|
});
|
readExecutor.scheduleAtFixedRate(() -> {
|
if (closed || Thread.currentThread().isInterrupted()) {
|
return;
|
}
|
try {
|
deviceLogCollectTime = Utils.getDeviceLogCollectTime();
|
readStatus();
|
} catch (Exception e) {
|
log.error("DualCrnThread Fail", e);
|
}
|
}, 0, 200, TimeUnit.MILLISECONDS);
|
|
processExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
|
@Override
|
public Thread newThread(Runnable r) {
|
Thread t = new Thread(r);
|
t.setName("DualCrnWriter-" + deviceConfig.getDeviceNo());
|
t.setDaemon(true);
|
return t;
|
}
|
});
|
processExecutor.scheduleAtFixedRate(() -> {
|
if (closed || Thread.currentThread().isInterrupted()) {
|
return;
|
}
|
try {
|
int step = 1;
|
Task task = MessageQueue.poll(SlaveType.DualCrn, deviceConfig.getDeviceNo());
|
if (task != null) {
|
step = task.getStep();
|
}
|
if (step == 2 && task != null) {
|
sendCommand((DualCrnCommand) task.getData());
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
}, 0, 200, TimeUnit.MILLISECONDS);
|
}
|
|
/**
|
* 初始化堆垛机状态
|
*/
|
private void initCrn() {
|
if (null == crnProtocol) {
|
crnProtocol = new DualCrnProtocol();
|
crnProtocol.setCrnNo(deviceConfig.getDeviceNo());
|
}
|
crnProtocol.setMode(-1);
|
|
//工位1
|
crnProtocol.setTaskNo(0);
|
crnProtocol.setStatus(-1);
|
crnProtocol.setBay(0);
|
crnProtocol.setLevel(0);
|
crnProtocol.setForkPos(-1);
|
crnProtocol.setLoaded(0);
|
crnProtocol.setWalkPos(0);
|
|
//工位2
|
crnProtocol.setTaskNoTwo(0);
|
crnProtocol.setStatusTwo(-1);
|
crnProtocol.setBayTwo(0);
|
crnProtocol.setLevelTwo(0);
|
crnProtocol.setForkPosTwo(-1);
|
crnProtocol.setLoadedTwo(0);
|
crnProtocol.setWalkPosTwo(0);
|
|
crnProtocol.setAlarm(0);
|
crnProtocol.setXSpeed(0);
|
crnProtocol.setYSpeed(0);
|
crnProtocol.setZSpeed(0);
|
crnProtocol.setXDistance(0);
|
crnProtocol.setYDistance(0);
|
crnProtocol.setXDuration(0);
|
crnProtocol.setYDuration(0);
|
}
|
|
@Override
|
public boolean connect() {
|
zyDualCrnConnectDriver = new ZyDualCrnConnectDriver(deviceConfig);
|
zyDualCrnConnectDriver.start();
|
DeviceConnectPool.put(SlaveType.Crn, deviceConfig.getDeviceNo(), zyDualCrnConnectDriver);
|
return true;
|
}
|
|
/**
|
* 读取状态
|
*/
|
private void readStatus(){
|
ZyDualCrnStatusEntity crnStatus = zyDualCrnConnectDriver.getStatus();
|
if (crnStatus == null) {
|
OutputQueue.DUAL_CRN.offer(MessageFormat.format("【{0}】读取双工位堆垛机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()));
|
return;
|
}
|
|
crnProtocol.setMode(crnStatus.getMode());
|
|
//工位1
|
crnProtocol.setTaskNo(crnStatus.getTaskNo());
|
crnProtocol.setStatus(crnStatus.getStatus());
|
crnProtocol.setBay(crnStatus.getBay());
|
crnProtocol.setLevel(crnStatus.getLevel());
|
crnProtocol.setForkPos(crnStatus.getForkPos());
|
crnProtocol.setLoaded(crnStatus.getLoaded());
|
crnProtocol.setWalkPos(crnStatus.getWalkPos());
|
|
//工位2
|
crnProtocol.setTaskNoTwo(crnStatus.getTaskNoTwo());
|
crnProtocol.setStatusTwo(crnStatus.getStatusTwo());
|
crnProtocol.setBayTwo(crnStatus.getBayTwo());
|
crnProtocol.setLevelTwo(crnStatus.getLevelTwo());
|
crnProtocol.setForkPosTwo(crnStatus.getForkPosTwo());
|
crnProtocol.setLoadedTwo(crnStatus.getLoadedTwo());
|
crnProtocol.setWalkPosTwo(crnStatus.getWalkPosTwo());
|
|
crnProtocol.setAlarm(crnStatus.getAlarm());
|
crnProtocol.setTemp1(crnStatus.getTemp1());
|
crnProtocol.setTemp2(crnStatus.getTemp2());
|
crnProtocol.setTemp3(crnStatus.getTemp3());
|
crnProtocol.setTemp4(crnStatus.getTemp4());
|
crnProtocol.setXSpeed(crnStatus.getXSpeed());
|
crnProtocol.setYSpeed(crnStatus.getYSpeed());
|
crnProtocol.setZSpeed(crnStatus.getZSpeed());
|
crnProtocol.setXDistance(crnStatus.getXDistance());
|
crnProtocol.setYDistance(crnStatus.getYDistance());
|
crnProtocol.setXDuration(crnStatus.getXDuration());
|
crnProtocol.setYDuration(crnStatus.getYDuration());
|
|
OutputQueue.DUAL_CRN.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo()));
|
|
if (crnProtocol.getAlarm() > 0) {
|
crnProtocol.setLastCommandTime(-1L);
|
}
|
|
if (crnProtocol.getAlarm() == 0 && crnProtocol.getLastCommandTime() == -1) {
|
crnProtocol.setLastCommandTime(System.currentTimeMillis());
|
}
|
|
if (System.currentTimeMillis() - crnProtocol.getDeviceDataLog() > deviceLogCollectTime) {
|
//保存数据记录
|
DeviceDataLog deviceDataLog = new DeviceDataLog();
|
deviceDataLog.setOriginData(JSON.toJSONString(crnStatus));
|
deviceDataLog.setWcsData(JSON.toJSONString(crnProtocol));
|
deviceDataLog.setType(String.valueOf(SlaveType.DualCrn));
|
deviceDataLog.setDeviceNo(crnProtocol.getCrnNo());
|
deviceDataLog.setCreateTime(new Date());
|
|
redisUtil.set(RedisKeyType.DEVICE_LOG_KEY.key + System.currentTimeMillis(), deviceDataLog, 60 * 60 * 24);
|
//更新采集时间
|
crnProtocol.setDeviceDataLog(System.currentTimeMillis());
|
}
|
|
BasDualCrnpService basDualCrnpService = null;
|
try {
|
basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class);
|
}catch (Exception e){
|
|
}
|
if (basDualCrnpService != null) {
|
BasDualCrnp basDualCrnp = basDualCrnpService.selectOne(new EntityWrapper<BasDualCrnp>().eq("crn_no", deviceConfig.getDeviceNo()));
|
if(basDualCrnp == null) {
|
basDualCrnp = new BasDualCrnp();
|
basDualCrnp.setCrnNo(deviceConfig.getDeviceNo());
|
basDualCrnp.setStatus(1);
|
basDualCrnp.setInEnable("N");
|
basDualCrnp.setOutEnable("N");
|
basDualCrnp.setMaxInTask(5);
|
basDualCrnp.setMaxOutTask(5);
|
basDualCrnp.setCreateTime(new Date());
|
basDualCrnpService.insert(basDualCrnp);
|
}
|
}
|
}
|
|
@Override
|
public void close() {
|
closed = true;
|
ScheduledExecutorService ex = readExecutor;
|
if (ex != null) {
|
try { ex.shutdownNow(); } catch (Exception ignore) {}
|
}
|
ScheduledExecutorService px = processExecutor;
|
if (px != null) {
|
try { px.shutdownNow(); } catch (Exception ignore) {}
|
}
|
if (zyDualCrnConnectDriver != null) {
|
zyDualCrnConnectDriver.close();
|
}
|
}
|
|
@Override
|
public DualCrnProtocol getStatus() {
|
return this.crnProtocol;
|
}
|
|
@Override
|
public DualCrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo, Integer station) {
|
DualCrnCommand crnCommand = new DualCrnCommand();
|
crnCommand.setCrnNo(crnNo); // 堆垛机编号
|
crnCommand.setTaskNo(taskNo.shortValue()); // 工作号
|
crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE.id.shortValue()); // 任务模式: 库位移转
|
crnCommand.setSourcePosX((short) Utils.getRow(sourceLocNo)); // 源库位排
|
crnCommand.setSourcePosY((short) Utils.getBay(sourceLocNo)); // 源库位列
|
crnCommand.setSourcePosZ((short) Utils.getLev(sourceLocNo)); // 源库位层
|
crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo)); // 目标库位排
|
crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo)); // 目标库位列
|
crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo)); // 目标库位层
|
crnCommand.setStation(station.shortValue());//工位
|
crnCommand.setCommand((short) 1); // 任务确认
|
return crnCommand;
|
}
|
|
@Override
|
public DualCrnCommand getMoveCommand(String targetLocNo, Integer taskNo, Integer crnNo) {
|
DualCrnCommand crnCommand = new DualCrnCommand();
|
crnCommand.setCrnNo(crnNo); // 堆垛机编号
|
crnCommand.setTaskNo(taskNo.shortValue()); // 工作号
|
crnCommand.setAckFinish((short) 0); // 任务完成确认位
|
crnCommand.setTaskMode(CrnTaskModeType.CRN_MOVE.id.shortValue()); // 任务模式: 堆垛机移动
|
crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo)); // 目标库位排
|
crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo)); // 目标库位列
|
crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo)); // 目标库位层
|
crnCommand.setCommand((short) 1); // 任务确认
|
return crnCommand;
|
}
|
|
@Override
|
public DualCrnCommand getResetCommand(Integer crnNo, Integer station) {
|
DualCrnCommand crnCommand = new DualCrnCommand();
|
crnCommand.setCrnNo(crnNo); // 堆垛机编号
|
crnCommand.setTaskNo((short) 0); // 工作号
|
crnCommand.setAckFinish((short) 1); // 任务完成确认位
|
crnCommand.setTaskMode(CrnTaskModeType.NONE.id.shortValue()); // 任务模式
|
crnCommand.setSourcePosX((short)0); // 源库位排
|
crnCommand.setSourcePosY((short)0); // 源库位列
|
crnCommand.setSourcePosZ((short)0); // 源库位层
|
crnCommand.setDestinationPosX((short)0); // 目标库位排
|
crnCommand.setDestinationPosY((short)0); // 目标库位列
|
crnCommand.setDestinationPosZ((short)0); // 目标库位层
|
crnCommand.setStation(station.shortValue());//工位
|
crnCommand.setCommand((short) 1); // 任务确认
|
return crnCommand;
|
}
|
|
@Override
|
public synchronized CommandResponse sendCommand(DualCrnCommand command) {
|
this.crnProtocol.setLastCommandTime(System.currentTimeMillis());
|
CommandResponse response = null;
|
try {
|
response = zyDualCrnConnectDriver.sendCommand(command);
|
return response;
|
} finally {
|
String sourceLocNo = Utils.getLocNo(command.getSourcePosX(), command.getSourcePosY(), command.getSourcePosZ());
|
String targetLocNo = Utils.getLocNo(command.getDestinationPosX(), command.getDestinationPosY(), command.getDestinationPosZ());
|
BasDualCrnpOptService bean = SpringUtils.getBean(BasDualCrnpOptService.class);
|
ZyDualCrnStatusEntity statusEntity = zyDualCrnConnectDriver.getStatus();
|
BasDualCrnpOpt basDualCrnpOpt = new BasDualCrnpOpt(
|
command.getTaskNo().intValue(),
|
command.getCrnNo(),
|
new Date(),
|
String.valueOf(command.getTaskMode()),
|
sourceLocNo,
|
targetLocNo,
|
null,
|
null,
|
null,
|
JSON.toJSONString(command),
|
JSON.toJSONString(statusEntity),
|
1,
|
JSON.toJSONString(response)
|
);
|
if (bean != null) {
|
bean.insert(basDualCrnpOpt);
|
}
|
}
|
}
|
}
|