diff --git a/app.db b/app.db
index 5abc800..bcc0fa2 100644
Binary files a/app.db and b/app.db differ
diff --git a/pom.xml b/pom.xml
index 71aa56c..eb7d419 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
com.iflytop
uf
- 0.0.21
+ 0.0.24
diff --git a/src/main/java/com/iflytop/a800/controller/DemoController.java b/src/main/java/com/iflytop/a800/controller/DemoController.java
index 65c9acf..c52bbef 100644
--- a/src/main/java/com/iflytop/a800/controller/DemoController.java
+++ b/src/main/java/com/iflytop/a800/controller/DemoController.java
@@ -1,6 +1,11 @@
package com.iflytop.a800.controller;
+import com.iflytop.a800.TaskManager;
import com.iflytop.a800.device.Device;
+import com.iflytop.a800.model.MdbProject;
import com.iflytop.a800.resource.BufferTube;
+import com.iflytop.a800.resource.TestTube;
+import com.iflytop.a800.task.TubeTestTask;
+import com.iflytop.uf.UfActiveRecord;
import com.iflytop.uf.UfActuatorCmdExecutor;
import com.iflytop.uf.controller.UfApiControllerBase;
import com.iflytop.uf.controller.UfApiResponse;
@@ -75,4 +80,17 @@ public class DemoController extends UfApiControllerBase {
}
return this.success();
}
+
+ @PostMapping("/api/demo/tube-test-task-start")
+ @ResponseBody
+ public UfApiResponse tubeTestTaskStart() {
+ var task = new TubeTestTask();
+ task.project = UfActiveRecord.findOne(MdbProject.class, "1");
+ task.tube = new TestTube();
+ task.tube.type = "EmergencyTube";
+ task.tube.index = 0;
+ var taskMan = TaskManager.getInstance();
+ taskMan.append(task);
+ return this.success();
+ }
}
diff --git a/src/main/java/com/iflytop/a800/device/Device.java b/src/main/java/com/iflytop/a800/device/Device.java
index 276a79e..c043fbc 100644
--- a/src/main/java/com/iflytop/a800/device/Device.java
+++ b/src/main/java/com/iflytop/a800/device/Device.java
@@ -2,6 +2,7 @@ package com.iflytop.a800.device;
import com.iflytop.a800.resource.BufferTubeManager;
import com.iflytop.a800.resource.LargeBufferTubeManager;
+import com.iflytop.a800.resource.TestCardManager;
public class Device {
// singleton instance
@@ -10,10 +11,16 @@ public class Device {
public final Feeder feeder = new Feeder();
// pipette
public final Pipette pipette = new Pipette();
+ // incubator
+ public final Incubator incubator = new Incubator();
+ // scanner
+ public final Scanner scanner = new Scanner();
// buffer tube manager
public final BufferTubeManager bufferTube = new BufferTubeManager();
// large buffer tube manager
public final LargeBufferTubeManager largeBufferTube = new LargeBufferTubeManager();
+ // test card manager
+ public final TestCardManager testCard = new TestCardManager();
// get instance
public static Device getInstance() {
diff --git a/src/main/java/com/iflytop/a800/device/Feeder.java b/src/main/java/com/iflytop/a800/device/Feeder.java
index 8e7b4b2..9dbdcae 100644
--- a/src/main/java/com/iflytop/a800/device/Feeder.java
+++ b/src/main/java/com/iflytop/a800/device/Feeder.java
@@ -12,9 +12,9 @@ public class Feeder {
}
// 读取试管架类型
- public Number readTubeRackType() {
+ public String readTubeRackType() {
UfCmdSnippetExecutor.execute("FeedTubeRackTypeReadPrepare");
- return 1;
+ return "wb";
}
// 读取试管是否存在
diff --git a/src/main/java/com/iflytop/a800/device/Incubator.java b/src/main/java/com/iflytop/a800/device/Incubator.java
index 323c007..9ecfb4f 100644
--- a/src/main/java/com/iflytop/a800/device/Incubator.java
+++ b/src/main/java/com/iflytop/a800/device/Incubator.java
@@ -1,4 +1,17 @@
package com.iflytop.a800.device;
-
+import com.iflytop.uf.UfCmdSnippetExecutor;
+import com.iflytop.uf.model.UfMdbOption;
+import java.util.Map;
public class Incubator {
+ // 推送新卡片
+ public void pushNewCard( Integer boxIndex ) {
+ Integer boxPos = UfMdbOption.getInteger(String.format("TestCardWarehouseBox.%d", boxIndex));
+ Map params = Map.of("box", boxPos);
+ UfCmdSnippetExecutor.execute("IncubatorTestCardPushIn", params);
+ }
+
+ // 退出到扫描
+ public void exitToScanner() {
+ UfCmdSnippetExecutor.execute("IncubatorTestCardExitToScanner");
+ }
}
diff --git a/src/main/java/com/iflytop/a800/device/Pipette.java b/src/main/java/com/iflytop/a800/device/Pipette.java
index 9efc0f0..0c7136d 100644
--- a/src/main/java/com/iflytop/a800/device/Pipette.java
+++ b/src/main/java/com/iflytop/a800/device/Pipette.java
@@ -60,20 +60,20 @@ public class Pipette {
Integer x = zoneStartX + indexX * distanceX;
Integer y = zoneStartY + indexY * distanceY;
+ Boolean tipStatusCheckEnable = UfMdbOption.getBoolean("PipetteTipStatusCheckEnable");
Map pickUpParams = Map.of("tipX", x, "tipY", y, "tipZ", zoneZ);
// 尝试三次拾取枪头
for ( int i=0; i<3; i++ ) {
LOG.info("[Pipette] Pick up tip at [{},{}](x={}, y={}, z={})", indexX, indexY, x, y, zoneZ);
UfCmdSnippetExecutor.execute("PipetteTipPickUp", pickUpParams);
String tipState = UfActuatorCmdExecutor.execute("Pipette", "read_pipette_tip_state");
- if ("1".equals(tipState)) {
+ if ( "1".equals(tipState) || !tipStatusCheckEnable ) {
break ;
}
-
}
String tipState = UfActuatorCmdExecutor.execute("Pipette", "read_pipette_tip_state");
- if ("0".equals(tipState)) {
+ if ("0".equals(tipState) && tipStatusCheckEnable ) {
this.tipPickUp();
return ; // 如果拾取失败,则跳过这个TIP取下一个
}
@@ -139,6 +139,75 @@ public class Pipette {
UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
}
+ // 混匀
+ public void mix( BufferTube tube, Integer count, Integer volume ) {
+ if ( 0 == count ) {
+ return ;
+ }
+
+ Integer startX = UfMdbOption.getInteger(String.format("%sZoneStartX.%d", tube.type, tube.zoneIndex));
+ Integer startY = UfMdbOption.getInteger(String.format("%sZoneStartY.%d", tube.type, tube.zoneIndex));
+ Integer distanceX = UfMdbOption.getInteger(String.format("%sDistanceX", tube.type));
+ Integer distanceY = UfMdbOption.getInteger(String.format("%sDistanceY", tube.type));
+ Integer indexX = tube.tubeIndex % 5;
+ Integer indexY = tube.tubeIndex / 5;
+ Integer tubeX = startX + indexX * distanceX;
+ Integer tubeY = startY + indexY * distanceY;
+ Map dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY);
+
+ String snippetKey = "SampleMixingAtDetectionTubePrepare";
+ if ( "BufferTube".equals(tube.type) ) {
+ snippetKey = "SampleMixingAtBufferTubePrepare";
+ }
+ UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
+
+ String volumeStr = Integer.toString(volume);
+ for ( int i=0; i dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY);
+
+ String snippetKey = "PunctureAtDetectionTube";
+ if ( "BufferTube".equals(tube.type) ) {
+ snippetKey = "PunctureAtBufferTube";
+ }
+ UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
+ }
+
+ // 从缓冲液管吸液并吐液到检测板
+ public void aspirateFromBufferTubeAndDispenseToTestCard( BufferTube tube, Integer volume ) {
+ Integer startX = UfMdbOption.getInteger(String.format("%sZoneStartX.%d", tube.type, tube.zoneIndex));
+ Integer startY = UfMdbOption.getInteger(String.format("%sZoneStartY.%d", tube.type, tube.zoneIndex));
+ Integer distanceX = UfMdbOption.getInteger(String.format("%sDistanceX", tube.type));
+ Integer distanceY = UfMdbOption.getInteger(String.format("%sDistanceY", tube.type));
+ Integer indexX = tube.tubeIndex % 5;
+ Integer indexY = tube.tubeIndex / 5;
+ Integer tubeX = startX + indexX * distanceX;
+ Integer tubeY = startY + indexY * distanceY;
+ Map dispenseParams = Map.of("tubeX", tubeX, "tubeY", tubeY, "volume", volume);
+
+ String snippetKey = "AspirateFromDetectionTubeAndDispenseToTestCard";
+ if ( "BufferTube".equals(tube.type) ) {
+ snippetKey = "AspirateFromBufferTubeAndDispenseToTestCard";
+ }
+ UfCmdSnippetExecutor.execute(snippetKey, dispenseParams);
+ }
+
// 从大缓冲液管吸液
public void aspirateFromLargeBufferTube(LargeBufferTube tube, Integer volume) {
Integer startX = UfMdbOption.getInteger("LargeBufferTubeZoneStartX");
@@ -208,8 +277,23 @@ public class Pipette {
this.aspirateWithLiquidLevelFollow(volume, depth);
}
+ // 从全血5ml吸液
+ public void aspirateFromWholeBlood5ml(Integer index, Integer volume) {
+ throw new RuntimeException("摇匀没接,暂时无法测试");
+ }
+
+ // 从全血3ml吸液
+ public void aspirateFromWholeBlood3ml(Integer index, Integer volume) {
+ throw new RuntimeException("摇匀没接,暂时无法测试");
+ }
+
// 移动到液面
private void moveToLiquidLevel( Integer maxDepth, Integer threshold ) {
+ Boolean liquidLevelDetectEnable = UfMdbOption.getBoolean("PipetteLiquidLevelDetectEnable");
+ if ( !liquidLevelDetectEnable ) {
+ return ;
+ }
+
int stepDepth = 10;
int depth = 0;
do {
diff --git a/src/main/java/com/iflytop/a800/device/Scanner.java b/src/main/java/com/iflytop/a800/device/Scanner.java
index 6ea0070..47fa1b5 100644
--- a/src/main/java/com/iflytop/a800/device/Scanner.java
+++ b/src/main/java/com/iflytop/a800/device/Scanner.java
@@ -1,4 +1,59 @@
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 {
+ // 扫描类型F
+ public void scanTypeF() {
+ UfCmdSnippetExecutor.execute("SampleResultAnalysisTypeF");
+ UfCommon.delay(20 * 1000);
+ }
+
+ // 扫描类型T
+ public void scanTypeT() {
+ UfCmdSnippetExecutor.execute("SampleResultAnalysisTypeT");
+ UfCommon.delay(20 * 1000);
+ }
+
+ // 读取结果
+ public float[] readResult() {
+ String sizeStr = UfActuatorCmdExecutor.execute("Scanner","module_get_reg", "10");
+ String countStr = UfActuatorCmdExecutor.execute("Scanner","module_get_reg", "11");
+ int size = Integer.parseInt(sizeStr);
+ int count = Integer.parseInt(countStr);
+ List data = new ArrayList<>();
+ for ( int i = 0; i < count; i++ ) {
+ String readParam = Integer.toString(i);
+ String response = UfActuatorCmdExecutor.execute("Scanner","module_read_raw", readParam);
+ Base64.Decoder decoder = Base64.getDecoder();
+ byte[] bytes = decoder.decode(response);
+ for (byte aByte : bytes) {
+ data.add(aByte);
+ }
+ UfCommon.delay(100);
+ }
+
+ byte[] result = new byte[data.size()];
+ for ( int i = 0; i < data.size(); i++ ) {
+ result[i] = data.get(i);
+ }
+ var buffer = ByteBuffer.wrap(result);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ float[] scanRawData = new float[buffer.capacity() / 2];
+ for (int i = 0; i < scanRawData.length; i++) {
+ scanRawData[i] = buffer.getShort();
+ }
+ return scanRawData;
+ }
+
+ // 丢弃卡片
+ public void dropCard() {
+ UfCmdSnippetExecutor.execute("SampleResultAnalysisDropCard");
+ }
}
diff --git a/src/main/java/com/iflytop/a800/model/MdbIdChip.java b/src/main/java/com/iflytop/a800/model/MdbIdChip.java
new file mode 100644
index 0000000..bcae114
--- /dev/null
+++ b/src/main/java/com/iflytop/a800/model/MdbIdChip.java
@@ -0,0 +1,8 @@
+package com.iflytop.a800.model;
+public class MdbIdChip {
+ public Integer peakCount;
+ public Integer itemCount;
+ public String items;
+ public Integer scanPeakCount;
+ public Integer scanType;
+}
diff --git a/src/main/java/com/iflytop/a800/model/MdbProject.java b/src/main/java/com/iflytop/a800/model/MdbProject.java
new file mode 100644
index 0000000..1fa7e92
--- /dev/null
+++ b/src/main/java/com/iflytop/a800/model/MdbProject.java
@@ -0,0 +1,15 @@
+package com.iflytop.a800.model;
+import com.iflytop.uf.UfActiveRecord;
+import com.iflytop.uf.UfActiveRecordField;
+public class MdbProject extends UfActiveRecord {
+ @UfActiveRecordField
+ public String name;
+
+ @UfActiveRecordField
+ public String steps;
+
+ // get table name
+ public static String getTableName() {
+ return "app_projects";
+ }
+}
diff --git a/src/main/java/com/iflytop/a800/resource/TestCard.java b/src/main/java/com/iflytop/a800/resource/TestCard.java
new file mode 100644
index 0000000..3ed7164
--- /dev/null
+++ b/src/main/java/com/iflytop/a800/resource/TestCard.java
@@ -0,0 +1,4 @@
+package com.iflytop.a800.resource;
+public class TestCard {
+ public Integer boxIndex;
+}
diff --git a/src/main/java/com/iflytop/a800/resource/TestCardManager.java b/src/main/java/com/iflytop/a800/resource/TestCardManager.java
new file mode 100644
index 0000000..14828ca
--- /dev/null
+++ b/src/main/java/com/iflytop/a800/resource/TestCardManager.java
@@ -0,0 +1,8 @@
+package com.iflytop.a800.resource;
+public class TestCardManager {
+ public TestCard alloc() {
+ var card = new TestCard();
+ card.boxIndex = 0;
+ return card;
+ }
+}
diff --git a/src/main/java/com/iflytop/a800/resource/TestTube.java b/src/main/java/com/iflytop/a800/resource/TestTube.java
index 3fe02df..44f2cab 100644
--- a/src/main/java/com/iflytop/a800/resource/TestTube.java
+++ b/src/main/java/com/iflytop/a800/resource/TestTube.java
@@ -4,7 +4,9 @@ public class TestTube {
// is tube existed
public Boolean isExisted = false;
// tube type
- public Number type;
+ public String type;
// tube bar code
public String barCode;
+ // tube index
+ public Integer index;
}
diff --git a/src/main/java/com/iflytop/a800/resource/TestTubeRack.java b/src/main/java/com/iflytop/a800/resource/TestTubeRack.java
index 10c5aa9..281062d 100644
--- a/src/main/java/com/iflytop/a800/resource/TestTubeRack.java
+++ b/src/main/java/com/iflytop/a800/resource/TestTubeRack.java
@@ -2,7 +2,7 @@ package com.iflytop.a800.resource;
import java.util.List;
public class TestTubeRack {
// tube rack type
- public Number type;
+ public String type;
// list of test tubes
public List tubes;
}
diff --git a/src/main/java/com/iflytop/a800/task/TubeRackTask.java b/src/main/java/com/iflytop/a800/task/TubeRackTask.java
index bfecdcb..7e52fe2 100644
--- a/src/main/java/com/iflytop/a800/task/TubeRackTask.java
+++ b/src/main/java/com/iflytop/a800/task/TubeRackTask.java
@@ -34,13 +34,13 @@ public class TubeRackTask extends TaskBase {
this.samplingTubes.add(tube);
tube.type = tubeRack.type;
- if ( !tube.type.equals(1) ) {
+ if ( !tube.type.equals("wb") ) {
continue;
}
Boolean isWb5ml = feeder.readIsWb5ml(i);
if ( isWb5ml ) {
- tube.type = 2;
+ tube.type = "wb5ml";
}
tube.barCode = feeder.readBarCode(i);
diff --git a/src/main/java/com/iflytop/a800/task/TubeTestTask.java b/src/main/java/com/iflytop/a800/task/TubeTestTask.java
index f1c37df..a31a801 100644
--- a/src/main/java/com/iflytop/a800/task/TubeTestTask.java
+++ b/src/main/java/com/iflytop/a800/task/TubeTestTask.java
@@ -1,25 +1,89 @@
package com.iflytop.a800.task;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.iflytop.a800.TaskBase;
-import com.iflytop.a800.resource.TestTube;
-import com.iflytop.a800.resource.TestTubeRack;
+import com.iflytop.a800.device.Device;
+import com.iflytop.a800.model.MdbIdChip;
+import com.iflytop.a800.model.MdbProject;
+import com.iflytop.a800.resource.*;
+import com.iflytop.a800.utils.ScanResultAnalysisAlgo;
import com.iflytop.uf.UfCmdSnippetExecutor;
+import com.iflytop.uf.util.UfCommon;
+import com.iflytop.uf.util.UfJsonHelper;
+
+import java.util.*;
+
public class TubeTestTask extends TaskBase {
+ // 测试项目
+ public MdbProject project;
public TestTubeRack tubeRack;
public TestTube tube;
public String status;
+ // 缓冲液试管
+ private BufferTube bufferTube;
+ // 大容量缓冲液试管
+ private LargeBufferTube largeBufferTube;
+ // 测试卡
+ private TestCard testCard;
+ // id chip
+ private MdbIdChip idChip;
+
+ // 任务准备
+ public void prepare() {
+ var device = Device.getInstance();
+ this.bufferTube = device.bufferTube.alloc();
+ this.largeBufferTube = device.largeBufferTube.getTube();
+ this.testCard = device.testCard.alloc();
+ this.idChip = new MdbIdChip();
+ this.idChip.peakCount = 3;
+ this.idChip.itemCount = 1;
+ this.idChip.scanPeakCount = 3;
+ this.idChip.items = UfJsonHelper.objectToJson(List.of(Map.of(
+ "item", "hsCRP",
+ "isPiecewiseFunction", false,
+ "nonPiecewiseFunction", Map.of(
+ "xValueSource", 1,
+ "serum", Map.of("a", 1.0, "b", 2.0, "c", 3.0, "d", 4.0),
+ "wb", Map.of("a", 1.0, "b", 2.0, "c", 3.0, "d", 4.0)
+ )
+ )));
+ }
+
@Override
public void run() {
- this.shake();
- this.uncap();
- this.sampling();
- this.cap();
- this.incubate();
- this.scan();
+ this.prepare();
+
+ ObjectMapper jsonMapper = new ObjectMapper();
+ JsonNode stepsJsonTree = null;
+ try {
+ stepsJsonTree = jsonMapper.readTree(this.project.steps);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+
+ for ( JsonNode stepNode : stepsJsonTree ) {
+ var stepEnable = stepNode.get("enable").asBoolean();
+ if ( !stepEnable ) {
+ continue;
+ }
+
+ var stepAction = stepNode.get("action").asText();
+ switch ( stepAction ) {
+// case "shaking" : this.shake(stepNode); break;
+ case "puncture" : this.executeStepPuncture(stepNode); break;
+ case "aspirate" : this.executeStepAspirate(stepNode); break;
+ 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;
+ }
+ }
}
// 摇匀
- private void shake() {
+ private void shake( JsonNode stepNode ) {
UfCmdSnippetExecutor.execute("SampleTestShake");
}
@@ -28,25 +92,206 @@ public class TubeTestTask extends TaskBase {
UfCmdSnippetExecutor.execute("SampleTestUnCap");
}
- // 取样
- private void sampling() {
- UfCmdSnippetExecutor.execute("SampleTestSamplingFromWb5ml");
- UfCmdSnippetExecutor.execute("SampleTestSamplingFromBufferTube");
- UfCmdSnippetExecutor.execute("SampleTestSamplingFromBufferTube");
+ // 穿孔
+ private void executeStepPuncture( JsonNode stepNode ) {
+ Device device = Device.getInstance();
+ var pipette = device.pipette;
+ pipette.tipPickUp();
+ pipette.puncture(this.bufferTube);
+ }
+
+ // 吸液
+ private void executeStepAspirate( JsonNode stepNode ) {
+ Device device = Device.getInstance();
+ var pipette = device.pipette;
+ pipette.tipPickUp();
+
+ String source = stepNode.get("source").asText();
+ Integer volume = stepNode.get("volume").asInt();
+ if ( "LargeBufferTube".equals(source) ) {
+ pipette.aspirateFromLargeBufferTube(this.largeBufferTube, volume);
+ } else if ( "Sample".equals(source) && "EmergencyTube".equals(this.tube.type) ) {
+ pipette.aspirateFromEmergencyTube(this.tube.index, volume);
+ } else if ( "Sample".equals(source) && "SampleEpp0_5Tube".equals(this.tube.type) ) {
+ pipette.aspirateFromSampleEpp0_5(this.tube.index, volume);
+ } else if ( "Sample".equals(source) && "SampleEpp1_5Tube".equals(this.tube.type) ) {
+ pipette.aspirateFromSampleEpp1_5(this.tube.index, volume);
+ } else if ( "Sample".equals(source) && "SampleWholeBlood5mlTube".equals(this.tube.type) ) {
+ pipette.aspirateFromWholeBlood5ml(this.tube.index, volume);
+ } else if ( "Sample".equals(source) && "SampleWholeBlood3mlTube".equals(this.tube.type) ) {
+ pipette.aspirateFromWholeBlood3ml(this.tube.index, volume);
+ } else {
+ throw new RuntimeException(String.format("无效的取样源 : %s/%s",source,this.tube.type));
+ }
+ pipette.dispense(this.bufferTube);
+ }
+
+ // 混匀
+ private void executeStepMixing( JsonNode stepNode ) {
+ Device device = Device.getInstance();
+ var pipette = device.pipette;
+ var mixCount = stepNode.get("count").asInt();
+ var mixVolume = stepNode.get("volume").asInt();
+ pipette.mix(this.bufferTube, mixCount, mixVolume);
}
- // 盖回
- private void cap() {
- UfCmdSnippetExecutor.execute("SampleTestCap");
+ // 丢弃吸头
+ private void executeStepDropTip( JsonNode stepNode ) {
+ Device device = Device.getInstance();
+ var pipette = device.pipette;
+ pipette.tipDrop();
}
// 孵育
- private void incubate() {
- UfCmdSnippetExecutor.execute("SampleTestIncubate");
+ private void executeStepIncubate( JsonNode stepNode ) {
+ Device device = Device.getInstance();
+ device.incubator.pushNewCard(this.testCard.boxIndex);
+
+ var pipette = device.pipette;
+ pipette.tipPickUp();
+
+ Integer volume = stepNode.get("volume").asInt();
+ pipette.aspirateFromBufferTubeAndDispenseToTestCard(this.bufferTube, volume);
+
+ pipette.tipDrop();
+
+ Integer duration = stepNode.get("duration").asInt();
+ UfCommon.delay(duration);
}
// 扫描
- private void scan() {
- UfCmdSnippetExecutor.execute("SampleTestScanResult");
+ private void executeStepAnalysis( JsonNode stepNode ) {
+ // 扫描
+ Device device = Device.getInstance();
+// device.incubator.exitToScanner();
+ var scanner = device.scanner;
+ scanner.scanTypeF();
+ var scanResult = scanner.readResult();
+ scanner.dropCard();
+
+ // 计算
+ var algo = new ScanResultAnalysisAlgo();
+ var algoResult = algo.calculate(scanResult, this.idChip.peakCount);
+
+ // 处理
+ String sampleType = "WB"; // @TODO : 这里要从样本中取 ~~~~
+ List