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 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().eq("devp_no", deviceConfig.getDeviceNo())); if (basDevp == null) { return; } List list = JSONObject.parseArray(basDevp.getStationList(), ZyStationStatusEntity.class); for (ZyStationStatusEntity entity : list) { StationProtocol stationProtocol = new StationProtocol(); stationProtocol.setStationId(entity.getStationId()); statusList.add(stationProtocol); } } List 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.setErrorMsg(statusEntity.getErrorMsg()); stationProtocol.setBarcode(statusEntity.getBarcode()); stationProtocol.setRunBlock(statusEntity.isRunBlock()); stationProtocol.setEnableIn(statusEntity.isEnableIn()); stationProtocol.setWeight(statusEntity.getWeight()); } } } 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 getStatus() { return statusList; } @Override public Map getStatusMap() { Map 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 path = calcPathStationIds(stationId, targetStationId); stationCommand.setNavigatePath(path); } } return stationCommand; } @Override public CommandResponse sendCommand(StationCommand command) { CommandResponse commandResponse = null; try { commandResponse = zyStationConnectDriver.sendCommand(command); } catch (Exception e) { e.printStackTrace(); } finally { BasStationOptService optService = SpringUtils.getBean(BasStationOptService.class); List 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); } } return commandResponse; } @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 calcPathStationIds(Integer startStationId, Integer targetStationId) { NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class); if (navigateUtils == null) { return new ArrayList<>(); } List nodes = navigateUtils.calcByStationId(startStationId, targetStationId); List 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 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 segmentTargets = new ArrayList<>(); List segmentEndIndices = new ArrayList<>(); int idx = 0; while (idx < total) { int end = Math.min(idx + 3, 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); long runTime = System.currentTimeMillis(); while (true) { try { StationProtocol currentStation = findCurrentStationByTask(original.getTaskNo()); if (currentStation == null) { if(System.currentTimeMillis() - runTime > 1000 * 60){ break; } Thread.sleep(500); continue; } runTime = System.currentTimeMillis(); if (currentStation.isRunBlock()) { break; } int currentIndex = path.indexOf(currentStation.getStationId()); if (currentIndex < 0) { Thread.sleep(500); continue; } int remaining = total - currentIndex - 1; if (remaining <= 0) { 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 StationProtocol findCurrentStationByTask(Integer taskNo) { try { com.zy.asrs.service.DeviceConfigService deviceConfigService = SpringUtils.getBean(com.zy.asrs.service.DeviceConfigService.class); if (deviceConfigService == null) { return null; } List devpList = deviceConfigService.selectList(new EntityWrapper() .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 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; } } } } catch (Exception e) { return null; } return null; } }