diff --git a/src/main/java/a8k/app/controler/api/v1/app/state/ConsumablesMgrControler.java b/src/main/java/a8k/app/controler/api/v1/app/state/ConsumablesMgrControler.java index 0b18981..5e1ef8e 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/state/ConsumablesMgrControler.java +++ b/src/main/java/a8k/app/controler/api/v1/app/state/ConsumablesMgrControler.java @@ -1,5 +1,8 @@ package a8k.app.controler.api.v1.app.state; +import a8k.app.hardware.type.A8kEcode; +import a8k.app.service.statemgr.DeviceWorkStateMgrService; +import a8k.app.service.statemgr.PreReactionStateMgr; import a8k.app.type.exception.AppException; import a8k.app.service.mainctrl.AppConsumablesScanService; import a8k.app.service.statemgr.ConsumablesMgrService; @@ -11,8 +14,10 @@ import a8k.app.type.a8k.pos.TipGroupPos; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; +import org.springframework.util.Assert; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @@ -22,13 +27,13 @@ import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "/api/v1/app/consumablesMgr/") @ResponseBody +@RequiredArgsConstructor public class ConsumablesMgrControler { - @Resource - AppConsumablesScanService appConsumablesScanService; //耗材扫描模块 - @Resource - ConsumablesMgrService consumablesMgrService; //耗材管理模块 - @Resource - GStateMgrService gstate; + + private final ConsumablesMgrService consumablesMgrService; //耗材管理模块 + private final PreReactionStateMgr preReactionStateMgr; + private final GStateMgrService gstate; + private final DeviceWorkStateMgrService deviceWorkStateMgrService; /** * 设置Tip数量 @@ -50,9 +55,10 @@ public class ConsumablesMgrControler { @Operation(summary = "设置耗材数量", description = "只允许在设备暂停或者停止状态下调用") @PostMapping("/setCounsumableNum") synchronized public ApiRet setCounsumableNum(ConsumableGroup group, Integer num) throws AppException { - consumablesMgrService.setCounsumableNum(group, num); + consumablesMgrService.setConsumablesNum(group, num); return ApiRet.success(); } + /** * 卸载耗材 * @param group 耗材组 @@ -70,7 +76,9 @@ public class ConsumablesMgrControler { @Operation(summary = "卸载耗材(全部)", description = "只允许在设备暂停或者停止状态下调用") @PostMapping("/unInstallAllConsumable") synchronized public void unInstallAllConsumable() throws AppException { - consumablesMgrService.unInstallAllConsumable(); + for (ConsumableGroup group : ConsumableGroup.values()) { + consumablesMgrService.unInstallConsumable(group); + } } diff --git a/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java b/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java index 217f764..7a19bb9 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java +++ b/src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java @@ -14,6 +14,7 @@ import a8k.app.service.background.FrontEndMessageBoxAndEventMgr; import a8k.app.utils.ZJsonHelper; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -33,6 +34,8 @@ public class AppWebSocketEndpointMgr { private AppUserMgrService appUserMgrService; @Resource private AppDeviceInitCtrlService appDeviceInitCtrlService; + @Autowired + private PreReactionStateMgr preReactionStateMgr; public static class Report { @@ -49,25 +52,25 @@ public class AppWebSocketEndpointMgr { @Resource - FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr; + FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr; @Resource - GStateMgrService gstate; + GStateMgrService gstate; @Resource - EngineerModeStateMgrService engineerModeStateMgrService; + EngineerModeStateMgrService engineerModeStateMgrService; @Resource - DeviceWorkStateMgrService deviceWorkStateMgrService; + DeviceWorkStateMgrService deviceWorkStateMgrService; @Resource - TubeStateMgr tubeStateMgrService; + TubeStateMgr tubeStateMgrService; @Resource - IncubationPlateStateMgr incubationPlateStateMgr; + IncubationPlateStateMgr incubationPlateStateMgr; @Resource - OptScanModuleStateMgr optScanModuleStateMgr; + OptScanModuleStateMgr optScanModuleStateMgr; @Resource - ConsumablesMgrService consumablesMgrService; + ConsumablesMgrService consumablesMgrService; @Resource - TubeHolderSettingMgrService tubeHolderSettingMgrService; + TubeHolderSettingMgrService tubeHolderSettingMgrService; @Resource - AppEventBusService appEventBusService; + AppEventBusService appEventBusService; List stateWebsocketSessions = new ArrayList<>(); @@ -170,6 +173,7 @@ public class AppWebSocketEndpointMgr { reportState("ConsumablesState", consumablesMgrService.getState()); reportState("GDeviceState", gstate.getGState()); reportState("EngineerModeState", engineerModeStateMgrService.getState()); + reportState("PreReactionPosState", preReactionStateMgr.getPreReactionPosState()); reportTubeHolderSetting(); } diff --git a/src/main/java/a8k/app/hardware/type/A8kEcode.java b/src/main/java/a8k/app/hardware/type/A8kEcode.java index 031d2e1..35f8eaf 100644 --- a/src/main/java/a8k/app/hardware/type/A8kEcode.java +++ b/src/main/java/a8k/app/hardware/type/A8kEcode.java @@ -120,6 +120,7 @@ public enum A8kEcode { APPE_SHAKE_MODULE_CLAMPM_NOT_IN_ZERO_POS(311), //摇匀模组夹紧模块没有在零点位置 APPE_INCUBATION_PLATE_OUTLET_STUCK_DETECTOR_SENSOR_IS_TRIGGER(312), //孵育板出料口卡板检测传感器触发 APPE_INCUBATION_PLATE_INLET_STUCK_DETECTOR_SENSOR_IS_TRIGGER(313), //孵育板入料口卡板检测传感器触发 + APPE_DEVICE_IS_WORKING(314), //设备正在工作中,不允许执行操作 // diff --git a/src/main/java/a8k/app/i18n/Internationalization.java b/src/main/java/a8k/app/i18n/Internationalization.java index 68349b9..9d2edd3 100644 --- a/src/main/java/a8k/app/i18n/Internationalization.java +++ b/src/main/java/a8k/app/i18n/Internationalization.java @@ -43,6 +43,7 @@ public class Internationalization { case APPE_SHAKE_MODULE_CLAMPM_NOT_IN_ZERO_POS -> "摇匀模组夹紧电机初始化时没有在零点位置"; case APPE_INCUBATION_PLATE_OUTLET_STUCK_DETECTOR_SENSOR_IS_TRIGGER -> "孵育板出料口卡板检测传感器触发"; case APPE_INCUBATION_PLATE_INLET_STUCK_DETECTOR_SENSOR_IS_TRIGGER -> "孵育板入料口卡板检测传感器触发"; + case APPE_DEVICE_IS_WORKING -> "执行失败,设备正在工作中"; case PROJ_CARD_ERROR_EXPIRYED -> "项目卡过期"; case PROJ_CARD_ERROR_WRONG_FUNCTION_NUM -> "项目卡配置的函数数量与项目配置不匹配"; diff --git a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java index 5ec1c6f..6e949f4 100644 --- a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java +++ b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java @@ -14,7 +14,8 @@ import a8k.app.service.module.TipOperationCtrlModule; import a8k.app.service.param.hbotpos.*; import a8k.app.service.utils.UISender; import a8k.app.service.utils.ZAppChecker; -import a8k.app.type.a8k.ConsumableType; + +import a8k.app.type.a8k.LittleBottleConsumableType; import a8k.app.type.a8k.Pos3d; import a8k.app.type.a8k.pos.LargeBufferPos; import a8k.app.type.a8k.pos.PreReactionPos; @@ -184,7 +185,7 @@ public class LiquidOperationCtrService { Pos3d pircePos; ContainerCpyId containerCpyId; - if (pos.type.equals(ConsumableType.ProbeSubstance)) { + if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { pircePos = hbotLittleBSPosMgr.getProbeSubstancePiercePos(pos.group, pos.index); containerCpyId = ContainerCpyId.DetectSubstancesCup; } else { @@ -212,7 +213,7 @@ public class LiquidOperationCtrService { Integer shakeUl = MIX_VOLUME_UL; Integer shakeTimes = 5; - if (pos.type.equals(ConsumableType.ProbeSubstance)) { + if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index); containerCpyId = ContainerCpyId.DetectSubstancesCup; } else { @@ -318,7 +319,7 @@ public class LiquidOperationCtrService { Pos3d reactionPos; ContainerCpyId containerCpyId; - if (pos.type.equals(ConsumableType.ProbeSubstance)) { + if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) { reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index); containerCpyId = ContainerCpyId.DetectSubstancesCup; } else { diff --git a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java index 86056ab..aa2772e 100644 --- a/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java +++ b/src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java @@ -9,7 +9,9 @@ import a8k.app.service.statemgr.ConsumablesMgrService; import a8k.app.service.lowerctrl.ConsumablesScanCtrlService; import a8k.app.dao.type.db.ProjExtInfoCard; +import a8k.app.service.statemgr.PreReactionStateMgr; import a8k.app.service.utils.ReactionPlate2DCodeHelper; +import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.a8k.LittleBottleConsumableType; import a8k.app.type.a8k.ReactionPlate2DCode; import a8k.app.type.a8k.container.*; @@ -64,6 +66,8 @@ public class AppConsumablesScanService { @Resource ConsumablesScanCtrlService scanCtrlService; @Resource + PreReactionStateMgr preReactionStateMgr; + @Resource ConsumablesMgrService consumablesMgrService; @Resource GStateMgrService gstate; @@ -213,9 +217,9 @@ public class AppConsumablesScanService { var reactionType = projCfg.reactionFlowType; - ReactionPlateContainerInfo reactionPlateContainer = null; - LittBottleConsumablesInfo littBottleConsumablesInfo = null; - LargeBottleConsumablesInfo largeBottleConsumablesInfo = null; + ReactionPlateContainerInfo reactionPlateContainer = null; + LittBottleConsumablesInfo littBottleConsumablesInfo = null; + LargeBottleConsumablesInfo largeBottleConsumablesInfo = null; if (reactionType.equals(A8kReactionFlowType.SampleAndBS)) { reactionPlateContainer = new ReactionPlateContainerInfo( @@ -234,20 +238,20 @@ public class AppConsumablesScanService { projExtInfoCard.color); } else if (reactionType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) { - reactionPlateContainer = new ReactionPlateContainerInfo( + reactionPlateContainer = new ReactionPlateContainerInfo( result.projId, projExtInfoCard.projName, projCfg.projShortName, result.lotId, projExtInfoCard.color); - littBottleConsumablesInfo = new LittBottleConsumablesInfo( + littBottleConsumablesInfo = new LittBottleConsumablesInfo( LittleBottleConsumableType.ProbeSubstance, result.projId, projExtInfoCard.projName, projCfg.projShortName, result.lotId, projExtInfoCard.color); - largeBottleConsumablesInfo = new LargeBottleConsumablesInfo( + largeBottleConsumablesInfo = new LargeBottleConsumablesInfo( result.projId, projExtInfoCard.projName, projCfg.projShortName, diff --git a/src/main/java/a8k/app/service/mainctrl/MainFlowCtrlScheduler.java b/src/main/java/a8k/app/service/mainctrl/MainFlowCtrlScheduler.java index 58a23ae..6706bfa 100644 --- a/src/main/java/a8k/app/service/mainctrl/MainFlowCtrlScheduler.java +++ b/src/main/java/a8k/app/service/mainctrl/MainFlowCtrlScheduler.java @@ -47,6 +47,7 @@ public class MainFlowCtrlScheduler { private final OptScanModuleStateMgr optScanModuleStateMgr; private final TubeStateMgr tubeStateMgr; private final AppEventBusService appEventBusService; + private final PreReactionStateMgr preReactionStateMgr; private ZWorkThread workThread; @@ -182,6 +183,9 @@ public class MainFlowCtrlScheduler { samplePreProcessModule.stopSchedule(); inFeedingCtrlModule.stopSchedule(); + consumablesMgrService.bakAllReserveConsumable(); + preReactionStateMgr.resetAll(); + deviceWorkStateMgrService.updateWorkState(A8kWorkState.IDLE); deviceWorkStateMgrService.clearPending(); diff --git a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java b/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java index c4d62e4..8b5c29a 100644 --- a/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java @@ -55,6 +55,7 @@ public class ConsumablesMgrService { private final LittBottleContainerStateMgr littBottleContainerStateMgr; private final ReactionPlateContainerStateMgr reactionPlateContainerStateMgr; private final TipStateMgr tipStateMgr; + private final PreReactionStateMgr preReactionStateMgr; //耗材状态 @@ -151,6 +152,7 @@ public class ConsumablesMgrService { if (littBottleConsumablesInfo != null) { littBottleContainerStateMgr.install(Objects.requireNonNull(ConsumableGroup.of(ch)), littBottleConsumablesInfo); + preReactionStateMgr.installConsumable(ConsumableGroup.of(ch), littBottleConsumablesInfo); } if (largeBottleConsumablesInfo != null) { @@ -165,7 +167,7 @@ public class ConsumablesMgrService { * @param ch 通道 * @param num 数量 */ - synchronized public void setCounsumableNum(ConsumableGroup ch, Integer num) throws AppException { + synchronized public void setConsumablesNum(ConsumableGroup ch, Integer num) throws AppException { if (deviceWorkStateMgrService.isDeviceWorking()) { throw AppException.of(A8kEcode.APPE_DO_ACTION_FAIL_DEVICE_IS_WORKING); } @@ -192,6 +194,10 @@ public class ConsumablesMgrService { throw AppException.of(A8kEcode.APPE_CONSUMABLES_IS_IN_USE_NOT_ALLOW_UNSTALL); } + if (deviceWorkStateMgrService.isNotInIDLE() && preReactionStateMgr.isHasInUSEReactionGrid(ch)) { + throw AppException.of(A8kEcode.APPE_CONSUMABLES_IS_IN_USE_NOT_ALLOW_UNSTALL); + } + preReactionStateMgr.unInstallConsumable(ch); larBottleContainerStateMgr.uninstall(Objects.requireNonNull(ch)); littBottleContainerStateMgr.uninstall(Objects.requireNonNull(ch)); reactionPlateContainerStateMgr.uninstall(Objects.requireNonNull(ch)); @@ -206,6 +212,7 @@ public class ConsumablesMgrService { stateVersion++; } + synchronized public List getUnInstallConsumableChannelOff() { List ret = new java.util.ArrayList<>(); for (var group : ConsumableGroup.values()) { diff --git a/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java b/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java index bdb0809..592f539 100644 --- a/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/DeviceWorkStateMgrService.java @@ -105,6 +105,20 @@ public class DeviceWorkStateMgrService { return deviceWorkState.workState.equals(A8kWorkState.WORKING); } + synchronized public Boolean isInIDLE() { + if (isPending()) { + return false; + } + return !deviceWorkState.workState.equals(A8kWorkState.IDLE); + } + + synchronized public Boolean isNotInIDLE() { + if (isPending()) { + return true; + } + return !deviceWorkState.workState.equals(A8kWorkState.IDLE); + } + synchronized public Boolean isPending() { return deviceWorkState.isPending(); } @@ -122,5 +136,4 @@ public class DeviceWorkStateMgrService { } - } diff --git a/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java b/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java new file mode 100644 index 0000000..131ea04 --- /dev/null +++ b/src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java @@ -0,0 +1,175 @@ +package a8k.app.service.statemgr; + +import a8k.app.type.PreReactionGrid; +import a8k.app.type.PreReactionGridGroup; +import a8k.app.type.PreReactionPosState; +import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.container.LittBottleConsumablesInfo; +import a8k.app.type.a8k.pos.PreReactionPos; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.log.Log; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +@Component +@Slf4j +@RequiredArgsConstructor +@EnableScheduling +public class PreReactionStateMgr { + + PreReactionPosState preReactionPosState = new PreReactionPosState(); + + public synchronized PreReactionPosState getPreReactionPosState() { + return ObjectUtil.cloneByStream(preReactionPosState); + } + + public synchronized PreReactionGridGroup getPreReactionGridGroupState(ConsumableGroup group) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(group); + return ObjectUtil.cloneByStream(gridGroup); + } + + public synchronized boolean isHasReactionCompleted() { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + if (gridGroup.isHasReactionCompleted) { + return true; + } + } + return false; + } + + public synchronized boolean isHasInReactionGrid() { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + if (gridGroup.isHasInReactionGrid) { + return true; + } + } + return false; + } + + public synchronized PreReactionPos getReactionCompletedPos() { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + if (gridGroup.isHasReactionCompleted) { + for (PreReactionGrid grid : gridGroup.grids) { + if (grid.state.equals(PreReactionGrid.State.REACTION_COMPLETED)) { + PreReactionPos pos = new PreReactionPos(); + pos.group = gridGroup.group; + pos.type = gridGroup.consumableType; + pos.index = grid.posIndex; + return pos; + } + } + } + } + return null; + } + + public synchronized void changeReactionGridStateToReacting(PreReactionPos preReactionPos, Long totalReactionTimeMs) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group); + Assert.notNull(gridGroup, "gridGroup != null"); + var grid = gridGroup.grids.get(preReactionPos.index); + grid.state = PreReactionGrid.State.REACTING; + grid.totalReactionTime = totalReactionTimeMs; + grid.startReactionTime = System.currentTimeMillis(); + grid.hasReactionTime = 0L; + gridGroup.isHasInReactionGrid = true; + } + + + public synchronized boolean isHasInUSEReactionGrid(ConsumableGroup group) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(group); + if (gridGroup != null) { + return gridGroup.isHasInReactionGrid || gridGroup.isHasReactionCompleted; + } + return false; + } + + + public synchronized void installConsumable(ConsumableGroup group, LittBottleConsumablesInfo littBottleConsumablesInfo) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(group); + Assert.notNull(gridGroup, "gridGroup != null"); + gridGroup.consumableType = littBottleConsumablesInfo.type; + gridGroup.isInstalled = true; + changeAllGridStateToIdle(gridGroup.group); + gridGroup.syncInfo(); + } + + public synchronized void unInstallConsumable(ConsumableGroup group) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(group); + Assert.notNull(gridGroup, "gridGroup != null"); + gridGroup.isInstalled = false; + changeAllGridStateToIdle(gridGroup.group); + } + + public synchronized void resetAll() { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + changeAllGridStateToIdle(gridGroup.group); + } + } + + // ********************************************************************************* + // PRIVATE METHODS + // ********************************************************************************* + + private void changeAllGridStateToIdle(ConsumableGroup group) { + PreReactionGridGroup gridGroup = getPreReactionGridGroup(group); + Assert.notNull(gridGroup, "gridGroup != null"); + gridGroup.isHasInReactionGrid = false; + gridGroup.isHasReactionCompleted = false; + for (PreReactionGrid grid : gridGroup.grids) { + grid.state = PreReactionGrid.State.IDLE; + grid.startReactionTime = 0L; + grid.hasReactionTime = 0L; + grid.totalReactionTime = 0L; + } + } + + private PreReactionGridGroup getPreReactionGridGroup(ConsumableGroup group) { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + if (gridGroup.group.equals(group)) { + return gridGroup; + } + } + return null; + } + + + private void autoRefreshPreReactionPosState(PreReactionGridGroup group) { + // update hasReactionTime + if (!group.isInstalled) { + return; + } + + boolean isHasInReactionGrid = false; + boolean isHasReactionCompleted = false; + for (PreReactionGrid grid : group.grids) { + if (grid.state.equals(PreReactionGrid.State.IDLE)) { + continue; + } + + if (grid.state.equals(PreReactionGrid.State.REACTING)) { + grid.hasReactionTime = System.currentTimeMillis() - grid.startReactionTime; + if (grid.hasReactionTime < grid.totalReactionTime) { + isHasInReactionGrid = true; + } else { + grid.state = PreReactionGrid.State.REACTION_COMPLETED; + isHasReactionCompleted = true; + } + } else if (grid.state.equals(PreReactionGrid.State.REACTION_COMPLETED)) { + isHasReactionCompleted = true; + } + } + group.isHasInReactionGrid = isHasInReactionGrid; + group.isHasReactionCompleted = isHasReactionCompleted; + } + + @Scheduled(fixedDelay = 600) + synchronized private void autoRefreshPreReactionPosState() { + for (PreReactionGridGroup gridGroup : preReactionPosState.preReactionGridGroups) { + autoRefreshPreReactionPosState(gridGroup); + } + } +} diff --git a/src/main/java/a8k/app/type/PreReactionGrid.java b/src/main/java/a8k/app/type/PreReactionGrid.java new file mode 100644 index 0000000..efc125e --- /dev/null +++ b/src/main/java/a8k/app/type/PreReactionGrid.java @@ -0,0 +1,41 @@ +package a8k.app.type; + +import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.LittleBottleConsumableType; + +import java.io.Serializable; + +public class PreReactionGrid implements Serializable { + public enum State { + IDLE, + REACTING, + REACTION_COMPLETED, + } + + public State state; + public LittleBottleConsumableType consumableType; + public ConsumableGroup group; + public Integer posIndex; + public Long startReactionTime; + public Long hasReactionTime; + public Long totalReactionTime; + + PreReactionGrid(ConsumableGroup group, Integer posIndex) { + this.group = group; + this.posIndex = posIndex; + this.state = State.IDLE; + this.startReactionTime = 0L; + this.hasReactionTime = 0L; + this.totalReactionTime = 0L; + } + + public PreReactionGrid() { + this.group = ConsumableGroup.CG1; + this.posIndex = 0; + this.state = State.IDLE; + this.startReactionTime = 0L; + this.hasReactionTime = 0L; + this.totalReactionTime = 0L; + } + +} diff --git a/src/main/java/a8k/app/type/PreReactionGridGroup.java b/src/main/java/a8k/app/type/PreReactionGridGroup.java new file mode 100644 index 0000000..acaa79e --- /dev/null +++ b/src/main/java/a8k/app/type/PreReactionGridGroup.java @@ -0,0 +1,36 @@ +package a8k.app.type; + +import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.LittleBottleConsumableType; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class PreReactionGridGroup implements Serializable { + + public List grids; + public ConsumableGroup group; + public LittleBottleConsumableType consumableType = LittleBottleConsumableType.BufferSolution; + public Boolean isHasInReactionGrid = false; + public Boolean isHasReactionCompleted = false; + public Boolean isInstalled = false; + + public PreReactionGridGroup(ConsumableGroup group) { + grids = new ArrayList<>(); + for (int i = 0; i < 25; i++) { + grids.add(new PreReactionGrid(group, i)); + } + this.group = group; + } + + public PreReactionGridGroup() { + } + + public void syncInfo() { + for (PreReactionGrid grid : grids) { + grid.consumableType = this.consumableType; + } + } + +} diff --git a/src/main/java/a8k/app/type/PreReactionPosState.java b/src/main/java/a8k/app/type/PreReactionPosState.java new file mode 100644 index 0000000..1992d31 --- /dev/null +++ b/src/main/java/a8k/app/type/PreReactionPosState.java @@ -0,0 +1,29 @@ +package a8k.app.type; + +import a8k.app.type.a8k.ConsumableGroup; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class PreReactionPosState implements Serializable { + + public List preReactionGridGroups; + + + public PreReactionPosState() { + this.preReactionGridGroups = new ArrayList<>(); + for (ConsumableGroup group : ConsumableGroup.values()) { + preReactionGridGroups.add(new PreReactionGridGroup(group)); + } + } + + public PreReactionGridGroup getPreReactionGridGroup(ConsumableGroup group) { + for (PreReactionGridGroup preReactionGridGroup : preReactionGridGroups) { + if (preReactionGridGroup.group.equals(group)) { + return preReactionGridGroup; + } + } + return null; + } +}; \ No newline at end of file diff --git a/src/main/java/a8k/app/type/a8k/ConsumableType.java b/src/main/java/a8k/app/type/a8k/ConsumableType.java index 1535446..22e1433 100644 --- a/src/main/java/a8k/app/type/a8k/ConsumableType.java +++ b/src/main/java/a8k/app/type/a8k/ConsumableType.java @@ -1,12 +1,12 @@ package a8k.app.type.a8k; -/** - * 耗材类型 - * 耗材类型只有两类耗材 - * 1. 探测物质+大瓶缓冲液 - * 2. 小瓶缓冲液 - */ -public enum ConsumableType { - ProbeSubstance,//探测物质+大瓶缓冲液 - SmallBottleBuffer,//小瓶缓冲液 -} +///** +// * 耗材类型 +// * 耗材类型只有两类耗材 +// * 1. 探测物质+大瓶缓冲液 +// * 2. 小瓶缓冲液 +// */ +//public enum ConsumableType { +// ProbeSubstance,//探测物质 +// SmallBottleBuffer,//小瓶缓冲液 +//} diff --git a/src/main/java/a8k/app/type/a8k/LittleBottleConsumableType.java b/src/main/java/a8k/app/type/a8k/LittleBottleConsumableType.java index 63182de..cf22dee 100644 --- a/src/main/java/a8k/app/type/a8k/LittleBottleConsumableType.java +++ b/src/main/java/a8k/app/type/a8k/LittleBottleConsumableType.java @@ -4,3 +4,4 @@ public enum LittleBottleConsumableType { BufferSolution, //缓冲液 ProbeSubstance, //探测物质 } + diff --git a/src/main/java/a8k/app/type/a8k/pos/PreReactionPos.java b/src/main/java/a8k/app/type/a8k/pos/PreReactionPos.java index 95b2031..6705958 100644 --- a/src/main/java/a8k/app/type/a8k/pos/PreReactionPos.java +++ b/src/main/java/a8k/app/type/a8k/pos/PreReactionPos.java @@ -1,7 +1,7 @@ package a8k.app.type.a8k.pos; import a8k.app.type.a8k.ConsumableGroup; -import a8k.app.type.a8k.ConsumableType; +import a8k.app.type.a8k.LittleBottleConsumableType; /** * 预反应位 @@ -9,11 +9,11 @@ import a8k.app.type.a8k.ConsumableType; * 2. 之所以叫预反应位,是因为样本都是先滴入小瓶缓冲液或者探测物质中,先混合后再滴入到反应板中 */ public class PreReactionPos { - public ConsumableType type = null; - public ConsumableGroup group = null; - public int index = 0; + public LittleBottleConsumableType type = null; + public ConsumableGroup group = null; + public int index = 0; - public PreReactionPos(ConsumableType type, ConsumableGroup group, int index) { + public PreReactionPos(LittleBottleConsumableType type, ConsumableGroup group, int index) { this.type = type; this.group = group; this.index = index; diff --git a/src/main/java/a8k/app/utils/ProjectParamUtils.java b/src/main/java/a8k/app/utils/ProjectParamUtils.java index 7d85464..a5e0d18 100644 --- a/src/main/java/a8k/app/utils/ProjectParamUtils.java +++ b/src/main/java/a8k/app/utils/ProjectParamUtils.java @@ -1,7 +1,7 @@ package a8k.app.utils; import a8k.app.type.a8k.A8kTubeHolderType; -import a8k.app.type.a8k.ConsumableType; +import a8k.app.type.a8k.LittleBottleConsumableType; import a8k.app.type.a8k.pos.PreReactionPos; import a8k.app.type.a8k.proj.A8kReactionFlowType; import a8k.app.type.a8k.state.ProjectPreProcessContext; @@ -44,12 +44,12 @@ public class ProjectParamUtils { PreReactionPos preReactionPos = new PreReactionPos(); switch (reactionFlowType) { case SampleAndBS -> { - preReactionPos.type = ConsumableType.SmallBottleBuffer; + preReactionPos.type = LittleBottleConsumableType.BufferSolution; preReactionPos.group = cxt.getConsumableInfo().group; preReactionPos.index = cxt.getConsumableInfo().pos; } case SampleAndBSAndProbeSubstance -> { - preReactionPos.type = ConsumableType.ProbeSubstance; + preReactionPos.type = LittleBottleConsumableType.ProbeSubstance; preReactionPos.group = cxt.getConsumableInfo().group; preReactionPos.index = cxt.getConsumableInfo().pos; } diff --git a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java index 3000a5d..54b4779 100644 --- a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java +++ b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java @@ -87,8 +87,9 @@ public class ExtApiPageGroupCfgMgr { new Menu("状态", ZList.of( new Menu(P11IncubationPlateStateDebugPageAll.class, "孵育盘"), new Menu(P12TueStateDebugPage.class, "试管"), - new Menu(P13OptModuleStateDebugPage.class, "光学模块") - )), + new Menu(P13OptModuleStateDebugPage.class, "光学模块"), + new Menu(PreReactionPosStateMgrDebugPage.class, "预反应区状态") + )), new Menu("数据库", ZList.of( new Menu(ProjInfoMgrPage.class, "项目信息管理"), new Menu(ReactionRecordMgrDebugPage.class, "反应记录") diff --git a/src/main/java/a8k/extui/page/debug/P02ConsumablesMgrDebugPage.java b/src/main/java/a8k/extui/page/debug/P02ConsumablesMgrDebugPage.java index ecb9318..b861802 100644 --- a/src/main/java/a8k/extui/page/debug/P02ConsumablesMgrDebugPage.java +++ b/src/main/java/a8k/extui/page/debug/P02ConsumablesMgrDebugPage.java @@ -1,5 +1,6 @@ package a8k.extui.page.debug; +import a8k.app.service.statemgr.PreReactionStateMgr; import a8k.app.type.a8k.ConsumableGroup; import a8k.app.type.a8k.pos.TipGroupPos; import a8k.app.type.a8k.container.LarBottleContainer; @@ -18,21 +19,18 @@ import a8k.extui.mgr.ExtApiPageMgr; import a8k.extui.type.ExtApiStatu; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component +@RequiredArgsConstructor public class P02ConsumablesMgrDebugPage { - @Resource - ConsumablesMgrService consumablesMgrService; - - @Resource - AppConsumablesScanService appConsumablesScanService; - @Resource - ProjIdCardInfoMgrService projIdCardInfoMgrService; - - @Resource - GStateMgrService gstate; + private final ConsumablesMgrService consumablesMgrService; + private final AppConsumablesScanService appConsumablesScanService; + private final PreReactionStateMgr preReactionStateMgr; + private final ProjIdCardInfoMgrService projIdCardInfoMgrService; + private final GStateMgrService gstate; // @ExtApiStatu(name = "", group = "反应板状态1", minWidth = "16%", order = 1) @@ -303,7 +301,7 @@ public class P02ConsumablesMgrDebugPage { } public void setConsumableNum(ConsumableGroup group, Integer num) throws AppException { - consumablesMgrService.setCounsumableNum(group, num); + consumablesMgrService.setConsumablesNum(group, num); } public void loadConsumablesManual(ConsumableGroup group, String lotid) throws AppException { diff --git a/src/main/java/a8k/extui/page/debug/PreReactionPosStateMgrDebugPage.java b/src/main/java/a8k/extui/page/debug/PreReactionPosStateMgrDebugPage.java new file mode 100644 index 0000000..65a7a13 --- /dev/null +++ b/src/main/java/a8k/extui/page/debug/PreReactionPosStateMgrDebugPage.java @@ -0,0 +1,84 @@ +package a8k.extui.page.debug; + +import a8k.app.service.statemgr.PreReactionStateMgr; +import a8k.app.type.PreReactionGridGroup; +import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.LittleBottleConsumableType; +import a8k.app.type.a8k.container.LittBottleConsumablesInfo; +import a8k.app.type.a8k.pos.PreReactionPos; +import a8k.app.type.a8k.state.IncubationSubTank; +import a8k.extui.mgr.ExtApiPageMgr; +import a8k.extui.type.ExtApiStatu; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class PreReactionPosStateMgrDebugPage { + + private final PreReactionStateMgr preReactionStateMgr; + private final ExtApiPageMgr extApiPageMgr; + + @ExtApiStatu(name = "", group = "孵育盘1状态", order = 1) + public PreReactionGridGroup getGroup1() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG1); + } + + @ExtApiStatu(name = "", group = "孵育盘2状态", order = 2) + public PreReactionGridGroup getGroup2() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG2); + } + + @ExtApiStatu(name = "", group = "孵育盘3状态", order = 3) + public PreReactionGridGroup getGroup3() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG3); + } + + @ExtApiStatu(name = "", group = "孵育盘4状态", order = 4) + public PreReactionGridGroup getGroup4() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG4); + } + + @ExtApiStatu(name = "", group = "孵育盘5状态", order = 5) + public PreReactionGridGroup getGroup5() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG5); + } + + @ExtApiStatu(name = "", group = "孵育盘6状态", order = 6) + public PreReactionGridGroup getGroup6() { + return preReactionStateMgr.getPreReactionGridGroupState(ConsumableGroup.CG6); + } + + public void installOne(ConsumableGroup group, LittleBottleConsumableType consumableType) { + LittBottleConsumablesInfo consumableInfo = new LittBottleConsumablesInfo(); + consumableInfo.type = consumableType; + preReactionStateMgr.installConsumable(group, consumableInfo); + } + + public void uninstall(ConsumableGroup group) { + preReactionStateMgr.unInstallConsumable(group); + } + + public void changeStateToReacting(ConsumableGroup group, Integer off, Integer reactionTimeS) { + + PreReactionPos pos = new PreReactionPos(); + pos.group = group; + pos.type = LittleBottleConsumableType.BufferSolution; + pos.index = off; + preReactionStateMgr.changeReactionGridStateToReacting(pos, reactionTimeS.longValue() * 1000); + } + + + @PostConstruct + void init() { + var page = extApiPageMgr.newPage(this); + page.newGroup("预反应位点状态管理(只在单元测试中使用)"); + page.addFunction("加载耗材", this::installOne); + page.addFunction("卸载耗材", this::uninstall); + page.addFunction("切换状态到反应中", this::changeStateToReacting); + extApiPageMgr.addPage(page); + } +} diff --git a/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java b/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java index c196451..baf3655 100644 --- a/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java +++ b/src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java @@ -42,17 +42,17 @@ public class P34LiquidOperationTestPage { } public void takeLargeBottleBufferLiquidToProbeSubstance(LargeBufferPos from, ConsumableGroup group, Integer index, Integer ul) throws AppException { - PreReactionPos topos = new PreReactionPos(ConsumableType.ProbeSubstance, group, index); + PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.ProbeSubstance, group, index); liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(from, topos, ul); } public void takeSampleToProbeSubstance(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException { - PreReactionPos topos = new PreReactionPos(ConsumableType.ProbeSubstance, toGroup, toIndex); + PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.ProbeSubstance, toGroup, toIndex); liquidOperationCtrService.takeSampleToPreReactionPos(from, topos, ul); } public void takePreReactionLiquidFromProbeSubstance(ConsumableGroup toGroup, Integer toIndex) throws AppException { - PreReactionPos pos = new PreReactionPos(ConsumableType.ProbeSubstance, toGroup, toIndex); + PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.ProbeSubstance, toGroup, toIndex); liquidOperationCtrService.takePreReactionLiquid(pos); } @@ -61,17 +61,17 @@ public class P34LiquidOperationTestPage { } public void takeSampleToLittleBuffer(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException { - PreReactionPos topos = new PreReactionPos(ConsumableType.SmallBottleBuffer, toGroup, toIndex); + PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex); liquidOperationCtrService.takeSampleToPreReactionPos(from, topos, ul); } public void pirceLittleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException { - PreReactionPos pos = new PreReactionPos(ConsumableType.SmallBottleBuffer, toGroup, toIndex); + PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex); liquidOperationCtrService.pirceLittleBuffer(pos); } public void takePreReactionLiquidFromSmallBottleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException { - PreReactionPos pos = new PreReactionPos(ConsumableType.SmallBottleBuffer, toGroup, toIndex); + PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex); liquidOperationCtrService.takePreReactionLiquid(pos); }