From 59b7091591ca7d4aceb0ea6c9323c955b81f0f82 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Tue, 8 Oct 2024 11:41:37 +0800 Subject: [PATCH] update --- .../java/a8k/baseservice/AppExceptionBuilder.java | 7 +- .../a8k/hardware/type/a8kcanprotocol/A8kEcode.java | 1 + .../a8k/service/appctrl/MainFlowCtrlService.java | 18 +- .../appctrl/action/base/A8kActionStepType.java | 3 +- .../mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java | 55 +--- .../action/mainflow/SEQ3_APPLAY_RESOURCE.java | 130 +++++++++ .../appctrl/action/mainflow/SEQ3_PRE_PROCESS.java | 294 --------------------- .../appctrl/action/mainflow/SEQ4_PRE_PROCESS.java | 258 ++++++++++++++++++ .../service/appstate/ConsumablesMgrService.java | 6 +- .../java/a8k/service/appstate/GStateService.java | 8 - .../appstate/IncubationPlateMgrService.java | 21 +- .../appstate/TubeProcessContextMgrService.java | 24 +- .../appstate/TubeProcessStateMgrService.java | 46 ++++ .../appstate/resource/A8kPublicResourceType.java | 1 + .../a8k/service/appstate/type/IncubationPlate.java | 29 -- .../service/appstate/type/ProjProcessContext.java | 13 +- src/main/java/a8k/service/appstate/type/Tube.java | 1 + .../a8k/service/appstate/type/state/TubeState.java | 13 + .../java/a8k/type/ecode/ConsumeNotEnoughError.java | 4 +- 19 files changed, 522 insertions(+), 410 deletions(-) create mode 100644 src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_APPLAY_RESOURCE.java delete mode 100644 src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_PRE_PROCESS.java create mode 100644 src/main/java/a8k/service/appctrl/action/mainflow/SEQ4_PRE_PROCESS.java create mode 100644 src/main/java/a8k/service/appstate/TubeProcessStateMgrService.java diff --git a/src/main/java/a8k/baseservice/AppExceptionBuilder.java b/src/main/java/a8k/baseservice/AppExceptionBuilder.java index 98ca1ec..6fd590b 100644 --- a/src/main/java/a8k/baseservice/AppExceptionBuilder.java +++ b/src/main/java/a8k/baseservice/AppExceptionBuilder.java @@ -1,5 +1,6 @@ package a8k.baseservice; +import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.type.ecode.AppCodeError; import a8k.type.ecode.AppError; import a8k.type.ecode.ConsumeNotEnoughError; @@ -31,7 +32,11 @@ public class AppExceptionBuilder { return new AppException(errors.get(0)); } - public AppException buildAppCodeErrorException(String extraMsg) { + public AppException buildAppCodeErrorException(String extraMsg) { return new AppException(new AppCodeError(extraMsg)); } + + public AppException buildAppException(A8kEcode code) { + return new AppException(new AppError(code)); + } } diff --git a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java index b9e35b6..5c6dcce 100644 --- a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java +++ b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java @@ -58,6 +58,7 @@ public enum A8kEcode { TubeHolderTypeIsNotSupport(140),//试管架类型不支持 EmergencySampleIsProcessing(141),//急诊样本正在处理中 ConsumeNotEnough(142),//耗材不足 + TipNotEnough(143),//tip不足 TakeTubeFail(143),//取试管失败 /** diff --git a/src/main/java/a8k/service/appctrl/MainFlowCtrlService.java b/src/main/java/a8k/service/appctrl/MainFlowCtrlService.java index 0813666..0df42fb 100644 --- a/src/main/java/a8k/service/appctrl/MainFlowCtrlService.java +++ b/src/main/java/a8k/service/appctrl/MainFlowCtrlService.java @@ -16,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import java.util.Arrays; import java.util.List; @Component @@ -66,10 +67,17 @@ public class MainFlowCtrlService { } Boolean isAllowPause() { - return gstate.getCurProcessingTube() == null || - gstate.getCurProcessingTube().state.equals(TubeState.TO_BE_PROCESSED) || - gstate.getCurProcessingTube().state.equals(TubeState.PROCESS_COMPLETE) || - gstate.getCurProcessingTube().state.equals(TubeState.EMPTY); + if (gstate.getCurProcessingTube() != null) { + return !gstate.getCurProcessingTube().state.isEq(List.of( + TubeState.PRE_PROCESSING, + TubeState.PRE_PROCESSED, + TubeState.PROCESSING, + TubeState.PROCESSED, + TubeState.POST_PROCESSING, + TubeState.POST_PROCESSED + )); + } + return true; } void checkBeforeGuess() { @@ -81,7 +89,7 @@ public class MainFlowCtrlService { } changeWorkState(A8kWorkState.WORKING); } else if (state.pauseActionPending) { - if(!isAllowPause()){ + if (!isAllowPause()) { return; } if (state.workState != A8kWorkState.WORKING) { diff --git a/src/main/java/a8k/service/appctrl/action/base/A8kActionStepType.java b/src/main/java/a8k/service/appctrl/action/base/A8kActionStepType.java index d0e5d78..be35eda 100644 --- a/src/main/java/a8k/service/appctrl/action/base/A8kActionStepType.java +++ b/src/main/java/a8k/service/appctrl/action/base/A8kActionStepType.java @@ -8,7 +8,8 @@ public enum A8kActionStepType { SEQ1_ENTER_TUBEHOLDER_AND_SCAN, //入料并扫描 SEQ2_SWITCH_TO_THE_NEXT_TUBE,// 切换到下一个试管 - SEQ3_PRE_PROCESS, + SEQ3_APPLAY_RESOURCE,//申请资源 + SEQ4_PRE_PROCESS, // SEQ4_PROCESS, // SEQ5_POS_PROCESS_TUBE, diff --git a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java index 3d26efc..19be978 100644 --- a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java +++ b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ2_SWITCH_TO_THE_NEXT_TUBE.java @@ -1,12 +1,8 @@ package a8k.service.appctrl.action.mainflow; -import a8k.baseservice.AppExceptionBuilder; -import a8k.baseservice.appeventbus.AppEventBusService; -import a8k.service.appctrl.ConsumablesScanService; import a8k.service.appctrl.action.base.A8kActionStepType; import a8k.service.appctrl.action.base.A8kStepAction; -import a8k.service.appstate.ConsumablesMgrService; -import a8k.service.appstate.GStateService; +import a8k.service.appstate.*; import a8k.service.appstate.resource.A8kPublicResourceType; import a8k.service.appstate.type.TubeHolder; import a8k.service.appstate.type.Tube; @@ -37,20 +33,11 @@ public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { } @Resource - GStateService gstate; - - @Resource - SampleScanTransportCtrl sstc; - - @Resource - ConsumablesMgrService consumablesMgrService; - + GStateService gstate; @Resource - AppEventBusService ebus; - + SampleScanTransportCtrl sstc; @Resource - AppExceptionBuilder ebuilder; - + TubeProcessStateMgrService tubeProcessStateMgrService; @PostConstruct void init() { @@ -71,19 +58,6 @@ public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { return nextTubeIndex; } - //检查是否有足够的耗材 - Boolean isHasEnoughConsumables(Tube tube) { - return consumablesMgrService.isHasEnoughConsumables(tube.projIndex); - } - - //检查孵育盘是否有空位 - Boolean checkReactionPlateResource(Tube tube) { - Integer needPos = tube.projIndex.size(); - Integer emptyNum = gstate.getIncubationPlate().getEmptyPosNum(); - return emptyNum >= needPos; - } - - @Override public void doaction() throws AppException { /* * 1. 将下一个试管移动到预处理位 @@ -95,7 +69,6 @@ public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { boolean isEmergencyTube = false; int nextTubeIndex = -1; - if (gstate.getEmergencyTubePos().tube.state.equals(TubeState.TO_BE_PROCESSED)) { nextProcessTube = gstate.getEmergencyTubePos().tube; isEmergencyTube = true; @@ -104,27 +77,15 @@ public class SEQ2_SWITCH_TO_THE_NEXT_TUBE extends A8kStepAction { assert nextTubeIndex != -1; nextProcessTube = gstate.getTubeHolder().tubes[nextTubeIndex]; } - //检查孵育盘是否有空位 - if (!checkReactionPlateResource(nextProcessTube)) { - return; - } - - //检查耗材是否足够 - for (Integer projIndex : nextProcessTube.projIndex) { - if (!consumablesMgrService.isHasEnoughConsumables(projIndex)) { - throw ebuilder.buildConsumeNotEnoughError(projIndex); - } - } - //设置状态 if (isEmergencyTube) { - logger.info("处理急诊试管:{}", nextProcessTube); + logger.info("处理急诊试管:{}", nextProcessTube.sampleid); } else { - logger.info("处理下一个试管:{}", nextProcessTube); + logger.info("处理下一个试管:{}", nextProcessTube.sampleid); sstc.moveTubeToPreProcessPos(nextTubeIndex); } - nextProcessTube.state = TubeState.PRE_PROCESSING; - gstate.setCurProcessingTube(nextProcessTube); + + tubeProcessStateMgrService.pendingTube(nextProcessTube); } @Override public Boolean checkCondition() { diff --git a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_APPLAY_RESOURCE.java b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_APPLAY_RESOURCE.java new file mode 100644 index 0000000..1dcd7ea --- /dev/null +++ b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_APPLAY_RESOURCE.java @@ -0,0 +1,130 @@ +package a8k.service.appctrl.action.mainflow; + +import a8k.baseservice.AppExceptionBuilder; +import a8k.hardware.type.a8kcanprotocol.A8kEcode; +import a8k.service.appdata.AppProjInfoMgrService; +import a8k.service.appctrl.action.base.A8kActionStepType; +import a8k.service.appctrl.action.base.A8kStepAction; +import a8k.service.appstate.*; +import a8k.service.appstate.resource.A8kPublicResourceType; +import a8k.service.appstate.type.Tube; +import a8k.service.appstate.type.state.TubeState; +import a8k.type.Consumable; +import a8k.type.IncubatorPos; +import a8k.type.TipPos; +import a8k.type.exception.AppException; +import a8k.type.projecttype.A8kReactionFlowType; +import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * 核对物料资源是否足够 + * + * TUBE + * TO_BE_PROCESSED --> PRE_PROCESSING + */ +@Component +public class SEQ3_APPLAY_RESOURCE extends A8kStepAction { + static Logger logger = LoggerFactory.getLogger(SEQ3_APPLAY_RESOURCE.class); + + SEQ3_APPLAY_RESOURCE() { + super(A8kActionStepType.SEQ3_APPLAY_RESOURCE); + } + + @Resource + GStateService gstate; + @Resource + ConsumablesMgrService consumablesMgrService; //耗材管理 + @Resource + AppExceptionBuilder ebuilder; //异常构造器 + @Resource + IncubationPlateMgrService incubationPlateMgrService; //孵育盘管理 + @Resource + AppProjInfoMgrService appProjInfoMgrService; //项目信息管理 + @Resource + TubeProcessStateMgrService tubeProcessStateMgrService; //试管处理状态管理 + + + @PostConstruct + void init() { + } + + @Override public void doaction() throws AppException { + Tube tube = gstate.getCurProcessingTube(); + assert tube != null; + List projs = gstate.getCurProcessingTube().projIndex; + + //检查是否有足够的耗材 + for (Integer projin : projs) { + if (!consumablesMgrService.isHasEnoughConsumables(projs)) { + throw ebuilder.buildConsumeNotEnoughError(projin); + } + } + logger.info("check consumables ok"); + + //检查tip是否足够 + int tipNum = 0; + for (Integer proj : projs) { + A8kReactionFlowType flow = appProjInfoMgrService.getA8kReactionFlowTypeByProjIndex(proj); + assert flow != null; //由于先核对的耗材,这里就一定有对应的项目 + tipNum += flow.tipUseNum; + } + if (!consumablesMgrService.isHasEnoughTips(tipNum)) { + throw ebuilder.buildAppException(A8kEcode.TipNotEnough); + } + logger.info("check tips ok"); + + assert incubationPlateMgrService.isHasEnoughIncubationIDLEPos(projs.size()); + logger.info("check incubationPlate ok"); + + //申请项目耗材 + List consumables = consumablesMgrService.takeConsumables(projs); + //申请孵育盘位置 + List incubatorPoss = incubationPlateMgrService.takeIncubationIDLEPos(projs.size()); + assert consumables != null; + assert incubatorPoss != null; + //找到项目对应的A8kIdCardInfo + List a8kIdCardInfo = new ArrayList<>(); + for (Consumable consumable : consumables) { + A8kIdCardInfo idcardInfo = appProjInfoMgrService.getA8kIdCardInfoByLotId(consumable.lotId); + assert idcardInfo != null; + a8kIdCardInfo.add(idcardInfo); + } + //申请tip头 + List> tipPos = new ArrayList<>(); + for (int i = 0; i < projs.size(); i++) { + List tips = consumablesMgrService.takeTip(a8kIdCardInfo.get(i).reactionFlowType); + assert tips != null; + tipPos.add(tips); + } + //创建项目处理上下文 + tubeProcessStateMgrService.startProcessTube(a8kIdCardInfo, consumables, tipPos, incubatorPoss); + logger.info("apply resource ok"); + } + + @Override public Boolean checkCondition() { + Tube tube = gstate.getCurProcessingTube(); + if (tube == null) + return false; + + //当前正在工作 + Boolean cond1 = gstate.isWorking(); + //没有试管在处理 或者 当前试管处理完成 + Boolean cond2 = tube.state.equals(TubeState.PENDING); + //急诊有待处理的试管,或者试管架正在处理 + Boolean cond3 = incubationPlateMgrService.isHasEnoughIncubationIDLEPos(tube.projIndex.size()); + return cond1 && cond2 && cond3; + } + + @Override public List getResourceList() { + return List.of(A8kPublicResourceType.CurTubeProcessToken); + } +} diff --git a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_PRE_PROCESS.java b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_PRE_PROCESS.java deleted file mode 100644 index ec256f5..0000000 --- a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ3_PRE_PROCESS.java +++ /dev/null @@ -1,294 +0,0 @@ -package a8k.service.appctrl.action.mainflow; - -import a8k.OS; -import a8k.service.appdata.AppProjInfoMgrService; -import a8k.baseservice.AppExceptionBuilder; -import a8k.baseservice.appeventbus.AppEventBusService; -import a8k.service.appctrl.action.base.A8kActionStepType; -import a8k.service.appctrl.action.base.A8kStepAction; -import a8k.service.appstate.ConsumablesMgrService; -import a8k.service.appstate.GStateService; -import a8k.service.appstate.IncubationPlateMgrService; -import a8k.service.appstate.TubeProcessContextMgrService; -import a8k.service.appstate.resource.A8kPublicResourceType; -import a8k.service.appstate.type.Tube; -import a8k.service.appstate.type.state.TubeState; -import a8k.service.devicedriver.ctrl.HbotControlService; -import a8k.service.devicedriver.ctrl.ReactionPlatesTransmitCtrl; -import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; -import a8k.service.devicedriver.ctrl.SamplesPreProcesCtrl; -import a8k.type.Consumable; -import a8k.type.ConsumableGroup; -import a8k.type.IncubatorPos; -import a8k.type.TipPos; -import a8k.type.exception.AppException; -import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.*; - -/** - * - * 核对物料资源是否足够 - * TUBE - * TO_BE_PROCESSED --> PRE_PROCESSING - */ -@Component -public class SEQ3_PRE_PROCESS extends A8kStepAction { - static Logger logger = LoggerFactory.getLogger(SEQ3_PRE_PROCESS.class); - - SEQ3_PRE_PROCESS() { - super(A8kActionStepType.SEQ2_SWITCH_TO_THE_NEXT_TUBE); - } - - @Resource - GStateService gstate; - - @Resource - SampleScanTransportCtrl sstc; - - - @Resource - ConsumablesMgrService consumablesMgrService; - - @Resource - IncubationPlateMgrService incubationPlateMgrService; - - @Resource - AppProjInfoMgrService appProjInfoMgrService; - - @Resource - AppEventBusService ebus; - - @Resource - AppExceptionBuilder ebuilder; - - @Resource - TubeProcessContextMgrService tubeProcessContextMgrService; - - @Resource - ReactionPlatesTransmitCtrl reactionPlatesTransmitCtrl; - - @Resource - SamplesPreProcesCtrl samplesPreProcesCtrl; - - @Resource - HbotControlService hbotControlService; - - ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10)); - - - @PostConstruct - void init() { - } - - - /** - * 推出反应板夹 - * @throws AppException 异常 - */ - void prepareReactionPlate() throws AppException { - // Tube tube = gstate.getCurProcessingTube(); - // List projIndex = tube.projIndex; - // List incubatorPos = tube.incubatorPos; - // List bindConsumablesCh = tube.bindConsumablesCh; - // - // for (int i = 0; i < projIndex.size(); i++) { - // var tank = gstate.getIncubationPlate().getSubTank(incubatorPos.get(i)); - // reactionPlatesTransmitCtrl.pushPlate(bindConsumablesCh.get(i), incubatorPos.get(i)); - // tank.state = IncubationSubTankState.WAITING_FOR_DROP; - // } - } - - /** - * 摇匀并取盖 - * @throws AppException - */ - void shakeAndTakeCap() throws AppException { - // Tube tube = gstate.getCurProcessingTube(); - // if (tube.isEmergency) { - // //如果事急诊位则什么也不做 - // return; - // } - // - // TubeHolder tubeHolder = gstate.getTubeHolder(); - // if (!tubeHolder.tubeHolderType.equals(A8kTubeHolderType.BloodTube)) { - // //如果不是全血试管则什么也不做 - // return; - // } - // - // logger.info("摇匀并取盖"); - // samplesPreProcesCtrl.takeTubeAndJudgeTubeExist(tube.isHighTube); - // samplesPreProcesCtrl.shakeTube(45, 5); - // samplesPreProcesCtrl.takeTubeCap(); - } - - void hbotPrepareTip() throws AppException { - // Tube tube = gstate.getCurProcessingTube(); - // // hbotControlService.takeTip(); - // TipPos tippos = consumablesMgrService.takeNextTipPosAndSetUsed(); - // if (tippos == null) { - // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请Tip失败"); - // } - // - // Boolean suc = hbotControlService.takeTip(tippos.group, tippos.pos); - // if (!suc) { - // logger.warn("takeTip fail"); - // tube.ecode = A8kEcode.TakeTipFail; - // tube.state = TubeState.ERROR; - // } - // - // logger.info("takeTip success"); - } - - // @Override public void doaction() throws AppException { - // Tube tube = gstate.getCurProcessingTube(); - // //构建样本和耗材绑定关系 - // List bindConsumableCH = new ArrayList<>(); - // List consumablePosIndexList = new ArrayList<>(); - // List incubatorPosList = new ArrayList<>(); - // for (Integer projIndex : tube.projIndex) { - // ConsumableGroup chNum = consumablesMgrService.getChannelNumByProjIndex(projIndex); - // Integer consumablePosIndex = consumablesMgrService.allocConsumable(chNum); - // - // - // if (chNum == null) { - // logger.error("apply consumable failed, projIndex:{}", projIndex); - // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请耗材失败"); - // } - // if (consumablePosIndex == null) { - // logger.error("alloc consumable failed, projIndex:{}", projIndex); - // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请耗材失败x"); - // } - // bindConsumableCH.add(chNum); - // consumablePosIndexList.add(consumablePosIndex); - // incubatorPosList = gstate.getIncubationPlate().getEmptyPosList(tube.projIndex.size()); - // } - // tube.bindConsumablesCh = bindConsumableCH; - // tube.consumablePos = consumablePosIndexList; - // tube.incubatorPos = incubatorPosList; - // - // tubeProcessContextMgrService.updateTubeContext(tube);//更新样本上下文 - // - // //检测反应板是否有空位 - // if (gstate.getIncubationPlate().getEmptyPosNum() < tube.projIndex.size()) { - // throw ebuilder.buildAppCodeErrorException("预处理阶段,反应板空位不足"); - // } - // - // //准备反应板夹 - // var doPrepareReactionPlateFuture = executor.submit(() -> ZFnCall.callfn(this::prepareReactionPlate)); - // //摇匀并取盖 - // var doShakeAndTakeCapFuture = executor.submit(() -> ZFnCall.callfn(this::shakeAndTakeCap)); - // //准备Hbot Tip - // var doHbotPrepareTipFuture = executor.submit(() -> ZFnCall.callfn(this::hbotPrepareTip)); - // - // wait(doPrepareReactionPlateFuture); - // wait(doShakeAndTakeCapFuture); - // wait(doHbotPrepareTipFuture); - // - // List errors = new java.util.ArrayList<>(List.of()); - // try { - // errors.add(doPrepareReactionPlateFuture.get()); - // errors.add(doShakeAndTakeCapFuture.get()); - // errors.add(doHbotPrepareTipFuture.get()); - // } catch (InterruptedException | ExecutionException ignored) { - // } - // errors.removeIf(Objects::isNull); - // if (!errors.isEmpty()) { - // throw ebuilder.buildMutiErrorAppException(errors); - // } - // } - - @Override public void doaction() throws AppException { - // - // 1.准备3份反应板夹 - // 2.取tip头 - // 3.摇匀,脱帽 - // - - // 根据要做的项目,申请耗材 - List projs = gstate.getCurProcessingTube().projIndex; - - //申请项目耗材 - List consumables = consumablesMgrService.takeConsumables(projs); - //申请孵育盘位置 - List incubatorPoss = incubationPlateMgrService.takeIncubationIDLEPos(projs.size()); - assert consumables != null; - assert incubatorPoss != null; - //找到项目对应的A8kIdCardInfo - List a8kIdCardInfo = new ArrayList<>(); - for (Consumable consumable : consumables) { - A8kIdCardInfo idcardInfo = appProjInfoMgrService.getA8kIdCardInfoByLotId(consumable.lotId); - assert idcardInfo != null; - a8kIdCardInfo.add(idcardInfo); - } - //申请tip头 - List> tipPos = new ArrayList<>(); - for (int i = 0; i < projs.size(); i++) { - List tips = consumablesMgrService.takeTip(a8kIdCardInfo.get(i).reactionFlowType); - tipPos.add(tips); - } - assert tipPos.size() == projs.size(); - - - Tube tube = gstate.getCurProcessingTube(); - for (int i = 0; i < projs.size(); i++) { - tubeProcessContextMgrService.createProjProcessContext(tube, projs.get(i), consumables.get(i), incubatorPoss.get(i)); - } - - - // List tipPos - // consumablesMgrService.getChannelNumByProjIndex(projIndex); - - - // - // 计算需要执行的动作 - // - - // - // 执行动作 - // - - // - // 赋值状态 - // - - // - // 恢复状态 - // - - } - - - @Override public Boolean checkCondition() { - //当前正在工作 - Boolean cond1 = gstate.isWorking(); - //有需要进行预处理的样本 - Boolean cond2 = gstate.getCurProcessingTube() != null && gstate.getCurProcessingTube().state.equals(TubeState.PRE_PROCESSING); - return cond1 && cond2; - } - - @Override public List getResourceList() { - return List.of( - A8kPublicResourceType.IncubationPlateMotor, - A8kPublicResourceType.PlatesBoxMotor, - A8kPublicResourceType.HBOT - ); - } - - // - // UTILS - // - - void wait(Future future) { - while (!future.isDone()) { - OS.forceSleep(100); - } - } -} diff --git a/src/main/java/a8k/service/appctrl/action/mainflow/SEQ4_PRE_PROCESS.java b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ4_PRE_PROCESS.java new file mode 100644 index 0000000..c9d981e --- /dev/null +++ b/src/main/java/a8k/service/appctrl/action/mainflow/SEQ4_PRE_PROCESS.java @@ -0,0 +1,258 @@ +package a8k.service.appctrl.action.mainflow; + +import a8k.OS; +import a8k.service.appdata.AppProjInfoMgrService; +import a8k.baseservice.AppExceptionBuilder; +import a8k.baseservice.appeventbus.AppEventBusService; +import a8k.service.appctrl.action.base.A8kActionStepType; +import a8k.service.appctrl.action.base.A8kStepAction; +import a8k.service.appstate.ConsumablesMgrService; +import a8k.service.appstate.GStateService; +import a8k.service.appstate.IncubationPlateMgrService; +import a8k.service.appstate.TubeProcessContextMgrService; +import a8k.service.appstate.resource.A8kPublicResourceType; +import a8k.service.appstate.type.state.TubeState; +import a8k.service.devicedriver.ctrl.HbotControlService; +import a8k.service.devicedriver.ctrl.ReactionPlatesTransmitCtrl; +import a8k.service.devicedriver.ctrl.SampleScanTransportCtrl; +import a8k.service.devicedriver.ctrl.SamplesPreProcesCtrl; +import a8k.type.exception.AppException; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.*; + +/** + * + * 核对物料资源是否足够 + * TUBE + * TO_BE_PROCESSED --> PRE_PROCESSING + */ +@Component +public class SEQ4_PRE_PROCESS extends A8kStepAction { + static Logger logger = LoggerFactory.getLogger(SEQ4_PRE_PROCESS.class); + + SEQ4_PRE_PROCESS() { + super(A8kActionStepType.SEQ4_PRE_PROCESS); + } + + @Resource + GStateService gstate; + + @Resource + SampleScanTransportCtrl sstc; + + + @Resource + ConsumablesMgrService consumablesMgrService; + + @Resource + IncubationPlateMgrService incubationPlateMgrService; + + @Resource + AppProjInfoMgrService appProjInfoMgrService; + + @Resource + AppEventBusService ebus; + + @Resource + AppExceptionBuilder ebuilder; + + @Resource + TubeProcessContextMgrService tubeProcessContextMgrService; + + @Resource + ReactionPlatesTransmitCtrl reactionPlatesTransmitCtrl; + + @Resource + SamplesPreProcesCtrl samplesPreProcesCtrl; + + @Resource + HbotControlService hbotControlService; + + ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10)); + + + @PostConstruct + void init() { + } + + + /** + * 推出反应板夹 + * @throws AppException 异常 + */ + void prepareReactionPlate() throws AppException { + // Tube tube = gstate.getCurProcessingTube(); + // List projIndex = tube.projIndex; + // List incubatorPos = tube.incubatorPos; + // List bindConsumablesCh = tube.bindConsumablesCh; + // + // for (int i = 0; i < projIndex.size(); i++) { + // var tank = gstate.getIncubationPlate().getSubTank(incubatorPos.get(i)); + // reactionPlatesTransmitCtrl.pushPlate(bindConsumablesCh.get(i), incubatorPos.get(i)); + // tank.state = IncubationSubTankState.WAITING_FOR_DROP; + // } + } + + /** + * 摇匀并取盖 + * @throws AppException + */ + void shakeAndTakeCap() throws AppException { + // Tube tube = gstate.getCurProcessingTube(); + // if (tube.isEmergency) { + // //如果事急诊位则什么也不做 + // return; + // } + // + // TubeHolder tubeHolder = gstate.getTubeHolder(); + // if (!tubeHolder.tubeHolderType.equals(A8kTubeHolderType.BloodTube)) { + // //如果不是全血试管则什么也不做 + // return; + // } + // + // logger.info("摇匀并取盖"); + // samplesPreProcesCtrl.takeTubeAndJudgeTubeExist(tube.isHighTube); + // samplesPreProcesCtrl.shakeTube(45, 5); + // samplesPreProcesCtrl.takeTubeCap(); + } + + void hbotPrepareTip() throws AppException { + // Tube tube = gstate.getCurProcessingTube(); + // // hbotControlService.takeTip(); + // TipPos tippos = consumablesMgrService.takeNextTipPosAndSetUsed(); + // if (tippos == null) { + // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请Tip失败"); + // } + // + // Boolean suc = hbotControlService.takeTip(tippos.group, tippos.pos); + // if (!suc) { + // logger.warn("takeTip fail"); + // tube.ecode = A8kEcode.TakeTipFail; + // tube.state = TubeState.ERROR; + // } + // + // logger.info("takeTip success"); + } + + // @Override public void doaction() throws AppException { + // Tube tube = gstate.getCurProcessingTube(); + // //构建样本和耗材绑定关系 + // List bindConsumableCH = new ArrayList<>(); + // List consumablePosIndexList = new ArrayList<>(); + // List incubatorPosList = new ArrayList<>(); + // for (Integer projIndex : tube.projIndex) { + // ConsumableGroup chNum = consumablesMgrService.getChannelNumByProjIndex(projIndex); + // Integer consumablePosIndex = consumablesMgrService.allocConsumable(chNum); + // + // + // if (chNum == null) { + // logger.error("apply consumable failed, projIndex:{}", projIndex); + // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请耗材失败"); + // } + // if (consumablePosIndex == null) { + // logger.error("alloc consumable failed, projIndex:{}", projIndex); + // throw ebuilder.buildAppCodeErrorException("预处理阶段,申请耗材失败x"); + // } + // bindConsumableCH.add(chNum); + // consumablePosIndexList.add(consumablePosIndex); + // incubatorPosList = gstate.getIncubationPlate().getEmptyPosList(tube.projIndex.size()); + // } + // tube.bindConsumablesCh = bindConsumableCH; + // tube.consumablePos = consumablePosIndexList; + // tube.incubatorPos = incubatorPosList; + // + // tubeProcessContextMgrService.updateTubeContext(tube);//更新样本上下文 + // + // //检测反应板是否有空位 + // if (gstate.getIncubationPlate().getEmptyPosNum() < tube.projIndex.size()) { + // throw ebuilder.buildAppCodeErrorException("预处理阶段,反应板空位不足"); + // } + // + // //准备反应板夹 + // var doPrepareReactionPlateFuture = executor.submit(() -> ZFnCall.callfn(this::prepareReactionPlate)); + // //摇匀并取盖 + // var doShakeAndTakeCapFuture = executor.submit(() -> ZFnCall.callfn(this::shakeAndTakeCap)); + // //准备Hbot Tip + // var doHbotPrepareTipFuture = executor.submit(() -> ZFnCall.callfn(this::hbotPrepareTip)); + // + // wait(doPrepareReactionPlateFuture); + // wait(doShakeAndTakeCapFuture); + // wait(doHbotPrepareTipFuture); + // + // List errors = new java.util.ArrayList<>(List.of()); + // try { + // errors.add(doPrepareReactionPlateFuture.get()); + // errors.add(doShakeAndTakeCapFuture.get()); + // errors.add(doHbotPrepareTipFuture.get()); + // } catch (InterruptedException | ExecutionException ignored) { + // } + // errors.removeIf(Objects::isNull); + // if (!errors.isEmpty()) { + // throw ebuilder.buildMutiErrorAppException(errors); + // } + // } + + @Override public void doaction() throws AppException { + // + // 1.准备3份反应板夹 + // 2.取tip头 + // 3.摇匀,脱帽 + // + + + + // List tipPos + // consumablesMgrService.getChannelNumByProjIndex(projIndex); + + + // + // 计算需要执行的动作 + // + + // + // 执行动作 + // + + // + // 赋值状态 + // + + // + // 恢复状态 + // + + } + + + @Override public Boolean checkCondition() { + //当前正在工作 + Boolean cond1 = gstate.isWorking(); + //有需要进行预处理的样本 + Boolean cond2 = gstate.getCurProcessingTube() != null && gstate.getCurProcessingTube().state.equals(TubeState.PRE_PROCESSING); + return cond1 && cond2; + } + + @Override public List getResourceList() { + return List.of( + A8kPublicResourceType.IncubationPlateMotor, + A8kPublicResourceType.PlatesBoxMotor, + A8kPublicResourceType.HBOT + ); + } + + // + // UTILS + // + + void wait(Future future) { + while (!future.isDone()) { + OS.forceSleep(100); + } + } +} diff --git a/src/main/java/a8k/service/appstate/ConsumablesMgrService.java b/src/main/java/a8k/service/appstate/ConsumablesMgrService.java index b00e4cf..73a7910 100644 --- a/src/main/java/a8k/service/appstate/ConsumablesMgrService.java +++ b/src/main/java/a8k/service/appstate/ConsumablesMgrService.java @@ -143,10 +143,8 @@ public class ConsumablesMgrService { * @param projIndex 项目索引 * @return 是否足够 */ - synchronized public Boolean isHasEnoughTips(List projIndex) { - Integer tipCnt = projIndex.size() * 5; - Integer total = priGetTipRemainNum(); - return total >= tipCnt; + synchronized public Boolean isHasEnoughTips(Integer tipNum) { + return priGetTipRemainNum() >= tipNum; } diff --git a/src/main/java/a8k/service/appstate/GStateService.java b/src/main/java/a8k/service/appstate/GStateService.java index 2424add..94bc5d4 100644 --- a/src/main/java/a8k/service/appstate/GStateService.java +++ b/src/main/java/a8k/service/appstate/GStateService.java @@ -75,12 +75,4 @@ public class GStateService { return tubeHolder.state; } - synchronized public Tube getCurProcessingTube() { - return curProcessingTube; - } - - synchronized public void setCurProcessingTube(Tube tube) { - curProcessingTube = tube; - } - } diff --git a/src/main/java/a8k/service/appstate/IncubationPlateMgrService.java b/src/main/java/a8k/service/appstate/IncubationPlateMgrService.java index 7b51b88..f201fbf 100644 --- a/src/main/java/a8k/service/appstate/IncubationPlateMgrService.java +++ b/src/main/java/a8k/service/appstate/IncubationPlateMgrService.java @@ -18,8 +18,21 @@ public class IncubationPlateMgrService { @Resource GStateService gstate; + synchronized public Boolean isHasEnoughIncubationIDLEPos(Integer num) { + var incubationState = gstate.getIncubationPlate(); + var subtanks = incubationState.subtanks; + + int count = 0; + for (IncubationSubTank subtank : subtanks) { + if (subtank.state.equals(IncubationSubTankState.EMPTY)) { + count++; + } + } + return count >= num; + } + - public List takeIncubationIDLEPos(Integer num) { + synchronized public List takeIncubationIDLEPos(Integer num) { var incubationState = gstate.getIncubationPlate(); var subtanks = incubationState.subtanks; @@ -42,7 +55,7 @@ public class IncubationPlateMgrService { return ret; } - public void setIncubationPlateState(IncubatorPos pos, IncubationSubTankState state) { + synchronized public void setIncubationPlateState(IncubatorPos pos, IncubationSubTankState state) { var incubationState = gstate.getIncubationPlate(); var subtanks = incubationState.subtanks; @@ -54,13 +67,13 @@ public class IncubationPlateMgrService { } } - public void setIncuabtionPlateState(List posList, IncubationSubTankState state) { + synchronized public void setIncuabtionPlateState(List posList, IncubationSubTankState state) { for (IncubatorPos pos : posList) { setIncubationPlateState(pos, state); } } - public void setIncubationPlateStateError(IncubatorPos pos, A8kEcode ecode) { + synchronized public void setIncubationPlateStateError(IncubatorPos pos, A8kEcode ecode) { var incubationState = gstate.getIncubationPlate(); var subtanks = incubationState.subtanks; diff --git a/src/main/java/a8k/service/appstate/TubeProcessContextMgrService.java b/src/main/java/a8k/service/appstate/TubeProcessContextMgrService.java index 6196bc2..51c6cb0 100644 --- a/src/main/java/a8k/service/appstate/TubeProcessContextMgrService.java +++ b/src/main/java/a8k/service/appstate/TubeProcessContextMgrService.java @@ -7,7 +7,10 @@ import a8k.service.appstate.type.TubeProcessContext; import a8k.service.appstate.type.state.TubeState; import a8k.type.Consumable; import a8k.type.IncubatorPos; +import a8k.type.TipPos; +import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; import jakarta.annotation.Resource; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; @@ -118,20 +121,17 @@ public class TubeProcessContextMgrService { return null; } - synchronized public void updateTubeContext(Tube tube) { - TubeProcessContext context = getTubeContext(tube.sampleid); - if (context != null) { - assignTubeProcessContext(context, tube); - } - } - synchronized public void createProjProcessContext(Tube tube, Integer projIndex, Consumable consumable, IncubatorPos incubatorPos) { + synchronized public void createProjProcessContext(@NotNull Tube tube, @NotNull A8kIdCardInfo idCardInfo,@NotNull Consumable consumable, @NotNull List tipPos, @NotNull IncubatorPos incubatorPos) { ProjProcessContext context = new ProjProcessContext(); - context.projIndex = projIndex; - context.consumable = consumable; - context.incubatorPos = incubatorPos; - context.sampleId = tube.sampleid; - context.uuid = UUID.randomUUID().toString(); + context.projIndex = idCardInfo.projIndex; + context.a8kIdCardInfo = idCardInfo; + context.consumable = consumable; + context.incubatorPos = incubatorPos; + context.tipPos = tipPos; + context.sampleId = tube.sampleid; + context.uuid = UUID.randomUUID().toString(); + tube.projProcessContexts.add(context); } } diff --git a/src/main/java/a8k/service/appstate/TubeProcessStateMgrService.java b/src/main/java/a8k/service/appstate/TubeProcessStateMgrService.java new file mode 100644 index 0000000..4802c42 --- /dev/null +++ b/src/main/java/a8k/service/appstate/TubeProcessStateMgrService.java @@ -0,0 +1,46 @@ +package a8k.service.appstate; + +import a8k.service.appstate.type.Tube; +import a8k.service.appstate.type.state.TubeState; +import a8k.type.Consumable; +import a8k.type.IncubatorPos; +import a8k.type.TipPos; +import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; +import jakarta.annotation.Resource; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class TubeProcessStateMgrService { + @Resource + GStateService gstate; + + @Resource + TubeProcessContextMgrService tubeProcessContextMgrService; + + synchronized public void setCurTubeState(TubeState state) { + Tube tube = gstate.getCurProcessingTube(); + assert tube != null; + tube.state = state; + } + + synchronized public void startProcessTube(@NotNull List idCardInfo, @NotNull List consumable, @NotNull List> tipPos, + @NotNull List incubatorPos) { + Tube tube = gstate.getCurProcessingTube(); + assert tube != null; + for (int i = 0; i < tube.projIndex.size(); i++) { + tubeProcessContextMgrService.createProjProcessContext(tube, idCardInfo.get(i), consumable.get(i), tipPos.get(i), incubatorPos.get(i)); + } + tube.state = TubeState.PRE_PROCESSING; + } + + synchronized public void pendingTube(Tube tube) { + tube.state = TubeState.PENDING; + gstate.curProcessingTube = tube; + } + +} + + diff --git a/src/main/java/a8k/service/appstate/resource/A8kPublicResourceType.java b/src/main/java/a8k/service/appstate/resource/A8kPublicResourceType.java index 7f4abcf..d80caa1 100644 --- a/src/main/java/a8k/service/appstate/resource/A8kPublicResourceType.java +++ b/src/main/java/a8k/service/appstate/resource/A8kPublicResourceType.java @@ -5,4 +5,5 @@ public enum A8kPublicResourceType { IncubationPlateMotor,//孵育盘电机 PlatesBoxMotor,//板夹仓电机 HBOT,//HBOT + CurTubeProcessToken,//当前管子处理令牌 } diff --git a/src/main/java/a8k/service/appstate/type/IncubationPlate.java b/src/main/java/a8k/service/appstate/type/IncubationPlate.java index 1c27e5d..4b9f39b 100644 --- a/src/main/java/a8k/service/appstate/type/IncubationPlate.java +++ b/src/main/java/a8k/service/appstate/type/IncubationPlate.java @@ -15,34 +15,5 @@ public class IncubationPlate { } } - synchronized public IncubatorPos getEmptyPos() { - for (IncubationSubTank subtank : subtanks) { - if (subtank.state.equals(IncubationSubTankState.EMPTY)) { - return subtank.pos; - } - } - return null; - } - - - synchronized public Integer getEmptyPosNum() { - Integer num = 0; - for (IncubationSubTank subtank : subtanks) { - if (subtank.state.equals(IncubationSubTankState.EMPTY)) { - num++; - } - } - return num; - } - - synchronized public IncubationSubTank getSubTank(IncubatorPos pos) { - for (IncubationSubTank subtank : subtanks) { - if (subtank.pos.equals(pos)) { - return subtank; - } - } - return null; - } - } diff --git a/src/main/java/a8k/service/appstate/type/ProjProcessContext.java b/src/main/java/a8k/service/appstate/type/ProjProcessContext.java index 7a1b1b8..f692a4e 100644 --- a/src/main/java/a8k/service/appstate/type/ProjProcessContext.java +++ b/src/main/java/a8k/service/appstate/type/ProjProcessContext.java @@ -2,12 +2,19 @@ package a8k.service.appstate.type; import a8k.type.Consumable; import a8k.type.IncubatorPos; +import a8k.type.TipPos; +import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; + +import java.util.List; public class ProjProcessContext { public String uuid; public String sampleId; //样本ID-系统生成-唯一标识一个样本 - public Integer projIndex;//项目代码 - public Consumable consumable;//耗材绑定的通道号 - public IncubatorPos incubatorPos;//孵育位置 + public Integer projIndex;//项目代码 + public A8kIdCardInfo a8kIdCardInfo;//a8k卡信息 + public Consumable consumable;//耗材绑定的通道号 + public IncubatorPos incubatorPos;//孵育位置 + public List tipPos;//吸头位置 + } diff --git a/src/main/java/a8k/service/appstate/type/Tube.java b/src/main/java/a8k/service/appstate/type/Tube.java index c7d709c..4e692db 100644 --- a/src/main/java/a8k/service/appstate/type/Tube.java +++ b/src/main/java/a8k/service/appstate/type/Tube.java @@ -24,4 +24,5 @@ public class Tube { public TubeState state = TubeState.EMPTY; //样本被处理的状态 public List projProcessContexts; public A8kEcode ecode = null; + } diff --git a/src/main/java/a8k/service/appstate/type/state/TubeState.java b/src/main/java/a8k/service/appstate/type/state/TubeState.java index 57b6901..9966083 100644 --- a/src/main/java/a8k/service/appstate/type/state/TubeState.java +++ b/src/main/java/a8k/service/appstate/type/state/TubeState.java @@ -1,9 +1,12 @@ package a8k.service.appstate.type.state; +import java.util.List; + public enum TubeState { // EMPTY,//空 TO_BE_PROCESSED,//待处理 + PENDING,//挂起的试管,即下一个被处理的试管 PRE_PROCESSING, //预处理 PRE_PROCESSED, //预处理结束 PROCESSING,//处理 @@ -12,4 +15,14 @@ public enum TubeState { POST_PROCESSED, //后处理完成 PROCESS_COMPLETE,//处理完成 ERROR,//处理出错 + ; + + public Boolean isEq(List states) { + for (TubeState state : states) { + if (this.equals(state)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/a8k/type/ecode/ConsumeNotEnoughError.java b/src/main/java/a8k/type/ecode/ConsumeNotEnoughError.java index 00c6163..6fb883d 100644 --- a/src/main/java/a8k/type/ecode/ConsumeNotEnoughError.java +++ b/src/main/java/a8k/type/ecode/ConsumeNotEnoughError.java @@ -3,8 +3,8 @@ package a8k.type.ecode; import a8k.hardware.type.a8kcanprotocol.A8kEcode; public class ConsumeNotEnoughError extends AppError { - Integer projIndex; - String projName; + public Integer projIndex; + public String projName; public ConsumeNotEnoughError(String projName, Integer projIndex) { super(A8kEcode.ConsumeNotEnough);