package com.zy.core.thread.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.core.common.DateUtils;
|
import com.core.common.SpringUtils;
|
import com.zy.asrs.entity.BasDevp;
|
import com.zy.asrs.entity.BasStationOpt;
|
import com.zy.asrs.entity.DeviceConfig;
|
import com.zy.asrs.entity.DeviceDataLog;
|
import com.zy.asrs.service.BasDevpService;
|
import com.zy.asrs.service.BasStationOptService;
|
import com.zy.asrs.utils.Utils;
|
import com.zy.common.model.NavigateNode;
|
import com.zy.common.utils.NavigateUtils;
|
import com.zy.common.utils.RedisUtil;
|
import com.zy.core.cache.MessageQueue;
|
import com.zy.core.cache.OutputQueue;
|
import com.zy.core.cache.SlaveConnection;
|
import com.zy.core.enums.RedisKeyType;
|
import com.zy.core.enums.SlaveType;
|
import com.zy.core.enums.StationCommandType;
|
import com.zy.core.model.CommandResponse;
|
import com.zy.core.model.Task;
|
import com.zy.core.model.command.StationCommand;
|
import com.zy.core.model.protocol.StationProtocol;
|
import com.zy.core.network.DeviceConnectPool;
|
import com.zy.core.network.ZyStationConnectDriver;
|
import com.zy.core.network.entity.ZyStationStatusEntity;
|
import lombok.Data;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.text.MessageFormat;
|
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.Executors;
|
import java.util.ArrayList;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
@Data
|
@Slf4j
|
public class ZyStationV3Thread implements Runnable, com.zy.core.thread.StationThread {
|
|
private List<StationProtocol> statusList = new ArrayList<>();
|
private DeviceConfig deviceConfig;
|
private RedisUtil redisUtil;
|
private ZyStationConnectDriver zyStationConnectDriver;
|
private int deviceLogCollectTime = 200;
|
private long deviceDataLogTime = System.currentTimeMillis();
|
private ExecutorService executor = Executors.newFixedThreadPool(9999);
|
|
public ZyStationV3Thread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
|
this.deviceConfig = deviceConfig;
|
this.redisUtil = redisUtil;
|
}
|
|
@Override
|
@SuppressWarnings("InfiniteLoopStatement")
|
public void run() {
|
this.connect();
|
deviceLogCollectTime = Utils.getDeviceLogCollectTime();
|
|
Thread readThread = new Thread(() -> {
|
while (true) {
|
try {
|
deviceLogCollectTime = Utils.getDeviceLogCollectTime();
|
readStatus();
|
Thread.sleep(100);
|
} catch (Exception e) {
|
log.error("StationV3Thread Fail", e);
|
}
|
}
|
});
|
readThread.start();
|
|
Thread processThread = new Thread(() -> {
|
while (true) {
|
try {
|
int step = 1;
|
Task task = MessageQueue.poll(SlaveType.Devp, deviceConfig.getDeviceNo());
|
if (task != null) {
|
step = task.getStep();
|
}
|
if (step == 2) {
|
StationCommand cmd = (StationCommand) task.getData();
|
executor.submit(() -> executeMoveWithSeg(cmd));
|
}
|
Thread.sleep(100);
|
} catch (Exception e) {
|
log.error("StationV3Process Fail", e);
|
}
|
}
|
});
|
processThread.start();
|
}
|
|
private void readStatus() {
|
if (zyStationConnectDriver == null) {
|
return;
|
}
|
|
if (statusList.isEmpty()) {
|
BasDevpService basDevpService = null;
|
try {
|
basDevpService = SpringUtils.getBean(BasDevpService.class);
|
} catch (Exception e) {
|
}
|
if (basDevpService == null) {
|
return;
|
}
|
|
BasDevp basDevp = basDevpService
|
.selectOne(new EntityWrapper<BasDevp>().eq("devp_no", deviceConfig.getDeviceNo()));
|
if (basDevp == null) {
|
return;
|
}
|
|
List<ZyStationStatusEntity> list = JSONObject.parseArray(basDevp.getStationList(), ZyStationStatusEntity.class);
|
for (ZyStationStatusEntity entity : list) {
|
StationProtocol stationProtocol = new StationProtocol();
|
stationProtocol.setStationId(entity.getStationId());
|
statusList.add(stationProtocol);
|
}
|
}
|
|
List<ZyStationStatusEntity> zyStationStatusEntities = zyStationConnectDriver.getStatus();
|
for (ZyStationStatusEntity statusEntity : zyStationStatusEntities) {
|
for (StationProtocol stationProtocol : statusList) {
|
if (stationProtocol.getStationId().equals(statusEntity.getStationId())) {
|
stationProtocol.setTaskNo(statusEntity.getTaskNo());
|
stationProtocol.setTargetStaNo(statusEntity.getTargetStaNo());
|
stationProtocol.setAutoing(statusEntity.isAutoing());
|
stationProtocol.setLoading(statusEntity.isLoading());
|
stationProtocol.setInEnable(statusEntity.isInEnable());
|
stationProtocol.setOutEnable(statusEntity.isOutEnable());
|
stationProtocol.setEmptyMk(statusEntity.isEmptyMk());
|
stationProtocol.setFullPlt(statusEntity.isFullPlt());
|
stationProtocol.setPalletHeight(statusEntity.getPalletHeight());
|
stationProtocol.setError(statusEntity.getError());
|
stationProtocol.setBarcode(statusEntity.getBarcode());
|
stationProtocol.setRunBlock(statusEntity.isRunBlock());
|
stationProtocol.setEnableIn(statusEntity.isEnableIn());
|
}
|
}
|
}
|
|
OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), deviceConfig.getDeviceNo()));
|
|
if (System.currentTimeMillis() - deviceDataLogTime > deviceLogCollectTime) {
|
DeviceDataLog deviceDataLog = new DeviceDataLog();
|
deviceDataLog.setOriginData(JSON.toJSONString(zyStationStatusEntities));
|
deviceDataLog.setWcsData(JSON.toJSONString(statusList));
|
deviceDataLog.setType(String.valueOf(SlaveType.Devp));
|
deviceDataLog.setDeviceNo(deviceConfig.getDeviceNo());
|
deviceDataLog.setCreateTime(new Date());
|
|
redisUtil.set(RedisKeyType.DEVICE_LOG_KEY.key + System.currentTimeMillis(), deviceDataLog, 60 * 60 * 24);
|
deviceDataLogTime = System.currentTimeMillis();
|
}
|
}
|
|
@Override
|
public boolean connect() {
|
zyStationConnectDriver = new ZyStationConnectDriver(deviceConfig, redisUtil);
|
zyStationConnectDriver.start();
|
DeviceConnectPool.put(SlaveType.Devp, deviceConfig.getDeviceNo(), zyStationConnectDriver);
|
return true;
|
}
|
|
@Override
|
public void close() {
|
if (zyStationConnectDriver != null) {
|
zyStationConnectDriver.close();
|
}
|
if (executor != null) {
|
try { executor.shutdownNow(); } catch (Exception ignore) {}
|
}
|
}
|
|
@Override
|
public List<StationProtocol> getStatus() {
|
return statusList;
|
}
|
|
@Override
|
public Map<Integer, StationProtocol> getStatusMap() {
|
Map<Integer, StationProtocol> map = new HashMap<>();
|
for (StationProtocol stationProtocol : statusList) {
|
map.put(stationProtocol.getStationId(), stationProtocol);
|
}
|
return map;
|
}
|
|
@Override
|
public StationCommand getCommand(StationCommandType commandType, Integer taskNo, Integer stationId, Integer targetStationId, Integer palletSize) {
|
StationCommand stationCommand = new StationCommand();
|
stationCommand.setTaskNo(taskNo);
|
stationCommand.setStationId(stationId);
|
stationCommand.setTargetStaNo(targetStationId);
|
stationCommand.setPalletSize(palletSize);
|
stationCommand.setCommandType(commandType);
|
|
if (commandType == StationCommandType.MOVE) {
|
if (!stationId.equals(targetStationId)) {
|
List<Integer> path = calcPathStationIds(stationId, targetStationId);
|
stationCommand.setNavigatePath(path);
|
}
|
}
|
return stationCommand;
|
}
|
|
@Override
|
public CommandResponse sendCommand(StationCommand command) {
|
CommandResponse commandResponse = null;
|
try {
|
commandResponse = zyStationConnectDriver.sendCommand(command);
|
return commandResponse;
|
} finally {
|
BasStationOptService optService = SpringUtils.getBean(BasStationOptService.class);
|
List<ZyStationStatusEntity> statusListEntity = zyStationConnectDriver.getStatus();
|
ZyStationStatusEntity matched = null;
|
if (statusListEntity != null) {
|
for (ZyStationStatusEntity e : statusListEntity) {
|
if (e.getStationId() != null && e.getStationId().equals(command.getStationId())) {
|
matched = e;
|
break;
|
}
|
}
|
}
|
BasStationOpt basStationOpt = new BasStationOpt(
|
command.getTaskNo(),
|
command.getStationId(),
|
new Date(),
|
String.valueOf(command.getCommandType()),
|
command.getStationId(),
|
command.getTargetStaNo(),
|
null,
|
null,
|
null,
|
JSON.toJSONString(command),
|
JSON.toJSONString(matched),
|
1,
|
JSON.toJSONString(commandResponse)
|
);
|
if (optService != null) {
|
optService.insert(basStationOpt);
|
}
|
}
|
}
|
|
@Override
|
public CommandResponse sendOriginCommand(String address, short[] data) {
|
return zyStationConnectDriver.sendOriginCommand(address, data);
|
}
|
|
@Override
|
public byte[] readOriginCommand(String address, int length) {
|
return zyStationConnectDriver.readOriginCommand(address, length);
|
}
|
|
private List<Integer> calcPathStationIds(Integer startStationId, Integer targetStationId) {
|
NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class);
|
if (navigateUtils == null) {
|
return new ArrayList<>();
|
}
|
List<NavigateNode> nodes = navigateUtils.calcByStationId(startStationId, targetStationId);
|
List<Integer> ids = new ArrayList<>();
|
for (NavigateNode n : nodes) {
|
JSONObject v = JSONObject.parseObject(n.getNodeValue());
|
if (v != null) {
|
ids.add(v.getInteger("stationId"));
|
}
|
}
|
return ids;
|
}
|
|
private void executeMoveWithSeg(StationCommand original) {
|
if(original.getCommandType() == StationCommandType.MOVE){
|
List<Integer> path = original.getNavigatePath();
|
if (path == null || path.isEmpty()) {
|
path = calcPathStationIds(original.getStationId(), original.getTargetStaNo());
|
}
|
if (path == null || path.isEmpty()) {
|
return;
|
}
|
|
int total = path.size();
|
List<Integer> segmentTargets = new ArrayList<>();
|
List<Integer> segmentEndIndices = new ArrayList<>();
|
int idx = 0;
|
while (idx < total) {
|
int end = Math.min(idx + 20, total) - 1;
|
segmentTargets.add(path.get(end));
|
segmentEndIndices.add(end);
|
idx = end + 1;
|
}
|
|
int segCursor = 0;
|
Integer currentTarget = segmentTargets.get(segCursor);
|
Integer currentEndIdx = segmentEndIndices.get(segCursor);
|
Integer currentStartIdx = 0;
|
|
StationCommand segCmd = new StationCommand();
|
segCmd.setTaskNo(original.getTaskNo());
|
segCmd.setStationId(original.getStationId());
|
segCmd.setTargetStaNo(original.getTargetStaNo());
|
segCmd.setCommandType(original.getCommandType());
|
segCmd.setPalletSize(original.getPalletSize());
|
segCmd.setNavigatePath(new ArrayList<>(path.subList(0, currentEndIdx + 1)));
|
sendCommand(segCmd);
|
|
boolean finished = false;
|
while (!finished) {
|
try {
|
Integer currentStationId = findCurrentStationByTask(original.getTaskNo());
|
if (currentStationId == null) {
|
Thread.sleep(500);
|
continue;
|
}
|
int currentIndex = path.indexOf(currentStationId);
|
if (currentIndex < 0) {
|
Thread.sleep(500);
|
continue;
|
}
|
int remaining = total - currentIndex - 1;
|
if (remaining <= 0) {
|
finished = true;
|
break;
|
}
|
int currentSegEndIndex = path.indexOf(segmentTargets.get(segCursor));
|
int currentSegStartIndex = segCursor == 0 ? 0 : path.indexOf(segmentTargets.get(segCursor - 1)) + 1;
|
int segLen = currentSegEndIndex - currentSegStartIndex + 1;
|
int remainingSegment = Math.max(0, currentSegEndIndex - currentIndex);
|
int thresholdSegment = (int) Math.ceil(segLen * 0.3);
|
if (remainingSegment <= thresholdSegment && segCursor < segmentTargets.size() - 1) {
|
segCursor++;
|
currentEndIdx = segmentEndIndices.get(segCursor);
|
currentStartIdx = segmentEndIndices.get(segCursor - 1) + 1;
|
|
StationCommand nextCmd = new StationCommand();
|
nextCmd.setTaskNo(original.getTaskNo());
|
nextCmd.setStationId(original.getStationId());
|
nextCmd.setTargetStaNo(original.getTargetStaNo());
|
nextCmd.setCommandType(original.getCommandType());
|
nextCmd.setPalletSize(original.getPalletSize());
|
nextCmd.setNavigatePath(new ArrayList<>(path.subList(currentStartIdx, currentEndIdx + 1)));
|
sendCommand(nextCmd);
|
}
|
Thread.sleep(500);
|
} catch (Exception e) {
|
break;
|
}
|
}
|
}else {
|
sendCommand(original);
|
}
|
}
|
|
private Integer findCurrentStationByTask(Integer taskNo) {
|
try {
|
com.zy.asrs.service.DeviceConfigService deviceConfigService = SpringUtils.getBean(com.zy.asrs.service.DeviceConfigService.class);
|
if (deviceConfigService == null) {
|
return null;
|
}
|
List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
|
.eq("device_type", String.valueOf(SlaveType.Devp)));
|
for (DeviceConfig dc : devpList) {
|
com.zy.core.thread.StationThread t = (com.zy.core.thread.StationThread) SlaveConnection.get(SlaveType.Devp, dc.getDeviceNo());
|
if (t == null) {
|
continue;
|
}
|
Map<Integer, StationProtocol> m = t.getStatusMap();
|
if (m == null || m.isEmpty()) {
|
continue;
|
}
|
for (StationProtocol sp : m.values()) {
|
if (sp.getTaskNo() != null && sp.getTaskNo().equals(taskNo) && sp.isLoading()) {
|
return sp.getStationId();
|
}
|
}
|
}
|
} catch (Exception e) {
|
return null;
|
}
|
return null;
|
}
|
}
|