Browse Source

update

master
zhaohe 2 months ago
parent
commit
7074c01c5f
  1. 2
      sh/mkexe.bat
  2. 36
      src/main/java/a8k/BoditechA800Application.java
  3. 8
      src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java
  4. 2
      src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java
  5. 22
      src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java
  6. 10
      src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java
  7. 18
      src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java
  8. 10
      src/main/java/a8k/app/i18n/Internationalization.java
  9. 8
      src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java
  10. 5
      src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java
  11. 29
      src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java
  12. 214
      src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java
  13. 75
      src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java
  14. 3
      src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java
  15. 211
      src/main/java/a8k/app/service/module/SamplePreProcessModule.java
  16. 11
      src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java
  17. 25
      src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java
  18. 2
      src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java
  19. 26
      src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java
  20. 18
      src/main/java/a8k/app/service/statemgr/TubeStateMgr.java
  21. 6
      src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java
  22. 7
      src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java
  23. 32
      src/main/java/a8k/app/service/utils/ProjInfoReader.java
  24. 7
      src/main/java/a8k/app/type/a8k/BloodType.java
  25. 34
      src/main/java/a8k/app/type/a8k/SupportBloodType.java
  26. 20
      src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java
  27. 10
      src/main/java/a8k/app/type/a8k/state/Tube.java
  28. 3
      src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java
  29. 30
      src/main/java/a8k/app/utils/ActionTaskPool.java
  30. 26
      src/main/java/a8k/app/utils/ProjectParamUtils.java
  31. 3
      src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java
  32. 3
      src/main/java/a8k/extui/page/extapp/A8kOptVerification.java
  33. 35
      src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java
  34. 18
      src/main/resources/application.yml
  35. 64
      src/main/resources/db/zapp_a8k_project_info.csv

2
sh/mkexe.bat

@ -27,6 +27,8 @@ if %errorlevel% neq 0 (
mkdir dist\A8000_VIRTUAL_BAK_END\appresource\
xcopy appresource dist\A8000_VIRTUAL_BAK_END\appresource\ /s /e
start explorer dist\
if %errorlevel% neq 0 (
echo 执行发生错误,退出脚本

36
src/main/java/a8k/BoditechA800Application.java

@ -1,6 +1,7 @@
package a8k;
import a8k.app.type.DeviceRunMode;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
@ -13,25 +14,26 @@ import org.springframework.core.env.Environment;
@SpringBootApplication
public class BoditechA800Application implements ApplicationListener<ContextRefreshedEvent> {
@Resource
private Environment env;
@Resource
private Environment env;
public static void main(String[] args) {
SpringApplication.run(BoditechA800Application.class, args);
public static void main(String[] args) {
SpringApplication.run(BoditechA800Application.class, args);
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// if (null == event.getApplicationContext().getParent()) {
// log.info("Springboot加载完成");
// try {
// Runtime.getRuntime().exec(String.format("cmd /c start http://127.0.0.1:%s/exui/index.html", env.getProperty("server.port")));
// } catch (Exception e) {
// }
// }
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
DeviceRunMode runmode = env.getProperty("device.runmode", DeviceRunMode.class);
if (runmode.equals(DeviceRunMode.VirtualMode)) {
if (null == event.getApplicationContext().getParent()) {
log.info("Springboot加载完成");
try {
Runtime.getRuntime().exec(String.format("cmd /c start http://127.0.0.1:%s/exui/index.html", env.getProperty("server.port")));
} catch (Exception ignored) {
}
}
}
}
}

8
src/main/java/a8k/app/controler/api/v1/app/data/A8kProjectInfoControler.java

@ -1,7 +1,9 @@
package a8k.app.controler.api.v1.app.data;
import a8k.app.dao.ProjectBaseInfoDao;
import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.dao.type.db.ProjectBaseInfo;
import a8k.app.service.data.ProjInfoMgrService;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import io.swagger.v3.oas.annotations.Operation;
@ -23,12 +25,12 @@ import java.util.List;
public class A8kProjectInfoControler {
@Resource
ProjectBaseInfoDao projectBaseInfoDao;
ProjInfoMgrService projInfoMgrService;
@Operation(summary = "读取设备支持的所有项目")
@PostMapping("/getAll")
public ApiRet<List<ProjectBaseInfo>> getAll() throws AppException {
return ApiRet.success(projectBaseInfoDao.getAll());
public ApiRet<List<ProjBuildInInfo>> getAll() throws AppException {
return ApiRet.success(projInfoMgrService.getAllProjBuildInInfo());
}
}

2
src/main/java/a8k/app/controler/api/v1/app/state/EmergencyTubeController.java

@ -53,7 +53,7 @@ public class EmergencyTubeController {
setting.getUserid(),
setting.getSampleBarcode(),
setting.getBloodType(),
setting.getProjIds(), false
setting.getProjIds()
);
return ApiRet.success();
}

22
src/main/java/a8k/app/controler/api/v1/app/state/TubeHolderSettingMgrController.java

@ -1,5 +1,6 @@
package a8k.app.controler.api.v1.app.state;
import a8k.app.i18n.Internationalization;
import a8k.app.type.a8k.BloodType;
import a8k.app.service.mainctrl.TubeHolderSettingMgrService;
import a8k.app.service.statemgr.GStateMgrService;
@ -57,14 +58,14 @@ public class TubeHolderSettingMgrController {
}
// @Operation(summary = "配置试管(Muti)")
// @PostMapping("/updateMutiTubeSettings")
// public ApiRet<Void> updateTubeSetting(@RequestBody List<TubeSettingVal> model) throws AppException {
// for (TubeSettingVal val : model) {
// tubeSettingMgrService.updateTubeSetting(val.uuid, val.setting);
// }
// return ApiRet.success();
// }
// @Operation(summary = "配置试管(Muti)")
// @PostMapping("/updateMutiTubeSettings")
// public ApiRet<Void> updateTubeSetting(@RequestBody List<TubeSettingVal> model) throws AppException {
// for (TubeSettingVal val : model) {
// tubeSettingMgrService.updateTubeSetting(val.uuid, val.setting);
// }
// return ApiRet.success();
// }
//添加试管架返回整个列表
@Operation(summary = "添加<试管架>配置")
@ -103,8 +104,9 @@ public class TubeHolderSettingMgrController {
@PostMapping("/getBloodTypes")
public ApiRet<List<EnumVal>> getBloodTypes() {
List<EnumVal> ret = new java.util.ArrayList<>();
ret.add(new EnumVal().key(BloodType.WHOLE_BLOOD.name(), "全血"));
ret.add(new EnumVal().key(BloodType.SERUM_OR_PLASMA.name(), "血清/血浆"));
for (BloodType type : BloodType.values()) {
ret.add(new EnumVal().key(type.name(), Internationalization.BloodTypeToString(type)));
}
return ApiRet.success(ret);
}

10
src/main/java/a8k/app/dao/type/combination/ProjBuildInInfo.java

@ -2,6 +2,7 @@ package a8k.app.dao.type.combination;
import a8k.app.dao.type.db.OptCfg;
import a8k.app.dao.type.db.ProjectBaseInfo;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.a8k.opt.A8kOptType;
import a8k.app.type.a8k.proj.A8kReactionFlowType;
import com.fasterxml.jackson.annotation.JsonIgnore;
@ -32,8 +33,10 @@ public class ProjBuildInInfo implements Serializable {
public A8kReactionFlowType reactionFlowType; //反应流程
/*样本配置*/
public Integer wBloodSampleVolUl; //全血样本量ul
public Integer serumSampleVolUl; //血清/血浆样本量ul
public Integer defaultSampleVolUl; //默认样本量ul
public Integer wBloodSampleVolUl; //全血样本量ul
public Integer serumSampleVolUl; //血清/血浆样本量ul
public Integer fecesSampleVolUl; //粪便样本量ul
public Integer shakeTimes; //摇匀次数
/*缓冲液配置*/
@ -42,11 +45,14 @@ public class ProjBuildInInfo implements Serializable {
/*缓和液预处理配置*/
public Integer mixedLiquidMixingTimes; //混合液混匀次数
public Integer mixedLiquidMixingVolUl; //混合液混匀量ul
public Integer mixedLiquidPreReactionTimeMin; //反应板预反应时间Min
/*孵育配置*/
public Integer reactionPlateIncubationTimeMin; //反应板孵育时间Min
public Integer reactionPlateDropletVolUl; //反应板滴样量ul
public List<BloodType> supportBloodTypes; //支持的血液类型
public List<OptCfg> optcfg;
public ProjBuildInInfo() {} //for json

18
src/main/java/a8k/app/dao/type/db/ProjectBaseInfo.java

@ -1,10 +1,21 @@
package a8k.app.dao.type.db;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.a8k.proj.A8kReactionFlowType;
import a8k.app.utils.ZJsonHelper;
import java.io.Serializable;
import java.util.List;
/**
*
* 项目基础信息
*
* 修改这个类之后,要同步修改
* 1. zapp_a8k_proj_info.csv
* 2. ProjBuildInInfo (字段要保持和ProjectBaseInfo同名,这样ProjBuildInInfo会自动被赋值)
*
*/
public class ProjectBaseInfo implements Serializable {
public int id;
@ -21,8 +32,10 @@ public class ProjectBaseInfo implements Serializable {
public A8kReactionFlowType reactionFlowType; //反应流程
/*样本配置*/
public Integer defaultSampleVolUl; //默认样本量ul
public Integer wBloodSampleVolUl; //全血样本量ul
public Integer serumSampleVolUl; //血清/血浆样本量ul
public Integer fecesSampleVolUl; //粪便样本量ul
public Integer shakeTimes; //摇匀次数
/*缓冲液配置*/
@ -31,11 +44,12 @@ public class ProjectBaseInfo implements Serializable {
/*缓和液预处理配置*/
public Integer mixedLiquidMixingTimes; //混合液混匀次数
public Integer mixedLiquidMixingVolUl; //混合液混匀量ul
public Integer mixedLiquidPreReactionTimeMin; //反应板预反应时间Min
/*孵育配置*/
public Integer reactionPlateIncubationTimeMin; //反应板孵育时间Min
public Integer reactionPlateDropletVolUl; //反应板滴样量ul
public List<BloodType> supportBloodTypes; //支持的血液类型
public String toString() {
return ZJsonHelper.objectToJson(this);
}

10
src/main/java/a8k/app/i18n/Internationalization.java

@ -1,5 +1,6 @@
package a8k.app.i18n;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.error.ConsumablesScanReportErrorType;
import a8k.app.hardware.type.A8kEcode;
@ -108,6 +109,15 @@ public class Internationalization {
case REACTION_PLATE_2D_CODE_FORMATE_ERROR -> "反应板二维码格式错误";
case CODE_ERROR_PROJINFO_IS_ERROR -> "代码错误,项目信息异常";
case UN_SUPPORT_PROJ -> "不支持的项目";
case PROJ_ONLY_NEED_REACTION_PLATE -> "当前项目只需要反应板";
};
}
public static String BloodTypeToString(BloodType bloodType) {
return switch (bloodType) {
case WHOLE_BLOOD -> "全血";
case SERUM_OR_PLASMA -> "血清/血浆";
case FECES -> "粪便";
};
}
}

8
src/main/java/a8k/app/optalgo/A8kPeakAnalyzer.java

@ -295,15 +295,19 @@ public class A8kPeakAnalyzer {
ProjExtInfoCard.A8kOptFnGroup fnFormual = ProjInfoUtils.getA8kOptFnFormula(optcxt.projInfoCxt.ext, optcxt.subProjIndex);
Assert.isTrue(fnFormual != null, "fnFormual must not be null");
Double result1 = null;
//
//粪便类型的样本使用,血清和血浆的参数
//ref:https://iflytop1.feishu.cn/wiki/AuDiwywvViKc8tkbGB7cJQBwnig?fromScene=spaceOverview
//
if (fnFormual.fnType.equals(A8kFnType.NormalFn)) {
result1 = switch (optcxt.sampleInfo.bloodType) {
case WHOLE_BLOOD -> callNorFn(optcxt, fnFormual.bloodNorFn, a8kOptPeakInfo);
case SERUM_OR_PLASMA -> callNorFn(optcxt, fnFormual.serumNorFn, a8kOptPeakInfo);
case SERUM_OR_PLASMA, FECES -> callNorFn(optcxt, fnFormual.serumNorFn, a8kOptPeakInfo);
};
} else if (fnFormual.fnType.equals(A8kFnType.PiecewiseFn)) {
result1 = switch (optcxt.sampleInfo.bloodType) {
case WHOLE_BLOOD -> callPiecewiseFn(optcxt, fnFormual.bloodPiecewiseFn, a8kOptPeakInfo);
case SERUM_OR_PLASMA -> callPiecewiseFn(optcxt, fnFormual.serumPiecewiseFn, a8kOptPeakInfo);
case SERUM_OR_PLASMA, FECES -> callPiecewiseFn(optcxt, fnFormual.serumPiecewiseFn, a8kOptPeakInfo);
};
}

5
src/main/java/a8k/app/service/analyzer/ConsumableStateAnalyzerService.java

@ -2,6 +2,7 @@ package a8k.app.service.analyzer;
import a8k.SpringBootBeanUtil;
import a8k.app.service.statemgr.ConsumablesMgrService;
import a8k.app.type.a8k.proj.A8kReactionFlowType;
import a8k.app.type.a8k.state.TubeHolderInfo;
import a8k.app.type.a8k.state.TubeInfo;
import a8k.app.type.exception.AppException;
@ -131,7 +132,7 @@ public class ConsumableStateAnalyzerService {
public Boolean isHasEnoughTip(List<Integer> projs) {
int tipNeed = 0;
tipNeed = projs.size() * 3;//每个项目假设需要3个tip
tipNeed = projs.size() * A8kReactionFlowType.getSupportTipPrepareNumEachProject();//每个项目假设需要3个tip
return consumablesMgrService.isHasEnoughTips(tipNeed);
}
@ -140,7 +141,7 @@ public class ConsumableStateAnalyzerService {
for (TubeInfo tube : tubeHolder.tubeInfos) {
tipNeed += tube.projIds.size();
}
tipNeed = tipNeed * 3;//每个项目假设需要3个tip
tipNeed = tipNeed * A8kReactionFlowType.getSupportTipPrepareNumEachProject();//每个项目假设需要3个tip
return consumablesMgrService.isHasEnoughTips(tipNeed);
}

29
src/main/java/a8k/app/service/lowerctrl/HbotMoveExCtrlService.java

@ -4,6 +4,7 @@ import a8k.app.constant.GearBacklashConstant;
import a8k.app.hardware.driver.PipetteCtrlDriverV2;
import a8k.app.service.param.hbotpos.*;
import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.a8k.pos.PreReactionPos;
import a8k.app.type.a8k.pos.TipGroupPos;
import a8k.app.type.a8k.Pos2d;
import a8k.app.type.a8k.Pos3d;
@ -22,12 +23,12 @@ import org.springframework.stereotype.Component;
public class HbotMoveExCtrlService {
private final HbotFixedPosParamMgr hbotFixedPosParamMgr;
private final HbotSamplePosParamMgr hbotSamplePosParamMgr;
private final HbotTipPosMgr hbotTipPosMgr;
private final Hbot2DCodeScanParamMgr hbot2DCodeScanParamMgr;
private final HbotLittleBSPosMgr hbotLittleBSPosMgr;
private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr;
private final HbotFixedPosParamMgr hbotFixedPosParamMgr;
private final HbotSamplePosParamMgr hbotSamplePosParamMgr;
private final HbotTipPosMgr hbotTipPosMgr;
private final Hbot2DCodeScanParamMgr hbot2DCodeScanParamMgr;
private final HbotLittleBSPosMgr hbotLittleBSPosMgr;
private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr;
private final PipetteCtrlDriverV2 pipetteCtrlDriver;
private final HbotMoveCtrlService hbotMoveCtrlService;
@ -96,15 +97,25 @@ public class HbotMoveExCtrlService {
hbotMoveCtrlService.hbotMoveTo(hbotFixedPosParamMgr.getDropLiquidPos());
}
public void moveToDropLiquidPosXY() throws AppException {
moveToXY(hbotFixedPosParamMgr.getDropLiquidPos());
}
public void moveTo(Pos3d pos) throws AppException {
hbotMoveCtrlService.hbotMoveTo(pos);
}
public void moveToXY(Pos3d pos) throws AppException {
Pos3d poscpy = new Pos3d(pos);
poscpy.z = 0;
hbotMoveCtrlService.hbotMoveTo(poscpy);
Pos3d posCpy = new Pos3d(pos);
posCpy.z = 0;
hbotMoveCtrlService.hbotMoveTo(posCpy);
}
public void moveToPreReactionPosXY(PreReactionPos preReactionPos) throws AppException {
switch (preReactionPos.type) {
case ProbeSubstance -> moveToXY(hbotLittleBSPosMgr.getProbeSubstanceContainerPos(preReactionPos.group, preReactionPos.index));
case BufferSolution -> moveToXY(hbotLittleBSPosMgr.getLittleBSContainerPos(preReactionPos.group, preReactionPos.index));
}
}

214
src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrService.java

@ -35,19 +35,19 @@ public class LiquidOperationCtrService {
/*
* CTRL-SERVICE
*/
private final HbotMoveExCtrlService hbotMoveExCtrlService;
private final PipetteCtrlDriverV2 pipetteCtrlDriverV2;
private final HbotMoveExCtrlService hbotMoveExCtrlService;
private final PipetteCtrlDriverV2 pipetteCtrlDriverV2;
/*
* PARAM-MGR
*/
private final HbotLittleBSPosMgr hbotLittleBSPosMgr;
private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr;
private final HbotLittleBSPosMgr hbotLittleBSPosMgr;
private final HbotLargeBottleBSPosMgr hbotLargeBottleBSPosMgr;
/**
* StateMgr
*/
private final HbotSamplePosParamMgr hbotSamplePosParamMgr;
private final HbotFixedPosParamMgr hbotFixedPosParamMgr;
private final TipOperationCtrlModule tipOperationCtrlModule;
private final HbotSamplePosParamMgr hbotSamplePosParamMgr;
private final HbotFixedPosParamMgr hbotFixedPosParamMgr;
private final TipOperationCtrlModule tipOperationCtrlModule;
ProjBuildInInfo projBuildinInfo;
@ -138,13 +138,34 @@ public class LiquidOperationCtrService {
};
}
public void pirceLittleBuffer(PreReactionPos pos) throws AppException {
// 取TIP
tipOperationCtrlModule.tryTakeTip();
ZAppChecker.check(pipetteCtrlDriverV2.readTipState(), A8kEcode.CODEERROR, "未检测到TIP");
Pos3d pircePos;
ContainerCpyId containerCpyId;
if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) {
pircePos = hbotLittleBSPosMgr.getProbeSubstancePiercePos(pos.group, pos.index);
containerCpyId = ContainerCpyId.DetectSubstancesCup;
} else {
pircePos = hbotLittleBSPosMgr.getLittleBSPiercePos(pos.group, pos.index);
containerCpyId = ContainerCpyId.LittleBufferCup;
}
hbotMoveExCtrlService.moveToXY(pircePos);
pipetteCtrlDriverV2.pierceThroughBlock(containerCpyId, pircePos.z);
}
/**
* 取样本
* @param from 样本位置
* @param ul 吸取量
* @throws AppException 异常
*/
public void takeSampleOnly(A8kSamplePos from, Integer ul) throws AppException {
public void takeSample(A8kSamplePos from, Integer ul) throws AppException {
log.info("takeSampleOnly: from={},ul={}ul", from, ul);
Pos3d sampleContainerPos = hbotSamplePosParamMgr.getSampleContainerPos(from);//样本位置
@ -177,37 +198,7 @@ public class LiquidOperationCtrService {
}
public void pirceLittleBuffer(PreReactionPos pos) throws AppException {
// 取TIP
tipOperationCtrlModule.tryTakeTip();
ZAppChecker.check(pipetteCtrlDriverV2.readTipState(), A8kEcode.CODEERROR, "未检测到TIP");
Pos3d pircePos;
ContainerCpyId containerCpyId;
if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) {
pircePos = hbotLittleBSPosMgr.getProbeSubstancePiercePos(pos.group, pos.index);
containerCpyId = ContainerCpyId.DetectSubstancesCup;
} else {
pircePos = hbotLittleBSPosMgr.getLittleBSPiercePos(pos.group, pos.index);
containerCpyId = ContainerCpyId.LittleBufferCup;
}
hbotMoveExCtrlService.moveToXY(pircePos);
pipetteCtrlDriverV2.pierceThroughBlock(containerCpyId, pircePos.z);
}
/**
* 取样本到探测物质
* @param from 样本位置
* @param pos 预先反应位置P
* @param ul 吸取量
* @throws AppException 异常
*/
public void takeSampleToPreReactionPos(A8kSamplePos from, PreReactionPos pos, Integer ul) throws AppException {
log.info("takeSampleToPreReactionPos: from={}, pos={}, ul={}ul", from, pos, ul);
takeSampleOnly(from, ul);
public void distributeSampleToPreReactionPos(PreReactionPos pos, boolean reposition, boolean zmAutoMoveToZero) throws AppException {
Pos3d reactionPos;
ContainerCpyId containerCpyId;
Integer shakeUl = MIX_VOLUME_UL;
@ -239,79 +230,18 @@ public class LiquidOperationCtrService {
DistribuType.SURFACE_DIST,
shakeUl * 10, // 预先反应位置的液体量
shakeTimes,
true
zmAutoMoveToZero
));
}
// /**
// * 取样本液到预反应位混合后再取样
// * @param from
// * @param pos
// * @param ul
// * @throws AppException
// */
// public void takeSampleToPreReactionPosAndAspirate(A8kSamplePos from, PreReactionPos pos, Integer ul) throws AppException {
// log.info("takeSampleToPreReactionPosAndTakeToReactionPlate: from={}, pos={}, ul={}ul", from, pos, ul);
// takeSampleOnly(from, ul);
//
// Pos3d reactionPos;
// ContainerCpyId containerCpyId;
// Integer shakeUl = MIX_VOLUME_UL;
// Integer shakeTimes = 5;
//
// if (pos.type.equals(ConsumableType.ProbeSubstance)) {
// reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index);
// containerCpyId = ContainerCpyId.DetectSubstancesCup;
// } else {
// reactionPos = hbotLittleBSPosMgr.getLittleBSContainerPos(pos.group, pos.index);
// containerCpyId = ContainerCpyId.LittleBufferCup;
// }
// if (projBuildinInfo != null) {
// shakeUl = projBuildinInfo.mixedLiquidMixingVolUl;
// shakeTimes = projBuildinInfo.mixedLiquidMixingTimes;
// }
//
// // 移动到反应位
// UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos);
// hbotMoveExCtrlService.moveToXY(reactionPos);
//
// //z轴移动到反应位
// UISender.txInfoMsg(log, "分配样本");
// pipetteCtrlDriverV2.distributeAllBlock(new DistribuAllParam(
// reactionPos.z,
// containerCpyId,
// LiquidConfigCpyIdx.Default,
// false,
// DistribuType.SURFACE_DIST,
// shakeUl * 10, // 预先反应位置的液体量
// shakeTimes,
// false
// ));
//
// UISender.txInfoMsg(log, "取混合液");
// pipetteCtrlDriverV2.aspirateBlock(new AspirationParam(
// 750, // 预先反应位置的液体量
// reactionPos.z,
// containerCpyId,
// LiquidConfigCpyIdx.Default,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0
// ));
// }
/**
* 取反应液到反应板上
* @param pos 反应板位置
* 取预先反应液体到反应位置
* @param pos 预先反应位置
* @param reposition 是否重新定位到预先反应位置
* @throws AppException 异常
*/
public void takePreReactionLiquid(PreReactionPos pos) throws AppException {
public void takePreReactionLiquid(PreReactionPos pos, boolean reposition) throws AppException {
log.info("takePreReactionLiquidToReactionPos: from pos={}", pos);
tipOperationCtrlModule.tryTakeTip();
@ -327,8 +257,12 @@ public class LiquidOperationCtrService {
containerCpyId = ContainerCpyId.LittleBufferCup;
}
UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos);
hbotMoveExCtrlService.moveToXY(reactionPos);
if (reposition) {
hbotMoveExCtrlService.moveToXY(reactionPos);
}
UISender.txInfoMsg(log, "取混合液");
pipetteCtrlDriverV2.aspirateBlock(new AspirationParam(
@ -345,8 +279,6 @@ public class LiquidOperationCtrService {
0,
0
));
}
public void dropLiquidToReactionPlate() throws AppException {
@ -372,4 +304,70 @@ public class LiquidOperationCtrService {
}
// /**
// * 取样本到探测物质
// * @param from 样本位置
// * @param pos 预先反应位置P
// * @param ul 吸取量
// * @throws AppException 异常
// */
// public void takeSampleToPreReactionPos(A8kSamplePos from, PreReactionPos pos, Integer ul, boolean takeMixLiquidFinal) throws AppException {
// log.info("takeSampleToPreReactionPos: from={}, pos={}, ul={}ul", from, pos, ul);
// takeSampleOnly(from, ul);
//
// Pos3d reactionPos;
// ContainerCpyId containerCpyId;
// Integer shakeUl = MIX_VOLUME_UL;
// Integer shakeTimes = 5;
//
// if (pos.type.equals(LittleBottleConsumableType.ProbeSubstance)) {
// reactionPos = hbotLittleBSPosMgr.getProbeSubstanceContainerPos(pos.group, pos.index);
// containerCpyId = ContainerCpyId.DetectSubstancesCup;
// } else {
// reactionPos = hbotLittleBSPosMgr.getLittleBSContainerPos(pos.group, pos.index);
// containerCpyId = ContainerCpyId.LittleBufferCup;
// }
// if (projBuildinInfo != null) {
// shakeUl = projBuildinInfo.mixedLiquidMixingVolUl;
// shakeTimes = projBuildinInfo.mixedLiquidMixingTimes;
// }
//
// // 移动到反应位
// UISender.txInfoMsg(log, "移动到预先反应位置:%s", reactionPos);
// hbotMoveExCtrlService.moveToXY(reactionPos);
//
// //z轴移动到反应位
// UISender.txInfoMsg(log, "分配样本");
// pipetteCtrlDriverV2.distributeAllBlock(new DistribuAllParam(
// reactionPos.z,
// containerCpyId,
// LiquidConfigCpyIdx.Default,
// false,
// DistribuType.SURFACE_DIST,
// shakeUl * 10, // 预先反应位置的液体量
// shakeTimes,
// !takeMixLiquidFinal
// ));
//
//
// if (takeMixLiquidFinal) {
// UISender.txInfoMsg(log, "取混合液");
// pipetteCtrlDriverV2.aspirateBlock(new AspirationParam(
// 750, // 预先反应位置的液体量
// reactionPos.z,
// containerCpyId,
// LiquidConfigCpyIdx.Default,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0,
// 0
// ));
// }
// }
}

75
src/main/java/a8k/app/service/mainctrl/AppConsumablesScanService.java

@ -11,7 +11,6 @@ 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.*;
@ -149,43 +148,63 @@ public class AppConsumablesScanService {
Integer projId = projExtInfoCard.projId;
A8kReactionFlowType reactionType = projBuildinInfo.reactionFlowType;
if (reactionType.equals(A8kReactionFlowType.SampleAndBS)) {
//校验小瓶缓冲液,小瓶缓冲液+样本
if (ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.MISS_LITTSB;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
}
switch (reactionType) {
case SampleAndBS -> {
{
//校验小瓶缓冲液,小瓶缓冲液+样本
if (ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.MISS_LITTSB;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
if (!rawResult.littBSScanResult.equals(rp2dcode.lotId)) {
ret.state = ConsumablesScanReportErrorType.LITTSB_LOTID_MISMATCH;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
}
return ret;
}
if (!rawResult.littBSScanResult.equals(rp2dcode.lotId)) {
ret.state = ConsumablesScanReportErrorType.LITTSB_LOTID_MISMATCH;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
} else if (reactionType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
// 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本
if (ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.MISS_LARBS;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
}
return ret;
}
}
if (!rawResult.larBSScanResult.equals(rp2dcode.lotId)) {
ret.state = ConsumablesScanReportErrorType.LARBS_LOTID_MISMATCH;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
case SampleAndBSAndProbeSubstance -> {
// 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本
if (ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.MISS_LARBS;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
}
if (!rawResult.larBSScanResult.equals(rp2dcode.lotId)) {
ret.state = ConsumablesScanReportErrorType.LARBS_LOTID_MISMATCH;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
return ret;
}
}
} else {
throw new RuntimeException("未知的反应流程类型");
case SampleOnly -> {
//仅样本反应
//只需要反应即可
if (!ZStringUtils.isNullOrEmpty(rawResult.larBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.PROJ_ONLY_NEED_REACTION_PLATE;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
log.warn("仅样本反应,扫描到大瓶缓冲液:{}", rawResult.larBSScanResult);
return ret;
}
if (!ZStringUtils.isNullOrEmpty(rawResult.littBSScanResult)) {
ret.state = ConsumablesScanReportErrorType.PROJ_ONLY_NEED_REACTION_PLATE;
ret.stateDesc = Internationalization.consumablesScanReportErrorType2String(ret.state);
log.warn("仅样本反应,扫描到小瓶缓冲液:{}", rawResult.littBSScanResult);
return ret;
}
}
}
ret.lotId = rp2dcode.lotId;
ret.projId = projId;
ret.state = ConsumablesScanReportErrorType.PASS;

3
src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java

@ -77,7 +77,7 @@ public class IncubationPlateCtrlModule {
private ZWorkThread workThread;
private State state = new State();
private State state = new State();
@PostConstruct
@ -122,6 +122,7 @@ public class IncubationPlateCtrlModule {
docmd("拉取反应板到滴定位", () -> turnableMoveCtrlService.trunableMoveToDropLiquidPos(incubatorPos));
dropLiquidAction.run();
UISender.txInfoMsg(log, "开始孵育");
incubationPlateStateMgr.startIncubating(incubatorPos, System.currentTimeMillis(), incubatedTimeSec);
} catch (Exception e) {
state.setFatalAppError(AppErrorFactory.exceptionToAppError(e));

211
src/main/java/a8k/app/service/module/SamplePreProcessModule.java

@ -1,10 +1,10 @@
package a8k.app.service.module;
import a8k.OS;
import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.dao.type.db.ReactionReport;
import a8k.app.engineer.service.type.A8kCmdRunnable;
import a8k.app.factory.AppErrorFactory;
import a8k.app.service.analyzer.A8kEcodeAnalyzer;
import a8k.app.service.ctrlmodule.TipOperationCtrlModule;
import a8k.app.service.lowerctrl.*;
import a8k.app.type.BoolCondition;
@ -12,6 +12,7 @@ import a8k.app.service.module.bean.SamplePreProcessModuleState;
import a8k.app.service.statemgr.*;
import a8k.app.service.utils.UISender;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.PreReactionGrid;
import a8k.app.type.a8k.A8kTubeHolderType;
import a8k.app.type.a8k.pos.IncubatorPos;
import a8k.app.type.a8k.pos.LargeBufferPos;
@ -39,6 +40,8 @@ import java.util.List;
@Slf4j
@RequiredArgsConstructor
public class SamplePreProcessModule {
private final HbotMoveExCtrlService hbotMoveExCtrlService;
static public class TubePosInfo {
public Boolean isEmergency;
public Integer tubeIndex;
@ -61,6 +64,7 @@ public class SamplePreProcessModule {
private final TubeFeedingCtrlService tubeFeedingCtrlService;
private final ConsumablesMgrService consumablesMgrService;
private final IncubationPlateCtrlModule incubationPlateCtrlModule;
private final PreReactionStateMgr preReactionStateMgr;
ActionTaskPool actionTaskPool = new ActionTaskPool(2);
@ -125,19 +129,21 @@ public class SamplePreProcessModule {
continue;
}
if (preReactionStateMgr.isHasReactionCompleted()) {
processPreReactionCompletedGrid(preReactionStateMgr.getReactionCompletedPos());
continue;
}
if (tubeStateMgrService.isHasSomeToBeProcessedTube()) {
TubePosInfo tubePosInfo = getNextToBeProcessedTube();
Boolean isHasEnoughIncubationIDLEPos = incubationPlateStateMgr.isHasEnoughIncubationIDLEPos(tubePosInfo.tube.getProjIds().size());
if (isHasEnoughIncubationIDLEPos) {
//processTube(tubePosInfo);
processTube(tubePosInfo);
//假装已经处理了试管架
tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex);
tubeStateMgrService.changeTubeStateToProcessComplete();
// tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex);
// tubeStateMgrService.changeTubeStateToProcessComplete();
continue;
}
}
@ -150,20 +156,40 @@ public class SamplePreProcessModule {
state.isWorking = false;
}
private void processPreReactionCompletedGrid(PreReactionPos preReactionPos) throws AppException {
if (preReactionPos == null)
return;
PreReactionGrid preReactionGrid = preReactionStateMgr.getPreReactionGrid(preReactionPos);
ProjBuildInInfo projBuildInInfo = preReactionGrid.projBuildinInfo;
log.info("处理预反应完成的格子: {}:{}", preReactionGrid.group, preReactionGrid.posIndex);
docmd("取预反应液", () -> liquidOperationCtrService.takePreReactionLiquid(preReactionPos, true));
preReactionStateMgr.changeReactionGridStateToUsed(preReactionPos);
incubationPlateCtrlModule.dropLiquidAndStartIncubating(
preReactionGrid.bindIncubatorPos,
() -> docmd("滴入反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate),
projBuildInInfo.reactionPlateIncubationTimeMin * 60
);
}
private void processTube(TubePosInfo tubePosInfo) throws AppException {
//change tube state to pending
tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex);
//
// PendTube
//
if (!tubePosInfo.isEmergency) {
docmd("移动到下一个试管", () -> tubeFeedingCtrlService.moveTubeToPreProcessPos(tubePosInfo.tubeIndex));
}
tubeStateMgrService.pendTube(tubePosInfo.isEmergency, tubePosInfo.tubeIndex);
//
// 为该试管中的每一个项目 预定孵育盘位置
//
Tube tube = tubeStateMgrService.getCurProcessingTube();
Assert.isTrue(tube != null, "tube != null");
// 预定孵育盘位置
for (var cxt : tube.getPreProcessContexts()) {
//预定孵育盘位置
var incubatorPos = incubationPlateStateMgr.takeOneIncubationIDLEPos((IncubatorPos pos) ->
incubationPlateStateMgr.syncCxtInfo(pos, cxt.getSampleInfo(), cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard(), cxt.getConsumableInfo())
);
@ -173,33 +199,31 @@ public class SamplePreProcessModule {
tubeStateMgrService.changeTubeStateToResourceIsReady();
//
// 执行任务
//
startTask();
actionTaskPool.waitAllDone();
if (actionTaskPool.isHasError()) {
sampleProcessRollback();
samplePrepareRollback();
docmd("摇匀模组复位", tubePreProcessCtrlService::resteModule);
docmd("HBOT复位", () -> {
tipOperationCtrlModule.dropTip();
hbotMoveCtrlService.moveToZero();
});
}
AppError samplePrepareAppError = actionTaskPool.getError(TaskLine.SamplePrepare);
if (samplePrepareAppError != null && A8kEcodeAnalyzer.isFatalError(samplePrepareAppError)) {
throw AppException.of(samplePrepareAppError);
AppError fatalError = actionTaskPool.getFatalError();
if (fatalError != null) {
throw AppException.of(fatalError);
}
AppError sampleProcessAppError = actionTaskPool.getError(TaskLine.SampleProcess);
if (sampleProcessAppError != null && A8kEcodeAnalyzer.isFatalError(sampleProcessAppError)) {
throw AppException.of(sampleProcessAppError);
}
if (samplePrepareAppError != null || sampleProcessAppError != null) {
//发生错误进行回滚
tubeStateMgrService.changeTubeStateToError(samplePrepareAppError, sampleProcessAppError);
AppError firstError = actionTaskPool.getFirstError();
if (firstError != null) {
tubeStateMgrService.changeTubeStateToError(firstError);
} else {
// 样本处理完成
tubeStateMgrService.changeTubeStateToProcessComplete();
}
}
void startTask() {
@ -245,76 +269,103 @@ public class SamplePreProcessModule {
//
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolder();
Tube tube = tubeStateMgrService.getCurProcessingTube();
A8kSamplePos samplePos = ProjectParamUtils.getSamplePos(tubeHolder, tube);
List<ProjectPreProcessContext> cxts = tube.getPreProcessContexts();
//! 等待样本准备完成
for (ProjectPreProcessContext cxt : cxts) {
boolean finalCxt = cxt.equals(cxts.getLast());
processTubeCxt(samplePos, tube, cxt, finalCxt);
}
sampleProcessFinishedCondition.setReady();
});
}
private void processTubeCxt(A8kSamplePos samplePos, Tube tube, ProjectPreProcessContext cxt, Boolean finalCxt) throws AppException {
Assert.isTrue(cxt.getIncubatorPos() != null, "cxt.incubatorPos != null");
Assert.isTrue(cxt.getIncubatorPos() != null, "cxt.incubatorPos != null");
PreReactionPos preReactionPos = ProjectParamUtils.getPreReactionPos(cxt);
A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType;
Integer sampleVol = ProjectParamUtils.getSampleUl(cxt);
ProjBuildInInfo projBuildInInfo = cxt.getProjBuildinInfo();
boolean finalCxt = cxt.equals(cxts.getLast());
PreReactionPos preReactionPos = ProjectParamUtils.getPreReactionPos(tubeHolder, tube, cxt);
A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType;
A8kSamplePos samplePos = ProjectParamUtils.getSamplePos(tubeHolder, tube);
Integer sampleVol = ProjectParamUtils.getSampleUl(cxt);
liquidOperationCtrService.setProjContext(cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard());
liquidOperationCtrService.setProjContext(cxt.getProjBuildinInfo(), cxt.getProjExtInfoCard());
switch (reactionFlowType) {
case SampleAndBSAndProbeSubstance -> {
UISender.txInfoMsg(log, "取大瓶缓冲液到探测物质中");
LargeBufferPos largeBufferPos = LargeBufferPos.of(cxt.getConsumableInfo().group);
Integer largeBSVolume = cxt.getProjBuildinInfo().bigBufferSampleUl;
Assert.notNull(largeBufferPos, "largeBufferPos != null");
Assert.notNull(preReactionPos, "preReactionPos != null");
docmd("取大瓶缓冲液", () -> liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(largeBufferPos, preReactionPos, largeBSVolume));
}
case SampleAndBS -> {
Assert.notNull(preReactionPos, "preReactionPos != null");
docmd("刺破小瓶缓冲液", () -> liquidOperationCtrService.pirceLittleBuffer(preReactionPos));
}
case SampleOnly -> {
//取TIP
docmd("取TIP", tipOperationCtrlModule::tryTakeTip);
}
}
//预处理
if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
UISender.txInfoMsg(log, "取大瓶缓冲液到探测物质中");
LargeBufferPos largeBufferPos = LargeBufferPos.of(cxt.getConsumableInfo().group);
Integer largeBSVolume = cxt.getProjBuildinInfo().bigBufferSampleUl;
Assert.notNull(largeBufferPos, "largeBufferPos != null");
docmd("取大瓶缓冲液", () -> {
liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(largeBufferPos, preReactionPos, largeBSVolume);
});
sampleIsReadyCondition.waitTrue();
} else if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBS)) {
docmd("刺破小瓶缓冲液", () -> liquidOperationCtrService.pirceLittleBuffer(preReactionPos));
}
//取样本到小缓冲瓶或者探测物质
docmd("取样", () -> liquidOperationCtrService.takeSample(samplePos, sampleVol));
sampleIsReadyCondition.waitTrue();
//远离取样位置,移动到下一个动作的位置
switch (reactionFlowType) {
case SampleAndBSAndProbeSubstance, SampleAndBS -> docmd(String.format("移动到预反应位置%s", preReactionPos), () -> hbotMoveExCtrlService.moveToPreReactionPosXY(preReactionPos));
case SampleOnly -> docmd("移动到滴定位", hbotMoveExCtrlService::moveToDropLiquidPosXY);
}
//取样本到小缓冲瓶或者探测物质
if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBS)) {
UISender.txInfoMsg(log, "取样");
docmd("取样", () -> liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preReactionPos, sampleVol));
} else if (reactionFlowType.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
UISender.txInfoMsg(log, "取样");
docmd("取样", () -> liquidOperationCtrService.takeSampleToPreReactionPos(samplePos, preReactionPos, sampleVol));
}
//如果当前项目是这个试管的最后一个项目,则在这里之后就不再需要样本了摇匀模组就可以回收样本了
if (finalCxt) {
sampleProcessFinishedCondition.setReady();
}
if (finalCxt) {// 在这里之后就不再需要样本了摇匀模组就可以回收样本了
sampleProcessFinishedCondition.setReady();
switch (reactionFlowType) {
case SampleAndBSAndProbeSubstance, SampleAndBS -> {
if (projBuildInInfo.getMixedLiquidPreReactionTimeMin() == 0) {
docmd("分配样本到预反应位", () -> liquidOperationCtrService.distributeSampleToPreReactionPos(preReactionPos, false, false));
docmd("取预反应液", () -> liquidOperationCtrService.takePreReactionLiquid(preReactionPos, false));
preReactionStateMgr.syncGridInfo(preReactionPos, tube, tube.getPos());
preReactionStateMgr.changeReactionGridStateToUsed(preReactionPos);
incubationPlateCtrlModule.dropLiquidAndStartIncubating(
cxt.getIncubatorPos(),
() -> {
docmd("滴入反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate);
},
cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60
);
} else {
/*
* 有些项目 样本和缓冲液混合后,需要先反应一定时间后,才开始孵育
*/
docmd("分配样本到预反应位置", () -> liquidOperationCtrService.distributeSampleToPreReactionPos(preReactionPos, false, true));
preReactionStateMgr.syncGridInfo(preReactionPos, tube, tube.getPos());
preReactionStateMgr.changeReactionGridStateToReacting(preReactionPos, projBuildInInfo.getMixedLiquidPreReactionTimeMin() * 60L);
}
liquidOperationCtrService.takePreReactionLiquid(preReactionPos);
//开始孵育
UISender.txInfoMsg(log, "开始孵育");
Integer incubatedTimeSec = cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60;
}
case SampleOnly -> {
incubationPlateCtrlModule.dropLiquidAndStartIncubating(
cxt.getIncubatorPos(),
() -> docmd("取反应液到孵育盘", liquidOperationCtrService::dropLiquidToReactionPlate),
incubatedTimeSec
cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60
);
//样本使用完可以回收了
sampleProcessFinishedCondition.setReady();
UISender.txInfoMsg(log, "开始孵育");
}
});
}
void samplePrepareRollback() throws AppException {
docmd("摇匀模组复位", tubePreProcessCtrlService::resteModule);
}
void sampleProcessRollback() throws AppException {
docmd("HBOT复位", () -> {
tipOperationCtrlModule.dropTip();
hbotMoveCtrlService.moveToZero();
});
}
}

11
src/main/java/a8k/app/service/peripheral_ctrl/PrinterService.java

@ -3,6 +3,7 @@ package a8k.app.service.peripheral_ctrl;
import a8k.app.dao.type.db.ProjExtInfoCard;
import a8k.app.dao.type.db.ReactionReport;
import a8k.app.hardware.channel.PrinterUartChannel;
import a8k.app.i18n.Internationalization;
import a8k.app.optalgo.type.ReactionResultStatus;
import a8k.app.service.data.ProjInfoMgrService;
import a8k.app.service.statemgr.GStateMgrService;
@ -25,12 +26,6 @@ public class PrinterService {
private final ProjInfoMgrService projInfoMgrService;
private final GStateMgrService gStateMgrService;
String bloodTypeToString(BloodType bloodType) {
return switch (bloodType) {
case WHOLE_BLOOD -> "全血";
case SERUM_OR_PLASMA -> "血清/血浆";
};
}
public void printDemoReactionReport() {
@ -97,7 +92,7 @@ public class PrinterService {
*
*/
// 定义日期格式
if(report == null) {
if (report == null) {
return;
}
@ -113,7 +108,7 @@ public class PrinterService {
printer.printf(" UID: %s\r\n", report.sampleUserid);
printer.printf(" BARCODE: %s\r\n", report.sampleBarcode);
printer.printf(" \r\n");
printer.printf(" 样本类型: %s\r\n", bloodTypeToString(report.sampleBloodType));
printer.printf(" 样本类型: %s\r\n", Internationalization.BloodTypeToString(report.sampleBloodType));
printer.printf(" 项目名称: %s\r\n", report.projName);
printer.printf(" 批次号: %s\r\n", report.lotId);
printer.printf(" \r\n");

25
src/main/java/a8k/app/service/statemgr/ConsumablesMgrService.java

@ -248,14 +248,16 @@ public class ConsumablesMgrService {
* @return 耗材组
*/
synchronized public ConsumableInfo reserveConsumable(A8kReactionFlowType flowType, Integer projId) {
ConsumableGroup reactionPlate = null;
ConsumableGroup larBottle = null;
ConsumableInfo littBottle = null;
ConsumableInfo reactionPlate = null;
ConsumableInfo larBottle = null;
ConsumableInfo littBottle = null;
switch (flowType) {
case SampleAndBS-> {
case SampleAndBS -> {
reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId);
littBottle = littBottleContainerStateMgr.reverse(reactionPlate);
if (reactionPlate != null)
littBottle = littBottleContainerStateMgr.reverse(reactionPlate.group);
if (reactionPlate == null || littBottle == null) {
log.error("预定SampleAndBS耗材失败,可能是没有可用的反应板或小瓶");
reactionPlateContainerStateMgr.bak(reactionPlate);
@ -265,10 +267,13 @@ public class ConsumablesMgrService {
stateVersion++;
return littBottle;
}
case SampleAndBSAndProbeSubstance-> {
case SampleAndBSAndProbeSubstance -> {
reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId);
littBottle = littBottleContainerStateMgr.reverse(reactionPlate);
larBottle = larBottleContainerStateMgr.reverse(reactionPlate);
if (reactionPlate != null)
littBottle = littBottleContainerStateMgr.reverse(reactionPlate.group);
if (reactionPlate != null)
larBottle = larBottleContainerStateMgr.reverse(reactionPlate.group);
if (reactionPlate == null || littBottle == null || larBottle == null) {
log.error("预定SampleAndBSAndProbeSubstance耗材失败,可能是没有可用的反应板、小瓶或大瓶");
reactionPlateContainerStateMgr.bak(reactionPlate);
@ -279,6 +284,10 @@ public class ConsumablesMgrService {
stateVersion++;
return littBottle;
}
case SampleOnly -> {
reactionPlate = reactionPlateContainerStateMgr.reverseOneByProjId(projId);
return reactionPlate;
}
}
return null;
}

2
src/main/java/a8k/app/service/statemgr/OptScanModuleStateMgr.java

@ -42,7 +42,7 @@ public class OptScanModuleStateMgr {
synchronized public OptScanModuleState getOptScanModule() {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
OptScanModuleState virstate = new OptScanModuleState();
virstate.state = OptScanModuleStateEnum.EMPTY;
virstate.state = OptScanModuleStateEnum.SCANNING;
virstate.setBloodType(BloodType.WHOLE_BLOOD);
virstate.setSampleBarcode("1234567890");
virstate.setUserid("2250103_003");

26
src/main/java/a8k/app/service/statemgr/PreReactionStateMgr.java

@ -91,6 +91,15 @@ public class PreReactionStateMgr {
return ObjectUtil.cloneByStream(gridGroup);
}
public synchronized PreReactionGrid getPreReactionGrid(PreReactionPos preReactionPos) {
PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group);
Assert.notNull(gridGroup, "gridGroup != null");
if (preReactionPos.index < 0 || preReactionPos.index >= gridGroup.grids.size()) {
return null;
}
return ObjectUtil.cloneByStream(gridGroup.grids.get(preReactionPos.index));
}
public synchronized Integer getPreReactionGridGroupVersion(ConsumableGroup group) {
if (gStateMgrService.isInMode(DeviceRunMode.VirtualStateGenerateMode)) {
return buildFakePreReactionGridGroup(group).version;
@ -138,7 +147,18 @@ public class PreReactionStateMgr {
return null;
}
public synchronized void changeReactionGridStateToReacting(PreReactionPos preReactionPos, Tube fromTube, Integer off, Long totalReactionTimeS) {
public synchronized void syncGridInfo(PreReactionPos preReactionPos, Tube fromTube, Integer off) {
PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group);
Assert.notNull(gridGroup, "gridGroup != null");
var grid = gridGroup.grids.get(preReactionPos.index);
grid.projBuildinInfo = fromTube.getPreProcessContexts().get(off).getProjBuildinInfo();
grid.projExtInfoCard = fromTube.getPreProcessContexts().get(off).getProjExtInfoCard();
grid.sampleInfo = fromTube.getSampleInfo();
grid.bindIncubatorPos = fromTube.getPreProcessContexts().get(off).getIncubatorPos();
gridGroup.version++;
}
public synchronized void changeReactionGridStateToReacting(PreReactionPos preReactionPos, Long totalReactionTimeS) {
PreReactionGridGroup gridGroup = getPreReactionGridGroup(preReactionPos.group);
Assert.notNull(gridGroup, "gridGroup != null");
var grid = gridGroup.grids.get(preReactionPos.index);
@ -146,10 +166,6 @@ public class PreReactionStateMgr {
grid.totalReactionTime = totalReactionTimeS;
grid.startReactionTime = System.currentTimeMillis() / 1000;
grid.reactionRemainingTime = totalReactionTimeS;
grid.projBuildinInfo = fromTube.getPreProcessContexts().get(off).getProjBuildinInfo();
grid.projExtInfoCard = fromTube.getPreProcessContexts().get(off).getProjExtInfoCard();
grid.sampleInfo = fromTube.getSampleInfo();
grid.bindIncubatorPos = fromTube.getPreProcessContexts().get(off).getIncubatorPos();
gridGroup.hasSomeGridInReacting = true;
gridGroup.version++;
}

18
src/main/java/a8k/app/service/statemgr/TubeStateMgr.java

@ -1,6 +1,7 @@
package a8k.app.service.statemgr;
import a8k.app.dao.type.db.DeviceStatistic;
import a8k.app.factory.ZAppPromoptFactory;
import a8k.app.service.analyzer.ConsumableStateAnalyzerService;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.a8k.pos.ConsumableInfo;
@ -221,7 +222,7 @@ public class TubeStateMgr {
* 提交后就默认样本已经放置好了所以需要前台提醒用户需要先暂停设备放好样本
*/
synchronized public void commitEmergencySampleSetting(String userid, String sampleBarcode, BloodType bloodType,//
List<Integer> projIds, Boolean isVirtual) throws AppException {
List<Integer> projIds) throws AppException {
Tube tube = emergencyTubePos.tube;
List<ProjBuildInInfo> projBuildInInfos = new ArrayList<>();
if (projIds.isEmpty()) {
@ -441,19 +442,12 @@ public class TubeStateMgr {
curProcessingTube.setState(TubeState.PROCESSING);
}
synchronized public void changeTubeStateToError(AppError... errs) {
List<AppError> errors = new ArrayList<>();
for (AppError err : errs) {
if (err != null)
errors.add(err);
}
changeTubeStateToError(errors);
}
synchronized public void changeTubeStateToError(List<AppError> errors) {
log.error("试管 状态->错误 SampleId:{} \n{}", curProcessingTube.getSampleId(), ZJsonHelper.objectToJson(errors));
synchronized public void changeTubeStateToError(AppError error) {
log.error("试管 状态->错误 SampleId:{} \n{}", curProcessingTube.getSampleId(), ZJsonHelper.objectToJson(error));
curProcessingTube.setState(TubeState.ERROR);
curProcessingTube.setErrors(errors);
curProcessingTube.setError(error);
curProcessingTube.setErrorInfo(ZAppPromoptFactory.buildAppPromopt(error));
curProcessingTube = null;
}

6
src/main/java/a8k/app/service/statemgr/consumables_mgr/LarBottleContainerStateMgr.java

@ -82,12 +82,11 @@ public class LarBottleContainerStateMgr {
return totalNum;
}
synchronized public ConsumableGroup reverse(ConsumableGroup group) {
synchronized public ConsumableInfo reverse(ConsumableGroup group) {
if (group == null) {
return null;
}
LarBottleContainer container = this.containers[group.off];
if (!container.isInstall) {
return null;
}
@ -97,7 +96,8 @@ public class LarBottleContainerStateMgr {
}
container.reserveNum++;
Assert.isTrue(container.reserveNum <= container.num, "Reserve number cannot exceed total number");
return group;
return new ConsumableInfo(container.lotId, group, AppConstant.CONSUMABLE_NUM - (container.num - (container.reserveNum - 1)));
}
synchronized public void bak(ConsumableInfo consumable) {

7
src/main/java/a8k/app/service/statemgr/consumables_mgr/ReactionPlateContainerStateMgr.java

@ -77,7 +77,7 @@ public class ReactionPlateContainerStateMgr {
return totalNum;
}
synchronized public ConsumableGroup reverseOneByProjId(Integer projId) {
synchronized public ConsumableInfo reverseOneByProjId(Integer projId) {
for (ConsumableGroup group : ConsumableGroup.values()) {
ReactionPlateContainer container = containers[group.off];
if (container.isInstall && container.projId.equals(projId)) {
@ -85,7 +85,7 @@ public class ReactionPlateContainerStateMgr {
log.debug("getOneByProjId: group={}, projId={}", group, projId);
container.reserveNum++;
Assert.isTrue(container.reserveNum <= container.num, "Reserve number cannot exceed total number");
return group;
return new ConsumableInfo(container.lotId, group, AppConstant.CONSUMABLE_NUM - (container.num - (container.reserveNum - 1)));
}
}
}
@ -127,6 +127,9 @@ public class ReactionPlateContainerStateMgr {
}
synchronized public void bak(ConsumableInfo consumable) {
if (consumable == null || consumable.group == null) {
return;
}
bak(consumable.group);
}

32
src/main/java/a8k/app/service/utils/ProjInfoReader.java

@ -1,32 +0,0 @@
package a8k.app.service.utils;
import a8k.app.type.a8k.BloodType;
import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.dao.type.db.ProjExtInfoCard;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ProjInfoReader {
static public Integer getSampleVol(ProjBuildInInfo buildinInfo, ProjExtInfoCard extInfoCard, BloodType bloodType) {
if (bloodType.equals(BloodType.WHOLE_BLOOD)) {
if (isEffectiveValue(extInfoCard.wBloodSampleVolUl)) {
return extInfoCard.wBloodSampleVolUl;
} else {
return buildinInfo.wBloodSampleVolUl;
}
} else {
if (isEffectiveValue(extInfoCard.serumSampleVolUl)) {
return extInfoCard.serumSampleVolUl;
} else {
return buildinInfo.serumSampleVolUl;
}
}
}
private static Boolean isEffectiveValue(Integer val) {
return val != null && val >= 0;
}
}

7
src/main/java/a8k/app/type/a8k/BloodType.java

@ -5,8 +5,13 @@ import io.swagger.v3.oas.annotations.media.Schema;
@Schema(description = """
血液类型:
* WHOLE_BLOOD:全血
* SERUM_OR_PLASMA:血清或者血浆""")
* SERUM_OR_PLASMA:血清或者血浆
* FECES:粪便
""")
public enum BloodType {
WHOLE_BLOOD,//全血
SERUM_OR_PLASMA,//血清或者血浆
FECES,//粪便
}

34
src/main/java/a8k/app/type/a8k/SupportBloodType.java

@ -1,18 +1,18 @@
package a8k.app.type.a8k;
//ID卡中的类型
public enum SupportBloodType {
WHOLE_BLOOD(0),//全血
PLASMA(1),//血浆
SERUM(2),
SERUM_AND_PLASMA(3),//血清或者血浆
WHOLE_BLOOD_AND_PLASMA(4),//全血和血浆
WHOLE_BLOOD_AND_SERUM_AND_PLASMA(5),//全血和血清或者血浆
URINE(6),//尿液
FAECES(7),//粪便
;
final int index;
SupportBloodType(int index) {
this.index = index;
}
}
//
////ID卡中的类型
//public enum SupportBloodType {
// WHOLE_BLOOD(0),//全血
// PLASMA(1),//血浆
// SERUM(2),
// SERUM_AND_PLASMA(3),//血清或者血浆
// WHOLE_BLOOD_AND_PLASMA(4),//全血和血浆
// WHOLE_BLOOD_AND_SERUM_AND_PLASMA(5),//全血和血清或者血浆
// URINE(6),//尿液
// FAECES(7),//粪便
// ;
// final int index;
// SupportBloodType(int index) {
// this.index = index;
// }
//}

20
src/main/java/a8k/app/type/a8k/proj/A8kReactionFlowType.java

@ -29,13 +29,31 @@ public enum A8kReactionFlowType {
* 滴定
*/
SampleAndBSAndProbeSubstance(2, 2),//样本大瓶缓冲液探测物质反应
/*
*
* 流程:
* 取TIP
* 取样本
* 放入反应板中
*/
SampleOnly(3, 1) //仅样本反应
;
public final int tipUseNum;
public final int valInIdCard;
public final int valInIdCard; // ID卡中的数值
A8kReactionFlowType(int valInIdCard, int tipUseNum) {
this.tipUseNum = tipUseNum;
this.valInIdCard = valInIdCard;
}
static public Integer getSupportTipPrepareNumEachProject() {
int max = 0;
for (A8kReactionFlowType type : A8kReactionFlowType.values()) {
if (type.tipUseNum > max) {
max = type.tipUseNum;
}
}
return max + 1;
}
}

10
src/main/java/a8k/app/type/a8k/state/Tube.java

@ -6,6 +6,7 @@ import a8k.app.type.error.AppError;
import a8k.app.type.a8k.BloodType;
import a8k.app.type.a8k.proj.ProjBriefInfo;
import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.type.ui.ZAppPromopt;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -40,13 +41,14 @@ public class Tube implements Serializable {
//
@Schema(description = "样本被处理的状态")
TubeState state = TubeState.EMPTY; //样本被处理的状态
TubeState state = TubeState.EMPTY; //样本被处理的状态
@Schema(description = "样本处理的错误信息")
List<AppError> errors = new ArrayList<>(); //错误信息
AppError error = null;
ZAppPromopt errorInfo = null; //错误提示
List<ProjectPreProcessContext> preProcessContexts = new ArrayList<>(); //预处理上下文
@JsonIgnore
A8kTubeHolderType tubeHolderType = null;
A8kTubeHolderType tubeHolderType = null;
@JsonIgnore
List<ProjBuildInInfo> projBuildInInfos = new ArrayList<>();
@ -65,7 +67,7 @@ public class Tube implements Serializable {
this.projIds.clear();
this.projInfo.clear();
this.state = TubeState.EMPTY;
this.errors.clear();
this.error = null;
this.preProcessContexts.clear();
}

3
src/main/java/a8k/app/type/error/ConsumablesScanReportErrorType.java

@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
* REACTION_PLATE_2D_CODE_FORMATE_ERROR:反应板二维码格式错误
* CODE_ERROR_PROJINFO_IS_ERROR:代码错误项目信息异常
* UN_SUPPORT_PROJ:不支持的项目
* UN_MATCHED_CONSUMABLES:耗材不匹配
""")
public enum ConsumablesScanReportErrorType {
PASS, //通过
@ -34,4 +35,6 @@ public enum ConsumablesScanReportErrorType {
CODE_ERROR_PROJINFO_IS_ERROR,//代码错误项目信息异常
UN_SUPPORT_PROJ,//不支持的项目
PROJ_ONLY_NEED_REACTION_PLATE, //当前项目只需要反应板
}

30
src/main/java/a8k/app/utils/ActionTaskPool.java

@ -1,6 +1,7 @@
package a8k.app.utils;
import a8k.OS;
import a8k.app.service.analyzer.A8kEcodeAnalyzer;
import a8k.app.type.error.AECodeError;
import a8k.app.type.error.AppError;
import a8k.app.type.exception.AppException;
@ -28,9 +29,9 @@ public class ActionTaskPool {
Boolean errorFlag = false;
List<Future<?>> futures = new ArrayList<>();
Map<Enum<?>, AppError> errorMap = new HashMap<>();
List<BoolCondition> boolConditions = new ArrayList<>();
Map<Enum<?>, AppError> errorMap = new HashMap<>();
List<AppError> errors = new ArrayList<>();
List<BoolCondition> boolConditions = new ArrayList<>();
public ActionTaskPool(Integer threadNum) {
executor = new ThreadPoolExecutor(threadNum, threadNum, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10));
@ -62,11 +63,29 @@ public class ActionTaskPool {
errorFlag = false;
errorMap.clear();
futures.clear();
errors.clear();
for (var boolCondition : boolConditions) {
boolCondition.clear();
}
}
public AppError getFatalError() {
for (var error : errorMap.values()) {
if (A8kEcodeAnalyzer.isFatalError(error.code)) {
return error;
}
}
return null;
}
public AppError getFirstError() {
if (errorMap.isEmpty()) {
return null;
}
return errors.get(0);
}
public AppError getError(Enum<?> taskLineMaskter) {
return errorMap.get(taskLineMaskter);
}
@ -83,7 +102,6 @@ public class ActionTaskPool {
log.info("Line {} done", taskLineMaskter.name());
} catch (Exception e) {
exception = e;
errorFlag = true;
}
if (exception != null) {
@ -91,11 +109,15 @@ public class ActionTaskPool {
if (!appException.error.code.equals(A8kEcode.ZAPP_INTERRUPT_EXCEPTION)) {
log.error("do {}.afterDoAction catch exception", taskLineMaskter.name(), appException);
errorMap.put(taskLineMaskter, appException.error);
errors.add(appException.error);
}
} else {
log.error("do {}.afterDoAction catch exception", taskLineMaskter.name(), exception);
errorMap.put(taskLineMaskter, new AECodeError(exception));
errors.add(new AECodeError(exception));
}
// this flag is used to interrupt other thread by check in condition val
errorFlag = true;
}

26
src/main/java/a8k/app/utils/ProjectParamUtils.java

@ -39,7 +39,7 @@ public class ProjectParamUtils {
return samplePos;
}
static public PreReactionPos getPreReactionPos(TubeHolder tubeHolder, Tube tube, ProjectPreProcessContext cxt) {
static public PreReactionPos getPreReactionPos( ProjectPreProcessContext cxt) {
A8kReactionFlowType reactionFlowType = cxt.getProjBuildinInfo().reactionFlowType;
PreReactionPos preReactionPos = new PreReactionPos();
switch (reactionFlowType) {
@ -47,11 +47,19 @@ public class ProjectParamUtils {
preReactionPos.type = LittleBottleConsumableType.BufferSolution;
preReactionPos.group = cxt.getConsumableInfo().group;
preReactionPos.index = cxt.getConsumableInfo().pos;
return preReactionPos;
}
case SampleAndBSAndProbeSubstance -> {
preReactionPos.type = LittleBottleConsumableType.ProbeSubstance;
preReactionPos.group = cxt.getConsumableInfo().group;
preReactionPos.index = cxt.getConsumableInfo().pos;
return preReactionPos;
}
case SampleOnly -> {
preReactionPos.type = null;
preReactionPos.group = null;
preReactionPos.index = 0;
return null;
}
}
return preReactionPos;
@ -62,15 +70,23 @@ public class ProjectParamUtils {
switch (cxt.getSampleInfo().bloodType) {
case WHOLE_BLOOD -> {
sampleUl = cxt.getProjBuildinInfo().wBloodSampleVolUl;
if (cxt.getProjExtInfoCard().wBloodSampleVolUl > 0) {
if (sampleUl == 0)
sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl;
if (cxt.getProjExtInfoCard().wBloodSampleVolUl > 0)
sampleUl = cxt.getProjExtInfoCard().wBloodSampleVolUl;
}
}
case SERUM_OR_PLASMA -> {
sampleUl = cxt.getProjBuildinInfo().serumSampleVolUl;
if (cxt.getProjExtInfoCard().serumSampleVolUl > 0) {
if (sampleUl == 0)
sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl;
if (cxt.getProjExtInfoCard().serumSampleVolUl > 0)
sampleUl = cxt.getProjExtInfoCard().serumSampleVolUl;
}
}
case FECES -> {
sampleUl = cxt.getProjBuildinInfo().fecesSampleVolUl;
if (sampleUl == 0)
sampleUl = cxt.getProjBuildinInfo().defaultSampleVolUl;
}
} ;
return sampleUl;

3
src/main/java/a8k/extui/page/debug/P01EmergencyTubeDebugPage.java

@ -69,8 +69,7 @@ public class P01EmergencyTubeDebugPage {
setting.userid,
setting.sampleBarcode,
setting.bloodType,
setting.projIds,
false
setting.projIds
);
}

3
src/main/java/a8k/extui/page/extapp/A8kOptVerification.java

@ -74,7 +74,7 @@ public class A8kOptVerification {
return switch (bloodType) {
case WHOLE_BLOOD -> "全血";
case SERUM_OR_PLASMA -> "血清/血浆";
default -> "未知";
case FECES -> "粪便";
};
}
@ -102,6 +102,7 @@ public class A8kOptVerification {
page.addFunction("进行一次光学扫描(自动推板,丢板)", this::autoScanAndDownloadScanResult);
extApiPageMgr.addPage(page);
}
public Map<String, String> getProjInfoBreifList() throws AppException {
var allproj = projInfoMgrService.getAllProjBuildInInfo();
Map<String, String> result = new java.util.HashMap<>();

35
src/main/java/a8k/extui/page/test/verification/P34LiquidOperationTestPage.java

@ -23,11 +23,11 @@ public class P34LiquidOperationTestPage {
@Resource
LiquidOperationCtrService liquidOperationCtrService;
@Resource
TurnableMoveCtrlService turnableMoveCtrlService;
TurnableMoveCtrlService turnableMoveCtrlService;
@Resource
TipOperationCtrlModule tipOperationCtrlModule;
TipOperationCtrlModule tipOperationCtrlModule;
@Resource
ExtApiPageMgr extApiPageMgr;
ExtApiPageMgr extApiPageMgr;
//
@ -46,23 +46,8 @@ public class P34LiquidOperationTestPage {
liquidOperationCtrService.takeLargeBottleBufferLiquidToProbeSubstance(from, topos, ul);
}
public void takeSampleToProbeSubstance(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException {
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(LittleBottleConsumableType.ProbeSubstance, toGroup, toIndex);
liquidOperationCtrService.takePreReactionLiquid(pos);
}
public void takeSampleOnly(A8kSamplePos from, Integer ul) throws AppException {
liquidOperationCtrService.takeSampleOnly(from, ul);
}
public void takeSampleToLittleBuffer(A8kSamplePos from, ConsumableGroup toGroup, Integer toIndex, Integer ul) throws AppException {
PreReactionPos topos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex);
liquidOperationCtrService.takeSampleToPreReactionPos(from, topos, ul);
liquidOperationCtrService.takeSample(from, ul);
}
public void pirceLittleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException {
@ -70,10 +55,6 @@ public class P34LiquidOperationTestPage {
liquidOperationCtrService.pirceLittleBuffer(pos);
}
public void takePreReactionLiquidFromSmallBottleBuffer(ConsumableGroup toGroup, Integer toIndex) throws AppException {
PreReactionPos pos = new PreReactionPos(LittleBottleConsumableType.BufferSolution, toGroup, toIndex);
liquidOperationCtrService.takePreReactionLiquid(pos);
}
public void dropLiquidToReactionPlate(IncubatorPos pos) throws AppException {
turnableMoveCtrlService.trunableMoveToDropLiquidPos(pos);
@ -88,13 +69,13 @@ public class P34LiquidOperationTestPage {
cfg.addFunction("丢Tip", this::dropTip);
cfg.newGroup("液体操作-大瓶缓冲液/探测物质");
cfg.addFunction("取大瓶缓冲液到探测物质位置", this::takeLargeBottleBufferLiquidToProbeSubstance);
cfg.addFunction("取样品到探测物质位置", this::takeSampleToProbeSubstance);
cfg.addFunction("取反应液", this::takePreReactionLiquidFromProbeSubstance);
// cfg.addFunction("取样品到探测物质位置", this::takeSampleToProbeSubstance);
// cfg.addFunction("取反应液", this::takePreReactionLiquidFromProbeSubstance);
cfg.addFunction("滴反应液到反应板上", this::dropLiquidToReactionPlate);
cfg.newGroup("液体操作-小瓶缓冲液");
cfg.addFunction("刺小瓶缓冲液", this::pirceLittleBuffer);
cfg.addFunction("取样品到小瓶缓冲液", this::takeSampleToLittleBuffer);
cfg.addFunction("取反应液", this::takePreReactionLiquidFromSmallBottleBuffer);
// cfg.addFunction("取样品到小瓶缓冲液", this::takeSampleToLittleBuffer);
// cfg.addFunction("取反应液", this::takePreReactionLiquidFromSmallBottleBuffer);
cfg.addFunction("滴反应液到反应板上", this::dropLiquidToReactionPlate);
cfg.newGroup("其他");
cfg.addFunction("取样本(Only)", this::takeSampleOnly);

18
src/main/resources/application.yml

@ -1,17 +1,17 @@
server:
port: 80
# server.port: 8082
server.port: 80
#device.runmode: "RealMode"
a8k.enableTemperatureCtrl: false
# device.runmode: "VirtualMode"
device.runmode: "RealMode"
device.enableCanBus: true
iflytophald:
# ip: 192.168.8.10
ip: 192.168.8.10
# ip: 127.0.0.1
cmdch.port: 19004
datach.port: 19005
# ip: 192.168.8.10
iflytophald.ip: 192.168.8.10
# iflytophald.ip: 127.0.0.1
iflytophald.cmdch.port: 19004
iflytophald.datach.port: 19005
#hardware.canbus.url: ws://127.0.0.1:19005

64
src/main/resources/db/zapp_a8k_project_info.csv

@ -1,32 +1,32 @@
id,projId,projName,projShortName,subProjNum,reactionTemperature,color,reactionFlowType,wBloodSampleVolUl,serumSampleVolUl,shakeTimes,bigBufferSampleUl,reactionPlateIncubationTimeMin,reactionPlateDropletVolUl,mixedLiquidMixingTimes,mixedLiquidMixingVolUl
1,1,hsCRP,CA,1,25,#FFC0CB,SampleAndBS,10,10,3,0,3,75,5,200
2,2,PCT,PC,1,25,#DC143C,SampleAndBS,150,150,3,0,12,75,5,200
3,3,TSH,TS,1,25,#DB7093,SampleAndBSAndProbeSubstance,150,150,3,75,12,75,5,150
4,4,PRL,PL,1,25,#FF69B4,SampleAndBS,75,75,3,0,10,75,5,200
5,5,T3,T3,1,25,#FF1493,SampleAndBSAndProbeSubstance,75,75,3,75,8,75,5,150
6,6,T4,T4,1,25,#C71585,SampleAndBSAndProbeSubstance,75,75,3,75,8,75,5,150
7,7,Total β hCG,HC,1,25,#DA70D6,SampleAndBS,50,30,3,0,15,75,5,200
8,8,LH,LH,1,25,#D8BFD8,SampleAndBS,150,150,3,0,15,75,5,200
9,9,FSH,FS,1,25,#DDA0DD,SampleAndBS,150,150,3,0,15,75,5,200
10,10,Progesterone,PG,1,25,#EE82EE,SampleAndBS,30,30,3,0,15,75,5,200
12,12,Tn-I plus,TG,1,25,#FF00FF,SampleAndBSAndProbeSubstance,50,50,3,150,12,75,5,150
13,13,NT-proBNP,NB,1,25,#8B008B,SampleAndBSAndProbeSubstance,10,10,3,150,12,75,5,150
14,14,CK-MB,CK,1,25,#800080,SampleAndBS,75,75,3,0,12,75,5,200
15,15,Myoglobin,MY,1,25,#BA55D3,SampleAndBS,10,10,3,0,12,75,5,200
16,16,D-Dimer,DD,1,25,#9400D3,SampleAndBS,10,10,3,0,12,75,5,200
17,17,HbAlC,HB,1,25,#9932CC,SampleAndBSAndProbeSubstance,5,5,3,100,12,75,5,150
18,18,PCT plus,PP,1,25,#4B0082,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
20,20,Tn-I/CK-MB/Myoglobin,CT,3,25,#9370DB,SampleAndBSAndProbeSubstance,75,75,3,150,12,75,5,150
22,22,PCT/hsCRP,PR,2,25,#6A5ACD,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
24,24,SAA,SA,1,25,#E6E6FA,SampleAndBS,10,10,3,0,3,75,5,200
25,25,AMH,AM,1,25,#F8F8FF,SampleAndBSAndProbeSubstance,50,50,3,150,12,75,5,150
26,26,SAA/CRP,SC,2,25,#0000FF,SampleAndBS,10,10,3,0,3,75,5,200
27,27,Vitamin D,VD,1,25,#0000FF,SampleAndBSAndProbeSubstance,30,30,3,150,12,75,5,150
33,33,ST2,ST,1,25,#6495ED,SampleAndBSAndProbeSubstance,75,75,3,150,12,75,5,150
36,36,MxA,MX,1,25,#708090,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
48,48,IL-6,IL,1,25,#AFEEEE,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
49,49,Gastrin 17,GA,1,25,#00FFFF,SampleAndBSAndProbeSubstance,50,50,3,150,15,75,5,150
50,50,Pepsinogen I/II,PS,2,25,#00FFFF,SampleAndBSAndProbeSubstance,10,10,3,150,10,75,5,150
52,52,NT-proBNP/ST2,NS,2,25,#2F4F4F,SampleAndBSAndProbeSubstance,10,10,3,150,12,75,5,150
54,54,Troponin T,TT,1,25,#008080,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
55,55,BNP,BP,1,25,#48D1CC,SampleAndBSAndProbeSubstance,35,35,3,150,12,75,5,150
id,projId,projName,projShortName,subProjNum,reactionTemperature,color,reactionFlowType,supportBloodTypes,defaultSampleVolUl,wBloodSampleVolUl,serumSampleVolUl,fecesSampleVolUl,shakeTimes,bigBufferSampleUl,reactionPlateIncubationTimeMin,reactionPlateDropletVolUl,mixedLiquidMixingTimes,mixedLiquidMixingVolUl,mixedLiquidPreReactionTimeMin,mixedLiquidPreReactionTimeMin
2,2,PCT,PC,1,25,#DC143C,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,12,75,5,200,0,0
1,1,hsCRP,CA,1,25,#FFC0CB,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0
7,7,Total β hCG,HC,1,25,#DA70D6,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,50,30,0,3,0,15,75,5,200,0,0
10,10,Progesterone,PG,1,25,#EE82EE,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",30,0,0,0,3,0,15,75,5,200,0,0
14,14,CK-MB,CK,1,35,#800080,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,0,12,75,5,200,0,0
16,16,D-Dimer,DD,1,25,#9400D3,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,12,75,5,200,0,0
15,15,Myoglobin,MY,1,25,#BA55D3,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,12,75,5,200,0,0
13,13,NT-proBNP,NB,1,25,#8B008B,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,12,75,5,150,0,0
12,12,Tn-I plus,TG,1,25,#FF00FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,12,75,5,150,0,0
22,22,PCT/hsCRP,PR,2,25,#6A5ACD,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
20,20,Tn-I/CK-MB/Myoglobin,CT,3,25,#9370DB,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,150,12,75,5,150,0,0
24,24,SAA,SA,1,25,#E6E6FA,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0
33,33,ST2,ST,1,25,#6495ED,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,150,12,75,5,150,0,0
25,25,AMH,AM,1,25,#F8F8FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,12,75,5,150,0,0
9,9,FSH,FS,1,25,#DDA0DD,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,15,75,5,200,0,0
8,8,LH,LH,1,25,#D8BFD8,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,0,15,75,5,200,0,0
4,4,PRL,PL,1,25,#FF69B4,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,0,10,75,5,200,0,0
3,3,TSH,TS,1,25,#DB7093,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",150,0,0,0,3,75,12,75,5,150,0,0
5,5,T3,T3,1,25,#FF1493,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,75,8,75,5,150,0,0
6,6,T4,T4,1,25,#C71585,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",75,0,0,0,3,75,8,75,5,150,0,0
17,17,HbAlC,HB,1,25,#9932CC,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",5,0,0,0,3,100,12,75,5,150,0,0
26,26,SAA/CRP,SC,2,25,#0000FF,SampleAndBS,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,0,3,75,5,200,0,0
48,48,IL-6,IL,1,25,#AFEEEE,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
50,50,Pepsinogen I/II,PS,2,25,#00FFFF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,10,75,5,150,0,0
55,55,BNP,BP,1,25,#48D1CC,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
54,54,Troponin T,TT,1,25,#008080,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
49,49,Gastrin 17,GA,1,25,#00FFFF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",50,0,0,0,3,150,15,75,5,150,0,0
52,52,NT-proBNP/ST2,NS,2,25,#2F4F4F,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",10,0,0,0,3,150,12,75,5,150,0,0
18,18,PCT plus,PP,1,25,#4B0082,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
27,27,Vitamin D,VD,1,25,#0000FF,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",30,0,0,0,3,150,12,75,5,150,0,0
36,36,MxA,MX,1,25,#708090,SampleAndBSAndProbeSubstance,"[WHOLE_BLOOD,SERUM_OR_PLASMA]",35,0,0,0,3,150,12,75,5,150,0,0
Loading…
Cancel
Save