| | |
| | | import com.zy.common.service.CommonService; |
| | | import com.zy.common.utils.NavigateUtils; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.move.StationMoveCoordinator; |
| | | import com.zy.core.move.StationMoveSession; |
| | | import com.zy.core.News; |
| | | import com.zy.core.cache.MessageQueue; |
| | | import com.zy.core.cache.SlaveConnection; |
| | |
| | | private StationTaskLoopService stationTaskLoopService; |
| | | @Autowired |
| | | private WrkAnalysisService wrkAnalysisService; |
| | | @Autowired |
| | | private StationMoveCoordinator stationMoveCoordinator; |
| | | |
| | | //执行输送站点入库任务 |
| | | public synchronized void stationInExecute() { |
| | |
| | | wrkMast.setModiTime(now); |
| | | if (wrkMastService.updateById(wrkMast)) { |
| | | wrkAnalysisService.markOutboundStationStart(wrkMast, now); |
| | | offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "crnStationOutExecute"); |
| | | boolean offered = offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "crnStationOutExecute"); |
| | | if (offered && stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.recordDispatch( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | "crnStationOutExecute", |
| | | command, |
| | | false |
| | | ); |
| | | } |
| | | News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5); |
| | | redisUtil.del(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo()); |
| | |
| | | if (wrkMast == null || wrkMast.getWrkNo() == null) { |
| | | return; |
| | | } |
| | | if (stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.finishSession(wrkMast.getWrkNo()); |
| | | } |
| | | Date now = new Date(); |
| | | wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts); |
| | | wrkMast.setIoTime(now); |
| | |
| | | } |
| | | |
| | | if (complete) { |
| | | if (stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.finishSession(wrkNo); |
| | | } |
| | | wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts); |
| | | wrkMast.setIoTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | |
| | | } |
| | | redisUtil.set(RedisKeyType.CHECK_STATION_RUN_BLOCK_LIMIT_.key + stationProtocol.getTaskNo(), "lock", 15); |
| | | |
| | | if (wrkMast.getIoType() == WrkIoType.IN.id && runBlockReassignLocStationList.contains(stationProtocol.getStationId())) { |
| | | //站点处于重新分配库位区域 |
| | | //运行堵塞,重新申请任务 |
| | | String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); |
| | | if (Cools.isEmpty(response)) { |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response); |
| | | continue; |
| | | } |
| | | JSONObject jsonObject = JSON.parseObject(response); |
| | | if (jsonObject.getInteger("code").equals(200)) { |
| | | StartupDto dto = jsonObject.getObject("data", StartupDto.class); |
| | | |
| | | String sourceLocNo = wrkMast.getLocNo(); |
| | | String locNo = dto.getLocNo(); |
| | | |
| | | LocMast sourceLocMast = locMastService.queryByLoc(sourceLocNo); |
| | | if (sourceLocMast == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位信息不存在", sourceLocNo); |
| | | continue; |
| | | } |
| | | |
| | | if (!sourceLocMast.getLocSts().equals("S")) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位状态不处于入库预约", sourceLocNo); |
| | | continue; |
| | | } |
| | | |
| | | LocMast locMast = locMastService.queryByLoc(locNo); |
| | | if (locMast == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位信息不存在", locNo); |
| | | continue; |
| | | } |
| | | |
| | | if (!locMast.getLocSts().equals("O")) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位状态不处于空库位", locNo); |
| | | continue; |
| | | } |
| | | |
| | | FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo); |
| | | if (findCrnNoResult == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo()); |
| | | continue; |
| | | } |
| | | Integer crnNo = findCrnNoResult.getCrnNo(); |
| | | |
| | | Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationProtocol.getStationId()); |
| | | if (targetStationId == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationProtocol.getStationId()); |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), targetStationId, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo()); |
| | | continue; |
| | | } |
| | | |
| | | //更新源库位 |
| | | sourceLocMast.setLocSts("O"); |
| | | sourceLocMast.setModiTime(new Date()); |
| | | locMastService.updateById(sourceLocMast); |
| | | |
| | | //更新目标库位 |
| | | locMast.setLocSts("S"); |
| | | locMast.setModiTime(new Date()); |
| | | locMastService.updateById(locMast); |
| | | |
| | | //更新工作档数据 |
| | | wrkMast.setLocNo(locNo); |
| | | wrkMast.setStaNo(targetStationId); |
| | | |
| | | if (findCrnNoResult.getCrnType().equals(SlaveType.Crn)) { |
| | | wrkMast.setCrnNo(crnNo); |
| | | } else if (findCrnNoResult.getCrnType().equals(SlaveType.DualCrn)) { |
| | | wrkMast.setDualCrnNo(crnNo); |
| | | } else { |
| | | throw new CoolException("未知设备类型"); |
| | | } |
| | | |
| | | if (wrkMastService.updateById(wrkMast)) { |
| | | offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct"); |
| | | } |
| | | } else { |
| | | News.error("请求WMS接口失败!!!response:{}", response); |
| | | } |
| | | } else { |
| | | //运行堵塞,重新计算路线 |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | wrkMast, |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo()) > 0) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getRunBlockRerouteCommand( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | 0, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), |
| | | "输送站点堵塞重规划未找到可下发路线,当前站点={},目标站点={}", |
| | | stationProtocol.getStationId(), |
| | | moveStaNo); |
| | | continue; |
| | | } |
| | | |
| | | resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo()); |
| | | offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_reroute"); |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderStationIds, dispatchDecision, command); |
| | | News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | if (shouldUseRunBlockDirectReassign(wrkMast, stationProtocol.getStationId(), runBlockReassignLocStationList)) { |
| | | executeRunBlockDirectReassign(basDevp, stationThread, stationProtocol, wrkMast); |
| | | continue; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | RerouteContext context = RerouteContext.create( |
| | | RerouteSceneType.RUN_BLOCK_REROUTE, |
| | | basDevp, |
| | | stationThread, |
| | | stationProtocol, |
| | | wrkMast, |
| | | outOrderStationIds, |
| | | pathLenFactor, |
| | | "checkStationRunBlock_reroute" |
| | | ).withRunBlockCommand() |
| | | .withCancelSessionBeforeDispatch() |
| | | .withResetSegmentCommandsBeforeDispatch(); |
| | | executeSharedReroute(context); |
| | | } |
| | | } |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), stationProtocol.getTaskNo()) > 0) { |
| | | continue; |
| | | } |
| | | |
| | | if (isWatchingCircleArrival(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | RerouteContext context = RerouteContext.create( |
| | | RerouteSceneType.OUT_ORDER, |
| | | basDevp, |
| | | stationThread, |
| | | stationProtocol, |
| | | wrkMast, |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo()); |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderStationIds, dispatchDecision, command); |
| | | offerDevpCommandWithDedup(stationObjModel.getDeviceNo(), command, "checkStationOutOrder"); |
| | | News.info(dispatchDecision.isCircle() ? "{}任务进行绕圈" : "{}任务直接去目标点", wrkMast.getWrkNo()); |
| | | pathLenFactor, |
| | | "checkStationOutOrder" |
| | | ).withDispatchDeviceNo(stationObjModel.getDeviceNo()) |
| | | .withSuppressDispatchGuard() |
| | | .withOutOrderDispatchLock() |
| | | .withResetSegmentCommandsBeforeDispatch(); |
| | | executeSharedReroute(context); |
| | | } |
| | | } |
| | | } |
| | |
| | | if (Objects.equals(stationProtocol.getStationId(), wrkMast.getStaNo())) { |
| | | continue; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | RerouteContext context = RerouteContext.create( |
| | | RerouteSceneType.WATCH_CIRCLE, |
| | | basDevp, |
| | | stationThread, |
| | | stationProtocol, |
| | | wrkMast, |
| | | outOrderList, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | resetSegmentMoveCommandsBeforeReroute(wrkMast.getWrkNo()); |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderList, dispatchDecision, command); |
| | | offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "watchCircleStation"); |
| | | pathLenFactor, |
| | | "watchCircleStation" |
| | | ).withSuppressDispatchGuard() |
| | | .withOutOrderDispatchLock() |
| | | .withResetSegmentCommandsBeforeDispatch(); |
| | | executeSharedReroute(context); |
| | | } |
| | | } |
| | | } |
| | |
| | | 0, |
| | | normalizePathLenFactor(pathLenFactor) |
| | | ); |
| | | } |
| | | |
| | | RerouteCommandPlan buildRerouteCommandPlan(RerouteContext context, |
| | | RerouteDecision decision) { |
| | | if (context == null) { |
| | | return RerouteCommandPlan.skip("missing-context"); |
| | | } |
| | | if (decision == null) { |
| | | return RerouteCommandPlan.skip("missing-decision"); |
| | | } |
| | | if (decision.skip()) { |
| | | return RerouteCommandPlan.skip(decision.skipReason()); |
| | | } |
| | | if (context.stationThread() == null || context.stationProtocol() == null || context.wrkMast() == null) { |
| | | return RerouteCommandPlan.skip("missing-runtime-dependency"); |
| | | } |
| | | Integer currentStationId = context.stationProtocol().getStationId(); |
| | | Integer targetStationId = decision.targetStationId(); |
| | | if (currentStationId == null || targetStationId == null) { |
| | | return RerouteCommandPlan.skip("missing-target-station"); |
| | | } |
| | | if (Objects.equals(currentStationId, targetStationId)) { |
| | | return RerouteCommandPlan.skip("same-station"); |
| | | } |
| | | |
| | | StationCommand command = context.useRunBlockCommand() |
| | | ? context.stationThread().getRunBlockRerouteCommand( |
| | | context.wrkMast().getWrkNo(), |
| | | currentStationId, |
| | | targetStationId, |
| | | 0, |
| | | context.pathLenFactor() |
| | | ) |
| | | : buildOutboundMoveCommand( |
| | | context.stationThread(), |
| | | context.wrkMast(), |
| | | currentStationId, |
| | | targetStationId, |
| | | context.pathLenFactor() |
| | | ); |
| | | if (command == null) { |
| | | if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) { |
| | | News.taskInfo(context.wrkMast().getWrkNo(), |
| | | "输送站点堵塞重规划未找到可下发路线,当前站点={},目标站点={}", |
| | | currentStationId, |
| | | targetStationId); |
| | | } else if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) { |
| | | News.taskInfo(context.wrkMast().getWrkNo(), |
| | | "站点任务停留超时后重算路径失败,当前站点={},目标站点={}", |
| | | currentStationId, |
| | | targetStationId); |
| | | } else { |
| | | News.taskInfo(context.wrkMast().getWrkNo(), "获取输送线命令失败"); |
| | | } |
| | | return RerouteCommandPlan.skip("missing-command"); |
| | | } |
| | | return RerouteCommandPlan.dispatch(command, decision, context.dispatchScene()); |
| | | } |
| | | |
| | | RerouteExecutionResult executeReroutePlan(RerouteContext context, |
| | | RerouteCommandPlan plan) { |
| | | if (context == null) { |
| | | return RerouteExecutionResult.skip("missing-context"); |
| | | } |
| | | if (plan == null) { |
| | | return RerouteExecutionResult.skip("missing-plan"); |
| | | } |
| | | if (plan.skip()) { |
| | | return RerouteExecutionResult.skip(plan.skipReason()); |
| | | } |
| | | StationProtocol stationProtocol = context.stationProtocol(); |
| | | if (stationProtocol == null) { |
| | | return RerouteExecutionResult.skip("missing-station-protocol"); |
| | | } |
| | | Integer taskNo = stationProtocol.getTaskNo(); |
| | | Integer stationId = stationProtocol.getStationId(); |
| | | if (taskNo == null || taskNo <= 0 || stationId == null) { |
| | | return RerouteExecutionResult.skip("invalid-station-task"); |
| | | } |
| | | if (context.checkRecentDispatch() |
| | | && shouldSkipIdleRecoverForRecentDispatch(taskNo, stationId)) { |
| | | return RerouteExecutionResult.skip("recent-dispatch"); |
| | | } |
| | | if (countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo) > 0) { |
| | | if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) { |
| | | News.info("输送站点任务停留超时,但缓存区仍存在当前任务命令,已跳过重算。站点号={},工作号={},当前任务命令数={}", |
| | | stationId, |
| | | taskNo, |
| | | countCurrentTaskBufferCommands(stationProtocol.getTaskBufferItems(), taskNo)); |
| | | } |
| | | return RerouteExecutionResult.skip("buffer-has-current-task"); |
| | | } |
| | | if (context.checkSuppressDispatch() |
| | | && stationMoveCoordinator != null |
| | | && stationMoveCoordinator.shouldSuppressDispatch(taskNo, stationId, plan.command())) { |
| | | return RerouteExecutionResult.skip("dispatch-suppressed"); |
| | | } |
| | | if (context.requireOutOrderDispatchLock() |
| | | && !tryAcquireOutOrderDispatchLock(taskNo, stationId)) { |
| | | return RerouteExecutionResult.skip("out-order-lock"); |
| | | } |
| | | |
| | | if (context.cancelSessionBeforeDispatch() && stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.cancelSession(taskNo); |
| | | } |
| | | if (!isBlank(context.executionLockKey())) { |
| | | Object lock = redisUtil.get(context.executionLockKey()); |
| | | if (lock != null) { |
| | | return RerouteExecutionResult.skip("scene-lock"); |
| | | } |
| | | redisUtil.set(context.executionLockKey(), "lock", context.executionLockSeconds()); |
| | | } |
| | | if (context.resetSegmentCommandsBeforeDispatch()) { |
| | | resetSegmentMoveCommandsBeforeReroute(taskNo); |
| | | } |
| | | |
| | | int clearedCommandCount = 0; |
| | | if (context.clearIdleIssuedCommands()) { |
| | | clearedCommandCount = clearIssuedMoveCommandsDuringIdleStay(context.idleTrack(), taskNo, stationId); |
| | | } |
| | | |
| | | boolean offered = offerDevpCommandWithDedup(context.dispatchDeviceNo(), plan.command(), plan.dispatchScene()); |
| | | if (!offered) { |
| | | return RerouteExecutionResult.skip("dispatch-dedup"); |
| | | } |
| | | |
| | | applyRerouteDispatchEffects(context, plan, clearedCommandCount); |
| | | return RerouteExecutionResult.dispatched(plan.command(), clearedCommandCount); |
| | | } |
| | | |
| | | RerouteDecision resolveSharedRerouteDecision(RerouteContext context) { |
| | | if (context == null || context.wrkMast() == null || context.stationProtocol() == null) { |
| | | return RerouteDecision.skip("missing-runtime-dependency"); |
| | | } |
| | | Integer currentStationId = context.stationProtocol().getStationId(); |
| | | if (currentStationId == null) { |
| | | return RerouteDecision.skip("missing-current-station"); |
| | | } |
| | | |
| | | if (context.sceneType() == RerouteSceneType.IDLE_RECOVER |
| | | && !Objects.equals(context.wrkMast().getWrkSts(), WrkStsType.STATION_RUN.sts)) { |
| | | Integer targetStationId = context.wrkMast().getStaNo(); |
| | | return targetStationId == null || Objects.equals(targetStationId, currentStationId) |
| | | ? RerouteDecision.skip("same-station") |
| | | : RerouteDecision.proceed(targetStationId); |
| | | } |
| | | |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | currentStationId, |
| | | context.wrkMast(), |
| | | context.outOrderStationIds(), |
| | | context.pathLenFactor() |
| | | ); |
| | | Integer targetStationId = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (targetStationId == null || Objects.equals(targetStationId, currentStationId)) { |
| | | return RerouteDecision.skip("same-station"); |
| | | } |
| | | return RerouteDecision.proceed(targetStationId, dispatchDecision); |
| | | } |
| | | |
| | | private RerouteExecutionResult executeSharedReroute(RerouteContext context) { |
| | | RerouteDecision decision = resolveSharedRerouteDecision(context); |
| | | if (decision.skip()) { |
| | | return RerouteExecutionResult.skip(decision.skipReason()); |
| | | } |
| | | RerouteCommandPlan plan = buildRerouteCommandPlan(context, decision); |
| | | return executeReroutePlan(context, plan); |
| | | } |
| | | |
| | | private void applyRerouteDispatchEffects(RerouteContext context, |
| | | RerouteCommandPlan plan, |
| | | int clearedCommandCount) { |
| | | if (context == null || plan == null || plan.command() == null || context.wrkMast() == null || context.stationProtocol() == null) { |
| | | return; |
| | | } |
| | | WrkMast wrkMast = context.wrkMast(); |
| | | StationProtocol stationProtocol = context.stationProtocol(); |
| | | OutOrderDispatchDecision dispatchDecision = plan.decision() == null ? null : plan.decision().dispatchDecision(); |
| | | |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), context.outOrderStationIds(), dispatchDecision, plan.command()); |
| | | if (stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.recordDispatch( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | plan.dispatchScene(), |
| | | plan.command(), |
| | | dispatchDecision != null && dispatchDecision.isCircle() |
| | | ); |
| | | } |
| | | if (context.sceneType() == RerouteSceneType.IDLE_RECOVER) { |
| | | saveStationTaskIdleTrack(new StationTaskIdleTrack(wrkMast.getWrkNo(), stationProtocol.getStationId(), System.currentTimeMillis())); |
| | | News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},清理旧分段命令数={},命令数据={}", |
| | | STATION_IDLE_RECOVER_SECONDS, |
| | | stationProtocol.getStationId(), |
| | | plan.command().getTargetStaNo(), |
| | | wrkMast.getWrkNo(), |
| | | clearedCommandCount, |
| | | JSON.toJSONString(plan.command())); |
| | | return; |
| | | } |
| | | if (context.sceneType() == RerouteSceneType.RUN_BLOCK_REROUTE) { |
| | | News.info("输送站点堵塞后重新计算路径命令下发成功,站点号={},工作号={},命令数据={}", |
| | | stationProtocol.getStationId(), |
| | | wrkMast.getWrkNo(), |
| | | JSON.toJSONString(plan.command())); |
| | | return; |
| | | } |
| | | if (context.sceneType() == RerouteSceneType.OUT_ORDER) { |
| | | News.info(dispatchDecision != null && dispatchDecision.isCircle() ? "{}任务进行绕圈" : "{}任务直接去目标点", wrkMast.getWrkNo()); |
| | | } |
| | | } |
| | | |
| | | private List<NavigateNode> calcOutboundNavigatePath(WrkMast wrkMast, |
| | |
| | | } |
| | | |
| | | private boolean isWatchingCircleArrival(Integer wrkNo, Integer stationId) { |
| | | if (stationMoveCoordinator != null) { |
| | | StationMoveSession session = stationMoveCoordinator.loadSession(wrkNo); |
| | | if (session != null && session.isActive() && stationId != null) { |
| | | if (stationId.equals(session.getNextDecisionStationId())) { |
| | | return true; |
| | | } |
| | | if (session.containsStation(stationId)) { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | StationCommand command = getWatchCircleCommand(wrkNo); |
| | | return command != null && stationId != null && stationId.equals(command.getTargetStaNo()); |
| | | } |
| | | |
| | | private boolean isWatchingCircleTransit(Integer wrkNo, Integer stationId) { |
| | | if (stationMoveCoordinator != null) { |
| | | StationMoveSession session = stationMoveCoordinator.loadSession(wrkNo); |
| | | if (session != null && session.isActive() && stationId != null) { |
| | | if (stationId.equals(session.getNextDecisionStationId())) { |
| | | return false; |
| | | } |
| | | if (session.containsStation(stationId)) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | StationCommand command = getWatchCircleCommand(wrkNo); |
| | | if (command == null || stationId == null || Objects.equals(stationId, command.getTargetStaNo())) { |
| | | return false; |
| | | } |
| | | List<Integer> navigatePath = command.getNavigatePath(); |
| | | return navigatePath != null && navigatePath.contains(stationId); |
| | | } |
| | | |
| | | private StationCommand getWatchCircleCommand(Integer wrkNo) { |
| | |
| | | } |
| | | |
| | | StationTaskIdleTrack idleTrack = touchStationTaskIdleTrack(stationProtocol.getTaskNo(), stationProtocol.getStationId()); |
| | | if (shouldSkipIdleRecoverForRecentDispatch(stationProtocol.getTaskNo(), stationProtocol.getStationId())) { |
| | | return; |
| | | } |
| | | if (idleTrack == null || !idleTrack.isTimeout(STATION_IDLE_RECOVER_SECONDS)) { |
| | | return; |
| | | } |
| | |
| | | if (lock != null) { |
| | | return; |
| | | } |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | RerouteContext context = RerouteContext.create( |
| | | RerouteSceneType.IDLE_RECOVER, |
| | | basDevp, |
| | | stationThread, |
| | | stationProtocol, |
| | | wrkMast, |
| | | outOrderList, |
| | | pathLenFactor, |
| | | "checkStationIdleRecover" |
| | | ).withCancelSessionBeforeDispatch() |
| | | .withExecutionLock(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), STATION_IDLE_RECOVER_LIMIT_SECONDS) |
| | | .withResetSegmentCommandsBeforeDispatch() |
| | | .clearIdleIssuedCommands(idleTrack); |
| | | executeSharedReroute(context); |
| | | } |
| | | |
| | | boolean shouldUseRunBlockDirectReassign(WrkMast wrkMast, |
| | | Integer stationId, |
| | | List<Integer> runBlockReassignLocStationList) { |
| | | return wrkMast != null |
| | | && Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id) |
| | | && stationId != null |
| | | && runBlockReassignLocStationList != null |
| | | && runBlockReassignLocStationList.contains(stationId); |
| | | } |
| | | |
| | | private void executeRunBlockDirectReassign(BasDevp basDevp, |
| | | StationThread stationThread, |
| | | StationProtocol stationProtocol, |
| | | WrkMast wrkMast) { |
| | | if (basDevp == null || stationThread == null || stationProtocol == null || wrkMast == null) { |
| | | return; |
| | | } |
| | | int currentTaskBufferCommandCount = countCurrentTaskBufferCommands( |
| | | stationProtocol.getTaskBufferItems(), |
| | | stationProtocol.getTaskNo() |
| | | ); |
| | | if (currentTaskBufferCommandCount > 0) { |
| | | News.info("输送站点任务停留超时,但缓存区仍存在当前任务命令,已跳过重算。站点号={},工作号={},当前任务命令数={}", |
| | | News.info("输送站点运行堵塞重分配已跳过,缓存区仍存在当前任务命令。站点号={},工作号={},当前任务命令数={}", |
| | | stationProtocol.getStationId(), |
| | | stationProtocol.getTaskNo(), |
| | | currentTaskBufferCommandCount); |
| | | return; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = null; |
| | | Integer moveStaNo; |
| | | if (Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)) { |
| | | dispatchDecision = resolveOutboundDispatchDecision(stationProtocol.getStationId(), wrkMast, outOrderList, pathLenFactor); |
| | | moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | } else { |
| | | moveStaNo = wrkMast.getStaNo(); |
| | | if (stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.cancelSession(wrkMast.getWrkNo()); |
| | | } |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); |
| | | if (Cools.isEmpty(response)) { |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response); |
| | | return; |
| | | } |
| | | JSONObject jsonObject = JSON.parseObject(response); |
| | | if (!jsonObject.getInteger("code").equals(200)) { |
| | | News.error("请求WMS接口失败!!!response:{}", response); |
| | | return; |
| | | } |
| | | |
| | | redisUtil.set(RedisKeyType.CHECK_STATION_IDLE_RECOVER_LIMIT_.key + stationProtocol.getTaskNo(), "lock", STATION_IDLE_RECOVER_LIMIT_SECONDS); |
| | | resetSegmentMoveCommandsBeforeReroute(stationProtocol.getTaskNo()); |
| | | int clearedCommandCount = clearIssuedMoveCommandsDuringIdleStay(idleTrack, stationProtocol.getTaskNo(), stationProtocol.getStationId()); |
| | | StartupDto dto = jsonObject.getObject("data", StartupDto.class); |
| | | String sourceLocNo = wrkMast.getLocNo(); |
| | | String locNo = dto.getLocNo(); |
| | | |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | LocMast sourceLocMast = locMastService.queryByLoc(sourceLocNo); |
| | | if (sourceLocMast == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位信息不存在", sourceLocNo); |
| | | return; |
| | | } |
| | | if (!sourceLocMast.getLocSts().equals("S")) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 源库位状态不处于入库预约", sourceLocNo); |
| | | return; |
| | | } |
| | | |
| | | LocMast locMast = locMastService.queryByLoc(locNo); |
| | | if (locMast == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位信息不存在", locNo); |
| | | return; |
| | | } |
| | | if (!locMast.getLocSts().equals("O")) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "库位号:{} 目标库位状态不处于空库位", locNo); |
| | | return; |
| | | } |
| | | |
| | | FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo); |
| | | if (findCrnNoResult == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo()); |
| | | return; |
| | | } |
| | | Integer crnNo = findCrnNoResult.getCrnNo(); |
| | | |
| | | Integer targetStationId = commonService.findInStationId(findCrnNoResult, stationProtocol.getStationId()); |
| | | if (targetStationId == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}站点,搜索入库站点失败", stationProtocol.getStationId()); |
| | | return; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), targetStationId, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "站点任务停留超时后重算路径失败,当前站点={},目标站点={}", stationProtocol.getStationId(), moveStaNo); |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo()); |
| | | return; |
| | | } |
| | | |
| | | offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationIdleRecover"); |
| | | syncOutOrderWatchState(wrkMast, stationProtocol.getStationId(), outOrderList, dispatchDecision, command); |
| | | saveStationTaskIdleTrack(new StationTaskIdleTrack(wrkMast.getWrkNo(), stationProtocol.getStationId(), System.currentTimeMillis())); |
| | | News.info("输送站点任务停留{}秒未运行,已重新计算路径并重启运行,站点号={},目标站={},工作号={},清理旧分段命令数={},命令数据={}", |
| | | STATION_IDLE_RECOVER_SECONDS, stationProtocol.getStationId(), moveStaNo, wrkMast.getWrkNo(), clearedCommandCount, JSON.toJSONString(command)); |
| | | sourceLocMast.setLocSts("O"); |
| | | sourceLocMast.setModiTime(new Date()); |
| | | locMastService.updateById(sourceLocMast); |
| | | |
| | | locMast.setLocSts("S"); |
| | | locMast.setModiTime(new Date()); |
| | | locMastService.updateById(locMast); |
| | | |
| | | wrkMast.setLocNo(locNo); |
| | | wrkMast.setStaNo(targetStationId); |
| | | |
| | | if (findCrnNoResult.getCrnType().equals(SlaveType.Crn)) { |
| | | wrkMast.setCrnNo(crnNo); |
| | | } else if (findCrnNoResult.getCrnType().equals(SlaveType.DualCrn)) { |
| | | wrkMast.setDualCrnNo(crnNo); |
| | | } else { |
| | | throw new CoolException("未知设备类型"); |
| | | } |
| | | |
| | | if (!wrkMastService.updateById(wrkMast)) { |
| | | return; |
| | | } |
| | | boolean offered = offerDevpCommandWithDedup(basDevp.getDevpNo(), command, "checkStationRunBlock_direct"); |
| | | if (!offered) { |
| | | return; |
| | | } |
| | | if (stationMoveCoordinator != null) { |
| | | stationMoveCoordinator.recordDispatch( |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | "checkStationRunBlock_direct", |
| | | command, |
| | | false |
| | | ); |
| | | } |
| | | } |
| | | |
| | | private boolean canRecoverIdleStationTask(WrkMast wrkMast, Integer currentStationId) { |
| | |
| | | } |
| | | return Objects.equals(wrkMast.getWrkSts(), WrkStsType.INBOUND_STATION_RUN.sts) |
| | | || Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts); |
| | | } |
| | | |
| | | private boolean shouldSkipIdleRecoverForRecentDispatch(Integer taskNo, Integer stationId) { |
| | | if (stationMoveCoordinator == null || taskNo == null || taskNo <= 0 || stationId == null) { |
| | | return false; |
| | | } |
| | | StationMoveSession session = stationMoveCoordinator.loadSession(taskNo); |
| | | if (session == null || !session.isActive() || session.getLastIssuedAt() == null) { |
| | | return false; |
| | | } |
| | | if (!Objects.equals(stationId, session.getCurrentStationId()) |
| | | && !Objects.equals(stationId, session.getDispatchStationId())) { |
| | | return false; |
| | | } |
| | | long elapsedMs = System.currentTimeMillis() - session.getLastIssuedAt(); |
| | | long thresholdMs = STATION_IDLE_RECOVER_SECONDS * 1000L; |
| | | if (elapsedMs >= thresholdMs) { |
| | | return false; |
| | | } |
| | | saveStationTaskIdleTrack(new StationTaskIdleTrack(taskNo, stationId, System.currentTimeMillis())); |
| | | News.info("输送站点任务刚完成命令下发,已跳过停留重算。站点号={},工作号={},距上次下发={}ms,routeVersion={}", |
| | | stationId, taskNo, elapsedMs, session.getRouteVersion()); |
| | | return true; |
| | | } |
| | | |
| | | private void resetSegmentMoveCommandsBeforeReroute(Integer taskNo) { |
| | |
| | | |
| | | private String buildStationCommandDispatchDedupKey(Integer deviceNo, StationCommand command) { |
| | | return RedisKeyType.STATION_COMMAND_DISPATCH_DEDUP_.key |
| | | + deviceNo + "_" |
| | | + command.getTaskNo() + "_" |
| | | + command.getStationId(); |
| | | + command.getStationId() + "_" |
| | | + (stationMoveCoordinator == null ? Integer.toHexString(buildFallbackPathSignature(command).hashCode()) |
| | | : stationMoveCoordinator.buildPathSignatureHash(command)); |
| | | } |
| | | |
| | | private String buildFallbackPathSignature(StationCommand command) { |
| | | if (command == null) { |
| | | return ""; |
| | | } |
| | | return String.valueOf(command.getCommandType()) |
| | | + "_" + command.getStationId() |
| | | + "_" + command.getTargetStaNo() |
| | | + "_" + command.getNavigatePath() |
| | | + "_" + command.getLiftTransferPath() |
| | | + "_" + command.getOriginalNavigatePath(); |
| | | } |
| | | |
| | | private int clearIssuedMoveCommandsDuringIdleStay(StationTaskIdleTrack idleTrack, |
| | |
| | | return pathLenFactor; |
| | | } |
| | | |
| | | enum RerouteSceneType { |
| | | RUN_BLOCK_REROUTE, |
| | | IDLE_RECOVER, |
| | | OUT_ORDER, |
| | | WATCH_CIRCLE |
| | | } |
| | | |
| | | static final class RerouteDecision { |
| | | private final boolean skip; |
| | | private final String skipReason; |
| | | private final Integer targetStationId; |
| | | private final OutOrderDispatchDecision dispatchDecision; |
| | | |
| | | private RerouteDecision(boolean skip, |
| | | String skipReason, |
| | | Integer targetStationId, |
| | | OutOrderDispatchDecision dispatchDecision) { |
| | | this.skip = skip; |
| | | this.skipReason = skipReason; |
| | | this.targetStationId = targetStationId; |
| | | this.dispatchDecision = dispatchDecision; |
| | | } |
| | | |
| | | static RerouteDecision skip(String reason) { |
| | | return new RerouteDecision(true, reason, null, null); |
| | | } |
| | | |
| | | static RerouteDecision proceed(Integer targetStationId) { |
| | | return new RerouteDecision(false, null, targetStationId, null); |
| | | } |
| | | |
| | | static RerouteDecision proceed(Integer targetStationId, |
| | | OutOrderDispatchDecision dispatchDecision) { |
| | | return new RerouteDecision(false, null, targetStationId, dispatchDecision); |
| | | } |
| | | |
| | | boolean skip() { |
| | | return skip; |
| | | } |
| | | |
| | | String skipReason() { |
| | | return skipReason; |
| | | } |
| | | |
| | | Integer targetStationId() { |
| | | return targetStationId; |
| | | } |
| | | |
| | | OutOrderDispatchDecision dispatchDecision() { |
| | | return dispatchDecision; |
| | | } |
| | | } |
| | | |
| | | static final class RerouteContext { |
| | | private final RerouteSceneType sceneType; |
| | | private final BasDevp basDevp; |
| | | private final StationThread stationThread; |
| | | private final StationProtocol stationProtocol; |
| | | private final WrkMast wrkMast; |
| | | private final List<Integer> outOrderStationIds; |
| | | private final Double pathLenFactor; |
| | | private final String dispatchScene; |
| | | private Integer dispatchDeviceNo; |
| | | private boolean useRunBlockCommand; |
| | | private boolean checkSuppressDispatch; |
| | | private boolean requireOutOrderDispatchLock; |
| | | private boolean cancelSessionBeforeDispatch; |
| | | private boolean resetSegmentCommandsBeforeDispatch; |
| | | private boolean clearIdleIssuedCommands; |
| | | private boolean checkRecentDispatch; |
| | | private String executionLockKey; |
| | | private int executionLockSeconds; |
| | | private StationTaskIdleTrack idleTrack; |
| | | |
| | | private RerouteContext(RerouteSceneType sceneType, |
| | | BasDevp basDevp, |
| | | StationThread stationThread, |
| | | StationProtocol stationProtocol, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds, |
| | | Double pathLenFactor, |
| | | String dispatchScene) { |
| | | this.sceneType = sceneType; |
| | | this.basDevp = basDevp; |
| | | this.stationThread = stationThread; |
| | | this.stationProtocol = stationProtocol; |
| | | this.wrkMast = wrkMast; |
| | | this.outOrderStationIds = outOrderStationIds == null ? Collections.emptyList() : outOrderStationIds; |
| | | this.pathLenFactor = pathLenFactor; |
| | | this.dispatchScene = dispatchScene; |
| | | this.dispatchDeviceNo = basDevp == null ? null : basDevp.getDevpNo(); |
| | | } |
| | | |
| | | static RerouteContext create(RerouteSceneType sceneType, |
| | | BasDevp basDevp, |
| | | StationThread stationThread, |
| | | StationProtocol stationProtocol, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds, |
| | | Double pathLenFactor, |
| | | String dispatchScene) { |
| | | return new RerouteContext(sceneType, basDevp, stationThread, stationProtocol, wrkMast, outOrderStationIds, pathLenFactor, dispatchScene); |
| | | } |
| | | |
| | | RerouteContext withDispatchDeviceNo(Integer dispatchDeviceNo) { |
| | | this.dispatchDeviceNo = dispatchDeviceNo; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withRunBlockCommand() { |
| | | this.useRunBlockCommand = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withSuppressDispatchGuard() { |
| | | this.checkSuppressDispatch = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withOutOrderDispatchLock() { |
| | | this.requireOutOrderDispatchLock = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withCancelSessionBeforeDispatch() { |
| | | this.cancelSessionBeforeDispatch = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withResetSegmentCommandsBeforeDispatch() { |
| | | this.resetSegmentCommandsBeforeDispatch = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext clearIdleIssuedCommands(StationTaskIdleTrack idleTrack) { |
| | | this.clearIdleIssuedCommands = true; |
| | | this.idleTrack = idleTrack; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withRecentDispatchGuard() { |
| | | this.checkRecentDispatch = true; |
| | | return this; |
| | | } |
| | | |
| | | RerouteContext withExecutionLock(String executionLockKey, int executionLockSeconds) { |
| | | this.executionLockKey = executionLockKey; |
| | | this.executionLockSeconds = executionLockSeconds; |
| | | return this; |
| | | } |
| | | |
| | | RerouteSceneType sceneType() { |
| | | return sceneType; |
| | | } |
| | | |
| | | BasDevp basDevp() { |
| | | return basDevp; |
| | | } |
| | | |
| | | StationThread stationThread() { |
| | | return stationThread; |
| | | } |
| | | |
| | | StationProtocol stationProtocol() { |
| | | return stationProtocol; |
| | | } |
| | | |
| | | WrkMast wrkMast() { |
| | | return wrkMast; |
| | | } |
| | | |
| | | List<Integer> outOrderStationIds() { |
| | | return outOrderStationIds; |
| | | } |
| | | |
| | | Double pathLenFactor() { |
| | | return pathLenFactor; |
| | | } |
| | | |
| | | String dispatchScene() { |
| | | return dispatchScene; |
| | | } |
| | | |
| | | Integer dispatchDeviceNo() { |
| | | return dispatchDeviceNo; |
| | | } |
| | | |
| | | boolean useRunBlockCommand() { |
| | | return useRunBlockCommand; |
| | | } |
| | | |
| | | boolean checkSuppressDispatch() { |
| | | return checkSuppressDispatch; |
| | | } |
| | | |
| | | boolean requireOutOrderDispatchLock() { |
| | | return requireOutOrderDispatchLock; |
| | | } |
| | | |
| | | boolean cancelSessionBeforeDispatch() { |
| | | return cancelSessionBeforeDispatch; |
| | | } |
| | | |
| | | boolean resetSegmentCommandsBeforeDispatch() { |
| | | return resetSegmentCommandsBeforeDispatch; |
| | | } |
| | | |
| | | boolean clearIdleIssuedCommands() { |
| | | return clearIdleIssuedCommands; |
| | | } |
| | | |
| | | boolean checkRecentDispatch() { |
| | | return checkRecentDispatch; |
| | | } |
| | | |
| | | String executionLockKey() { |
| | | return executionLockKey; |
| | | } |
| | | |
| | | int executionLockSeconds() { |
| | | return executionLockSeconds; |
| | | } |
| | | |
| | | StationTaskIdleTrack idleTrack() { |
| | | return idleTrack; |
| | | } |
| | | } |
| | | |
| | | static final class RerouteCommandPlan { |
| | | private final boolean skip; |
| | | private final String skipReason; |
| | | private final StationCommand command; |
| | | private final RerouteDecision decision; |
| | | private final String dispatchScene; |
| | | |
| | | private RerouteCommandPlan(boolean skip, |
| | | String skipReason, |
| | | StationCommand command, |
| | | RerouteDecision decision, |
| | | String dispatchScene) { |
| | | this.skip = skip; |
| | | this.skipReason = skipReason; |
| | | this.command = command; |
| | | this.decision = decision; |
| | | this.dispatchScene = dispatchScene; |
| | | } |
| | | |
| | | static RerouteCommandPlan skip(String reason) { |
| | | return new RerouteCommandPlan(true, reason, null, null, null); |
| | | } |
| | | |
| | | static RerouteCommandPlan dispatch(StationCommand command, |
| | | RerouteDecision decision, |
| | | String dispatchScene) { |
| | | return new RerouteCommandPlan(false, null, command, decision, dispatchScene); |
| | | } |
| | | |
| | | boolean skip() { |
| | | return skip; |
| | | } |
| | | |
| | | String skipReason() { |
| | | return skipReason; |
| | | } |
| | | |
| | | StationCommand command() { |
| | | return command; |
| | | } |
| | | |
| | | RerouteDecision decision() { |
| | | return decision; |
| | | } |
| | | |
| | | String dispatchScene() { |
| | | return dispatchScene; |
| | | } |
| | | } |
| | | |
| | | static final class RerouteExecutionResult { |
| | | private final boolean skipped; |
| | | private final String skipReason; |
| | | private final boolean dispatched; |
| | | private final StationCommand command; |
| | | private final int clearedCommandCount; |
| | | |
| | | private RerouteExecutionResult(boolean skipped, |
| | | String skipReason, |
| | | boolean dispatched, |
| | | StationCommand command, |
| | | int clearedCommandCount) { |
| | | this.skipped = skipped; |
| | | this.skipReason = skipReason; |
| | | this.dispatched = dispatched; |
| | | this.command = command; |
| | | this.clearedCommandCount = clearedCommandCount; |
| | | } |
| | | |
| | | static RerouteExecutionResult skip(String reason) { |
| | | return new RerouteExecutionResult(true, reason, false, null, 0); |
| | | } |
| | | |
| | | static RerouteExecutionResult dispatched(StationCommand command, |
| | | int clearedCommandCount) { |
| | | return new RerouteExecutionResult(false, null, true, command, clearedCommandCount); |
| | | } |
| | | |
| | | boolean skipped() { |
| | | return skipped; |
| | | } |
| | | |
| | | String skipReason() { |
| | | return skipReason; |
| | | } |
| | | |
| | | boolean dispatched() { |
| | | return dispatched; |
| | | } |
| | | |
| | | StationCommand command() { |
| | | return command; |
| | | } |
| | | |
| | | int clearedCommandCount() { |
| | | return clearedCommandCount; |
| | | } |
| | | } |
| | | |
| | | private static class OutOrderDispatchDecision { |
| | | private final Integer targetStationId; |
| | | private final boolean circle; |