| package com.zy.core.thread; | 
|   | 
| import com.alibaba.fastjson.JSON; | 
| import com.alibaba.fastjson.JSONObject; | 
| import com.core.common.DateUtils; | 
| import com.core.common.SpringUtils; | 
| import com.zy.asrs.entity.*; | 
| import com.zy.asrs.mapper.WrkMastMapper; | 
| import com.zy.asrs.service.*; | 
|   | 
| import com.zy.asrs.utils.Utils; | 
| import com.zy.common.model.NavigateNode; | 
| import com.zy.common.service.CommonService; | 
| import com.zy.common.utils.*; | 
| import com.zy.core.News; | 
| import com.zy.core.ThreadHandler; | 
| import com.zy.core.cache.MessageQueue; | 
| import com.zy.core.cache.OutputQueue; | 
| import com.zy.core.cache.SlaveConnection; | 
| import com.zy.core.enums.*; | 
| import com.zy.core.model.LiftSlave; | 
| import com.zy.core.model.ShuttleSlave; | 
| import com.zy.core.model.Task; | 
| import com.zy.core.model.command.*; | 
| import com.zy.core.model.protocol.LiftProtocol; | 
| import com.zy.core.model.protocol.NyShuttleProtocol; | 
| import com.zy.core.properties.SlaveProperties; | 
| import lombok.Data; | 
| import lombok.extern.slf4j.Slf4j; | 
|   | 
| import java.io.IOException; | 
| import java.net.Socket; | 
| import java.text.MessageFormat; | 
| import java.util.ArrayList; | 
| import java.util.Date; | 
| import java.util.HashMap; | 
| import java.util.List; | 
|   | 
| /** | 
|  * 牛眼四向穿梭车线程 | 
|  */ | 
| @Data | 
| @Slf4j | 
| public class NyShuttleThread implements  Runnable, ThreadHandler { | 
|   | 
|     private ShuttleSlave slave; | 
|     private NyShuttleProtocol shuttleProtocol; | 
|     private RedisUtil redisUtil; | 
|     private Socket socket; | 
|   | 
|     public NyShuttleThread(ShuttleSlave slave,RedisUtil redisUtil) { | 
|         this.slave = slave; | 
|         this.redisUtil = redisUtil; | 
|     } | 
|   | 
|     @Override | 
|     public void run() { | 
|         this.connect(); | 
|         while (true) { | 
|             try { | 
|                 int step = 1; | 
|                 Task task = MessageQueue.poll(SlaveType.Shuttle, slave.getId()); | 
|                 if (task != null) { | 
|                     step = task.getStep(); | 
|                 } | 
|                 switch (step) { | 
|                     // 读数据 | 
|                     case 1: | 
|                         read(); | 
|                         break; | 
| //                    // 写入数据 | 
| //                    case 2: | 
| //                        write((NyShuttleHttpCommand) task.getData()); | 
| //                        break; | 
|                     //下发任务 | 
|                     case 3: | 
|                         assignWork((ShuttleAssignCommand) task.getData()); | 
|                         break; | 
|                     default: | 
|                         break; | 
|                 } | 
|                 Thread.sleep(500); | 
|             } catch (Exception e) { | 
|                 e.printStackTrace(); | 
|             } | 
|         } | 
|     } | 
|   | 
|     private void read() { | 
|         try { | 
|             if (this.socket == null || this.socket.isClosed()) { | 
|                 //链接断开重新链接 | 
|                 this.connect(); | 
|             } | 
|             readStatus(); | 
|             //四向穿梭车空闲、有任务、标记为true、存在任务指令,需要执行任务的下一条指令 | 
|             if (shuttleProtocol.getFree() == ShuttleStatusType.IDLE.id | 
|                     && shuttleProtocol.getTaskNo() != 0 | 
|                     && !shuttleProtocol.getPakMk()) { | 
|                 //执行下一步指令 | 
|                 executeWork(shuttleProtocol.getTaskNo().shortValue()); | 
|             } | 
|   | 
|             //小车空闲且有跑库程序 | 
|             if (shuttleProtocol.isIdle() && shuttleProtocol.getMoveLoc()) { | 
|                 moveLoc(); | 
|             } | 
|         } catch (Exception e) { | 
|             e.printStackTrace(); | 
|             OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向穿梭车plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort())); | 
|         } | 
|     } | 
|   | 
|     private void readStatus() { | 
|         try { | 
|             //----------读取四向穿梭车状态----------- | 
|             NyShuttleHttpCommand readStatusCommand = NyHttpUtils.getReadStatusCommand(slave.getId()); | 
|             JSONObject jsonObject = NyHttpUtils.requestCommand(socket, readStatusCommand); | 
|             if (jsonObject == null) { | 
|                 shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.OFFLINE); | 
|                 OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向穿梭车Socket状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort())); | 
|             }else { | 
|                 //手动状态/自动状态 | 
|                 shuttleProtocol.setWorkingMode(jsonObject.getInteger("workingMode")); | 
|                 //允许状态 0:运行中1:空闲 | 
|                 shuttleProtocol.setFree(jsonObject.getInteger("free")); | 
|                 //当前速度 | 
|                 shuttleProtocol.setSpeed(jsonObject.getInteger("speed")); | 
|                 //负载状态 | 
|                 shuttleProtocol.setLoadState(jsonObject.getInteger("loadState")); | 
|                 //管制状态 | 
|                 shuttleProtocol.setSuspendState(jsonObject.getInteger("suspendState")); | 
|                 //顶升位置 | 
|                 shuttleProtocol.setLiftPosition(jsonObject.getInteger("liftPosition")); | 
|                 //运行方向 | 
|                 shuttleProtocol.setRunDir(jsonObject.getInteger("runDir")); | 
|                 //运行方向 | 
|                 shuttleProtocol.setRunDir2(jsonObject.getInteger("runDir2")); | 
|                 //充电状态 | 
|                 shuttleProtocol.setChargState(jsonObject.getInteger("chargState")); | 
|                 //电池电量 | 
|                 shuttleProtocol.setPowerPercent(jsonObject.getInteger("powerPercent")); | 
|                 //最高电芯电压(mV) | 
|                 shuttleProtocol.setMaxCellVoltage(jsonObject.getInteger("maxCellVoltage")); | 
|                 //最低电芯电压(mV) | 
|                 shuttleProtocol.setMinCellVoltage(jsonObject.getInteger("minCellVoltage")); | 
|                 //电池电压 | 
|                 shuttleProtocol.setVoltage(jsonObject.getInteger("voltage")); | 
|                 //充放电循环次数 | 
|                 shuttleProtocol.setChargeCycleTimes(jsonObject.getInteger("chargeCycleTimes")); | 
|                 //剩余电量 | 
|                 shuttleProtocol.setSurplusQuantity(jsonObject.getInteger("surplusQuantity")); | 
|                 //总电量 | 
|                 shuttleProtocol.setCountQuantity(jsonObject.getInteger("countQuantity")); | 
|                 //实际库位xyz | 
|                 shuttleProtocol.setPoint(jsonObject.getObject("point", NyShuttleProtocol.NyShuttlePointClass.class)); | 
|                 //实际坐标xyz | 
|                 shuttleProtocol.setCoord(jsonObject.getObject("coord", NyShuttleProtocol.NyShuttlePointClass.class)); | 
|                 //任务目的库位 | 
|                 shuttleProtocol.setTask(jsonObject.getObject("task", NyShuttleProtocol.TaskClass.class)); | 
|                 //任务状态 | 
|                 shuttleProtocol.setTaskState(jsonObject.getInteger("taskState")); | 
|                 //故障状态 | 
|                 shuttleProtocol.setErrState(jsonObject.getInteger("errState")); | 
|                 ArrayList<Integer> errCode = new ArrayList<>(); | 
|                 for (Object o : jsonObject.getJSONArray("errCode")) { | 
|                     errCode.add(Integer.parseInt(o.toString())); | 
|                 } | 
|                 //故障码 | 
|                 shuttleProtocol.setErrCode(errCode.get(0)); | 
|                 //总里程数 | 
|                 shuttleProtocol.setStatusSum(jsonObject.getObject("statusSum", NyShuttleProtocol.StatusSumClass.class)); | 
|                 //非自动状态时间计时 | 
|                 shuttleProtocol.setErrTime(jsonObject.getInteger("errTime")); | 
|   | 
|                 //小车处于运行中,将标记置为false | 
|                 if (shuttleProtocol.getFree() == 0) { | 
|                     shuttleProtocol.setPakMk(false); | 
|                 } | 
|   | 
|                 //将四向穿梭车状态保存至数据库 | 
|                 BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class); | 
|                 BasShuttle basShuttle = shuttleService.selectById(slave.getId()); | 
|                 if (basShuttle == null) { | 
|                     basShuttle = new BasShuttle(); | 
|                     //四向穿梭车号 | 
|                     basShuttle.setShuttleNo(slave.getId()); | 
|                     shuttleService.insert(basShuttle); | 
|                 } | 
|                 //工作模式 | 
|                 basShuttle.setWorkingMode(shuttleProtocol.getWorkingMode()); | 
|                 //运行状态 | 
|                 basShuttle.setFree(shuttleProtocol.getFree()); | 
|                 //当前速度 | 
|                 basShuttle.setSpeed(shuttleProtocol.getSpeed()); | 
|                 //负载状态 | 
|                 basShuttle.setLoadState(shuttleProtocol.getLoadState()); | 
|                 //管制状态 | 
|                 basShuttle.setSuspendState(shuttleProtocol.getSuspendState()); | 
|                 //顶升位置 | 
|                 basShuttle.setLiftPosition(shuttleProtocol.getLiftPosition()); | 
|                 //运行方向 | 
|                 basShuttle.setRunDir(shuttleProtocol.getRunDir()); | 
|                 //运行方向 | 
|                 basShuttle.setRunDir2(shuttleProtocol.getRunDir2()); | 
|                 //充电状态 | 
|                 basShuttle.setChargState(shuttleProtocol.getChargState()); | 
|                 //电池电量 | 
|                 basShuttle.setPowerPercent(shuttleProtocol.getPowerPercent()); | 
|                 //最高电芯电压 | 
|                 basShuttle.setMaxCellVoltage(shuttleProtocol.getMaxCellVoltage()); | 
|                 //电池电压 | 
|                 basShuttle.setVoltage(shuttleProtocol.getVoltage()); | 
|                 //充放电循环次数 | 
|                 basShuttle.setChargeCycleTimes(shuttleProtocol.getChargeCycleTimes()); | 
|                 //剩余电量 | 
|                 basShuttle.setSurplusQuantity(shuttleProtocol.getSurplusQuantity()); | 
|                 //总电量 | 
|                 basShuttle.setCountQuantity(shuttleProtocol.getCountQuantity()); | 
|                 //实际库位 | 
|                 basShuttle.setPoint(JSONObject.toJSONString(shuttleProtocol.getPoint())); | 
|                 //实际坐标 | 
|                 basShuttle.setCoord(JSONObject.toJSONString(shuttleProtocol.getCoord())); | 
|                 //任务目的库位 | 
|                 basShuttle.setTask(JSONObject.toJSONString(shuttleProtocol.getTask())); | 
|                 //任务状态 | 
|                 basShuttle.setTaskState(shuttleProtocol.getTaskState()); | 
|                 //故障状态 | 
|                 basShuttle.setErrState(shuttleProtocol.getErrState()); | 
|                 //总里程数 | 
|                 basShuttle.setStatusSum(JSONObject.toJSONString(shuttleProtocol.getStatusSum())); | 
|                 //非自动状态时间计时 | 
|                 basShuttle.setErrTime(shuttleProtocol.getErrTime()); | 
|                 //任务号 | 
|                 basShuttle.setWrkNo(shuttleProtocol.getTaskNo().intValue()); | 
|                 //修改时间 | 
|                 basShuttle.setUpdateTime(new Date()); | 
|                 //作业标记 | 
|                 basShuttle.setPakMk(shuttleProtocol.getPakMk()); | 
|                 if (shuttleService.updateById(basShuttle)) { | 
|                     OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), slave.getId())); | 
| //                    log.info(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), slave.getId())); | 
|                 } | 
| //                log.warn(JSON.toJSONString(shuttleProtocol));//输出小车状态 | 
|             } | 
|         } catch (Exception e) { | 
|             e.printStackTrace(); | 
|             OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向穿梭车Socket状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort())); | 
|             try { | 
|                 this.socket.close(); | 
|                 this.socket = null; | 
|                 Thread.sleep(1000); | 
|                 this.connect(); | 
|             } catch (IOException | InterruptedException exception) { | 
|                 e.printStackTrace(); | 
|             } | 
|         } | 
|     } | 
|   | 
|     @Override | 
|     public boolean connect() { | 
|         try { | 
|             Socket socket = new Socket(slave.getIp(),slave.getPort()); | 
|             socket.setSoTimeout(60000); | 
|             socket.setKeepAlive(true); | 
|             this.socket = socket; | 
|             if (null == shuttleProtocol) { | 
|                 shuttleProtocol = new NyShuttleProtocol(); | 
|                 shuttleProtocol.setShuttleNo(slave.getId().shortValue()); | 
|             } | 
|             shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE); | 
|             log.info(MessageFormat.format("【{0}】四向穿梭车Socket链接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort())); | 
|         } catch (IOException e) { | 
|             OutputQueue.SHUTTLE.offer(MessageFormat.format("【{0}】四向穿梭车Socket链接失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort())); | 
|         } | 
|         return true; | 
|     } | 
|   | 
|     @Override | 
|     public void close() { | 
|   | 
|     } | 
|   | 
|     private boolean write(NyShuttleHttpCommand command, ShuttleAssignCommand assignCommand) { | 
|         if (null == command) { | 
|             News.error("四向穿梭车写入命令为空"); | 
|             return false; | 
|         } | 
|         BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class); | 
|         if (shuttleService == null) { | 
|             News.error("系统错误"); | 
|             return false; | 
|         } | 
|   | 
|         BasShuttle basShuttle = shuttleService.selectById(slave.getId().shortValue()); | 
|         if (basShuttle == null) { | 
|             News.error("四向穿梭车不存在"); | 
|             return false; | 
|         } | 
|   | 
|         //发出请求 | 
|         JSONObject result = null; | 
|         try { | 
|             result = NyHttpUtils.requestCommand(socket, command); | 
|         } catch (IOException e) { | 
|             try { | 
|                 this.socket.close(); | 
|                 this.socket = null; | 
|                 Thread.sleep(1000); | 
|                 this.connect(); | 
|             } catch (IOException exception) { | 
|                 exception.printStackTrace(); | 
|             } catch (InterruptedException ex) { | 
|                 throw new RuntimeException(ex); | 
|             } | 
|         } | 
|   | 
|         //保存数据到数据库做流水 | 
|         BasShuttleOptService shuttleOptService = SpringUtils.getBean(BasShuttleOptService.class); | 
|         BasShuttleOpt opt = null; | 
|         if (shuttleOptService != null) { | 
|             opt = new BasShuttleOpt( | 
|                     assignCommand.getTaskNo().intValue(), | 
|                     assignCommand.getShuttleNo().intValue(), | 
|                     new Date(), | 
|                     ShuttleTaskModeType.get(assignCommand.getTaskMode()).desc, | 
|                     assignCommand.getSourceLocNo(), | 
|                     assignCommand.getLocNo(), | 
|                     null, | 
|                     null, | 
|                     null, | 
|                     JSON.toJSONString(command), | 
|                     null, | 
|                     JSON.toJSONString(shuttleProtocol) | 
|             ); | 
|             opt.setSend(1);//已下发 | 
|             opt.setResponse(JSON.toJSONString(result));//请求响应 | 
|             opt.setDeviceWrk(command.getWrkNo().toString());//设备工作号 | 
|             shuttleOptService.insert(opt); | 
|         } | 
|   | 
|         if (result == null) { | 
|             return false;//请求失败 | 
|         } | 
|   | 
|         shuttleProtocol.setSendTime(System.currentTimeMillis());//指令下发时间 | 
|   | 
|         return true; | 
|     } | 
|   | 
|     //分配任务 | 
|     private void assignWork(ShuttleAssignCommand assignCommand) { | 
|         ShuttleRedisCommand redisCommand = new ShuttleRedisCommand(); | 
|         redisCommand.setShuttleNo(assignCommand.getShuttleNo());//四向穿梭车号 | 
|         redisCommand.setWrkNo(assignCommand.getTaskNo());//工作号 | 
|         redisCommand.setCommandStep(0);//命令执行步序 | 
|         redisCommand.setAssignCommand(assignCommand);//命令 | 
|         shuttleProtocol.setTaskNo(assignCommand.getTaskNo().intValue()); | 
|         shuttleProtocol.setAssignCommand(assignCommand); | 
|         shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.WORKING); | 
|         //任务数据保存到redis | 
|         redisUtil.set(RedisKeyType.SHUTTLE.key + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand)); | 
|         //执行下发任务 | 
|         executeWork(assignCommand.getTaskNo()); | 
|     } | 
|   | 
|     //执行下发的指令 | 
|     private boolean executeWork(Short wrkNo) { | 
|         //读取redis数据 | 
|         if (wrkNo == null) { | 
|             return false; | 
|         } | 
|   | 
|         NavigateMapUtils navigateMapUtils = SpringUtils.getBean(NavigateMapUtils.class); | 
|         WrkMastMapper wrkMastMapper = SpringUtils.getBean(WrkMastMapper.class); | 
|         WrkMast wrkMast = wrkMastMapper.selectByWorkNo(wrkNo.intValue()); | 
|   | 
|         Object o = redisUtil.get(RedisKeyType.SHUTTLE.key + wrkNo); | 
|         if (o == null) { | 
|             return false; | 
|         } | 
|   | 
|         ShuttleRedisCommand redisCommand = JSON.parseObject(o.toString(), ShuttleRedisCommand.class); | 
|         ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand(); | 
|         List<NyShuttleHttpCommand> commands = redisCommand.getAssignCommand().getCommands(); | 
|         //当前步序 | 
|         int commandStep = redisCommand.getCommandStep(); | 
|         if (commands.size() == 0) { | 
|             return false; | 
|         } | 
|   | 
|         checkIOSta(commands, commandStep);//检测小车是否进出提升机输送站 | 
|   | 
|         boolean isLock = false;//是否解锁路径 | 
|         //取出命令 | 
|         NyShuttleHttpCommand command = null; | 
|         if (commandStep < commands.size()) { | 
|             command = commands.get(commandStep);//当前命令 | 
|         } | 
|         if (commandStep != 0) { | 
|             //判断上一条指令是否完成 | 
|             NyShuttleHttpCommand lastCommand = commands.get(commandStep - 1); | 
|             String requestType = lastCommand.getRequest().getBody().get("requestType").toString(); | 
|             if (requestType.equals("move") || requestType.equals("intoLift") || requestType.equals("outLift")) { | 
|                 //移动命令、出入提升机命令 | 
|                 NyShuttleProtocol.NyShuttlePointClass target = JSON.parseObject(lastCommand.getRequest().getBody().get("target").toString(), NyShuttleProtocol.NyShuttlePointClass.class); | 
|                 if (shuttleProtocol.getPoint().equals(target)) { | 
|                     //上一条指令的目标位置和当前小车位置相同,则认定上一条任务完成 | 
|                     lastCommand.setComplete(true); | 
|                     //解锁锁定路径,上一条路径 | 
|                     List<NavigateNode> nodes = JSON.parseArray(JSON.toJSONString(lastCommand.getNodes()), NavigateNode.class);//进行深度copy | 
| //                    //解锁当前路径 | 
| //                    if (command != null && command.getNodes() != null) { | 
| //                        nodes.addAll(command.getNodes()); | 
| //                    } | 
|                     if (nodes != null) { | 
|                         NavigateNode targetNode = assignCommand.getNodes().get(assignCommand.getNodes().size() - 1);//最终节点 | 
|                         NavigateNode node = nodes.get(nodes.size() - 1); | 
|                         if (!(targetNode.getX() == node.getX() && targetNode.getY() == node.getY())) { | 
|                             nodes.remove(nodes.size() - 1);//剔除尾节点 | 
|                         } | 
|                         boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(shuttleProtocol.getCurrentLocNo()), nodes, false);//解锁路径 | 
|                         if (!result) { | 
|                             return false;//解锁失败 | 
|                         } | 
|                         isLock = true;//解锁过路径 | 
|                     } | 
|                 } | 
|             }else { | 
|                 lastCommand.setComplete(true);//其他命令默认认为完成 | 
|             } | 
|             //任务数据保存到redis | 
|             redisUtil.set(RedisKeyType.SHUTTLE.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand)); | 
|   | 
|             if (!lastCommand.getComplete()) { | 
|                 //上一条任务未完成,禁止下发命令 | 
|                 return false; | 
|             } | 
|   | 
|             //判断是否为最后一条命令且命令执行完成,抛出等待确认状态 | 
|             NyShuttleHttpCommand endCommand = commands.get(commands.size() - 1); | 
|             if (endCommand.getComplete()) { | 
|                 //删除redis | 
|                 redisUtil.del(RedisKeyType.SHUTTLE.key + redisCommand.getWrkNo()); | 
|   | 
|                 if (!assignCommand.getCharge()) { | 
|                     //对主线程抛出等待确认状态waiting | 
|                     shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.WAITING); | 
|                 }else { | 
|                     shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.CHARGING_WAITING); | 
|                 } | 
|                 News.info("四向穿梭车任务执行下发完成等待执行结束,穿梭车号={},任务数据={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(commands)); | 
|   | 
|                 return false;//禁止再下发命令 | 
|             } | 
|         } | 
|   | 
|         List<NavigateNode> nextNodes = null;//下一步命令行走路径 | 
|         if (commandStep + 1 < commands.size()) { | 
|             NyShuttleHttpCommand nextCommand = commands.get(commandStep + 1);//下一步命令 | 
|             nextNodes = nextCommand.getNodes();//下一步命令行走路径 | 
|         } | 
|   | 
|         if (shuttleProtocol.getFree() == ShuttleStatusType.BUSY.id) { | 
|             String requestType = command.getRequest().getBody().get("requestType").toString(); | 
|             //停止充电 管制命令 | 
|             if(!(requestType.equals("stopCharge") && shuttleProtocol.getChargState() == 1) && !requestType.equals("resume")){ | 
|                 return false;//小车状态忙,禁止执行命令 | 
|             } | 
|         } | 
|   | 
| //        //检测小车是否要进提升机,如需要进提升机则调度提升机 | 
| //        if (!checkLiftStation(wrkNo)) { | 
| //            return false; | 
| //        } | 
|   | 
|         //检测穿梭车是否在提升机内 | 
|         if (!checkShuttleInTheLift(wrkNo)) { | 
|             return false; | 
|         } | 
|   | 
| //        if (command.getRequest().getBody().get("requestType").equals("move")) { | 
| //            ArrayList<int[]> whiteList = new ArrayList<>();//设置节点的白名单 | 
| //            if (wrkMast != null && ((wrkMast.getIoType() > 100 && wrkMast.getIoType() < 200) || wrkMast.getIoType() == 11)) { | 
| //                //出库任务,不检测首节点 | 
| //                int[] startArr = NavigatePositionConvert.positionToXY(wrkMast.getSourceLocNo());//开始节点 | 
| //                whiteList.add(startArr); | 
| //            } | 
| // | 
| //            //解锁过路径,只检测下一段路径是否可走(当前路径已经被锁定无需再检测) | 
| //            if (isLock) { | 
| //                //只检测下一段路径是否可走(当前路径已经被锁定无需再检测) | 
| //                //检测路径是否可行走 | 
| //                if (!checkPath(nextNodes == null ? command.getNodes() : nextNodes, null, whiteList)) { | 
| //                    return false; | 
| //                } | 
| //            }else { | 
| //                //检测当前路径和下一段路径 | 
| //                //检测路径是否可行走 | 
| //                if (!checkPath(command.getNodes(), nextNodes, whiteList)) { | 
| //                    return false; | 
| //                } | 
| //            } | 
| // | 
| //            //锁定路径,锁定当前路径和下一步路径 | 
| //            List<NavigateNode> nodes = command.getNodes(); | 
| //            if (nextNodes != null) { | 
| //                nodes.addAll(nextNodes); | 
| //            } | 
| //            if (nodes != null) { | 
| //                boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(shuttleProtocol.getCurrentLocNo()), nodes, true);//所使用的路径进行锁定禁用 | 
| //                if (!result) { | 
| //                    return false;//路径锁定失败 | 
| //                } | 
| //            } | 
| //        } | 
|   | 
|         //可执行命令 | 
|         if (!write(command, assignCommand)) { | 
|             News.error("四向穿梭车命令下发失败,穿梭车号={},任务数据={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command)); | 
|             return false; | 
|         } | 
|   | 
|         News.info("四向穿梭车命令下发成功,穿梭车号={},任务数据={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command)); | 
|         //将标记置为false(防止重发) | 
|         shuttleProtocol.setPakMk(true); | 
|   | 
|         String requestType = command.getRequest().getBody().get("requestType").toString(); | 
|         if (requestType.equals("updateFloor")) { | 
|             //更新楼层命令 | 
|             shuttleProtocol.setPakMk(false);//恢复标记 | 
|         } | 
|   | 
|         commandStep++; | 
|         //更新redis数据 | 
|         redisCommand.setCommandStep(commandStep); | 
|         //任务数据保存到redis | 
|         redisUtil.set(RedisKeyType.SHUTTLE.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand)); | 
|   | 
|         return true; | 
|     } | 
|   | 
|     //检测小车是否要进提升机,如需要进提升机则调度提升机 | 
|     private boolean checkLiftStation(Short wrkNo) { | 
|         //读取redis数据 | 
|         if (wrkNo == null) { | 
|             return false; | 
|         } | 
|   | 
|         Object o = redisUtil.get(RedisKeyType.SHUTTLE.key + wrkNo); | 
|         if (o == null) { | 
|             return false; | 
|         } | 
|   | 
|         WrkMastMapper wrkMastMapper = SpringUtils.getBean(WrkMastMapper.class); | 
|   | 
|         ShuttleRedisCommand redisCommand = JSON.parseObject(o.toString(), ShuttleRedisCommand.class); | 
|         //当前步序 | 
|         int commandStep = redisCommand.getCommandStep(); | 
|   | 
|         //检测是否存在提升机口的指令 | 
|         List<NyShuttleHttpCommand> commands = redisCommand.getAssignCommand().getCommands(); | 
|         if (commands.isEmpty()) { | 
|             return false; | 
|         } | 
|         NyShuttleHttpCommand command = commands.get(commandStep);//当前命令 | 
|         if (!command.getMsgType().equals("intoLift")) { | 
|             return true;//不是入提升机命令,直接放行 | 
|         } | 
|   | 
|         //获取起点(输送站点) | 
|         NyShuttleProtocol.NyShuttlePointClass start = JSON.parseObject(command.getRequest().getBody().get("start").toString(), NyShuttleProtocol.NyShuttlePointClass.class); | 
|         //将牛眼坐标转换成WCS库位号 | 
|         String startLocNo = NavigatePositionConvert.nyXyzToLocNo(start.getX(), start.getY(), start.getZ()); | 
|   | 
|         BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); | 
|         BasDevp basDevp = basDevpService.queryByLocNo(startLocNo); | 
|         if (basDevp == null) { | 
|             return false;//查不到站点,禁止下发 | 
|         } | 
|   | 
|         //拿到提升机线程 | 
|         LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, basDevp.getLiftNo()); | 
|         if (liftThread == null) { | 
|             return false; | 
|         } | 
|         LiftProtocol liftProtocol = liftThread.getLiftProtocol(); | 
|         if (liftProtocol == null) { | 
|             return false; | 
|         } | 
|         if (!liftProtocol.isIdle()) { | 
|             return false; | 
|         } | 
|   | 
|         if (liftProtocol.getLev().intValue() == Utils.getLev(shuttleProtocol.getCurrentLocNo())) { | 
|             return true;//提升机达到小车楼层,放行 | 
|         } | 
|   | 
|         //搜索是否有其他任务占用了提升机,如果占用提升机的任务和当前任务相同,则运行执行 | 
|         WrkMast wrkMast1 = wrkMastMapper.selectLiftWrkMast(liftProtocol.getLiftNo().intValue()); | 
|         if (wrkMast1 != null && wrkMast1.getWrkNo() != wrkNo.intValue()) { | 
|             return false; | 
|         } | 
|   | 
|         //提升机未到达小车楼层,呼叫提升机 | 
|         //获取提升机命令 | 
|         NyLiftCommand liftCommand = NyLiftUtils.getLiftCommand(liftProtocol.getLiftNo().intValue(), NyLiftTaskModelType.MOVE_CAR.id, null, basDevp.getDevNo(), wrkNo.intValue()); | 
|         ArrayList<NyLiftCommand> liftCommands = new ArrayList<>(); | 
|         liftCommands.add(liftCommand); | 
|   | 
|         //提交到线程去工作 | 
|         LiftAssignCommand assignCommand = new LiftAssignCommand(); | 
|         assignCommand.setCommands(liftCommands); | 
|         assignCommand.setLiftNo(liftProtocol.getLiftNo()); | 
|         assignCommand.setTaskNo(wrkNo); | 
|         assignCommand.setTaskMode(NyLiftTaskModelType.MOVE_CAR.id.shortValue()); | 
|   | 
|         //下发任务 | 
|         MessageQueue.offer(SlaveType.Lift, liftProtocol.getLiftNo().intValue(), new Task(3, assignCommand)); | 
|   | 
|         return false;//默认不放行 | 
|     } | 
|   | 
|     /** | 
|      * 检测穿梭车是否在提升机内 | 
|      * 如穿梭车在提升机内,必须等待提升机空闲才可执行穿梭车命令 | 
|      */ | 
|     private boolean checkShuttleInTheLift(Short wrkNo) { | 
|         //读取redis数据 | 
|         if (wrkNo == null) { | 
|             return false; | 
|         } | 
|   | 
|         Object o = redisUtil.get(RedisKeyType.SHUTTLE.key + wrkNo); | 
|         if (o == null) { | 
|             return false; | 
|         } | 
|   | 
|         SlaveProperties slaveProperties = SpringUtils.getBean(SlaveProperties.class); | 
|         BasLiftService liftService = SpringUtils.getBean(BasLiftService.class); | 
|         for (LiftSlave liftSlave : slaveProperties.getLift()) { | 
|             BasLift basLift = liftService.selectById(liftSlave.getId()); | 
|             if (basLift == null) { | 
|                 continue; | 
|             } | 
|             Integer liftX = basLift.getPoint$().getX(); | 
|             Integer liftY = basLift.getPoint$().getY(); | 
|             if (liftX.equals(shuttleProtocol.getPoint().getX()) && liftY.equals(shuttleProtocol.getPoint().getY())) { | 
|                 //小车在提升机内 | 
|                 //判断提升机是否空闲 | 
|                 LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftSlave.getId()); | 
|                 if (liftThread == null) { | 
|                     return false; | 
|                 } | 
|                 LiftProtocol liftProtocol = liftThread.getLiftProtocol(); | 
|                 if (liftProtocol == null) { | 
|                     return false; | 
|                 } | 
|                 if (liftProtocol.isIdle()) { | 
|                     //提升机处于空闲,放行 | 
|                     return true; | 
|                 } | 
|             }else { | 
|                 return true;//不在提升机内,放行 | 
|             } | 
|         } | 
|         return false;//默认不放行 | 
|     } | 
|   | 
|     /** | 
|      * 检测路径是否可行走 | 
|      * 如果路径为目标库位,但不可行走,系统将尝试重新计算路径 | 
|      */ | 
|     private boolean checkPath(List<NavigateNode> currentNodes, List<NavigateNode> nextNodes, List<int[]> whitePoints) { | 
|         //检测路径是否可行走(检查路径锁定状态,检测路径是否有其他小车) | 
|         //检测当前行走路径,和下一步路径 | 
|         boolean checkPathIsAvailable = NavigateUtils.checkPathIsAvailable(currentNodes, shuttleProtocol.getShuttleNo().intValue(), Utils.getLev(shuttleProtocol.getCurrentLocNo()), whitePoints); | 
|         if (nextNodes == null) { | 
|             if (checkPathIsAvailable) { | 
|                 return true;//可行走 | 
|             } | 
|             return false; | 
|         }else { | 
|             boolean checkPathIsAvailable2 = NavigateUtils.checkPathIsAvailable(nextNodes, shuttleProtocol.getShuttleNo().intValue(), Utils.getLev(shuttleProtocol.getCurrentLocNo()), whitePoints); | 
|             if (checkPathIsAvailable && checkPathIsAvailable2) { | 
|                 return true;//可行走 | 
|             } | 
|         } | 
|   | 
| //        ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand(); | 
| //        NavigateNode currentTarget = currentNodes.get(currentNodes.size() - 1); | 
| //        String currentLocNo = NavigatePositionConvert.nodeToLocNo(currentTarget); | 
| //        NavigateNode nextTarget = nextNodes.get(nextNodes.size() - 1); | 
| //        String nextLocNo = NavigatePositionConvert.nodeToLocNo(nextTarget); | 
| //        if (assignCommand.getLocNo().equals(currentLocNo) || assignCommand.getLocNo().equals(nextLocNo)) { | 
| //            //当前路径最后一个节点是目标库位,进行路径检测,如果不可行走,重新计算路径 | 
| //            //不可行走,重新计算路径 | 
| //            NyShuttleOperaResult result = NyShuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getShuttleNo().intValue(), shuttleProtocol.getTaskNo(), shuttleProtocol.getCurrentLocNo(), assignCommand.getLocNo()); | 
| //            if (result == null) { | 
| //                return false;//路径计算失败,不可行走 | 
| //            } | 
| // | 
| //            List<NyShuttleHttpCommand> newCommands = result.getCommands();//新路径 | 
| // | 
| //            //当前步序 | 
| //            int commandStep = redisCommand.getCommandStep(); | 
| //            List<NyShuttleHttpCommand> commands = assignCommand.getCommands(); | 
| // | 
| //            commands.remove(commandStep);//移除当前步序指令 | 
| //            if (assignCommand.getLocNo().equals(currentLocNo)) { | 
| //                //当前路径,需要再多移除下一步指令 | 
| //                commands.remove(commandStep + 1); | 
| //            } | 
| // | 
| //            //将新路径添加进指令集合 | 
| //            commands.addAll(commandStep, newCommands); | 
| //            assignCommand.setCommands(commands); | 
| //            redisCommand.setAssignCommand(assignCommand); | 
| //            //任务数据保存到redis | 
| //            redisUtil.set(RedisKeyType.SHUTTLE.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand)); | 
| //            return false;//当前不可行走,等待下一次执行走新路径 | 
| //        } | 
|   | 
|         return false;//不可行走 | 
|     } | 
|   | 
|     /** | 
|      * 跑库程序 | 
|      */ | 
|     private void moveLoc() { | 
|         LocMastService locMastService = SpringUtils.getBean(LocMastService.class); | 
|         ShuttleDispatchUtils shuttleDispatchUtils = SpringUtils.getBean(ShuttleDispatchUtils.class); | 
|         CommonService commonService = SpringUtils.getBean(CommonService.class); | 
|         WrkMastMapper wrkMastMapper = SpringUtils.getBean(WrkMastMapper.class); | 
|         int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车当前楼层 | 
|         if (!shuttleProtocol.isIdle()) { | 
|             return; | 
|         } | 
|   | 
|         WrkMast wrkMast = wrkMastMapper.selectShuttleHasMoveWorking(shuttleProtocol.getShuttleNo().intValue()); | 
|         if (wrkMast != null) { | 
|             return; | 
|         } | 
|   | 
|         if (shuttleProtocol.getYCurrent() > shuttleProtocol.getYTarget()) { | 
|             //跑库结束 | 
|             shuttleProtocol.setMoveLoc(false); | 
|             shuttleProtocol.setMoveType(0); | 
|             shuttleProtocol.setXStart(0); | 
|             shuttleProtocol.setXTarget(0); | 
|             shuttleProtocol.setXCurrent(0); | 
|             shuttleProtocol.setYStart(0); | 
|             shuttleProtocol.setYTarget(0); | 
|             shuttleProtocol.setYCurrent(0); | 
|             return; | 
|         } | 
|   | 
|         if (shuttleProtocol.getMoveType() == 0) {//跑轨道 | 
|             ArrayList<String> locs = new ArrayList<>(); | 
|             for (int i = shuttleProtocol.getXCurrent(); i <= shuttleProtocol.getXTarget(); i++) { | 
|                 String locNo = Utils.getLocNo(i, shuttleProtocol.getYCurrent(), lev); | 
|                 locs.add(locNo); | 
|             } | 
|             List<LocMast> locMasts = locMastService.selectEmptyLocNos(locs); | 
|             if (locMasts.isEmpty()) { | 
|                 //空库位 | 
|                 shuttleProtocol.setYCurrent(shuttleProtocol.getYCurrent() + 1); | 
|                 return; | 
|             } | 
|   | 
|             LocMast start = locMasts.get(0); | 
|             LocMast target = locMasts.get(locMasts.size() - 1); | 
|             //判断小车是否在起点位置 | 
|             if (!shuttleProtocol.getCurrentLocNo().equals(start.getLocNo())) {//不在起点位置,调度去起点位置 | 
|                 shuttleDispatchUtils.dispatchShuttle(commonService.getWorkNo(3), start.getLocNo()); | 
|             }else { | 
|                 //在起点位置,调度去目标位置 | 
|                 if (shuttleProtocol.getCurrentLocNo().equals(target.getLocNo())) { | 
|                     shuttleProtocol.setYCurrent(shuttleProtocol.getYCurrent() + 1);//小车和目标位置一致,跳过 | 
|                 }else { | 
|                     boolean result = shuttleDispatchUtils.dispatchShuttle(commonService.getWorkNo(3), target.getLocNo()); | 
|                     if (result) {//调度成功 | 
|                         shuttleProtocol.setYCurrent(shuttleProtocol.getYCurrent() + 1); | 
|                     } | 
|                 } | 
|             } | 
|         }else {//跑库位 | 
|             Integer xCurrent = shuttleProtocol.getXCurrent(); | 
|             if (xCurrent > shuttleProtocol.getXTarget()) {//当X值大于X目标值,进行归零且Y方向+1 | 
|                 shuttleProtocol.setXCurrent(shuttleProtocol.getXStart()); | 
|                 shuttleProtocol.setYCurrent(shuttleProtocol.getYCurrent() + 1); | 
|                 return; | 
|             } | 
|   | 
|             Integer yCurrent = shuttleProtocol.getYCurrent(); | 
|             String locNo = Utils.getLocNo(xCurrent, yCurrent, lev); | 
|             LocMast target = locMastService.selectById(locNo); | 
|             if (target == null) { | 
|                 shuttleProtocol.setXCurrent(shuttleProtocol.getXCurrent() + 1); | 
|                 return; | 
|             } | 
|   | 
|             if (!target.getLocSts().equals("O")) { | 
|                 shuttleProtocol.setXCurrent(shuttleProtocol.getXCurrent() + 1); | 
|                 return; | 
|             } | 
|   | 
|             //调度去目标位置 | 
|             if (shuttleProtocol.getCurrentLocNo().equals(target.getLocNo())) { | 
|                 shuttleProtocol.setXCurrent(shuttleProtocol.getXCurrent() + 1);//小车和目标位置一致,跳过 | 
|             }else { | 
|                 boolean result = shuttleDispatchUtils.dispatchShuttle(commonService.getWorkNo(3), target.getLocNo()); | 
|                 if (result) {//调度成功 | 
|                     shuttleProtocol.setXCurrent(shuttleProtocol.getXCurrent() + 1); | 
|                 } | 
|             } | 
|         } | 
|     } | 
|   | 
|     //检测小车是否进出提升机输送站 | 
|     public void checkIOSta(List<NyShuttleHttpCommand> commands, int commandStep) { | 
|         if (commandStep != 0) { | 
|             NyShuttleHttpCommand lastCommand = commands.get(commandStep - 1);//上一步命令 | 
|             if (lastCommand.getRequest().getBody().get("requestType").equals("move")) { | 
|                 //检测起点是否为提升机输送站点 | 
|                 NyShuttleProtocol.NyShuttlePointClass start = JSON.parseObject(lastCommand.getRequest().getBody().get("start").toString(), NyShuttleProtocol.NyShuttlePointClass.class); | 
|                 int[] startPoint = NavigatePositionConvert.NyXyzToWCSXyz(start.getX(), start.getY(), start.getZ()); | 
|                 if (startPoint[0] == 13 && (startPoint[1] == 22 || startPoint[1] == 38 || startPoint[1] == 57)) { | 
|                     //输送站点位置 | 
|   | 
|                     int liftNo; | 
|                     if (startPoint[1] == 22) { | 
|                         liftNo = 1; | 
|                     } else if (startPoint[1] == 38) { | 
|                         liftNo = 2; | 
|                     } else { | 
|                         liftNo = 3; | 
|                     } | 
|   | 
|                     HashMap<String, Object> data = new HashMap<>(); | 
|                     data.put("lev", startPoint[2]); | 
|                     data.put("status", false);//出输送站 | 
|   | 
|                     //下发任务 | 
|                     MessageQueue.offer(SlaveType.Lift, liftNo, new Task(4, data)); | 
|                 } | 
|             } | 
|         } | 
|   | 
|         if (commands.size() == commandStep) { | 
|             return; | 
|         } | 
|         NyShuttleHttpCommand command = commands.get(commandStep);//当前命令 | 
|         if (command.getRequest().getBody().get("requestType").equals("move")) { | 
|             NyShuttleProtocol.NyShuttlePointClass target = JSON.parseObject(command.getRequest().getBody().get("target").toString(), NyShuttleProtocol.NyShuttlePointClass.class); | 
|             int[] targetPoint = NavigatePositionConvert.NyXyzToWCSXyz(target.getX(), target.getY(), target.getZ()); | 
|             //检测目标位置是否为提升机输送站点 | 
|             if (targetPoint[0] == 13 && (targetPoint[1] == 22 || targetPoint[1] == 38 || targetPoint[1] == 57)) { | 
|                 //输送站点位置 | 
|   | 
|                 int liftNo; | 
|                 if (targetPoint[1] == 22) { | 
|                     liftNo = 1; | 
|                 } else if (targetPoint[1] == 38) { | 
|                     liftNo = 2; | 
|                 } else { | 
|                     liftNo = 3; | 
|                 } | 
|   | 
|                 HashMap<String, Object> data = new HashMap<>(); | 
|                 data.put("lev", targetPoint[2]); | 
|                 data.put("status", true);//进输送站 | 
|   | 
|                 //下发任务 | 
|                 MessageQueue.offer(SlaveType.Lift, liftNo, new Task(4, data)); | 
|             } | 
|         } | 
|     } | 
|   | 
| } |