Browse Source

update

tags/v0
zhaohe 7 months ago
parent
commit
85289e51e5
  1. 4
      appresource/static/engineer/css/app.89317f4a.css
  2. 2
      appresource/static/engineer/index.html
  3. 2
      appresource/static/engineer/js/app.6b28088f.js
  4. 1
      appresource/static/engineer/js/app.6b28088f.js.map
  5. 2
      appresource/static/engineer/js/app.ab8e6e32.js
  6. 1
      appresource/static/engineer/js/app.ab8e6e32.js.map
  7. 6
      appresource/static/engineer/js/chunk-vendors.5158647c.js
  8. 2
      appresource/static/engineer/js/chunk-vendors.5158647c.js.map
  9. 30
      src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java
  10. 16
      src/main/java/a8k/app/factory/AppErrorFactory.java
  11. 11
      src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java
  12. 23
      src/main/java/a8k/app/service/mainctrl/erroranalyzer/ErrorProcessor.java
  13. 278
      src/main/java/a8k/app/service/mainctrl/mainflowctrl/action/AC41ProcessSample.java
  14. 4
      src/main/java/a8k/app/service/mainctrl/mainflowctrl/action/AC42FinishProcesseTube.java
  15. 12
      src/main/java/a8k/app/utils/ActionTaskPool.java
  16. 170
      src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java

4
appresource/static/engineer/css/app.89317f4a.css
File diff suppressed because it is too large
View File

2
appresource/static/engineer/index.html

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>a8k_webui</title><script defer="defer" src="js/chunk-vendors.a96a0e7f.js"></script><script defer="defer" src="js/app.6b28088f.js"></script><link href="css/app.521f1f85.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but a8k_webui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>a8k_webui</title><script defer="defer" src="js/chunk-vendors.5158647c.js"></script><script defer="defer" src="js/app.ab8e6e32.js"></script><link href="css/app.89317f4a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but a8k_webui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

2
appresource/static/engineer/js/app.6b28088f.js
File diff suppressed because it is too large
View File

1
appresource/static/engineer/js/app.6b28088f.js.map
File diff suppressed because it is too large
View File

2
appresource/static/engineer/js/app.ab8e6e32.js
File diff suppressed because it is too large
View File

1
appresource/static/engineer/js/app.ab8e6e32.js.map
File diff suppressed because it is too large
View File

6
appresource/static/engineer/js/chunk-vendors.5158647c.js
File diff suppressed because it is too large
View File

2
appresource/static/engineer/js/chunk-vendors.5158647c.js.map
File diff suppressed because it is too large
View File

30
src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java

@ -36,9 +36,9 @@ public class AppWebSocketEndpointMgr {
@Resource
FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr;
FrontEndMessageBoxAndEventMgr frontEndMessageBoxAndEventMgr;
@Resource
GStateMgrService gstate;
GStateMgrService gstate;
@Resource
DeviceWorkStateMgrService deviceWorkStateMgrService;
@Resource
@ -54,10 +54,22 @@ public class AppWebSocketEndpointMgr {
List<Session> stateWebsocketSessions = new ArrayList<>();
List<Session> eventWebsocketSessions = new ArrayList<>();
Thread workThread;
Boolean newStateSession = false;
synchronized void setNewStateSession() {
this.newStateSession = true;
}
synchronized Boolean getAndClearNewStateSession() {
Boolean ret = this.newStateSession;
this.newStateSession = false;
return ret;
}
synchronized public void pushStateWebsocketSession(Session session) {
stateWebsocketSessions.add(session);
setNewStateSession();
}
synchronized public void removeStateWebsocketSession(Session session) {
@ -136,15 +148,25 @@ public class AppWebSocketEndpointMgr {
// private
@Scheduled(fixedDelay = 30)
public void reportConsumableStateState() {
if (!Objects.equals(reportConsumableStateStateVersion, consumablesMgrService.getStateVersion())) {
boolean forceReport = false;
if (getAndClearNewStateSession()) {
forceReport = true;
}
if (forceReport || !Objects.equals(reportConsumableStateStateVersion, consumablesMgrService.getStateVersion())) {
reportConsumableStateStateVersion = consumablesMgrService.getStateVersion();
reportState("ConsumablesStateService", consumablesMgrService.getState());
}
if (!reportFrontEndMessageBoxStateVersion.equals(frontEndMessageBoxAndEventMgr.getMessageBoxState().stateVersion)) {
if (forceReport || !reportFrontEndMessageBoxStateVersion.equals(frontEndMessageBoxAndEventMgr.getMessageBoxState().stateVersion)) {
reportFrontEndMessageBoxStateVersion = frontEndMessageBoxAndEventMgr.getMessageBoxState().stateVersion;
reportState("MessageBoxState", frontEndMessageBoxAndEventMgr.getMessageBoxState());
}
if (forceReport) {
reportDeviceState();
}
}
}

16
src/main/java/a8k/app/factory/AppErrorFactory.java

@ -0,0 +1,16 @@
package a8k.app.factory;
import a8k.app.a8ktype.error.AECodeError;
import a8k.app.a8ktype.error.AppError;
import a8k.app.a8ktype.exception.AppException;
public class AppErrorFactory {
public static AppError exceptionToAppError(Exception e) {
if (e instanceof AppException appException) {
return appException.error;
} else {
return new AECodeError(e);
}
}
}

11
src/main/java/a8k/app/service/lowerctrl/LiquidOperationCtrlService.java

@ -1,6 +1,7 @@
package a8k.app.service.lowerctrl;
import a8k.app.a8ktype.DeviceRunMode;
import a8k.app.a8ktype.device.*;
import a8k.app.a8ktype.param.A8kSamplePos;
import a8k.app.dao.db.type.ProjExtInfoCard;
@ -14,6 +15,7 @@ import a8k.app.service.param.HbotSamplePosParamMgr;
import a8k.app.service.param.PipetteGunExParamMgr;
import a8k.app.service.param.PipetteGunLLFParamMgr;
import a8k.app.service.statemgr.ConsumablesMgrService;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.utils.ProjBuildinInfo;
import a8k.app.utils.ZAppChecker;
import jakarta.annotation.Resource;
@ -28,6 +30,9 @@ public class LiquidOperationCtrlService {
static public final Integer aspiratePumpVmax = 100;
static public final Integer reactionVolumeUL = 75;
@Resource
GStateMgrService gstate;
/*
* CTRL-SERVICE
*/
@ -121,7 +126,7 @@ public class LiquidOperationCtrlService {
//清空tip中的液体和空气同时预先吸入部分空气以便后续清空由于lld吸入的液体提高lld的准确性
lddprepare();
ldd(largeBottlePos.z, 1000, 30);
if (pipetteCtrlDriver.lldIsDetectLiquid()) {
if (pipetteCtrlDriver.lldIsDetectLiquid() && gstate.isInMode(DeviceRunMode.RealMode)) {
throw AppException.of(A8kEcode.APPE_TAKE_LARGE_BUFFER_LIQUID_FAIL);
}
liquidLevel = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);
@ -170,7 +175,7 @@ public class LiquidOperationCtrlService {
/**
* 取样本到探测物质
* @param from 样本位置
* @param pos 预先反应位置
* @param pos 预先反应位置P
* @param ul 吸取量
* @throws AppException 异常
*/
@ -332,7 +337,7 @@ public class LiquidOperationCtrlService {
//清空tip中的液体和空气同时预先吸入部分空气以便后续清空由于lld吸入的液体提高lld的准确性
lddprepare();
ldd(sampleStartPos.z, sampleEndPos.z, 30);
if (!pipetteCtrlDriver.lldIsDetectLiquid()) {
if (!pipetteCtrlDriver.lldIsDetectLiquid() && gstate.isInMode(DeviceRunMode.RealMode)) {
throw AppException.of(A8kEcode.APPE_TAKE_SAMPLE_FAIL);
}
liquidLevel = pipetteCtrlDriver.getReg(PipetteRegIndex.kreg_pipette_zm_pos);

23
src/main/java/a8k/app/service/mainctrl/erroranalyzer/ErrorAnalyzer.java → src/main/java/a8k/app/service/mainctrl/erroranalyzer/ErrorProcessor.java

@ -1,11 +1,13 @@
package a8k.app.service.mainctrl.erroranalyzer;
import a8k.app.a8ktype.exception.AppException;
import a8k.app.a8ktype.exception.ZAppInterruptException;
import a8k.app.hardware.type.a8kcanprotocol.A8kEcode;
import a8k.app.a8ktype.error.AppError;
import java.util.List;
public class ErrorAnalyzer {
public class ErrorProcessor {
static public Boolean isFatalError(A8kEcode ecode) {
if (ecode.index >= A8kEcode.LOW_ERROR_HARDWARE_ERROR_START.index) {
//部分底层错误属于非必须停机的错误
@ -15,15 +17,22 @@ public class ErrorAnalyzer {
return false;
}
static public Boolean isContainFatalError(List<AppError> errors) {
for (AppError error : errors) {
if (isFatalError(error.code)) {
return true;
}
static public Boolean isFatalException(Exception e) {
if (e instanceof AppException appError) {
return isFatalError(appError.error.code);
}
return false;
return true;
}
// static public Boolean isContainFatalError(List<AppError> errors) {
// for (AppError error : errors) {
// if (isFatalError(error.code)) {
// return true;
// }
// }
// return false;
// }
static public Boolean isContainError(List<AppError> errors, A8kEcode ecode) {
for (AppError error : errors) {
if (error.code.equals(ecode)) {

278
src/main/java/a8k/app/service/mainctrl/mainflowctrl/action/AC41ProcessSample.java

@ -1,7 +1,7 @@
package a8k.app.service.mainctrl.mainflowctrl.action;
import a8k.OS;
import a8k.app.a8ktype.device.*;
import a8k.app.factory.AppErrorFactory;
import a8k.app.service.lowerctrl.*;
import a8k.app.service.mainctrl.mainflowctrl.base.*;
import a8k.app.service.statemgr.IncubationPlateStateMgrService;
@ -11,7 +11,7 @@ import a8k.app.a8ktype.state.ProjectTaskContext;
import a8k.app.a8ktype.state.Tube;
import a8k.app.a8ktype.state.TubeHolder;
import a8k.app.a8ktype.state.enumtype.TubeState;
import a8k.app.service.mainctrl.erroranalyzer.ErrorAnalyzer;
import a8k.app.service.mainctrl.erroranalyzer.ErrorProcessor;
import a8k.app.dao.db.type.a8kidcard.zenum.A8kReactionFlowType;
import a8k.app.utils.ActionTaskPool;
import a8k.teststate.VirtualDevice;
@ -27,7 +27,6 @@ import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
@Component
@MainFlowProcesser
@ -63,7 +62,8 @@ public class AC41ProcessSample extends A8kActionTask {
// PRIVATE VAR
//
ActionTaskPool actionTaskPool = new ActionTaskPool(3);
ActionTaskPool actionTaskPool = new ActionTaskPool(3);
List<AppError> errorsCollection = new ArrayList<>();
BoolCondition reactionPlateReadyCondition = actionTaskPool.createBoolCondition("ReactionPlateReady");
BoolCondition sampleIsReadyCondition = actionTaskPool.createBoolCondition("SampleIsReady");
@ -101,43 +101,15 @@ public class AC41ProcessSample extends A8kActionTask {
} else {
startTask();
}
return afterDoAction(actionTaskPool.waitAllDone());
return actionTaskPool.waitAllDone();
}
/**
* 动作处理完成后的处理串行一般用于修改状态
*/
private List<AppError> afterDoAction(List<AppError> errors) {
Tube tube = tubeStateMgrService.getCurProcessingTube();
List<ProjectTaskContext> ctxs = projectContextMgrService.findCxts(tube.getSampleId());
//如果存在致命错误则直接结束
if (!errors.isEmpty() && ErrorAnalyzer.isContainFatalError(errors)) {
tubeStateMgrService.changeTubeStateToError(errors);
for (ProjectTaskContext cxt : ctxs) {
incubationPlateStateMgrService.setIncubationToErrorState(cxt.getIncubatorPos(), errors);
}
return errors;
}
//如果存在非致命错误则只是将相关的试管打上错误的标记
if (!errors.isEmpty()) {
tubeStateMgrService.changeTubeStateToError(errors);
for (ProjectTaskContext cxt : ctxs) {
incubationPlateStateMgrService.setIncubationToErrorState(cxt.getIncubatorPos(), errors);
}
return new ArrayList<>();
}
//正常处理
for (ProjectTaskContext cxt : ctxs) {
incubationPlateStateMgrService.syncSampleInfo(cxt.getIncubatorPos(), Objects.requireNonNull(ProjInfoUtils.buildProjBrefInfo(cxt)), cxt.getSampleInfo());
incubationPlateStateMgrService.startIncubating(cxt.getIncubatorPos(), cxt.getStartIncubatedTime(), cxt.getIncubatedTimeSec());
}
tubeStateMgrService.changeTubeStateToProcessed();
return new ArrayList<>();
}
// private List<AppError> afterDoAction(List<AppError> errors) {
//// !!!tubeStateMgrService.changeTubeStateToError(errors);
// }
//
@ -145,7 +117,7 @@ public class AC41ProcessSample extends A8kActionTask {
//
void startVirtualTask() {
actionTaskPool.pushTask("samplePrepare", new ActionTaskPool.ActionTask() {
actionTaskPool.pushTask("samplePrepareAndRecyle", new ActionTaskPool.ActionTask() {
@Override public void doAction() throws AppException, ZAppInterruptException {
}
@ -154,6 +126,10 @@ public class AC41ProcessSample extends A8kActionTask {
return null;
}
@Override public void rollback() throws AppException {
}
});
actionTaskPool.pushTask("paltePrepare", new ActionTaskPool.ActionTask() {
@ -165,6 +141,9 @@ public class AC41ProcessSample extends A8kActionTask {
return null;
}
@Override public void rollback() throws AppException {
}
});
@ -175,14 +154,16 @@ public class AC41ProcessSample extends A8kActionTask {
@Override public Exception processError(Exception e) {
return null;
}
@Override public void rollback() throws AppException {
}
});
}
void startTask() {
actionTaskPool.pushTask("samplePrepare", new ActionTaskPool.ActionTask() {
actionTaskPool.pushTask("samplePrepareAndRecyle", new ActionTaskPool.ActionTask() {
@Override public void doAction() throws AppException, ZAppInterruptException {
Tube tube = tubeStateMgrService.getCurProcessingTube();
TubeHolder tubeHolder = tubeStateMgrService.getTubeHolder();
@ -212,20 +193,17 @@ public class AC41ProcessSample extends A8kActionTask {
//等待样本处理完成 wait condition isReady
sampleProcessFinishedCondition.waitTrue();
//样本后处理
tubePreProcesCtrlService.resteModule();
}
@Override public Exception processError(Exception e) throws AppException {
/*
* 该阶段遇到异常基本上是硬件异常无法被处理
*/
if (e instanceof ZAppInterruptException) {
tubePreProcesCtrlService.resteModule();
return null;
}
return e;
@Override public Exception processError(Exception e) {
return processException(e);
}
//when error, rollback
@Override public void rollback() throws AppException {
tubePreProcesCtrlService.resteModule();
}
});
@ -248,81 +226,91 @@ public class AC41ProcessSample extends A8kActionTask {
}
@Override public Exception processError(Exception e) {
return processException(e);
}
if (e instanceof ZAppInterruptException) {
Tube tube = tubeStateMgrService.getCurProcessingTube();
List<ProjectTaskContext> cxts = projectContextMgrService.findCxts(tube.getSampleId());
for (ProjectTaskContext cxt : cxts) {
IncubatorPos incubatorPos = cxt.getIncubatorPos();
// plateBoxCtrlService.pushPlateQuick(cxt.getConsumable().getGroup(), incubatorPos);
// plateBoxCtrlService.resetIncubatorPos()
}
//when error, rollback
@Override public void rollback() throws AppException {
//
// 清空孵育盘中反应板
//
Tube tube = tubeStateMgrService.getCurProcessingTube();
List<ProjectTaskContext> cxts = projectContextMgrService.findCxts(tube.getSampleId());
for (ProjectTaskContext cxt : cxts) {
IncubatorPos incubatorPos = cxt.getIncubatorPos();
//丢弃反应板
optScanModuleCtrlService.pullPlate(incubatorPos);
optScanModuleCtrlService.dropPlate();
//重置孵育盘位置状态
incubationPlateStateMgrService.resetIncubatorPos(incubatorPos);
}
return null;
}
});
actionTaskPool.pushTask("sampleProcess", new ActionTaskPool.ActionTask() {
@Override public void doAction() throws AppException, ZAppInterruptException {
//
// 取样本到小缓冲瓶或者探测物质中进行反应
//
Tube tube = tubeStateMgrService.getCurProcessingTube();
List<ProjectTaskContext> cxts = projectContextMgrService.findCxts(tube.getSampleId());
Assert.isTrue(!cxts.isEmpty(), "项目上下文不能为空");
// 反应液准备
for (ProjectTaskContext cxt : cxts) {
preProcessSample(cxt);
}
//! 等待样本准备完成
sampleIsReadyCondition.waitTrue();
for (ProjectTaskContext cxt : cxts) {
Boolean cxtIsFinal = cxt.equals(cxts.get(cxts.size() - 1));
doSampleProcess(cxt, cxtIsFinal);
}
//样本使用完可以回收了
sampleProcessFinishedCondition.setReady();
}
@Override public Exception processError(Exception e) {
return null;
return processException(e);
}
@Override public void rollback() throws AppException {
//
}
});
}
/**
* 样本准备
* 1. 脱帽盖帽摇匀
* 2. 恢复模组
* @throws AppException e
* @throws ZAppInterruptException e
*/
void samplePrepare() throws AppException, ZAppInterruptException {
}
/**
* 反应板准备
* 1. 推入反应板到赋予盘
* @throws AppException e
* @throws ZAppInterruptException e
*/
void paltePrepare() throws AppException, ZAppInterruptException {
Tube tube = tubeStateMgrService.getCurProcessingTube();
List<ProjectTaskContext> cxts = projectContextMgrService.findCxts(tube.getSampleId());
for (ProjectTaskContext cxt : cxts) {
IncubatorPos incubatorPos = cxt.getIncubatorPos();
plateBoxCtrlService.pushPlateQuick(cxt.getConsumable().getGroup(), incubatorPos);
reactionPlateReadyCondition.setReady();
Exception processException(Exception e) {
if (e instanceof ZAppInterruptException) {
return null;
} else if (!ErrorProcessor.isFatalException(e)) {
errorsCollection.add(AppErrorFactory.exceptionToAppError(e));
return null;
} else {
errorsCollection.add(AppErrorFactory.exceptionToAppError(e));
return e;
}
}
void sampleProcess() throws AppException, ZAppInterruptException {
Tube tube = tubeStateMgrService.getCurProcessingTube();
//准备第一个项目的tip头
List<ProjectTaskContext> cxts = projectContextMgrService.findCxts(tube.getSampleId());
Assert.isTrue(!cxts.isEmpty(), "项目上下文不能为空");
void preProcessSample(ProjectTaskContext cxt) throws AppException, ZAppInterruptException {
//取探测物质
A8kReactionFlowType type = cxt.getProjBuildinInfo().reactionFlowType;
liquidOperationCtrlService.setProjContext(cxt.projBuildinInfo, cxt.projExtInfoCard);
for (ProjectTaskContext cxt : cxts) {
//
// 取样本到小缓冲瓶
//
if (type.equals(A8kReactionFlowType.SampleAndBS)) {
Boolean cxtIsFinal = cxt.equals(cxts.get(cxts.size() - 1));
doSampleProcess(cxt, cxtIsFinal);
} else if (type.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
log.info("取大瓶缓冲液");
liquidOperationCtrlService.takeLargeBottleBufferLiquidToProbeSubstance( //
cxt.getLargeBufferPos(), cxt.getPreReactionPos(), cxt.getTakeLargeBSVolume());
}
sampleProcessFinishedCondition.setReady();
}
/**
@ -340,11 +328,11 @@ public class AC41ProcessSample extends A8kActionTask {
* @throws AppException e
* @throws ZAppInterruptException e
*/
void doSampleProcess(ProjectTaskContext cxt, Boolean finalCxt) throws AppException, ZAppInterruptException {
log.info("开始处理样本 cxtid:{} sampleId:{}", cxt.cxtId, cxt.sampleInfo.sampleId);
A8kReactionFlowType type = cxt.getProjBuildinInfo().reactionFlowType;
liquidOperationCtrlService.setProjContext(cxt.projBuildinInfo, cxt.projExtInfoCard);
// !!! 等待样本准备完成 !!!
//
// 取样本到小缓冲瓶
@ -352,30 +340,14 @@ public class AC41ProcessSample extends A8kActionTask {
if (type.equals(A8kReactionFlowType.SampleAndBS)) {
log.info("FlowType1:");
log.info(" FlowType1->刺破小缓冲瓶");
liquidOperationCtrlService.pirceLittleBuffer(cxt.getPreReactionPos());
// !!! 等待样本准备完成 !!!
sampleIsReadyCondition.waitTrue();
// 取样
log.info(" FlowType1->取样");
liquidOperationCtrlService.takeSample(cxt.getSamplePos(), cxt.getPreReactionPos(), cxt.getSampleVol());
} else if (type.equals(A8kReactionFlowType.SampleAndBSAndProbeSubstance)) {
log.info("FlowType2:");
// 取大瓶缓冲液
log.info(" FlowType2->取大瓶缓冲液");
liquidOperationCtrlService.takeLargeBottleBufferLiquidToProbeSubstance( //
cxt.getLargeBufferPos(), cxt.getPreReactionPos(), cxt.getTakeLargeBSVolume());
// !!! 等待样本准备完成 !!!
sampleIsReadyCondition.waitTrue();
// 取样
log.info(" FlowType2->取样");
liquidOperationCtrlService.takeSample(cxt.getSamplePos(), cxt.getPreReactionPos(), cxt.getSampleVol());
}
@ -385,82 +357,28 @@ public class AC41ProcessSample extends A8kActionTask {
sampleProcessFinishedCondition.setReady();
}
//
// 取初步反应混合液到反应板
//
// ! 等待反应板准备完成
reactionPlateReadyCondition.waitTrue();
turnableMoveCtrlService.trunableMoveToDropLiquidPos(cxt.getIncubatorPos()); //孵育盘移动到吐液位置
liquidOperationCtrlService.takePreReactionLiquidToLiquid(cxt.getPreReactionPos()); //取反应液到反应板上
//孵育
cxt.setStartIncubatedTime(System.currentTimeMillis());
cxt.setIncubatedTimeSec(cxt.getProjBuildinInfo().reactionPlateIncubationTimeMin * 60);
incubationPlateStateMgrService.syncSampleInfo(cxt.getIncubatorPos(), Objects.requireNonNull(ProjInfoUtils.buildProjBrefInfo(cxt)), cxt.getSampleInfo());
incubationPlateStateMgrService.startIncubating(cxt.getIncubatorPos(), cxt.getStartIncubatedTime(), cxt.getIncubatedTimeSec());
}
//
// UTILS
// 异常由各个Action自行进行处理返回给上层则认为是无法处理的异常直接结束
//
List<AppError> wait(List<Future<AppError>> futures) {
for (var future : futures) {
while (!future.isDone()) {
OS.forceSleep(100);
}
}
List<AppError> errors = new ArrayList<>();
for (var future : futures) {
try {
errors.add(future.get());
} catch (InterruptedException | ExecutionException ignored) {
}
}
errors.removeIf(Objects::isNull);
return errors;
}
// Future<AppError> doActionTask(String actionTaskMarker, ActionTask actionTask) {
// return executor.submit(() -> {
// AppError error = null;
// String oldName = Thread.currentThread().getName();
// try {
// Thread.currentThread().setName(this.getClass().getName() + actionTaskMarker);
// actionTask.call();
// log.info("Line {} 执行完成", actionTaskMarker);
// } catch (AppException e) {
// reactionPlateReady.interrupt();
// sampleIsReady.interrupt();
// sampleProcessFinished.interrupt();
// log.error("{} catch 异常", actionTaskMarker, e);
// error = e.error;
// } catch (ZAppInterruptException ignored) {
// log.warn("{} catch 中断", actionTaskMarker);
// } catch (Exception e) {
// log.error("{} catch 异常", actionTaskMarker, e);
// error = new AECodeError(e);
// }
// Thread.currentThread().setName(oldName);
// return error;
// });
// }
/*
* 逻辑:
* 处理 --> 发生异常 ---> 其他线程自动在指定位置结束动作
*
* ---> 后处理(机械结构归位试管归位)
* ---> 异常处理
*
* doAction
* startWork(work, errorProcess, afterWork)
* startWork(work, errorProcess, afterWork)
* startWork(work, errorProcess, afterWork)
*
* waitForAllDone
* return remainingErrors
*
*/
}

4
src/main/java/a8k/app/service/mainctrl/mainflowctrl/action/AC42FinishProcesseTube.java

@ -9,7 +9,7 @@ import a8k.app.a8ktype.state.Tube;
import a8k.app.a8ktype.state.enumtype.TubeState;
import a8k.app.service.lowerctrl.HbotMoveExCtrlService;
import a8k.app.service.lowerctrl.TubePreProcesModuleExCtrlService;
import a8k.app.service.mainctrl.erroranalyzer.ErrorAnalyzer;
import a8k.app.service.mainctrl.erroranalyzer.ErrorProcessor;
import a8k.app.utils.ZList;
import a8k.teststate.VirtualDevice;
import a8k.app.a8ktype.error.AppError;
@ -89,7 +89,7 @@ public class AC42FinishProcesseTube extends A8kActionTask {
return ZList.of(e.getError());
}
Tube tube = tubeStateMgrService.getCurProcessingTube();
if (ErrorAnalyzer.isContainError(tube.getErrors(), A8kEcode.APPE_TAKE_TIP_FAIL)) {
if (ErrorProcessor.isContainError(tube.getErrors(), A8kEcode.APPE_TAKE_TIP_FAIL)) {
deviceWorkStateMgrService.setPauseActionPending(true);
}

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

@ -19,7 +19,10 @@ import java.util.concurrent.TimeUnit;
public class ActionTaskPool {
public interface ActionTask {
void doAction() throws AppException, ZAppInterruptException;
Exception processError(Exception e) throws AppException;
Exception processError(Exception e);
void rollback() throws AppException;
}
//线程池
@ -56,7 +59,6 @@ public class ActionTaskPool {
}
private Future<?> doActionTask(String actionTaskMarker, ActionTask actionTask) {
return executor.submit(() -> {
String oldName = Thread.currentThread().getName();
@ -82,14 +84,18 @@ public class ActionTaskPool {
remainingErrors.add(new AECodeError(e));
}
}
if (e == null) {
actionTask.rollback();
}
} catch (AppException e) {
//这里的错误基本上就是硬件错误是无法被代码处理的
errorFlag = true;
remainingErrors.add(e.error);
log.error("do {}.afterDoAction catch exception", actionTaskMarker, e);
}
}
Thread.currentThread().setName(oldName);
});
}

170
src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java

@ -37,17 +37,19 @@ public class ExtApiPageGroupCfgMgr {
public List<Menu> children = null;
public Menu(String key, String label, Menu... menu) {
this.key = key;
this.label = label;
if (menu.length != 0) {
children = new ArrayList<>();
Collections.addAll(children, menu);
}
public Menu(Class<?> key, String label) {
this.key = key.getSimpleName();
this.label = label;
}
public Menu(String label, List<Menu> menus) {
this.key = label;
this.label = label;
this.children = menus;
}
public Menu pushSubMenu(String key, String label) {
public Menu pushSubMenu(Class<?> key, String label) {
if (children == null)
children = new ArrayList<>();
children.add(new Menu(key, label));
@ -55,9 +57,11 @@ public class ExtApiPageGroupCfgMgr {
}
public Menu pushSubMenu(Class<?> key, String label) {
return pushSubMenu(key.getSimpleName(), label);
public Menu pushSubMenuGroup(String label, List<Menu> menus) {
if (children == null)
children = new ArrayList<>();
children.add(new Menu(label, menus));
return this;
}
}
@ -69,79 +73,87 @@ public class ExtApiPageGroupCfgMgr {
List<Menu> menuList = new ArrayList<>();
Menu pushMenu(String label) {
Menu menu = new Menu(String.format("Menu%s", menuList.size()), label );
menuList.add(menu);
return menu;
void pushMenu(Menu label) {
menuList.add(label);
}
@PostConstruct
void init() {
pushMenu("测量")
.pushSubMenu(DeviceInitializeUtilsPage.class, "设备初始化")
.pushSubMenu(HbotPosMeasurePage.class, "HBOT测量");
pushMenu("位置标定")
.pushSubMenu(P02TubeFeedingModulePosCalibrationPage.class, "试管入料校准")
.pushSubMenu(P03TubePreProcesPosCalibrationPage.class, "试管预处理校准")
.pushSubMenu(P04ReactionPlatesTransmitControlerCalibrationPage.class, "反应板相关位置校准")
.pushSubMenu(P20HbotTipPosCalibrationPage.class, "Tip耗材位置校准")
.pushSubMenu(P21HbotLittleBSPosCalibrationPage.class, "小瓶BS耗材位置校准")
.pushSubMenu(P23HbotLargeBottleBSPosCalibrationPage.class, "大瓶BS耗材位置校准")
.pushSubMenu(P24Hbot2DCodeScanPosCalibrationPage.class, "耗材扫描校准")
.pushSubMenu(P25HbotSamplePosCalibrationPage.class, "取样位置校准");
pushMenu( "验证")
.pushSubMenu(P00PosVerifyUitilsPage.class, "工具")
.pushSubMenu(P10ProjejIDCardTestPage.class, "ID卡")
.pushSubMenu(P30InfeedAndPreProcessPosVerificationPage.class, "单步-入料和预处理")
.pushSubMenu(P31ReactionPlatesTransmitPosVerificationPage.class, "单步-反应板传输")
.pushSubMenu(P32HbotPosVerificationPage.class, "单步-HBOT位置")
.pushSubMenu(P33HbotSamplePosVerificationPage.class, "单步-取样品位置")
.pushSubMenu(P34LiquidOperationTestPage.class, "单步-液体操作")
.pushSubMenu(P50VerificationScriptPage.class, "脚本-模块验证")
.pushSubMenu(P51FullFlowVerificationPage.class, "脚本-全流程验证");
pushMenu( "光学标定与验证")
.pushSubMenu(A8kOptVerification.class, "光学模组验证")
.pushSubMenu(OptModuleParamCalibration.class, "光学模块参数校准")
.pushSubMenu(OptFormulaTestPageV2.class, "光学公式测试1")
.pushSubMenu(OptFormulaTestPage.class, "光学公式测试2");
pushMenu("验证(过检专用)")
.pushSubMenu(P01PipetteGunVerification.class, "移液枪验证")
.pushSubMenu(P02A8kTemperaturaVerfication.class, "温度控制验证");
pushMenu("调试")
.pushSubMenu(P21AppDebugModeConfigPage.class, "设备模式配置")
.pushSubMenu(P00AppEventAndMessageBoxDebugPage.class, "事件与消息")
.pushSubMenu(P22UserOperaionInRunOnlyModePage.class, "空转模式用户操作")
.pushSubMenu(P22UserOperaionInVertualModePage.class, "虚拟模式用户操作")
.pushSubMenu(P00MainflowCtrlServiceDebugPage.class, "主流程调试")
.pushSubMenu(P02ConsumablesMgrDebugPage.class, "耗材")
.pushSubMenu(P01EmergencyTubeDebugPage.class, "急诊")
.pushSubMenu(P02TubeSettingDebugPage.class, "试管配置")
.pushSubMenu(P01ProjInfoDebugPage.class, "ID卡操作")
.pushSubMenu(P11IncubationPlateStateDebugPageAll.class, "状态.孵育盘")
.pushSubMenu(P12TueStateDebugPage.class, "状态.试管")
.pushSubMenu(P13OptModuleStateDebugPage.class, "状态.光学模块")
.pushSubMenu(P20AppSettingDebugPage.class, "设置.系统设置");
pushMenu("驱动调试")
.pushSubMenu(LowLevelBoardVersionPreviewPage.class, "低级板版本预览")
.pushSubMenu(PipetteCtrlDriverPage.getPageClass(), "移液抢驱动");
pushMenu("数据")
.pushSubMenu(DeviceActionParameterSettingPage.class, "设备动作参数设置")
.pushSubMenu(ProjInfoMgrPage.class, "项目信息管理");
pushMenu("前端测试助手")
.pushSubMenu(FakeReactionRecordGeneratorPage.class, "虚拟反应记录生成")
.pushSubMenu(VirtualEventGeneratorPage.class, "虚拟事件生成");
pushMenu("压力测试")
.pushSubMenu(PipetteGunStressTest.class, "移液枪压力测试");
pushMenu(new Menu("测量", List.of(
new Menu(DeviceInitializeUtilsPage.class, "设备初始化"),
new Menu(HbotPosMeasurePage.class, "HBOT测量")
)));
pushMenu(new Menu("位置标定", List.of(
new Menu(P02TubeFeedingModulePosCalibrationPage.class, "试管入料校准"),
new Menu(P03TubePreProcesPosCalibrationPage.class, "试管预处理校准"),
new Menu(P04ReactionPlatesTransmitControlerCalibrationPage.class, "反应板相关位置校准"),
new Menu(P20HbotTipPosCalibrationPage.class, "Tip耗材位置校准"),
new Menu(P21HbotLittleBSPosCalibrationPage.class, "小瓶BS耗材位置校准"),
new Menu(P23HbotLargeBottleBSPosCalibrationPage.class, "大瓶BS耗材位置校准"),
new Menu(P24Hbot2DCodeScanPosCalibrationPage.class, "耗材扫描校准"),
new Menu(P25HbotSamplePosCalibrationPage.class, "取样位置校准")
)));
pushMenu(new Menu("验证", List.of(
new Menu(P00PosVerifyUitilsPage.class, "工具"),
new Menu(P10ProjejIDCardTestPage.class, "ID卡"),
new Menu(P30InfeedAndPreProcessPosVerificationPage.class, "单步-入料和预处理"),
new Menu(P31ReactionPlatesTransmitPosVerificationPage.class, "单步-反应板传输"),
new Menu(P32HbotPosVerificationPage.class, "单步-HBOT位置"),
new Menu(P33HbotSamplePosVerificationPage.class, "单步-取样品位置"),
new Menu(P34LiquidOperationTestPage.class, "单步-液体操作"),
new Menu(P50VerificationScriptPage.class, "脚本-模块验证"),
new Menu(P51FullFlowVerificationPage.class, "脚本-全流程验证")
)));
pushMenu(new Menu("光学标定与验证", List.of(
new Menu(A8kOptVerification.class, "光学模组验证"),
new Menu(OptModuleParamCalibration.class, "光学模块参数校准"),
new Menu(OptFormulaTestPageV2.class, "光学公式测试1"),
new Menu(OptFormulaTestPage.class, "光学公式测试2")
)));
pushMenu(new Menu("验证(过检专用)", List.of(
new Menu(P01PipetteGunVerification.class, "移液枪验证"),
new Menu(P02A8kTemperaturaVerfication.class, "温度控制验证")
)));
pushMenu(new Menu("调试", List.of(
new Menu(P21AppDebugModeConfigPage.class, "设备模式配置"),
new Menu(P00AppEventAndMessageBoxDebugPage.class, "事件与消息"),
new Menu(P22UserOperaionInRunOnlyModePage.class, "空转模式用户操作"),
new Menu(P22UserOperaionInVertualModePage.class, "虚拟模式用户操作"),
new Menu(P00MainflowCtrlServiceDebugPage.class, "主流程调试"),
new Menu(P02ConsumablesMgrDebugPage.class, "耗材"),
new Menu(P01EmergencyTubeDebugPage.class, "急诊"),
new Menu(P02TubeSettingDebugPage.class, "试管配置"),
new Menu(P01ProjInfoDebugPage.class, "ID卡操作"),
new Menu(P11IncubationPlateStateDebugPageAll.class, "状态.孵育盘"),
new Menu(P12TueStateDebugPage.class, "状态.试管"),
new Menu(P13OptModuleStateDebugPage.class, "状态.光学模块"),
new Menu(P20AppSettingDebugPage.class, "设置.系统设置"),
new Menu("前端测试助手", List.of(
new Menu(FakeReactionRecordGeneratorPage.class, "虚拟反应记录生成"),
new Menu(VirtualEventGeneratorPage.class, "虚拟事件生成")
))
)));
pushMenu(new Menu("驱动调试", List.of(
new Menu(LowLevelBoardVersionPreviewPage.class, "低级板版本预览"),
new Menu(PipetteCtrlDriverPage.getPageClass(), "移液抢驱动")
)));
pushMenu(new Menu("数据", List.of(
new Menu(DeviceActionParameterSettingPage.class, "设备动作参数设置"),
new Menu(ProjInfoMgrPage.class, "项目信息管理")
)));
pushMenu(new Menu("压力测试", List.of(
new Menu(PipetteGunStressTest.class, "移液枪压力测试")
)));
}
}
Loading…
Cancel
Save