From e552c33bda401a7b5157e490b704a2c6c4500424 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Sat, 26 Apr 2025 17:27:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E8=87=B4=E6=80=A7?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E7=9A=84=E9=85=8D=E7=BD=AE=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + deply.bat | 32 --- mkexe.bat | 41 ---- sh/deply.bat | 32 +++ sh/mkexe.bat | 41 ++++ sh/sync_from_board.bat | 2 + src/main/java/a8k/app/constant/AppConstant.java | 2 + .../ExperimentConsistencyTestingControler.java | 18 +- .../ExperimentConsistencyTestingService.java | 205 +++++++++++------- .../qatest/QATemperatureCtrlTestService.java | 12 +- .../app/engineer/service/type/TubeExConfig.java | 5 + .../engineer/service/type/TubeHolderExConfig.java | 16 ++ .../a8k/app/hardware/driver/CodeScanerDriver.java | 2 +- .../background/SensorDataUpdateService.java | 19 +- .../service/background/TemperatureCtrlService.java | 1 + .../service/lowerctrl/HbotMoveExCtrlService.java | 12 +- .../lowerctrl/LiquidOperationCtrlService.java | 3 +- .../lowerctrl/OptScanModuleCtrlService.java | 6 + .../statemgr/IncubationPlateStateMgrService.java | 9 + .../app/service/statemgr/TubeStateMgrService.java | 5 + .../java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java | 6 +- .../page/extapp/P01PipetteGunVerification.java | 228 --------------------- .../page/extapp/P02A8kTemperaturaVerfication.java | 170 --------------- .../ExperimentConsistencyTestingPage.java | 97 +++++++++ .../profession_test/P01PipetteGunVerification.java | 80 ++++++++ .../P02A8kTemperaturaVerfication.java | 170 +++++++++++++++ 26 files changed, 658 insertions(+), 557 deletions(-) delete mode 100644 deply.bat delete mode 100644 mkexe.bat create mode 100644 sh/deply.bat create mode 100644 sh/mkexe.bat create mode 100644 sh/sync_from_board.bat create mode 100644 src/main/java/a8k/app/engineer/service/type/TubeExConfig.java create mode 100644 src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java delete mode 100644 src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java delete mode 100644 src/main/java/a8k/extui/page/extapp/P02A8kTemperaturaVerfication.java create mode 100644 src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java create mode 100644 src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java create mode 100644 src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java diff --git a/.gitignore b/.gitignore index 76f5060..19a6885 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ tmp/ app.db !/bak/app.db /logs/* +appresource/static/app/ diff --git a/deply.bat b/deply.bat deleted file mode 100644 index 936c162..0000000 --- a/deply.bat +++ /dev/null @@ -1,32 +0,0 @@ -@echo off -setlocal - -:: 设置变量 -set TARGET_DIR=target -set JAR_FILE=%TARGET_DIR%\*.jar -set REMOTE_USER=root -set REMOTE_HOST=192.168.8.10 -set REMOTE_DIR=/app/ -set REMOTE_FILE=app.jar - -:: 输出操作开始信息 -ssh %REMOTE_USER%@%REMOTE_HOST% `systemctl stop zapp` -:: 执行 SCP 命令,将 JAR 文件复制到远程服务器并重命名 -scp %JAR_FILE% %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_DIR%%REMOTE_FILE% -:: 拷贝appresource -@REM scp -r appresource %REMOTE_USER%@%REMOTE_HOST%:/app/ - -:: 重启远程服务器 -ssh %REMOTE_USER%@%REMOTE_HOST% `systemctl start zapp` - -:: 判断 SCP 命令是否成功 -if %errorlevel% neq 0 ( - echo SCP failed! - exit /b 1 -) else ( - echo SCP completed successfully. -) - -:: 结束脚本 -endlocal -pause \ No newline at end of file diff --git a/mkexe.bat b/mkexe.bat deleted file mode 100644 index 28e0c0a..0000000 --- a/mkexe.bat +++ /dev/null @@ -1,41 +0,0 @@ -@echo off -setlocal - -rmdir /s /q out -rmdir /s /q dist - -mkdir out -mkdir out\A8000_VIRTUAL_BAK_END -mkdir out\A8000_VIRTUAL_BAK_END\appresource - -mkdir dist -mkdir dest\A8000_VIRTUAL_BAK_END\appresource\ -copy target\a8000-1.jar out\A8000_VIRTUAL_BAK_END\ -if %errorlevel% neq 0 ( - echo 执行发生错误,退出脚本 - exit /b %errorlevel% -) - -"C:\Program Files\Java\jdk-21\bin\jpackage.exe" ^ - --type app-image ^ - --name A8000_VIRTUAL_BAK_END ^ - --input out\A8000_VIRTUAL_BAK_END ^ - --main-jar a8000-1.jar ^ - --win-console ^ - --dest dist - -mkdir dist\A8000_VIRTUAL_BAK_END\appresource\ -xcopy appresource dist\A8000_VIRTUAL_BAK_END\appresource\ /s /e - - -if %errorlevel% neq 0 ( - echo 执行发生错误,退出脚本 - exit /b %errorlevel% -) - - -@REM .\tools\makesfx.exe -ic -mf -ft -we -di -un -oo .\dist\A8000_VIRTUAL_BAK_END\ .\dist\A8000_VIRTUAL_BAK_END.exe .\logo.ico .\dist\A8000_VIRTUAL_BAK_END\A8000_VIRTUAL_BAK_END.exe - -:: 结束脚本 -endlocal -pause \ No newline at end of file diff --git a/sh/deply.bat b/sh/deply.bat new file mode 100644 index 0000000..936c162 --- /dev/null +++ b/sh/deply.bat @@ -0,0 +1,32 @@ +@echo off +setlocal + +:: 设置变量 +set TARGET_DIR=target +set JAR_FILE=%TARGET_DIR%\*.jar +set REMOTE_USER=root +set REMOTE_HOST=192.168.8.10 +set REMOTE_DIR=/app/ +set REMOTE_FILE=app.jar + +:: 输出操作开始信息 +ssh %REMOTE_USER%@%REMOTE_HOST% `systemctl stop zapp` +:: 执行 SCP 命令,将 JAR 文件复制到远程服务器并重命名 +scp %JAR_FILE% %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_DIR%%REMOTE_FILE% +:: 拷贝appresource +@REM scp -r appresource %REMOTE_USER%@%REMOTE_HOST%:/app/ + +:: 重启远程服务器 +ssh %REMOTE_USER%@%REMOTE_HOST% `systemctl start zapp` + +:: 判断 SCP 命令是否成功 +if %errorlevel% neq 0 ( + echo SCP failed! + exit /b 1 +) else ( + echo SCP completed successfully. +) + +:: 结束脚本 +endlocal +pause \ No newline at end of file diff --git a/sh/mkexe.bat b/sh/mkexe.bat new file mode 100644 index 0000000..28e0c0a --- /dev/null +++ b/sh/mkexe.bat @@ -0,0 +1,41 @@ +@echo off +setlocal + +rmdir /s /q out +rmdir /s /q dist + +mkdir out +mkdir out\A8000_VIRTUAL_BAK_END +mkdir out\A8000_VIRTUAL_BAK_END\appresource + +mkdir dist +mkdir dest\A8000_VIRTUAL_BAK_END\appresource\ +copy target\a8000-1.jar out\A8000_VIRTUAL_BAK_END\ +if %errorlevel% neq 0 ( + echo 执行发生错误,退出脚本 + exit /b %errorlevel% +) + +"C:\Program Files\Java\jdk-21\bin\jpackage.exe" ^ + --type app-image ^ + --name A8000_VIRTUAL_BAK_END ^ + --input out\A8000_VIRTUAL_BAK_END ^ + --main-jar a8000-1.jar ^ + --win-console ^ + --dest dist + +mkdir dist\A8000_VIRTUAL_BAK_END\appresource\ +xcopy appresource dist\A8000_VIRTUAL_BAK_END\appresource\ /s /e + + +if %errorlevel% neq 0 ( + echo 执行发生错误,退出脚本 + exit /b %errorlevel% +) + + +@REM .\tools\makesfx.exe -ic -mf -ft -we -di -un -oo .\dist\A8000_VIRTUAL_BAK_END\ .\dist\A8000_VIRTUAL_BAK_END.exe .\logo.ico .\dist\A8000_VIRTUAL_BAK_END\A8000_VIRTUAL_BAK_END.exe + +:: 结束脚本 +endlocal +pause \ No newline at end of file diff --git a/sh/sync_from_board.bat b/sh/sync_from_board.bat new file mode 100644 index 0000000..96ae038 --- /dev/null +++ b/sh/sync_from_board.bat @@ -0,0 +1,2 @@ + scp -r root@192.168.8.10://app/appresource/static/app .\appresource\static/ + scp root@192.168.8.10://app/appresource/db/app.db .\appresource\db/ \ No newline at end of file diff --git a/src/main/java/a8k/app/constant/AppConstant.java b/src/main/java/a8k/app/constant/AppConstant.java index a996bd4..79e11ac 100644 --- a/src/main/java/a8k/app/constant/AppConstant.java +++ b/src/main/java/a8k/app/constant/AppConstant.java @@ -2,11 +2,13 @@ package a8k.app.constant; public class AppConstant { public static final int CONSUMABLE_NUM = 25; + public static final int TUBEHOLER_SIZE = 10;//试管架中可容纳的试管的数量 public static final int CONSUMABLE_COL_NUM = 5; public static final int CONSUMABLE_ROW_NUM = 5; public static final int TIP_NUM = 120; public static final String APP_VERSION = "1.3.1"; + public static final int CONSUMABLE_CHANNEL_NUM = 6; } diff --git a/src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java b/src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java index d90eefb..eb1cb12 100644 --- a/src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java +++ b/src/main/java/a8k/app/controler/api/v1/engineer/ExperimentConsistencyTestingControler.java @@ -2,6 +2,7 @@ package a8k.app.controler.api.v1.engineer; import a8k.app.engineer.service.qatest.ExperimentConsistencyTestingService; +import a8k.app.engineer.service.type.TubeHolderExConfig; import a8k.app.type.exception.AppException; import a8k.app.type.ui.ApiRet; import io.swagger.v3.oas.annotations.Operation; @@ -24,9 +25,22 @@ public class ExperimentConsistencyTestingControler { @Operation(summary = "开始测试(所有配置从应用获得)") @PostMapping("/startTest") - public ApiRet startTest(Integer repeatTimes) throws AppException { - experimentConsistencyTestingService.startTest(repeatTimes); + public ApiRet startTest() throws AppException { + experimentConsistencyTestingService.startTest(); return ApiRet.success(); } + @Operation(summary = "提交配置") + @PostMapping("/submitConfig") + public ApiRet submitConfig(TubeHolderExConfig tubeHolderExConfig) { + experimentConsistencyTestingService.submitTubeExConfig(tubeHolderExConfig); + return ApiRet.success(); + } + + @Operation(summary = "获取配置") + @PostMapping("/getConfig") + public ApiRet getConfig() { + TubeHolderExConfig tubeHolderExConfig = experimentConsistencyTestingService.getTubeExConfig(); + return ApiRet.success(tubeHolderExConfig); + } } diff --git a/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java b/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java index b913856..5a49d11 100644 --- a/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java +++ b/src/main/java/a8k/app/engineer/service/qatest/ExperimentConsistencyTestingService.java @@ -1,12 +1,14 @@ package a8k.app.engineer.service.qatest; import a8k.OS; +import a8k.app.constant.AppConstant; import a8k.app.dao.type.combination.ProjBuildinInfo; import a8k.app.dao.type.db.ProjExtInfoCard; import a8k.app.dao.type.db.ReactionReport; import a8k.app.engineer.service.executor.EngineerModeActionExecutor; import a8k.app.engineer.service.state.EngineerModeStateMgrService; import a8k.app.engineer.service.type.A8kCmdRunnable; +import a8k.app.engineer.service.type.TubeHolderExConfig; import a8k.app.engineer.service.utils.BeforeDoEngineerActionChecker; import a8k.app.hardware.driver.OptModuleDriver; import a8k.app.hardware.type.A8kEcode; @@ -56,6 +58,7 @@ import java.util.Objects; @Slf4j @RequiredArgsConstructor public class ExperimentConsistencyTestingService { + final private A8kTubeHolderType expectedTubeHolderType = A8kTubeHolderType.BulletTube1P5; final private Integer expectedProjId = 1; final private Integer takeSampleUl = 10; @@ -96,18 +99,39 @@ public class ExperimentConsistencyTestingService { final private LiquidOperationCtrlService liquidOperationCtrlService; final private HbotMoveExCtrlService hbotMoveExCtrlService; private final OptModuleDriver optModuleDriver; + private final HbotMoveCtrlService hbotMoveCtrlService; + + + private TubeHolderSetting curTubeHolderSetting; + private TubeHolderExConfig tubeHolderExConfig = new TubeHolderExConfig(); + + synchronized public void submitTubeExConfig(TubeHolderExConfig tubeExTubeHolderExConfig) { + if (tubeExTubeHolderExConfig != null) { + this.tubeHolderExConfig = tubeExTubeHolderExConfig; + } + } + synchronized public TubeHolderExConfig getTubeExConfig() { + return tubeHolderExConfig; + } + + public Integer getRepeatTimes(Integer tubeoff) { + if (tubeoff < 0 || tubeoff >= AppConstant.TUBEHOLER_SIZE) { + throw new IllegalArgumentException("tubeoff is out of range"); + } + if (tubeoff >= tubeHolderExConfig.tubeExConfigs.size()) { + return 1; + } + return getTubeExConfig().tubeExConfigs.get(tubeoff).repeatTimes; + } - private TubeHolderSetting curTubeHolderSetting; - private Integer repeatTimes = 1; /** * 开始测试 - * @param repeatTimes 重复次数 + * @param * @throws AppException */ - public void startTest(Integer repeatTimes) throws AppException { - this.repeatTimes = repeatTimes; + public void startTest() throws AppException { /* * 检查当前是否有其他项目正在进行测试 */ @@ -174,15 +198,17 @@ public class ExperimentConsistencyTestingService { try { log.error("Catch exception: ", e); UISender.txErrorPrompt(e); + docmd("HBOT复位", hbotMoveCtrlService::moveToZero); + docmd("推出试管架", tubeFeedingCtrlService::ejectTubeHolder); //清空光学模组 optScanModuleStateMgrService.changeOptScanModuleStateToEmpty(); - docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate()); + docmd("丢反应板", optScanModuleCtrlService::dropPlate); //清空孵育盘 List all = incubationPlateStateMgrService.getAllNotFreeIncubationSubTanks(); for (IncubationSubTank notFreeTank : all) { - docmd("拉取反应板", () -> {optScanModuleCtrlService.pullPlate(notFreeTank.pos);}); - docmd("丢反应板", () -> {optScanModuleCtrlService.dropPlate();}); + docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(notFreeTank.pos)); + docmd("丢反应板", optScanModuleCtrlService::dropPlate); } incubationPlateStateMgrService.resetAll(); } catch (AppException ex) { @@ -228,7 +254,7 @@ public class ExperimentConsistencyTestingService { hasTubeHolder = false; docmd("入料", () -> { hasTubeHolder = tubeFeedingCtrlService.enterTubeHolder(); - }, () -> {hasTubeHolder = true;}); + }, () -> hasTubeHolder = true); if (!hasTubeHolder) { throw AppException.of(A8kEcode.ERROR_OPERATION, "入料超时,未检测到试管架"); } @@ -250,56 +276,68 @@ public class ExperimentConsistencyTestingService { verifyTubeHolderSettingAndTubeHolderScanResult(curTubeHolderSetting, scanResult); // - for (int i = 0; i < curTubeHolderSetting.tubeSettings.length; i++) { - TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[i]; + //构建试管架 + // setTubeHolderDirect + for (int tubeoff = 0; tubeoff < curTubeHolderSetting.tubeSettings.length; tubeoff++) { + TubeSetting tubeSetting = curTubeHolderSetting.tubeSettings[tubeoff]; if (tubeSetting.projId.isEmpty()) { continue; } - Assert.isTrue(scanResult.tube[i].isTubeExist, String.format("位置[%d]未放入是试管", i + 1)); + Assert.isTrue(scanResult.tube[tubeoff].isTubeExist, String.format("位置[%d]未放入是试管", tubeoff + 1)); + + + //移动试管架到预处理位置 + int finalTubeoff = tubeoff; + docmd("移动试管到处理位", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(finalTubeoff)); + + //尝试处理孵育完成的反应板 + incubationPlateProcess(false); + + //申请耗材 + var consumableInfo = consumablesMgrService.reserveConsumable(expectedProjId); + if (consumableInfo == null) { + throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量,此时应该不会不足 + } + consumablesMgrService.useReserveConsumable(consumableInfo); + + //构造项目信息 + ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); + ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); + ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); + + Assert.notNull(projBuildinInfo, "projBuildInInfo is null"); + Assert.notNull(projExtInfoCard, "projExtInfoCard is null"); //处理样本 - for (int j = 0; j < repeatTimes; j++) { + Tube tube = new Tube(tubeoff); + tube.setIsHighTube(false); + tube.setIsEmergency(false); + tube.setBloodType(BloodType.WHOLE_BLOOD); + tube.setSampleBarcode(tubeSetting.sampleBarcode); + tube.setUserid(tubeSetting.userid); + tube.setProjInfo(ZList.of(projBriefInfo)); + tube.setProjIds(ZList.of(expectedProjId)); + String sampleId = tubeStateMgrService.newSample(tube); + tube.setSampleId(sampleId); + + + for (int j = 0; j < getRepeatTimes(tubeoff); j++) { //处理试管 - processTube(i, tubeSetting); + processTube(tube, tubeoff, consumableInfo, tubeSetting); + if (!tube.getErrors().isEmpty()) { + log.warn("样本异常,跳过当前样本"); + break; + } } } - } - - private void processTube(Integer offset, TubeSetting tubeSetting) throws AppException { - //移动试管架到预处理位置 - docmd("移动试管到处理位", () -> { - tubeFeedingCtrlService.moveTubeToPreProcessPos(offset); - }); - //尝试处理孵育完成的反应板 - incubationPlateProcess(); + incubationPlateProcess(true); + } - //申请耗材 - var consumableInfo = consumablesMgrService.reserveConsumable(expectedProjId); - if (consumableInfo == null) { - throw AppException.of(A8kEcode.CODEERROR, "耗材不足?"); //理论上开始阶段已经核对过了耗材数量,此时应该不会不足 - } - consumablesMgrService.useReserveConsumable(consumableInfo); + private void processTube(Tube tube, Integer offset, ConsumablesMgrService.ConsumableInfo consumableInfo, TubeSetting tubeSetting) throws AppException { - //构造项目信息 ProjBuildinInfo projBuildinInfo = projInfoMgrService.getProjBuildInInfo(expectedProjId); ProjExtInfoCard projExtInfoCard = projInfoMgrService.getProjExtInfoCard(consumableInfo.lotid); - ProjBriefInfo projBriefInfo = ProjInfoUtils.buildProjBrefInfo(projBuildinInfo); - - Assert.notNull(projBuildinInfo, "projBuildInInfo is null"); - Assert.notNull(projExtInfoCard, "projExtInfoCard is null"); - - Tube tube = new Tube(offset); - tube.setIsHighTube(false); - tube.setIsEmergency(false); - tube.setBloodType(BloodType.WHOLE_BLOOD); - tube.setSampleBarcode(tubeSetting.sampleBarcode); - tube.setUserid(tubeSetting.userid); - tube.setProjInfo(ZList.of(projBriefInfo)); - tube.setProjIds(ZList.of(expectedProjId)); - - String sampleId = tubeStateMgrService.newSample(tube); - tube.setSampleId(sampleId); //拉取一个板夹到孵育盘 @@ -315,9 +353,9 @@ public class ExperimentConsistencyTestingService { // optScanModuleCtrlService.pullPlate(freeIncubationPos); // optScanModuleCtrlService.dropPlate(); - docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate()); + docmd("丢反应板", optScanModuleCtrlService::dropPlate); docmd("拉取反应板", () -> optScanModuleCtrlService.pullPlate(freeIncubationPos)); - docmd("丢反应板", () -> optScanModuleCtrlService.dropPlate()); + docmd("丢反应板", optScanModuleCtrlService::dropPlate); // plateBoxCtrlService.pushPlateQuick(consumableInfo.group, freeIncubationPos); @@ -328,38 +366,58 @@ public class ExperimentConsistencyTestingService { docmd("样本处理", () -> { - liquidOperationCtrlService.setProjContext(projBuildinInfo, projExtInfoCard); - var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos); - //取tip - liquidOperationCtrlService.forceTakeTip(); - //刺破缓冲液 - hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos); - //取样品 - Assert.isTrue(expectedTubeHolderType.equals(A8kTubeHolderType.BulletTube1P5), "expectedTubeHolderType != BulletTube1P5"); - hbotMoveExCtrlService.moveToSamplePosXY(A8kSamplePos.Bulltube1P5Pos); - liquidOperationCtrlService.takeSample(A8kSamplePos.Bulltube1P5Pos, preProcessPos, takeSampleUl); - //取混合液到预反应位 - liquidOperationCtrlService.takePreReactionLiquidToReation(preProcessPos); + try { + liquidOperationCtrlService.setProjContext(projBuildinInfo, projExtInfoCard); + var preProcessPos = new PreReactionPos(ConsumableType.SmallBottleBuffer, consumableInfo.group, consumableInfo.pos); + //取tip + liquidOperationCtrlService.forceTakeTip(); + //刺破缓冲液 + hbotMoveExCtrlService.moveToLittleBufferPiercePos(consumableInfo.group, consumableInfo.pos); + //取样品 + Assert.isTrue(expectedTubeHolderType.equals(A8kTubeHolderType.BulletTube1P5), "expectedTubeHolderType != BulletTube1P5"); + hbotMoveExCtrlService.moveToSamplePosXY(A8kSamplePos.Bulltube1P5Pos); + liquidOperationCtrlService.takeSample(A8kSamplePos.Bulltube1P5Pos, preProcessPos, takeSampleUl); + //取混合液到预反应位 + liquidOperationCtrlService.takePreReactionLiquidToReation(preProcessPos); + incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); + } catch (AppException e) { + if (e.getError().eq(A8kEcode.APPE_TAKE_SAMPLE_FAIL)) { + hbotMoveExCtrlService.moveQuickToZero(); + tube.setErrors(ZList.of(e.getError())); + incubationPlateStateMgrService.resetIncubatorPos(freeIncubationPos); + //丢反应板 + optScanModuleCtrlService.forceDropPlate(freeIncubationPos); + UISender.txErrorMsg(log, e, "取样失败"); + } else { + throw e; + } + } + }, () -> { + incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); }); {//开始孵育 - incubationPlateStateMgrService.startIncubating(freeIncubationPos, System.currentTimeMillis(), projBuildinInfo.reactionPlateIncubationTimeMin * 60); } } - private void incubationPlateProcess() throws AppException { + private void incubationPlateProcess(Boolean waittingForAll) throws AppException { do { IncubationSubTank tankPos = incubationPlateStateMgrService.getOneExpiredPlate(); - if (incubationPlateStateMgrService.isHasEnoughIncubationIDLEPos(1) && tankPos == null) { - break; + if (!waittingForAll) { + if (incubationPlateStateMgrService.isHasEnoughIncubationIDLEPos(1) && tankPos == null) { + break; + } + } else { + if (incubationPlateStateMgrService.isAllIncubationSubTanksFree()) { + break; + } } - //拉取反应板到光学模组 - { - //执行动作 + if (tankPos != null) { + //拉取反应板到光学模组 docmd("拉取反应板到光学模块", () -> {optScanModuleCtrlService.pullPlate(tankPos.getPos());}); //设置光学模组状态 @@ -367,21 +425,22 @@ public class ExperimentConsistencyTestingService { optScanModuleStateMgrService.syncProjInfo(tankPos.projBuildinInfo, tankPos.projExtInfoCard); //复位孵育盘状态 incubationPlateStateMgrService.resetIncubatorPos(tankPos.getPos()); - } - //光学扫描 - { + // + //光学扫描 + // + //光学扫描 optScanModuleStateMgrService.changeOptScanModuleStateToScanning(); doOptScan(); //丢板 - docmd("丢弃反应板", () -> {optScanModuleCtrlService.dropPlate();}); + docmd("丢弃反应板", optScanModuleCtrlService::dropPlate); optScanModuleStateMgrService.changeOptScanModuleStateToEmpty(); } - + actionExecutor.sleep(100); } while (true); } @@ -420,7 +479,7 @@ public class ExperimentConsistencyTestingService { private void verifyTubeHolderSettingAndTubeHolderScanResult(TubeHolderSetting tubeHolderSetting, TubeFeedingCtrlService.TubeHolderScanResult scanResult) throws AppException { A8kTubeHolderType tubeHolderType = A8kTubeHolderType.of(scanResult.tubeHolderType); - if (expectedTubeHolderType.equals(tubeHolderType)) { + if (!expectedTubeHolderType.equals(tubeHolderType)) { throw AppException.of(A8kEcode.APPE_TUBE_HOLDER_TYPE_IS_NOT_SUPPORT, "请使用子弹头1.5ml试管架"); } diff --git a/src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java b/src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java index 2716dfd..a35c853 100644 --- a/src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java +++ b/src/main/java/a8k/app/engineer/service/qatest/QATemperatureCtrlTestService.java @@ -3,6 +3,7 @@ package a8k.app.engineer.service.qatest; import a8k.app.service.background.SensorDataUpdateService; import a8k.app.service.background.TemperatureCtrlService; import a8k.app.service.setting.AppSettingsMgrService; +import a8k.app.service.statemgr.GStateMgrService; import a8k.app.type.TemperatureRecordPoint; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -22,12 +23,13 @@ public class QATemperatureCtrlTestService { private final TemperatureCtrlService temperatureCtrlService; private final AppSettingsMgrService appSettingsMgrService; private final SensorDataUpdateService sensorDataUpdateService; + private final GStateMgrService gStateMgrService; /** * 修改温度控制目标温度 */ - synchronized public void setTargetVal(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) { + synchronized public void setTargetVal(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) { log.info("changeTemperatureCtrlTargetVal: targetIncubatorBoxTemperature = {}, targetPlatesBoxTemperature = {}", targetIncubatorBoxTemperature, targetPlatesBoxTemperature); appSettingsMgrService.setIncubateBoxTemperature(targetIncubatorBoxTemperature); appSettingsMgrService.setPlateBoxTemperature(targetPlatesBoxTemperature); @@ -49,6 +51,14 @@ public class QATemperatureCtrlTestService { return temperatureCtrlService.getTargetPlatesBoxTemperatureSetVal(); } + synchronized public Double getIncubateBoxTemp() { + return sensorDataUpdateService.getIncubateBoxTemperature(); + } + + synchronized public Double getPlateBoxTemp() { + return sensorDataUpdateService.getPlateBoxTemperature(); + } + /** * 获取孵育盘温度曲线 * @return curve diff --git a/src/main/java/a8k/app/engineer/service/type/TubeExConfig.java b/src/main/java/a8k/app/engineer/service/type/TubeExConfig.java new file mode 100644 index 0000000..2349986 --- /dev/null +++ b/src/main/java/a8k/app/engineer/service/type/TubeExConfig.java @@ -0,0 +1,5 @@ +package a8k.app.engineer.service.type; + +public class TubeExConfig { + public Integer repeatTimes = 1; +} diff --git a/src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java b/src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java new file mode 100644 index 0000000..261e5d0 --- /dev/null +++ b/src/main/java/a8k/app/engineer/service/type/TubeHolderExConfig.java @@ -0,0 +1,16 @@ +package a8k.app.engineer.service.type; + +import a8k.app.constant.AppConstant; + +import java.util.ArrayList; +import java.util.List; + +public class TubeHolderExConfig { + public List tubeExConfigs = new ArrayList<>(); + + public TubeHolderExConfig() { + for (int i = 0; i < AppConstant.TUBEHOLER_SIZE; i++) { + tubeExConfigs.add(new TubeExConfig()); + } + } +} diff --git a/src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java b/src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java index 3df44d7..59ce537 100644 --- a/src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java +++ b/src/main/java/a8k/app/hardware/driver/CodeScanerDriver.java @@ -27,7 +27,7 @@ public class CodeScanerDriver { } public String pipetteModCodeScannerScanCode() throws AppException { - return pipetteModCodeScannerScanCode(500); + return pipetteModCodeScannerScanCode(300); } public void pipetteModCodeScannerStartScan() throws AppException { diff --git a/src/main/java/a8k/app/service/background/SensorDataUpdateService.java b/src/main/java/a8k/app/service/background/SensorDataUpdateService.java index d053bd2..8b4421f 100644 --- a/src/main/java/a8k/app/service/background/SensorDataUpdateService.java +++ b/src/main/java/a8k/app/service/background/SensorDataUpdateService.java @@ -24,7 +24,6 @@ import java.util.List; public class SensorDataUpdateService { - private final GStateMgrService gStateMgrService; private final TemperatureControlDriver temperatureControlDriver; private final OptScanModuleStateMgrService optScanModuleStateMgrService; @@ -39,6 +38,9 @@ public class SensorDataUpdateService { List incubateBoxTemperatureCurve = new ArrayList<>(); List plateBoxTemperatureCurve = new ArrayList<>(); + Double incubateBoxTemperature = 0.0; + Double plateBoxTemperature = 0.0; + public void setErrorFlag(AppException e) { if (!errorFlag) { appEventBusService.pushAppExceptionEvent(e); @@ -56,11 +58,21 @@ public class SensorDataUpdateService { error = null; } + synchronized public Double getIncubateBoxTemperature() { + return incubateBoxTemperature; + } + + synchronized public Double getPlateBoxTemperature() { + return plateBoxTemperature; + } + + synchronized private void addIncubateBoxTemperatureCurve(Double temperature) { TemperatureRecordPoint point = new TemperatureRecordPoint(); point.tp = System.currentTimeMillis(); point.val = temperature; incubateBoxTemperatureCurve.add(point); + incubateBoxTemperature = temperature; if (incubateBoxTemperatureCurve.size() > 2000) { incubateBoxTemperatureCurve.remove(0); } @@ -68,8 +80,9 @@ public class SensorDataUpdateService { synchronized private void addPlateBoxTemperatureCurve(Double temperature) { TemperatureRecordPoint point = new TemperatureRecordPoint(); - point.tp = System.currentTimeMillis(); - point.val = temperature; + point.tp = System.currentTimeMillis(); + point.val = temperature; + plateBoxTemperature = temperature; plateBoxTemperatureCurve.add(point); if (plateBoxTemperatureCurve.size() > 2000) { plateBoxTemperatureCurve.remove(0); diff --git a/src/main/java/a8k/app/service/background/TemperatureCtrlService.java b/src/main/java/a8k/app/service/background/TemperatureCtrlService.java index 432541e..ce5b8fd 100644 --- a/src/main/java/a8k/app/service/background/TemperatureCtrlService.java +++ b/src/main/java/a8k/app/service/background/TemperatureCtrlService.java @@ -119,6 +119,7 @@ public class TemperatureCtrlService { } + private void startCtrlTemperature(Integer incubatorTemperature, Integer platesBoxTemperature) throws AppException { log.info("start control incubatorTemperature: {},platesBoxTemperature: {}", incubatorTemperature, platesBoxTemperature); temperatureControlDriver.startCtrlTemperature(incubatorTemperature.doubleValue(), platesBoxTemperature.doubleValue()); diff --git a/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java index a8022d7..e1f9355 100644 --- a/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java @@ -56,6 +56,12 @@ public class HbotMoveExCtrlService { Pos3d tipPos = hbotConsumableExParamMgr.getTipPos(tipGroupPos, index); hbotMoveCtrlService.hbotMoveTo(tipPos); + if (!pipetteCtrlDriver.isHasTip()) { + //TODO:单片机支持移动以mm为单位的距离的方法 + pipetteCtrlDriver.zMotorMoveByBlock(-100); + pipetteCtrlDriver.pipetteInitDeviceBlock(); + } + pipetteCtrlDriver.zMotorMoveToZeroPointQuickBlock(); } @@ -215,7 +221,6 @@ public class HbotMoveExCtrlService { } - // public void moveToProbeSubstanceSamplePos(ConsumableGroup group, Integer off) throws AppException { // hbotBaseMoveExDriver.hbotMoveTo(hbotConsumableParamMgr.getProbeSubstanceSamplePos(group, off)); // } @@ -247,14 +252,13 @@ public class HbotMoveExCtrlService { } - public void moveToSampleStartPos(A8kSamplePos pos) throws AppException { hbotMoveCtrlService.hbotMoveTo(hbotSamplePosParamMgr.getSampleStartPos(pos)); } public void moveToSampleEndPos(A8kSamplePos pos) throws AppException { - Pos3d startpos = hbotSamplePosParamMgr.getSampleStartPos(pos); - Integer endpos = hbotSamplePosParamMgr.getSampleEndPos(pos); + Pos3d startpos = hbotSamplePosParamMgr.getSampleStartPos(pos); + Integer endpos = hbotSamplePosParamMgr.getSampleEndPos(pos); startpos.z = endpos; hbotMoveCtrlService.hbotMoveTo(startpos); } diff --git a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java index ac0c026..fbd2a59 100644 --- a/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java @@ -110,6 +110,7 @@ public class LiquidOperationCtrlService { } while (true) { hbotMoveExCtrlService.takeTip(consumablesMgrService.takeNextTipPos()); + if (gstate.isInMode(DeviceRunMode.RunOnlyMode)) { break; } @@ -339,7 +340,7 @@ public class LiquidOperationCtrlService { private void ldd(Integer startpos, Integer maxpos, Integer p_threshold) throws AppException { log.info("lld: startpos={}, maxpos={}, p_threshold={}", startpos, maxpos, p_threshold); - + pipetteCtrlDriver.zMotorMoveToBlock(startpos); // pipetteCtrlDriver.liquidOperationClearParams(); diff --git a/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java b/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java index 7cacbde..c11aa65 100644 --- a/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java +++ b/src/main/java/a8k/app/service/lowerctrl/OptScanModuleCtrlService.java @@ -97,6 +97,12 @@ public class OptScanModuleCtrlService { stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModScannerM, optModuleParamsMgr.getOptScanerScandbyPos()); } + public void forceDropPlate(IncubatorPos turntablePosIndex) throws AppException { + dropPlate(); + pullPlate(turntablePosIndex); + dropPlate(); + } + public Integer[] startOptScan(A8kOptType optType, Integer lasterGain, Integer rawScanGain) throws AppException { Integer forwardScanPos = optModuleExtParamsMgr.getOptScanStartPos(optType); diff --git a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java b/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java index dccc7fa..ed53adb 100644 --- a/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/IncubationPlateStateMgrService.java @@ -214,6 +214,15 @@ public class IncubationPlateStateMgrService { return list; } + synchronized public Boolean isAllIncubationSubTanksFree() { + for (IncubationSubTank subtank : incubationPlate.subtanks) { + if (!subtank.state.equals(IncubationSubTankState.EMPTY)) { + return false; + } + } + return true; + } + @Scheduled(fixedDelay = 500) synchronized public void updateRemainTime() { diff --git a/src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java b/src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java index 98f6d37..375063f 100644 --- a/src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/TubeStateMgrService.java @@ -176,6 +176,11 @@ public class TubeStateMgrService { return null; } + public synchronized void setTubeHolderDirect(TubeHolder tubeHolder) throws AppException { + this.tubeHolder = tubeHolder; + } + + // // 急诊试管状态管理 // diff --git a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java index efbe354..92cfbf8 100644 --- a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java +++ b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java @@ -4,7 +4,10 @@ import a8k.app.utils.ZList; import a8k.extui.page.debug.*; import a8k.extui.page.driver.*; import a8k.extui.page.extapp.*; +import a8k.extui.page.extapp.P02A8kTemperaturaVerfication; import a8k.extui.page.extapp.debug_assistant.IDCardDataGeneratorPage; +import a8k.extui.page.extapp.profession_test.ExperimentConsistencyTestingPage; +import a8k.extui.page.extapp.profession_test.P01PipetteGunVerification; import a8k.extui.page.extsetting.db.A8kSubModuleParameterInitDebugPage; import a8k.extui.page.extsetting.db.DeviceActionParameterSettingPage; import a8k.extui.page.extsetting.db.ProjInfoMgrPage; @@ -140,7 +143,8 @@ public class ExtApiPageGroupCfgMgr { )), new Menu("过检专用", ZList.of( new Menu(P01PipetteGunVerification.class, "移液枪验证"), - new Menu(P02A8kTemperaturaVerfication.class, "温度控制验证") + new Menu(P02A8kTemperaturaVerfication.class, "温度控制验证"), + new Menu(ExperimentConsistencyTestingPage.class, "一致性测试") )), new Menu("坐标测量", ZList.of( new Menu(HbotPosMeasurePage.class, "HBOT测量(电控)"), diff --git a/src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java b/src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java deleted file mode 100644 index 58c1576..0000000 --- a/src/main/java/a8k/extui/page/extapp/P01PipetteGunVerification.java +++ /dev/null @@ -1,228 +0,0 @@ -package a8k.extui.page.extapp; - -import a8k.app.constant.AppConstant; -import a8k.app.service.lowerctrl.LiquidOperationCtrlService; -import a8k.app.service.param.exparam.HbotConsumableExParamMgr; -import a8k.app.service.param.hbotpos.HbotTipPosMgr; -import a8k.app.service.param.pipetteparam.PipetteGunExParamMgr; -import a8k.extui.mgr.ExtApiPageMgr; -import a8k.extui.type.ExtUIPageCfg; -import a8k.app.hardware.type.LldType; -import a8k.app.service.lowerctrl.HbotMoveExCtrlService; -import a8k.app.hardware.driver.PipetteCtrlDriver; -import a8k.app.hardware.type.PipetteRegIndex; -import a8k.app.service.lowerctrl.HbotMoveCtrlService; -import a8k.app.type.a8k.ConsumableGroup; -import a8k.app.type.a8k.Pos3d; -import a8k.app.type.exception.AppException; -import a8k.app.type.a8k.pos.TipPos; -import a8k.app.type.a8k.pos.TipGroupPos; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -public class P01PipetteGunVerification { - @Resource - HbotTipPosMgr hbotTipPosMgr; - - @Resource - PipetteCtrlDriver pipetteCtrlDriver; - @Resource - HbotMoveCtrlService hbotMoveCtrlService; - @Resource - HbotMoveExCtrlService hbotMoveExCtrlService; - - @Resource - HbotConsumableExParamMgr hbotConsumableExParamMgr; - - @Resource - PipetteGunExParamMgr pipetteGunExParamMgr; - - @Resource - ExtApiPageMgr extApiPageMgr; - - Integer tipNum = 0; - Integer liquidPos = null; - Boolean stopFlag = false; - - @PostConstruct - void init() { - ExtUIPageCfg page = new ExtUIPageCfg(this); - page.newGroup("基础"); - page.addFunction("测试准备", this::initTestMode); - page.addFunction("停止测试", this::stopTest); - page.addFunction("设置校准系数", this::calibration) - .setParamVal("coefficientA", () -> pipetteGunExParamMgr.getCoefficientA()) - .setParamVal("coefficientB", () -> pipetteGunExParamMgr.getCoefficientB()); - page.newGroup("测试0"); - page.addFunction("取一次10ul", this::aspirate10ul); - page.addFunction("取一次75ul", this::aspirate75ul); - page.newGroup("测试1"); - page.addFunction("取一次5ul", this::aspirate5ul); - page.addFunction("取一次30ul", this::aspirate30ul); - page.addFunction("取一次50ul", this::aspirate50ul); - page.addFunction("停止测试", this::stopTest); - - extApiPageMgr.addPage(page); - } - - public void pipetteGunInit() throws AppException { - pipetteCtrlDriver.pipetteInitDeviceBlock(); - } - - public void initTestMode() throws AppException { - pipetteCtrlDriver.zMotorEnable(1); - hbotMoveCtrlService.enable(1); - pipetteCtrlDriver.zMotorMoveZeroBlock(); - hbotMoveCtrlService.moveToZero(); - hbotMoveCtrlService.hbotMoveTo(hbotTipPosMgr.getDropTipPos()); - pipetteGunInit(); - hbotMoveCtrlService.hbotMoveTo(new Pos3d(0, 0, 0)); - tipNum = AppConstant.TIP_NUM; - } - - public void stopTest() throws AppException { - pipetteCtrlDriver.zMotorEnable(0); - hbotMoveCtrlService.enable(0); - } - - public void calibration(Double coefficientA, Double coefficientB) { - pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficientA, coefficientB); - } - - - Boolean takeOneTip() throws AppException { - hbotMoveCtrlService.hbotMoveTo(hbotTipPosMgr.getDropTipPos()); - pipetteGunInit(); - TipPos tipPos = new TipPos(); - tipPos.group = TipGroupPos.TipG1; - if (tipNum == 0) { - tipNum = 120; - } - - tipPos.index = AppConstant.TIP_NUM - tipNum; - tipNum--; - log.info(" 取TIP {}", tipPos); - return hbotMoveExCtrlService.takeTipNoCheck(tipPos.group, tipPos.index); - } - - void takeTip() throws AppException { - while (!pipetteCtrlDriver.isHasTip()) { - if (takeOneTip()) { - break; - } - } - } - - public void pumpMoveTo(Integer pumpvmax, Double ul) throws AppException { - pipetteCtrlDriver.liquidOperationClearParams(); - pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 1000, pumpvmax); - pipetteCtrlDriver.liquidOperationFreshParams(); - pipetteCtrlDriver.pipettePumpMoveTo(ul); - } - - public Integer lld() throws AppException { - liquidPos = 0; - hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG1); - pipetteCtrlDriver.zMotorMoveToBlock(0); - pumpMoveTo(8000, 0.0); - pumpMoveTo(300, 100.0); - pumpMoveTo(8000, 0.0); - pumpMoveTo(300, 50.0); - - Pos3d toPos = hbotConsumableExParamMgr.getLargeBufferSamplePos(ConsumableGroup.CG1); - Pos3d maxPos = hbotConsumableExParamMgr.getLargeBufferSamplePosEnd(ConsumableGroup.CG1); - pipetteCtrlDriver.zMotorMoveToBlock(toPos.z); - pipetteCtrlDriver.liquidOperationClearParams(); - pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 30); - pipetteCtrlDriver.liquidOperationSetZMotorRunParams(toPos.z, maxPos.z, 60 * 80 / LiquidOperationCtrlService.helicalPitch); - pipetteCtrlDriver.liquidOperationFreshParams(); - pipetteCtrlDriver.pipetteLld(LldType.kplld, 0, 30); - if (pipetteCtrlDriver.lldIsDetectLiquid()) { - liquidPos = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos); - } - pipetteCtrlDriver.zMotorMoveToBlock(0); - pumpMoveTo(8000, 0.0); - return liquidPos; - } - - public void takeLiquid(Double ul) throws AppException { - hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG1); - pipetteCtrlDriver.zMotorMoveToBlock(0); - pumpMoveTo(8000, 0.0); - pumpMoveTo(8000, 150.0); - pipetteCtrlDriver.zMotorMoveToBlock(liquidPos); - pipetteCtrlDriver.liquidOperationClearParams(); - pipetteCtrlDriver.liquidOperationSetGunRunParams(14, 14, 0, 900, 100); - pipetteCtrlDriver.liquidOperationSetZMotorRunParams(0, 300, 10 * 80 / LiquidOperationCtrlService.helicalPitch); - pipetteCtrlDriver.liquidOperationFreshParams(); - ul = pipetteGunExParamMgr.calibrateVolume(ul); - log.info("取液体 {}", ul); - pipetteCtrlDriver.pipetteAspirate(ul); - pipetteCtrlDriver.zMotorMoveToBlock(0); - } - - public void distributeLiquid() throws AppException { - hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG6); - pipetteCtrlDriver.zMotorMoveToBlock(50); - pumpMoveTo(8000, 0.0); - pipetteCtrlDriver.zMotorMoveToBlock(0); - } - - public void resetPos() throws AppException { - hbotMoveExCtrlService.moveToLargeBSSamplePosXY(ConsumableGroup.CG2); - } - - public void aspirate10ul() throws AppException { - takeTip(); - lld(); - if (liquidPos == 0) - throw AppException.ofAECodeError("未检测到液体"); - takeLiquid(10.0); - distributeLiquid(); - resetPos(); - } - - public void aspirate75ul() throws AppException { - takeTip(); - lld(); - if (liquidPos == 0) - throw AppException.ofAECodeError("未检测到液体"); - takeLiquid(75.0); - distributeLiquid(); - resetPos(); - } - - public void aspirate5ul() throws AppException { - takeTip(); - lld(); - if (liquidPos == 0) - throw AppException.ofAECodeError("未检测到液体"); - takeLiquid(5.0); - distributeLiquid(); - resetPos(); - } - - public void aspirate30ul() throws AppException { - takeTip(); - lld(); - if (liquidPos == 0) - throw AppException.ofAECodeError("未检测到液体"); - takeLiquid(30.0); - distributeLiquid(); - resetPos(); - } - - public void aspirate50ul() throws AppException { - takeTip(); - lld(); - if (liquidPos == 0) - throw AppException.ofAECodeError("未检测到液体"); - takeLiquid(50.0); - distributeLiquid(); - resetPos(); - } -} diff --git a/src/main/java/a8k/extui/page/extapp/P02A8kTemperaturaVerfication.java b/src/main/java/a8k/extui/page/extapp/P02A8kTemperaturaVerfication.java deleted file mode 100644 index b29773e..0000000 --- a/src/main/java/a8k/extui/page/extapp/P02A8kTemperaturaVerfication.java +++ /dev/null @@ -1,170 +0,0 @@ -package a8k.extui.page.extapp; - -import a8k.app.hardware.driver.TemperatureControlDriver; -import a8k.app.service.background.TemperatureCtrlService; -import a8k.app.service.param.pos.TemperatureCtrlParamMgr; -import a8k.app.type.exception.AppException; -import a8k.app.type.param.TemperatureCtrlParam; -import a8k.extui.factory.CurveBuilder; -import a8k.extui.mgr.ExtApiPageMgr; -import a8k.extui.type.ExtApiStatu; -import a8k.extui.type.ret.ExtApiCurve; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; - - -/** - * - */ -@Component -@Slf4j -public class P02A8kTemperaturaVerfication { - @Resource - ExtApiPageMgr extApiPageMgr; - - @Resource - TemperatureCtrlService temperatureCtrlService; - @Resource - TemperatureControlDriver temperatureControlDriver; - @Resource - TemperatureCtrlParamMgr temperatureCtrlParamMgr; - - - List incubateBoxTemperatureCurve = new ArrayList<>(); - List plateBoxTemperatureCurve = new ArrayList<>(); - - Thread tempSampleThread; - - Double incubateBoxTemperatureCache = 0.0; - Double plateBoxTemperatureCache = 0.0; - Integer hasStartedTimeMS = 0; - Double targetIncubateBoxTemp = 25.0; - Double targetPlateBoxTemp = 25.0; - Boolean workingFlag = false; - - - @ExtApiStatu(name = "", group = "孵育盘温度", order = 3) - public Double readIncubateBoxTemperature() throws AppException { - return (incubateBoxTemperatureCache); - } - - @ExtApiStatu(name = "", group = "板夹仓温度", order = 4) - public Double readPlateBoxTemperature() throws AppException { - return (plateBoxTemperatureCache); - } - - @ExtApiStatu(name = "", group = "状态", order = 5) - public String hasStartedTime() { - int S = hasStartedTimeMS / 1000; - return String.format("%s:%s:%s", (int) Math.floor((double) S / 3600), (int) Math.floor((double) (S % 3600) / 60), S % 60); - } - - - @PostConstruct - public void init() throws NoSuchMethodException { - var page = extApiPageMgr.newPage(this); - - page.newGroup("基础"); - page.addFunction("设置孵育盘温度偏移", this::setIncubatorBoxTemperatureOff) - .setParamVal("offset", () -> temperatureCtrlParamMgr.getParam(TemperatureCtrlParam.IncubatorTCMTempOffset)); - page.addFunction("设置板夹仓温度偏移", this::setPlatesBoxTCMTempOffset) - .setParamVal("offset", () -> temperatureCtrlParamMgr.getParam(TemperatureCtrlParam.PlatesBoxTCMTempOffset)); - - page.newGroup("操作"); - page.addFunction("启动温度控制", this::startCtrl); - page.addFunction("停止温度控制", this::stopCtrl); - page.addFunction("查看孵育盘温度曲线", this::showIncubateBoxTemperatureCurve); - page.addFunction("查看板夹仓温度曲线", this::showPlateBoxTemperatureCurve); - extApiPageMgr.addPage(page); - } - - public void setIncubatorBoxTemperatureOff(Double offset) throws AppException, InterruptedException { - temperatureCtrlParamMgr.setParam(TemperatureCtrlParam.IncubatorTCMTempOffset, offset); - if (workingFlag) { - startCtrl(targetIncubateBoxTemp.intValue(), null); - } - } - - - public void setPlatesBoxTCMTempOffset(Double offset) throws AppException, InterruptedException { - temperatureCtrlParamMgr.setParam(TemperatureCtrlParam.PlatesBoxTCMTempOffset, offset); - if (workingFlag) { - startCtrl(null, targetPlateBoxTemp.intValue()); - } - } - - - synchronized public void startCtrl(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) throws AppException, InterruptedException { - if (targetIncubatorBoxTemperature != null) { - temperatureCtrlService.setTargetIncubatorTemperature(targetIncubatorBoxTemperature); - targetIncubateBoxTemp = targetIncubatorBoxTemperature.doubleValue(); - } - if (targetPlatesBoxTemperature != null) { - temperatureCtrlService.setTargetPlatesBoxTemperature(targetPlatesBoxTemperature); - targetPlateBoxTemp = targetPlatesBoxTemperature.doubleValue(); - } - if (tempSampleThread != null) { - tempSampleThread.interrupt(); - tempSampleThread.join(); - } - hasStartedTimeMS = 0; - tempSampleThread = new Thread(() -> { - while (true) { - try { - Thread.sleep(2000); - hasStartedTimeMS += 2000; - incubateBoxTemperatureCache = temperatureControlDriver.readIncubateBoxTemperature(); - plateBoxTemperatureCache = temperatureControlDriver.readPlateBoxTemperature(); - addIncubateBoxTemperatureCurve(incubateBoxTemperatureCache); - addPlateBoxTemperatureCurve(plateBoxTemperatureCache); - log.info("孵育盘[ 温度:{} PWM:{} ], 板夹仓[ 温度:{} PWM:{} ]", - incubateBoxTemperatureCache, temperatureControlDriver.readIncubateBoxPWMOutput(), - plateBoxTemperatureCache, temperatureControlDriver.readPlateBoxPWMOutput()); - } catch (InterruptedException ignored) { - break; - } catch (Exception e) { - log.error("温度采样线程异常", e); - } - } - }); - tempSampleThread.start(); - workingFlag = true; - } - - synchronized public void stopCtrl() throws AppException, InterruptedException { - temperatureCtrlService.clearTargetTemperature(); - if (tempSampleThread != null) { - tempSampleThread.interrupt(); - tempSampleThread.join(); - } - workingFlag = false; - } - - public ExtApiCurve showIncubateBoxTemperatureCurve() { - return CurveBuilder.buidCurve("孵育盘温度曲线", "time", "value", targetIncubateBoxTemp - 10, targetIncubateBoxTemp + 10, incubateBoxTemperatureCurve); - } - - public ExtApiCurve showPlateBoxTemperatureCurve() { - return CurveBuilder.buidCurve("板夹仓温度曲线", "time", "value", targetPlateBoxTemp - 10, targetPlateBoxTemp + 10, plateBoxTemperatureCurve); - } - - - private void addIncubateBoxTemperatureCurve(Double temperature) { - incubateBoxTemperatureCurve.add(new Object[]{System.currentTimeMillis(), temperature}); - if (incubateBoxTemperatureCurve.size() > 3000) { - incubateBoxTemperatureCurve.remove(0); - } - } - - private void addPlateBoxTemperatureCurve(Double temperature) { - plateBoxTemperatureCurve.add(new Object[]{System.currentTimeMillis(), temperature}); - if (plateBoxTemperatureCurve.size() > 3000) { - plateBoxTemperatureCurve.remove(0); - } - } -} diff --git a/src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java b/src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java new file mode 100644 index 0000000..0899809 --- /dev/null +++ b/src/main/java/a8k/extui/page/extapp/profession_test/ExperimentConsistencyTestingPage.java @@ -0,0 +1,97 @@ +package a8k.extui.page.extapp.profession_test; + + +import a8k.app.engineer.service.qatest.ExperimentConsistencyTestingService; +import a8k.app.engineer.service.type.TubeExConfig; +import a8k.app.engineer.service.type.TubeHolderExConfig; +import a8k.app.type.exception.AppException; +import a8k.extui.mgr.ExtApiPageMgr; +import a8k.extui.type.ExtApiStatu; +import a8k.extui.type.ExtUIPageCfg; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class ExperimentConsistencyTestingPage { + + private final ExtApiPageMgr extApiPageMgr; + private final ExperimentConsistencyTestingService experimentConsistencyTestingService; + + @ExtApiStatu(name = "", group = "试管1", order = 1) + public TubeExConfig getTubeExConfig1() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(0); + } + + @ExtApiStatu(name = "", group = "试管2", order = 2) + public TubeExConfig getTubeExConfig2() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(1); + } + + @ExtApiStatu(name = "", group = "试管3", order = 3) + public TubeExConfig getTubeExConfig3() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(2); + } + + @ExtApiStatu(name = "", group = "试管4", order = 4) + public TubeExConfig getTubeExConfig4() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(3); + } + + @ExtApiStatu(name = "", group = "试管5", order = 5) + public TubeExConfig getTubeExConfig5() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(4); + } + + @ExtApiStatu(name = "", group = "试管6", order = 6) + public TubeExConfig getTubeExConfig6() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(5); + } + + @ExtApiStatu(name = "", group = "试管7", order = 7) + public TubeExConfig getTubeExConfig7() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(6); + } + + @ExtApiStatu(name = "", group = "试管8", order = 8) + public TubeExConfig getTubeExConfig8() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(7); + } + + @ExtApiStatu(name = "", group = "试管9", order = 9) + public TubeExConfig getTubeExConfig9() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(8); + } + + @ExtApiStatu(name = "", group = "试管10", order = 10) + public TubeExConfig getTubeExConfig10() { + return experimentConsistencyTestingService.getTubeExConfig().tubeExConfigs.get(9); + } + + + @PostConstruct + void init() { + ExtUIPageCfg page = new ExtUIPageCfg(this); + page.newGroup("配置"); + page.addFunction("设置配置", this::setTubeRepeatTime).setParamVal("tubeOff", () -> 1).setParamVal("repeatTimes", () -> 1); + page.newGroup("基础"); + page.addFunction("开始测试", this::startTest); + extApiPageMgr.addPage(page); + } + + public void startTest() throws AppException { + experimentConsistencyTestingService.startTest(); + } + + public void setTubeRepeatTime(Integer tubeOff, Integer repeatTimes) { + tubeOff = tubeOff + 1; + TubeHolderExConfig tubeHolderExConfig = experimentConsistencyTestingService.getTubeExConfig(); + tubeHolderExConfig.tubeExConfigs.get(tubeOff).repeatTimes = repeatTimes; + log.info("setTubeRepeatTime: tubeOff = {}, repeatTimes = {}", tubeOff, repeatTimes); + } + + +} diff --git a/src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java b/src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java new file mode 100644 index 0000000..11dd5eb --- /dev/null +++ b/src/main/java/a8k/extui/page/extapp/profession_test/P01PipetteGunVerification.java @@ -0,0 +1,80 @@ +package a8k.extui.page.extapp.profession_test; + +import a8k.app.constant.AppConstant; +import a8k.app.engineer.service.qatest.LiquidAbsorptionAndDistributionTestService; +import a8k.app.service.lowerctrl.LiquidOperationCtrlService; +import a8k.app.service.param.exparam.HbotConsumableExParamMgr; +import a8k.app.service.param.hbotpos.HbotTipPosMgr; +import a8k.app.service.param.pipetteparam.PipetteGunExParamMgr; +import a8k.extui.mgr.ExtApiPageMgr; +import a8k.extui.type.ExtUIPageCfg; +import a8k.app.hardware.type.LldType; +import a8k.app.service.lowerctrl.HbotMoveExCtrlService; +import a8k.app.hardware.driver.PipetteCtrlDriver; +import a8k.app.hardware.type.PipetteRegIndex; +import a8k.app.service.lowerctrl.HbotMoveCtrlService; +import a8k.app.type.a8k.ConsumableGroup; +import a8k.app.type.a8k.Pos3d; +import a8k.app.type.exception.AppException; +import a8k.app.type.a8k.pos.TipPos; +import a8k.app.type.a8k.pos.TipGroupPos; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class P01PipetteGunVerification { + private final PipetteGunExParamMgr pipetteGunExParamMgr; + private final ExtApiPageMgr extApiPageMgr; + private final LiquidAbsorptionAndDistributionTestService liquidAbsorptionAndDistributionTestService; + + + @PostConstruct + void init() { + ExtUIPageCfg page = new ExtUIPageCfg(this); + page.newGroup("基础"); + page.addFunction("设置校准系数", this::setCalibrationParam) + .setParamVal("coefficientA", pipetteGunExParamMgr::getCoefficientA) + .setParamVal("coefficientB", pipetteGunExParamMgr::getCoefficientB); + page.newGroup("测试0"); + page.addFunction("取一次10ul", this::aspirate10ul); + page.addFunction("取一次75ul", this::aspirate75ul); + page.newGroup("测试1"); + page.addFunction("取一次5ul", this::aspirate5ul); + page.addFunction("取一次30ul", this::aspirate30ul); + page.addFunction("取一次50ul", this::aspirate50ul); + extApiPageMgr.addPage(page); + } + + + public void setCalibrationParam(Double coefficientA, Double coefficientB) { + pipetteGunExParamMgr.setVolumeCalibrationCoefficient(coefficientA, coefficientB); + } + + + public void aspirate10ul() throws AppException { + liquidAbsorptionAndDistributionTestService.absorbAndDistribute(10); + } + + public void aspirate75ul() throws AppException { + liquidAbsorptionAndDistributionTestService.absorbAndDistribute(75); + } + + public void aspirate5ul() throws AppException { + liquidAbsorptionAndDistributionTestService.absorbAndDistribute(5); + + } + + public void aspirate30ul() throws AppException { + liquidAbsorptionAndDistributionTestService.absorbAndDistribute(30); + } + + public void aspirate50ul() throws AppException { + liquidAbsorptionAndDistributionTestService.absorbAndDistribute(50); + + } +} diff --git a/src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java b/src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java new file mode 100644 index 0000000..b29773e --- /dev/null +++ b/src/main/java/a8k/extui/page/extapp/profession_test/P02A8kTemperaturaVerfication.java @@ -0,0 +1,170 @@ +package a8k.extui.page.extapp; + +import a8k.app.hardware.driver.TemperatureControlDriver; +import a8k.app.service.background.TemperatureCtrlService; +import a8k.app.service.param.pos.TemperatureCtrlParamMgr; +import a8k.app.type.exception.AppException; +import a8k.app.type.param.TemperatureCtrlParam; +import a8k.extui.factory.CurveBuilder; +import a8k.extui.mgr.ExtApiPageMgr; +import a8k.extui.type.ExtApiStatu; +import a8k.extui.type.ret.ExtApiCurve; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + + +/** + * + */ +@Component +@Slf4j +public class P02A8kTemperaturaVerfication { + @Resource + ExtApiPageMgr extApiPageMgr; + + @Resource + TemperatureCtrlService temperatureCtrlService; + @Resource + TemperatureControlDriver temperatureControlDriver; + @Resource + TemperatureCtrlParamMgr temperatureCtrlParamMgr; + + + List incubateBoxTemperatureCurve = new ArrayList<>(); + List plateBoxTemperatureCurve = new ArrayList<>(); + + Thread tempSampleThread; + + Double incubateBoxTemperatureCache = 0.0; + Double plateBoxTemperatureCache = 0.0; + Integer hasStartedTimeMS = 0; + Double targetIncubateBoxTemp = 25.0; + Double targetPlateBoxTemp = 25.0; + Boolean workingFlag = false; + + + @ExtApiStatu(name = "", group = "孵育盘温度", order = 3) + public Double readIncubateBoxTemperature() throws AppException { + return (incubateBoxTemperatureCache); + } + + @ExtApiStatu(name = "", group = "板夹仓温度", order = 4) + public Double readPlateBoxTemperature() throws AppException { + return (plateBoxTemperatureCache); + } + + @ExtApiStatu(name = "", group = "状态", order = 5) + public String hasStartedTime() { + int S = hasStartedTimeMS / 1000; + return String.format("%s:%s:%s", (int) Math.floor((double) S / 3600), (int) Math.floor((double) (S % 3600) / 60), S % 60); + } + + + @PostConstruct + public void init() throws NoSuchMethodException { + var page = extApiPageMgr.newPage(this); + + page.newGroup("基础"); + page.addFunction("设置孵育盘温度偏移", this::setIncubatorBoxTemperatureOff) + .setParamVal("offset", () -> temperatureCtrlParamMgr.getParam(TemperatureCtrlParam.IncubatorTCMTempOffset)); + page.addFunction("设置板夹仓温度偏移", this::setPlatesBoxTCMTempOffset) + .setParamVal("offset", () -> temperatureCtrlParamMgr.getParam(TemperatureCtrlParam.PlatesBoxTCMTempOffset)); + + page.newGroup("操作"); + page.addFunction("启动温度控制", this::startCtrl); + page.addFunction("停止温度控制", this::stopCtrl); + page.addFunction("查看孵育盘温度曲线", this::showIncubateBoxTemperatureCurve); + page.addFunction("查看板夹仓温度曲线", this::showPlateBoxTemperatureCurve); + extApiPageMgr.addPage(page); + } + + public void setIncubatorBoxTemperatureOff(Double offset) throws AppException, InterruptedException { + temperatureCtrlParamMgr.setParam(TemperatureCtrlParam.IncubatorTCMTempOffset, offset); + if (workingFlag) { + startCtrl(targetIncubateBoxTemp.intValue(), null); + } + } + + + public void setPlatesBoxTCMTempOffset(Double offset) throws AppException, InterruptedException { + temperatureCtrlParamMgr.setParam(TemperatureCtrlParam.PlatesBoxTCMTempOffset, offset); + if (workingFlag) { + startCtrl(null, targetPlateBoxTemp.intValue()); + } + } + + + synchronized public void startCtrl(Integer targetIncubatorBoxTemperature, Integer targetPlatesBoxTemperature) throws AppException, InterruptedException { + if (targetIncubatorBoxTemperature != null) { + temperatureCtrlService.setTargetIncubatorTemperature(targetIncubatorBoxTemperature); + targetIncubateBoxTemp = targetIncubatorBoxTemperature.doubleValue(); + } + if (targetPlatesBoxTemperature != null) { + temperatureCtrlService.setTargetPlatesBoxTemperature(targetPlatesBoxTemperature); + targetPlateBoxTemp = targetPlatesBoxTemperature.doubleValue(); + } + if (tempSampleThread != null) { + tempSampleThread.interrupt(); + tempSampleThread.join(); + } + hasStartedTimeMS = 0; + tempSampleThread = new Thread(() -> { + while (true) { + try { + Thread.sleep(2000); + hasStartedTimeMS += 2000; + incubateBoxTemperatureCache = temperatureControlDriver.readIncubateBoxTemperature(); + plateBoxTemperatureCache = temperatureControlDriver.readPlateBoxTemperature(); + addIncubateBoxTemperatureCurve(incubateBoxTemperatureCache); + addPlateBoxTemperatureCurve(plateBoxTemperatureCache); + log.info("孵育盘[ 温度:{} PWM:{} ], 板夹仓[ 温度:{} PWM:{} ]", + incubateBoxTemperatureCache, temperatureControlDriver.readIncubateBoxPWMOutput(), + plateBoxTemperatureCache, temperatureControlDriver.readPlateBoxPWMOutput()); + } catch (InterruptedException ignored) { + break; + } catch (Exception e) { + log.error("温度采样线程异常", e); + } + } + }); + tempSampleThread.start(); + workingFlag = true; + } + + synchronized public void stopCtrl() throws AppException, InterruptedException { + temperatureCtrlService.clearTargetTemperature(); + if (tempSampleThread != null) { + tempSampleThread.interrupt(); + tempSampleThread.join(); + } + workingFlag = false; + } + + public ExtApiCurve showIncubateBoxTemperatureCurve() { + return CurveBuilder.buidCurve("孵育盘温度曲线", "time", "value", targetIncubateBoxTemp - 10, targetIncubateBoxTemp + 10, incubateBoxTemperatureCurve); + } + + public ExtApiCurve showPlateBoxTemperatureCurve() { + return CurveBuilder.buidCurve("板夹仓温度曲线", "time", "value", targetPlateBoxTemp - 10, targetPlateBoxTemp + 10, plateBoxTemperatureCurve); + } + + + private void addIncubateBoxTemperatureCurve(Double temperature) { + incubateBoxTemperatureCurve.add(new Object[]{System.currentTimeMillis(), temperature}); + if (incubateBoxTemperatureCurve.size() > 3000) { + incubateBoxTemperatureCurve.remove(0); + } + } + + private void addPlateBoxTemperatureCurve(Double temperature) { + plateBoxTemperatureCurve.add(new Object[]{System.currentTimeMillis(), temperature}); + if (plateBoxTemperatureCurve.size() > 3000) { + plateBoxTemperatureCurve.remove(0); + } + } +}