28 changed files with 763 additions and 285 deletions
-
241doc/代码框架.md
-
3src/main/java/a8k/controler/extapi/pagecontrol/ExtApiTabConfig.java
-
7src/main/java/a8k/optalgo/OptAlgo.java
-
9src/main/java/a8k/optalgo/type/OptAlgoError.java
-
14src/main/java/a8k/optalgo/type/OptAlgoResult.java
-
11src/main/java/a8k/optalgo/type/PeakInfo.java
-
31src/main/java/a8k/service/app/AppA8kDeviceStateMgrService.java
-
3src/main/java/a8k/service/app/AppConsumablesMgrService.java
-
3src/main/java/a8k/service/app/AppDeviceInitializationModule.java
-
4src/main/java/a8k/service/app/AppSampleFormulaMgrService.java
-
105src/main/java/a8k/service/appctrl/AppCoreCtrlService.java
-
89src/main/java/a8k/service/appctrl/AppRunTask.java
-
28src/main/java/a8k/service/appstate/A8kState.java
-
6src/main/java/a8k/service/appstate/type/EmergencyPosRunState.java
-
5src/main/java/a8k/service/appstate/type/IncubationPlateStatus.java
-
7src/main/java/a8k/service/appstate/type/ReactingPlateState.java
-
4src/main/java/a8k/service/appstate/type/SampleState.java
-
16src/main/java/a8k/service/appstate/type/TubeHolderState.java
-
26src/main/java/a8k/service/bak_appbase/A8kDeviceState.java
-
6src/main/java/a8k/service/bak_appbase/progress/TubeHolderProgress.java
-
20src/main/java/a8k/service/bak_appbase/runstate/TubeHolderRunState.java
-
4src/main/java/a8k/type/exception/ActionBreakException.java
-
4src/main/java/a8k/type/exception/AppPauseException.java
@ -0,0 +1,241 @@ |
|||||
|
/* |
||||
|
* |
||||
|
* while(!isWaitingForStop()){ |
||||
|
* if(当前样本处理完成){ |
||||
|
* if(入料口有样本){ |
||||
|
* 扫描样本 && 判断耗材是否充足 |
||||
|
* 如果耗材不足, |
||||
|
* 提示用户(抛出提示事件), |
||||
|
* 暂停设备(退出线程(抛出pause异常)) |
||||
|
* 如果扫描样本有误 |
||||
|
* 提示用户 |
||||
|
* 暂停设备 |
||||
|
* } |
||||
|
* } |
||||
|
* else{ |
||||
|
* 处理样本 |
||||
|
* } |
||||
|
* } |
||||
|
* |
||||
|
* try{ |
||||
|
* |
||||
|
* }catch(PauseException e){ |
||||
|
* //pauseSelf |
||||
|
* //抛出事件 |
||||
|
* } |
||||
|
* |
||||
|
* if(event){ |
||||
|
* pauseSampleProcessThread(); |
||||
|
* } |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
经验: |
||||
|
动作与赋值分开 |
||||
|
当一组动作完全执行完之后,再赋值给状态,这样就可以使得动作在执行过程中任意时间点都可以被打断。 |
||||
|
|
||||
|
|
||||
|
while(true){ |
||||
|
TubeCfg cfg = getTubeCfg(i); |
||||
|
moveTubeHolderProcessPos |
||||
|
if(tubeType == xxx) |
||||
|
takeTube |
||||
|
shakeTube(times,degree) |
||||
|
takeHap |
||||
|
move |
||||
|
else if(){ |
||||
|
... |
||||
|
|
||||
|
} |
||||
|
pausePoint; |
||||
|
} |
||||
|
|
||||
|
问题: |
||||
|
有两种暂停状态: |
||||
|
一种是复位势暂停。 |
||||
|
一种是保持现状势暂停。(前提是循环中) |
||||
|
|
||||
|
pause/stop |
||||
|
|
||||
|
|
||||
|
动作划分为状态机 |
||||
|
scan{ |
||||
|
. |
||||
|
. |
||||
|
. |
||||
|
. |
||||
|
} |
||||
|
|
||||
|
|
||||
|
状态机->enter |
||||
|
状态机->enter |
||||
|
|
||||
|
|
||||
|
{ |
||||
|
IDLE |
||||
|
{ |
||||
|
if(state.eq(wokring)){ |
||||
|
state.changeTo(scanPrepare) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
SCANPREPARE |
||||
|
{ |
||||
|
enterState |
||||
|
exitState |
||||
|
|
||||
|
if(ioTrigger){ |
||||
|
moveTubeHolderTo |
||||
|
waitForIoTrigger |
||||
|
changeStateTo(scanTubeHolderType) |
||||
|
if(error){ |
||||
|
changeStateToError |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
SCANHODLER |
||||
|
{ |
||||
|
move |
||||
|
scan |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
|
SCAN |
||||
|
|
||||
|
PAUSE |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
``` |
||||
|
用户PAUSE --> 暂停,恢复,全局状态的变更。 |
||||
|
遇到错误 --> 通知,记录,清空工作位。无需恢复。 |
||||
|
状态机 --> |
||||
|
修改全局状态。 |
||||
|
记录。 |
||||
|
执行动作。 |
||||
|
|
||||
|
|
||||
|
|
||||
|
前端接口: |
||||
|
pause; |
||||
|
continue; |
||||
|
|
||||
|
|
||||
|
全局都有哪些状态? |
||||
|
1. 类似于配置, |
||||
|
初始化 |
||||
|
运行过程中修改(前端提交) |
||||
|
|
||||
|
2. 运行过程控制,记录当前设备运行到哪一步,以便执行下一步。 |
||||
|
|
||||
|
|
||||
|
步骤与暂停之间的关系。 |
||||
|
步骤与恢复? |
||||
|
|
||||
|
|
||||
|
步骤与停止之间的关系。 |
||||
|
|
||||
|
步骤 |
||||
|
步骤 |
||||
|
步骤 |
||||
|
步骤 |
||||
|
步骤 |
||||
|
暂停 |
||||
|
步骤 |
||||
|
|
||||
|
---------------------------------------------- |
||||
|
每一步都有几种处理方法 |
||||
|
1. firstEnter |
||||
|
checkCondition是否满足 |
||||
|
2. finalExit |
||||
|
3. loop |
||||
|
4. pause |
||||
|
5. continue |
||||
|
|
||||
|
waitting_for_take_sample |
||||
|
|
||||
|
pause |
||||
|
stepPause; |
||||
|
stepContinue; |
||||
|
|
||||
|
stop |
||||
|
|
||||
|
|
||||
|
协作? |
||||
|
全局状态 |
||||
|
|
||||
|
|
||||
|
|
||||
|
{ |
||||
|
|
||||
|
take_tip |
||||
|
take_xxx |
||||
|
put_xxx |
||||
|
waitting_for |
||||
|
onPause{ |
||||
|
.... |
||||
|
} |
||||
|
onStop{ |
||||
|
... |
||||
|
} |
||||
|
|
||||
|
pauseCondtion{ |
||||
|
... |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
{ |
||||
|
pause... |
||||
|
} |
||||
|
|
||||
|
pause_point |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
|
||||
|
``` |
||||
|
服务的提供者, |
||||
|
服务的使用者, |
||||
|
|
||||
|
相互配合呢? |
||||
|
|
||||
|
triggerHasTakeSample |
||||
|
doNext |
||||
|
|
||||
|
|
||||
|
---处理--- |
||||
|
| | |
||||
|
| --搬运--(等待) |
||||
|
| | |
||||
|
扫描与预处理(等待) 抛出事件。 |
||||
|
|
||||
|
|
||||
|
机械臂 |
||||
|
takeSampleEnd |
||||
|
|
||||
|
---------------------------- |
||||
|
暂停: |
||||
|
waitingForPause,不需要弹出,只有单次循环结束 |
||||
|
停止: |
||||
|
break? |
||||
|
异常: |
||||
|
exception? |
||||
|
|
||||
|
|
||||
|
第一假如需要允许暂停,则需要将步骤进行拆分,暂停点作为一步。 |
||||
|
|
||||
|
|
||||
|
机械动作的暂停,涉及到,暂停和暂停恢复,不能简单的在代码中添加一个pause就可以的。 |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
``` |
@ -0,0 +1,7 @@ |
|||||
|
package a8k.optalgo; |
||||
|
|
||||
|
public class OptAlgo { |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
package a8k.optalgo.type; |
||||
|
|
||||
|
public enum OptAlgoError { |
||||
|
Success, |
||||
|
LostPeak, |
||||
|
LostPeakStart, |
||||
|
LostPeakEnd, |
||||
|
} |
||||
|
|
@ -0,0 +1,14 @@ |
|||||
|
package a8k.optalgo.type; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public class OptAlgoResult { |
||||
|
// vector<float> ogigin_val; // 1200 |
||||
|
// vector<float> supper_val; // 原始数据,线性填充,1200*5=6000 |
||||
|
// vector<float> supper_median_val; // supper_val 窗口平滑滤波,6000 |
||||
|
// vector<float> supper_smooth_sub_val; // supper_smooth_val 均值压缩,6000/6=1000 |
||||
|
public Float[] ogiginVal; |
||||
|
public Float[] supperVal; |
||||
|
public Float[] supperMedianVal; |
||||
|
public Float[] supperSmoothSubVal; |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package a8k.optalgo.type; |
||||
|
|
||||
|
public class PeakInfo { |
||||
|
public Boolean findPeak; |
||||
|
public Float peakFullArea; |
||||
|
public Float peakBaseLineArea; |
||||
|
public Float area; |
||||
|
public Integer peakPos; |
||||
|
public Integer peakStartPos; |
||||
|
public Integer peakEndPos; |
||||
|
} |
@ -0,0 +1,105 @@ |
|||||
|
package a8k.service.appctrl; |
||||
|
|
||||
|
import a8k.controler.extapi.pagecontrol.ExtApiTabConfig; |
||||
|
import a8k.controler.extapi.utils.ExtApiTab; |
||||
|
import a8k.service.app.AppA8kDeviceStateMgrService; |
||||
|
import a8k.service.bak_appbase.progress.TubeHolderProgress; |
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
import jakarta.annotation.Resource; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@ExtApiTab(cfg = ExtApiTabConfig.AppCoreCtrlService) |
||||
|
@Component |
||||
|
public class AppCoreCtrlService { |
||||
|
|
||||
|
@Resource |
||||
|
AppA8kDeviceStateMgrService sms; |
||||
|
|
||||
|
AppRunTask sampleScanAndPreProcessThread; |
||||
|
AppRunTask sampleProcessThread; |
||||
|
AppRunTask incubationPlateCtrlThread; |
||||
|
AppRunTask plateClampResultScanThread; |
||||
|
|
||||
|
|
||||
|
@PostConstruct |
||||
|
void init() { |
||||
|
sampleScanAndPreProcessThread = new AppRunTask(); |
||||
|
sampleProcessThread = new AppRunTask(); |
||||
|
incubationPlateCtrlThread = new AppRunTask(); |
||||
|
plateClampResultScanThread = new AppRunTask(); |
||||
|
|
||||
|
sampleScanAndPreProcessThread.init(this::sampleScanAndPreProcessThreadWorkFn); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void startWork() { |
||||
|
//启动所有线程 |
||||
|
// setGState,notify |
||||
|
} |
||||
|
|
||||
|
public void pauseWork() { |
||||
|
//暂停掉 入料和样本处理线程 |
||||
|
// setGstate,notify |
||||
|
// waitForStop |
||||
|
// waitForStop |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
public void continueWork() { |
||||
|
//继续入料和样本处理线程 |
||||
|
//setGState |
||||
|
//notify |
||||
|
} |
||||
|
|
||||
|
public void stopWork() { |
||||
|
//停止所有线程 |
||||
|
//setGState |
||||
|
//notify |
||||
|
//waitForStop |
||||
|
} |
||||
|
|
||||
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
||||
|
* PRIV 私有方法 |
||||
|
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ |
||||
|
|
||||
|
private void doSampleScanAndPreProcessThreadWorkFn() { |
||||
|
AppRunTask appRunTask = sampleScanAndPreProcessThread; |
||||
|
while (!appRunTask.isWaitingForStop()) { |
||||
|
//试管架处理状态-空闲 |
||||
|
if (sms.getTubeHolderProgress().equals(TubeHolderProgress.Idle)) { |
||||
|
} else if (sms.getTubeHolderProgress().equals(TubeHolderProgress.Processing)) { |
||||
|
} else if (sms.getTubeHolderProgress().equals(TubeHolderProgress.Scaning)) { |
||||
|
} |
||||
|
} |
||||
|
/* |
||||
|
* |
||||
|
* motorRun |
||||
|
* waitForTrigger |
||||
|
* scanTubeHolderType |
||||
|
* pausePoint() |
||||
|
* for(int i < 6){ |
||||
|
* scanTubeAndAssignTubeCfg; |
||||
|
* pausePoint(){throw PauseException;} |
||||
|
* } |
||||
|
* assignTubeCfg(); |
||||
|
* |
||||
|
* 用户暂停 |
||||
|
* 程序出错主动暂停 |
||||
|
* |
||||
|
* // pause |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
private void sampleScanAndPreProcessThreadWorkFn() { |
||||
|
try { |
||||
|
doSampleScanAndPreProcessThreadWorkFn(); |
||||
|
} catch (Exception ignored) { |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,89 @@ |
|||||
|
package a8k.service.appctrl; |
||||
|
|
||||
|
|
||||
|
public class AppRunTask { |
||||
|
|
||||
|
Thread workThread; |
||||
|
Runnable task; |
||||
|
|
||||
|
Boolean ctrlState = false; |
||||
|
Boolean runState = false; |
||||
|
|
||||
|
public AppRunTask() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public void init(Runnable task) { |
||||
|
this.task = task; |
||||
|
this.workThread = new Thread(this::work); |
||||
|
this.workThread.start(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private void work() { |
||||
|
while (true) { |
||||
|
if (ctrlState) { |
||||
|
runState = true; |
||||
|
if (task != null) |
||||
|
task.run(); |
||||
|
runState = false; |
||||
|
} else { |
||||
|
sleep(500); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public Boolean isWaitingForStop() { |
||||
|
return !ctrlState; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 启动线程 |
||||
|
*/ |
||||
|
public void start() { |
||||
|
ctrlState = true; |
||||
|
this.task.notify(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 停止线程 |
||||
|
*/ |
||||
|
public void stop() { |
||||
|
ctrlState = false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 等待线程停止 |
||||
|
*/ |
||||
|
public void waitForStop() { |
||||
|
while (runState) { |
||||
|
sleep(10); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 睡眠 |
||||
|
* @param mills 毫秒 |
||||
|
*/ |
||||
|
public void sleep(Integer mills) { |
||||
|
try { |
||||
|
Thread.sleep(mills); |
||||
|
} catch (InterruptedException ignored) { |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 强制睡眠,不会被打断 |
||||
|
* @param mills 毫秒 |
||||
|
*/ |
||||
|
public void forceSleep(Integer mills) { |
||||
|
int end = mills + (int) System.currentTimeMillis(); |
||||
|
while (System.currentTimeMillis() < end) { |
||||
|
sleep(50); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package a8k.service.appstate; |
||||
|
|
||||
|
import a8k.service.appstate.type.*; |
||||
|
import a8k.service.bak_appbase.progress.TubeHolderProgress; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public class A8kState { |
||||
|
public TubeHolderProgress tubeHolderProgress = TubeHolderProgress.Idle; |
||||
|
|
||||
|
|
||||
|
//当前正在被处理的试管架状态 |
||||
|
public TubeHolderState tubeHolderState = new TubeHolderState(); |
||||
|
//急诊为状态 |
||||
|
public EmergencyPosRunState emergencyPosRunState = new EmergencyPosRunState(); |
||||
|
//孵育盘状态 |
||||
|
public IncubationPlateStatus incubationPlateStatus = new IncubationPlateStatus(); |
||||
|
//温度 |
||||
|
public Integer temperature = 25; |
||||
|
//设备是否初始化过 |
||||
|
public Boolean deviceInited = false; |
||||
|
|
||||
|
//所有样本的状态(包含本次开机已经处理过的样本的状态) |
||||
|
public List<SampleState> sampleStates; |
||||
|
//所有反应盘的状态(包含本次开机已经处理过的反应盘的状态) |
||||
|
public List<ReactingPlateState> reactingPlateStates; |
||||
|
|
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
package a8k.service.appstate.type; |
||||
|
|
||||
|
public class IncubationPlateStatus { |
||||
|
public ReactingPlateState[] plateStates = new ReactingPlateState[20]; |
||||
|
} |
@ -1,9 +1,9 @@ |
|||||
package a8k.service.bak_appbase.runstate; |
|
||||
|
package a8k.service.appstate.type; |
||||
|
|
||||
import a8k.type.sampleinfo.SampleInfo; |
import a8k.type.sampleinfo.SampleInfo; |
||||
import a8k.service.bak_appbase.progress.TubeProcessProgress; |
import a8k.service.bak_appbase.progress.TubeProcessProgress; |
||||
|
|
||||
public class TubeRunState { |
|
||||
|
public class SampleState { |
||||
public TubeProcessProgress tubeProcessProgress = TubeProcessProgress.EMPTY; //样本运行状态 |
public TubeProcessProgress tubeProcessProgress = TubeProcessProgress.EMPTY; //样本运行状态 |
||||
public SampleInfo bindSample = new SampleInfo(); //绑定的样本运行状态 |
public SampleInfo bindSample = new SampleInfo(); //绑定的样本运行状态 |
||||
} |
} |
@ -0,0 +1,16 @@ |
|||||
|
package a8k.service.appstate.type; |
||||
|
|
||||
|
import a8k.type.type.A8kTubeType; |
||||
|
import a8k.type.type.BloodType; |
||||
|
import a8k.service.bak_appbase.progress.TubeHolderProgress; |
||||
|
|
||||
|
public class TubeHolderState { |
||||
|
public A8kTubeType tubeHolderType = A8kTubeType.BloodTube; //管子类型 |
||||
|
public BloodType bloodType = BloodType.WHOLE_BLOOD; //血型 |
||||
|
|
||||
|
//样本状态 |
||||
|
public SampleState[] sampleStates = new SampleState[10]; |
||||
|
|
||||
|
public TubeHolderProgress tubeHolderProgress = TubeHolderProgress.Idle; //管子状态 |
||||
|
public Integer processingTubeIndex = -1; //当前正在被处理的试管索引 |
||||
|
} |
@ -1,26 +0,0 @@ |
|||||
package a8k.service.bak_appbase; |
|
||||
|
|
||||
import a8k.service.app.app_consumables_mgr_service.ConsumableState; |
|
||||
import a8k.service.bak_appbase.runstate.ReactingPlateRunState; |
|
||||
import a8k.service.bak_appbase.runstate.EmergencyPosRunState; |
|
||||
import a8k.service.bak_appbase.runstate.TubeHolderRunState; |
|
||||
|
|
||||
import java.util.List; |
|
||||
|
|
||||
public class A8kDeviceState { |
|
||||
//耗材状态 |
|
||||
public ConsumableState consumable = new ConsumableState(); |
|
||||
//急诊为状态 |
|
||||
public EmergencyPosRunState emergencyPosRunState = new EmergencyPosRunState(); |
|
||||
//正在孵育的任务状态 |
|
||||
public List<ReactingPlateRunState> incubatingPlateStates = null; |
|
||||
//当前正在被处理的试管架状态 |
|
||||
public TubeHolderRunState tubeHolderRunState = new TubeHolderRunState(); |
|
||||
//温度 |
|
||||
public Integer temperature = 25; |
|
||||
|
|
||||
|
|
||||
public Boolean deviceInited = false; //设备是否初始化过 |
|
||||
public Boolean devicePoweredOffNormally = false; //设备是否正常关机 |
|
||||
|
|
||||
} |
|
@ -1,7 +1,7 @@ |
|||||
package a8k.service.bak_appbase.progress; |
package a8k.service.bak_appbase.progress; |
||||
|
|
||||
public enum TubeHolderProgress { |
public enum TubeHolderProgress { |
||||
TubeHolderStateIdle, //空闲 |
|
||||
TubeHolderStateProcessing, //处理中 |
|
||||
TubeHolderStateProcessed, //处理完成 |
|
||||
|
Idle, //空闲 |
||||
|
Processing, //处理中 |
||||
|
Scaning, //处理中 |
||||
} |
} |
@ -1,20 +0,0 @@ |
|||||
package a8k.service.bak_appbase.runstate; |
|
||||
|
|
||||
import a8k.type.type.A8kTubeType; |
|
||||
import a8k.type.type.BloodType; |
|
||||
import a8k.service.bak_appbase.progress.TubeHolderProgress; |
|
||||
|
|
||||
public class TubeHolderRunState { |
|
||||
public BloodType bloodType = BloodType.WHOLE_BLOOD; //血型 |
|
||||
public A8kTubeType tubeHolderType = A8kTubeType.BloodTube; //管子类型 |
|
||||
public TubeHolderProgress tubeHolderProgress = TubeHolderProgress.TubeHolderStateIdle; //管子状态 |
|
||||
public TubeRunState[] tubeRunStates = new TubeRunState[10]; //管子 |
|
||||
public Integer processingTubeIndex = -1; //当前正在被处理的试管索引 |
|
||||
|
|
||||
public TubeHolderRunState() { |
|
||||
for (int i = 0; i < tubeRunStates.length; i++) { |
|
||||
tubeRunStates[i] = new TubeRunState(); |
|
||||
} |
|
||||
processingTubeIndex = 1; |
|
||||
} |
|
||||
} |
|
@ -1,4 +0,0 @@ |
|||||
package a8k.type.exception; |
|
||||
|
|
||||
public class ActionBreakException extends Exception { |
|
||||
} |
|
@ -0,0 +1,4 @@ |
|||||
|
package a8k.type.exception; |
||||
|
|
||||
|
public class AppPauseException extends Exception { |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue