diff --git a/app.db b/app.db index 3fb31de..f828ff8 100644 Binary files a/app.db and b/app.db differ diff --git a/src/main/java/com/iflytop/a800/device/DeviceComponent.java b/src/main/java/com/iflytop/a800/device/DeviceComponent.java index f88f447..d7bd212 100644 --- a/src/main/java/com/iflytop/a800/device/DeviceComponent.java +++ b/src/main/java/com/iflytop/a800/device/DeviceComponent.java @@ -16,7 +16,8 @@ abstract public class DeviceComponent { // lock public DeviceComponentLock lock( String name ) { - LOG.info("LOCK : {}", name); + var comName = this.getClass().getSimpleName(); + LOG.info("[Device:{}] LOCK => {}", comName, name); var lock = new DeviceComponentLock(); lock.name = name; @@ -27,28 +28,33 @@ abstract public class DeviceComponent { } } - LOG.info("LOCK WAITING : {}", name); - try { - lock.wait(); - } catch (InterruptedException e) { - throw new RuntimeException(e); + LOG.info("[Device:{}] LOCK WAITING => {}", comName, name); + synchronized ( lock ) { + try { + lock.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } - LOG.info("LOCK DONE : {}", name); + LOG.info("[Device:{}] LOCK DONE => {}", comName, name); return lock; } // unlock public void unlock( DeviceComponentLock lock ) { + var comName = this.getClass().getSimpleName(); synchronized ( this.locks ) { - LOG.info("UNLOCK : {}", lock.name); + LOG.info("[Device:{}] UNLOCK => {}", comName, lock.name); this.locks.remove(lock); if ( this.locks.isEmpty() ) { return ; } + } - var next = this.locks.get(0); - LOG.info("NOTIFY NEXT : {}", next.name); + var next = this.locks.get(0); + LOG.info("[Device:{}] NOTIFY NEXT => {}", comName, next.name); + synchronized ( next ) { next.notifyAll(); } } diff --git a/src/main/java/com/iflytop/a800/device/Incubator.java b/src/main/java/com/iflytop/a800/device/Incubator.java index a48babb..74a4c40 100644 --- a/src/main/java/com/iflytop/a800/device/Incubator.java +++ b/src/main/java/com/iflytop/a800/device/Incubator.java @@ -1,6 +1,7 @@ package com.iflytop.a800.device; import com.iflytop.a800.resource.IncubatorSlot; import com.iflytop.a800.resource.TestCard; +import com.iflytop.uf.UfActuatorCmdExecutor; import com.iflytop.uf.UfCmdSnippetExecutor; import com.iflytop.uf.model.UfMdbOption; import java.util.ArrayList; @@ -23,6 +24,14 @@ public class Incubator extends DeviceComponent { } } + // 移动至提交位置 + public void moveToCommitPos( IncubatorSlot slot ) { + Integer commitStartPos = UfMdbOption.getInteger("IncubatorSlotCommitStartPos"); + Integer commitDistance = UfMdbOption.getInteger("IncubatorSlotCommitDistance"); + int commitPos = commitStartPos + commitDistance * slot.index; + UfActuatorCmdExecutor.execute("MotorIncubatorRotate", "motor_easy_move_to", Integer.toString(commitPos)); + } + // 推送新卡片 public IncubatorSlot pushNewCard(TestCard card) { var lock = this.lock("PushNewCard"); @@ -63,13 +72,11 @@ public class Incubator extends DeviceComponent { // 退出到扫描 public void exitCardToScanner( IncubatorSlot slot ) { - var lock = this.lock("ExitCardToScanner"); Integer startPos = UfMdbOption.getInteger("IncubatorSlotExitStartPos"); Integer distance = UfMdbOption.getInteger("IncubatorSlotExitDistance"); Integer slotPos = startPos + distance * slot.index; Map params = Map.of("slot", slotPos); UfCmdSnippetExecutor.execute("IncubatorTestCardExitToScanner", params); slot.card = null; - this.unlock(lock); } } diff --git a/src/main/java/com/iflytop/a800/device/Scanner.java b/src/main/java/com/iflytop/a800/device/Scanner.java index 56e1c94..2c74c88 100644 --- a/src/main/java/com/iflytop/a800/device/Scanner.java +++ b/src/main/java/com/iflytop/a800/device/Scanner.java @@ -2,13 +2,12 @@ package com.iflytop.a800.device; import com.iflytop.uf.UfActuatorCmdExecutor; import com.iflytop.uf.UfCmdSnippetExecutor; import com.iflytop.uf.util.UfCommon; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Base64; import java.util.List; -public class Scanner { +public class Scanner extends DeviceComponent { // 扫描类型F public void scanTypeF() { UfCmdSnippetExecutor.execute("SampleResultAnalysisTypeF"); diff --git a/src/main/java/com/iflytop/a800/task/TubeTestTask.java b/src/main/java/com/iflytop/a800/task/TubeTestTask.java index 0d611d7..be72a64 100644 --- a/src/main/java/com/iflytop/a800/task/TubeTestTask.java +++ b/src/main/java/com/iflytop/a800/task/TubeTestTask.java @@ -164,7 +164,6 @@ public class TubeTestTask extends TaskBase { case "mixing" : this.executeStepMixing(stepNode); break; case "drop-tip" : this.executeStepDropTip(stepNode); break; case "incubate" : this.executeStepIncubate(stepNode); break; - case "analysis" : this.executeStepAnalysis(stepNode); break; case "sampling-done" : this.executeStepSamplingDone(stepNode); break; } } catch ( InterruptedException e ) { @@ -172,7 +171,9 @@ public class TubeTestTask extends TaskBase { } } + this.analysis(); this.taskFinish(); + this.log("项目测试结束"); } // 采样完成 @@ -305,6 +306,7 @@ public class TubeTestTask extends TaskBase { // 提交样本至孵育盘测试卡 var incubatorLock = device.incubator.lock("SampleCommit"); + device.incubator.moveToCommitPos(this.incubatorSlot); Integer volume = stepNode.get("volume").asInt(); pipette.aspirateFromBufferTubeAndDispenseToTestCard(this.bufferTube, volume); device.incubator.unlock(incubatorLock); @@ -327,16 +329,40 @@ public class TubeTestTask extends TaskBase { this.log("孵育完成,等待扫描结果"); } - // 扫描 - private void executeStepAnalysis( JsonNode stepNode ) { - this.log("扫描结果"); + // 扫描分析结果 + private void analysis() { + var asyncEnable = UfMdbOption.getBoolean("AnalysisAsyncEnable", false); + if ( !asyncEnable ) { + this.executeAnalysis(); + this.log("结果分析完成"); + return ; + } + + var thread = new Thread(this::executeAnalysis); + thread.start(); + this.taskWait("AnalysisDone"); + this.log("结果分析完成"); + } + + /** + * 执行扫描分析操作 + */ + private void executeAnalysis() { + this.log("结果扫描"); Device device = Device.getInstance(); - device.incubator.exitCardToScanner(this.incubatorSlot); var scanner = device.scanner; + var scannerLock = scanner.lock("ScanResult"); + + var incubator = device.incubator; + var exitCardLock = incubator.lock("ExitCard"); + incubator.exitCardToScanner(this.incubatorSlot); + incubator.unlock(exitCardLock); + scanner.scanTypeF(); var scanResult = scanner.readResult(); scanner.dropCard(); + scanner.unlock(scannerLock); // 计算 var algo = new ScanResultAnalysisAlgo(); @@ -395,6 +421,11 @@ public class TubeTestTask extends TaskBase { this.test.result = UfJsonHelper.objectToJson(results); this.test.save(); + + var asyncEnable = UfMdbOption.getBoolean("AnalysisAsyncEnable", false); + if ( asyncEnable ) { + this.setStatus("READY"); + } } /**