| | |
| | | } |
| | | |
| | | public void submitStationInTasks(MainProcessLane lane, long minIntervalMs) { |
| | | // 入库下发依赖单轮共享的承载预占状态,必须整体串行,避免多个站点并发时同时通过容量检查。 |
| | | mainProcessTaskSubmitter.submitSerialTask( |
| | | MainProcessLane.STATION, |
| | | "stationInExecute", |
| | | MainProcessLane.STATION_SCAN, |
| | | "submitStationInTasks", |
| | | minIntervalMs, |
| | | new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | stationInExecute(); |
| | | submitStationInTasksInternal(lane, minIntervalMs); |
| | | } |
| | | } |
| | | ); |
| | | } |
| | | |
| | | private void submitStationInTasksInternal(MainProcessLane lane, long minIntervalMs) { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (final BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | Map<Integer, StationProtocol> stationMap = stationThread.getStatusMap(); |
| | | if (stationMap == null || stationMap.isEmpty()) { |
| | | continue; |
| | | } |
| | | List<StationObjModel> list = basDevp.getBarcodeStationList$(); |
| | | for (final StationObjModel stationObjModel : list) { |
| | | Integer stationId = stationObjModel == null ? null : stationObjModel.getStationId(); |
| | | if (stationId == null || !stationMap.containsKey(stationId)) { |
| | | continue; |
| | | } |
| | | mainProcessTaskSubmitter.submitKeyedSerialTask( |
| | | lane, |
| | | stationId, |
| | | "stationInExecute", |
| | | minIntervalMs, |
| | | new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | stationInExecute(basDevp, stationObjModel); |
| | | } |
| | | } |
| | | ); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public void submitCrnStationOutTasks(long minIntervalMs) { |
| | |
| | | } |
| | | |
| | | public void submitCrnStationOutTasks(MainProcessLane lane, long minIntervalMs) { |
| | | // 出库站点下发同样会预占输送线/环线容量,与 stationInExecute 共用 STATION lane 串行。 |
| | | mainProcessTaskSubmitter.submitSerialTask( |
| | | MainProcessLane.STATION, |
| | | "crnStationOutExecute", |
| | | MainProcessLane.STATION_SCAN, |
| | | "submitCrnStationOutTasks", |
| | | minIntervalMs, |
| | | new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | crnStationOutExecute(); |
| | | submitCrnStationOutTasksInternal(lane, minIntervalMs); |
| | | } |
| | | } |
| | | ); |
| | | } |
| | | |
| | | private void submitCrnStationOutTasksInternal(MainProcessLane lane, long minIntervalMs) { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | .eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts) |
| | | .isNotNull("crn_no") |
| | | ); |
| | | for (final WrkMast wrkMast : wrkMasts) { |
| | | Integer laneKey = getCrnStationOutLaneKey(wrkMast); |
| | | mainProcessTaskSubmitter.submitKeyedSerialTask( |
| | | lane, |
| | | laneKey, |
| | | "crnStationOutExecute", |
| | | minIntervalMs, |
| | | new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | crnStationOutExecute(wrkMast); |
| | | } |
| | | } |
| | | ); |
| | | } |
| | | } |
| | | |
| | | public void submitDualCrnStationOutTasks(long minIntervalMs) { |
| | |
| | | && stationProtocol.getTaskNo() > 0 |
| | | ) { |
| | | //检测任务是否生成 |
| | | WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("barcode", stationProtocol.getBarcode())); |
| | | WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>() |
| | | .eq("barcode", stationProtocol.getBarcode()) |
| | | .eq("io_type", WrkIoType.IN.id) |
| | | ); |
| | | if (wrkMast == null) { |
| | | logDebugLimited("station_in_wait_wrk_" + stationId + "_" + stationProtocol.getTaskNo(), 3, |
| | | "[WCS Debug][条码站入库] 条码站已有站点任务号但未找到入库工作档,等待任务生成。stationId={},stationTaskNo={},barcode={},isLoading={},isAutoing={}", |
| | | stationId, stationProtocol.getTaskNo(), stationProtocol.getBarcode(), |
| | | stationProtocol.isLoading(), stationProtocol.isAutoing()); |
| | | return false; |
| | | } |
| | | |
| | | if (wrkMast.getWrkSts() == WrkStsType.INBOUND_DEVICE_RUN.sts) { |
| | | logDebugLimited("station_in_already_run_" + wrkMast.getWrkNo(), 5, |
| | | "[WCS Debug][条码站入库] 入库工作档已处于设备上走状态,等待输送线/PLC状态推进。stationId={},wrkNo={},barcode={},locNo={},wrkSts={}", |
| | | stationId, wrkMast.getWrkNo(), stationProtocol.getBarcode(), |
| | | wrkMast.getLocNo(), wrkMast.getWrkSts()); |
| | | return false; |
| | | } |
| | | |
| | | String locNo = wrkMast.getLocNo(); |
| | | News.info("[WCS Debug][条码站入库] 准备匹配入库目标站。stationId={},stationTaskNo={},wrkNo={},barcode={},locNo={},wrkSts={}", |
| | | stationId, stationProtocol.getTaskNo(), wrkMast.getWrkNo(), |
| | | stationProtocol.getBarcode(), locNo, wrkMast.getWrkSts()); |
| | | FindCrnNoResult findCrnNoResult = commonService.findCrnNoByLocNo(locNo); |
| | | if (findCrnNoResult == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,未匹配到堆垛机", wrkMast.getWrkNo()); |
| | |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), targetStationId, loadGuardState); |
| | | |
| | | if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) { |
| | | logDebugLimited("station_in_dispatch_blocked_" + wrkMast.getWrkNo(), 3, |
| | | "[WCS Debug][条码站入库] 入库输送命令暂缓,下发容量/环线负载受限。stationId={},targetStationId={},wrkNo={},currentStationTaskCount={},throughLoop={},loopNo={},hitStationId={}", |
| | | stationId, targetStationId, wrkMast.getWrkNo(), currentStationTaskCountRef[0], |
| | | loopHitResult.isThroughLoop(), loopHitResult.getLoopNo(), loopHitResult.getHitStationId()); |
| | | return true; |
| | | } |
| | | |
| | | long commandStartMs = System.currentTimeMillis(); |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationId, targetStationId, 0); |
| | | News.info("[WCS Debug][条码站入库] 获取入库输送命令完成。stationId={},targetStationId={},wrkNo={},costMs={},command={}", |
| | | stationId, targetStationId, wrkMast.getWrkNo(), |
| | | System.currentTimeMillis() - commandStartMs, JSON.toJSONString(command)); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "{}工作,获取输送线命令失败", wrkMast.getWrkNo()); |
| | | return false; |
| | |
| | | if (wrkMastService.updateById(wrkMast)) { |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | News.info("输送站点入库命令下发成功,站点号={},工作号={},命令数据={}", stationId, wrkMast.getWrkNo(), JSON.toJSONString(command)); |
| | | News.info("[WCS Debug][条码站入库] 入库输送命令已入队。stationId={},targetStationId={},wrkNo={},barcode={},locNo={},deviceNo={}", |
| | | stationId, targetStationId, wrkMast.getWrkNo(), stationProtocol.getBarcode(), |
| | | locNo, basDevp.getDevpNo()); |
| | | redisUtil.set(RedisKeyType.STATION_IN_EXECUTE_LIMIT.key + stationId, "lock", 5); |
| | | loadGuardState.reserveLoopTask(loopHitResult.getLoopNo()); |
| | | saveLoopLoadReserve(wrkMast.getWrkNo(), loopHitResult); |
| | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | private Integer getCrnStationOutLaneKey(WrkMast wrkMast) { |
| | | if (wrkMast == null) { |
| | | return null; |
| | | } |
| | | Object infoObj = redisUtil.get(RedisKeyType.CRN_OUT_TASK_COMPLETE_STATION_INFO.key + wrkMast.getWrkNo()); |
| | | if (infoObj != null) { |
| | | try { |
| | | StationObjModel stationObjModel = JSON.parseObject(infoObj.toString(), StationObjModel.class); |
| | | if (stationObjModel != null && stationObjModel.getStationId() != null) { |
| | | return stationObjModel.getStationId(); |
| | | } |
| | | } catch (Exception e) { |
| | | News.error("[WCS Debug][站点出库] 解析出库缓存站点失败,工作号={},cache={}", wrkMast.getWrkNo(), infoObj); |
| | | } |
| | | } |
| | | if (wrkMast.getSourceStaNo() != null) { |
| | | return wrkMast.getSourceStaNo(); |
| | | } |
| | | if (wrkMast.getStaNo() != null) { |
| | | return wrkMast.getStaNo(); |
| | | } |
| | | return wrkMast.getWrkNo(); |
| | | } |
| | | |
| | | public void crnStationOutExecute(WrkMast wrkMast) { |
| | |
| | | redisUtil.expire(RedisKeyType.STATION_CYCLE_LOAD_RESERVE.key, LOOP_LOAD_RESERVE_EXPIRE_SECONDS); |
| | | } |
| | | |
| | | private void logDebugLimited(String lockKey, int seconds, String format, Object... arguments) { |
| | | String redisKey = RedisKeyType.LOG_LIMIT.key + "wcs_debug_" + lockKey; |
| | | try { |
| | | Object lock = redisUtil.get(redisKey); |
| | | if (lock != null) { |
| | | return; |
| | | } |
| | | redisUtil.set(redisKey, "lock", seconds); |
| | | } catch (Exception e) { |
| | | // 诊断日志不能影响主流程。 |
| | | } |
| | | News.info(format, arguments); |
| | | } |
| | | |
| | | private DispatchLimitConfig getDispatchLimitConfig() { |
| | | DispatchLimitConfig config = new DispatchLimitConfig(); |
| | | Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); |