Browse Source

多组测试同时进行,检查锁

master
sige 1 year ago
parent
commit
cec9e0a61d
  1. BIN
      app.db
  2. 55
      src/main/java/com/iflytop/digester/DigestionTaskThread.java
  3. 4
      src/main/java/com/iflytop/digester/controller/HeatSlotController.java
  4. 2
      src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableSlot.java
  5. 48
      src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java
  6. 4
      src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java

BIN
app.db

55
src/main/java/com/iflytop/digester/DigestionTaskThread.java

@ -8,9 +8,7 @@ import com.iflytop.digester.underframework.dao.model.UfMdbOption;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class DigestionTaskThread extends Thread {
// 任务完成回调
public interface FinishCallback {
@ -148,6 +146,7 @@ public class DigestionTaskThread extends Thread {
this.taskModel.save();
if ( "auto".equals(this.taskModel.mode) ) {
this.lockLiquidPlate();
// 打开门
device.door.open();
// 等待放入试管架
@ -175,6 +174,7 @@ public class DigestionTaskThread extends Thread {
// 搬运到加热转盘
device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index);
this.unlockLiquidPlate();
// 加热
for ( var heating : digestionRound.heatings ) {
@ -184,6 +184,7 @@ public class DigestionTaskThread extends Thread {
}
// 移至加液区 以便执行下一轮
this.lockLiquidPlate();
device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index);
this.updateTaskStatus("RoundFinish", "配置轮次执行结束");
}
@ -204,6 +205,9 @@ public class DigestionTaskThread extends Thread {
}
this.updateTaskStatus("Liquid", "摇匀");
liquidAddition.shake(digestionRound.shakingCount);
// 搬运到加热转盘
device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index);
this.unlockLiquidPlate();
// 预检查定时 在结束前10分钟执行
Integer totalDurationCount = 0;
@ -245,6 +249,10 @@ public class DigestionTaskThread extends Thread {
this.updateTaskStatus("PreCheckWait", "预检完成");
}
// 移动到加液盘准备取出
this.lockLiquidPlate();
device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index); // 移动到加液盘
// 加水定容
if ( 0 < digestionRound.waterVolume ) {
this.updateTaskStatus("Water", String.format("加水定容 : %d", digestionRound.waterVolume));
@ -253,12 +261,12 @@ public class DigestionTaskThread extends Thread {
// 正常消解结束
this.updateTaskStatus("LastRound", "取出试管架");
device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index); // 移动到加液盘
device.door.open(); // 打开门
this.waitForTubeRackTakeOut(); // 等待取出
device.door.close(); // 关闭门
this.heatingSlot.setTubeRackNo(null); // 释放加热位
this.updateTaskStatus("LastRound", "执行最后一轮配置结束");
this.unlockLiquidPlate();
}
// 执行消解最后一轮预检查
@ -268,6 +276,8 @@ public class DigestionTaskThread extends Thread {
// 检查试管
var device = Device.getInstance();
this.lockLiquidPlate();
// 移动到加液盘
device.transferArm.moveTubeRackToLiquidPlate(this.heatingSlot.index);
// 拍照检查异常试管
@ -302,6 +312,7 @@ public class DigestionTaskThread extends Thread {
// 将正常试管放入加热转盘
device.transferArm.moveTubeRackToHeatingTurntable(this.heatingSlot.index);
this.unlockLiquidPlate();
// 启动异常处理线程
DigestionTaskThread.this.errorProcessThread = new Thread(DigestionTaskThread.this::executeErrorProcess);
@ -361,6 +372,7 @@ public class DigestionTaskThread extends Thread {
this.updateTaskStatus("TubeCheck", String.format("取出剩余异常试管 : [%s]", errorTubeIndexes));
// 如果还存在异常 则直接取出
var device = Device.getInstance();
this.lockLiquidPlate();
// 等待放入空试管架
device.door.open();
this.waitForEmptyTubeRackPutIn();
@ -377,6 +389,7 @@ public class DigestionTaskThread extends Thread {
device.door.open();
this.waitForTubeRackTakeOut();
device.door.close();
this.unlockLiquidPlate();
} catch (InterruptedException e) {
UfMdbNotification.error("消解异常处理失败 : " + e.getMessage());
this.updateTaskStatus("Error", String.format("消解异常处理失败 : %s", e.getMessage()));
@ -399,6 +412,7 @@ public class DigestionTaskThread extends Thread {
}
this.updateTaskStatus("ErrorRound", "移动异常试管架至加液区");
this.lockLiquidPlate();
device.transferArm.moveTubeRackToLiquidPlate(errorSlot.index);
var liquidAddition = device.liquidAddition;
@ -412,6 +426,7 @@ public class DigestionTaskThread extends Thread {
this.updateTaskStatus("ErrorRound", "移动异常试管架至加热区");
device.transferArm.moveTubeRackToHeatingTurntable(errorSlot.index);
this.unlockLiquidPlate();
for ( var heating : errorRound.heatings ) {
this.updateTaskStatus("ErrorRoundHeating", String.format("异常加热 %d℃ %d分钟", heating.temperature, heating.duration));
@ -420,19 +435,21 @@ public class DigestionTaskThread extends Thread {
}
this.updateTaskStatus("ErrorRound", "移动异常试管架至加液区");
this.lockLiquidPlate();
device.transferArm.moveTubeRackToLiquidPlate(errorSlot.index);
// 拍照检查是否存在消解完成的试管
this.executeErrorRoundTakeShotAndCheckFinishedTubes();
this.updateTaskStatus("ErrorRound", "移动异常试管架至加热区");
device.transferArm.moveTubeRackToHeatingTurntable(errorSlot.index);
// 如果不存在消解完成的试管则本轮次结束
if (this.finishedErrorTubeIndexes.isEmpty()) {
this.unlockLiquidPlate();
return ;
}
this.updateTaskStatus("ErrorRound", "移动异常试管架至加热区");
device.transferArm.moveTubeRackToHeatingTurntable(errorSlot.index);
// 等待放入空试管架
device.door.open();
this.waitForEmptyTubeRackPutIn();
@ -446,6 +463,7 @@ public class DigestionTaskThread extends Thread {
device.door.open();
this.waitForTubeRackTakeOut();
device.door.close();
this.unlockLiquidPlate();
// 更新异常试管索引列表
this.errorTubeIndexes.removeAll(this.finishedErrorTubeIndexes);
@ -539,6 +557,31 @@ public class DigestionTaskThread extends Thread {
this.updateTaskStatus("TubeRackTakeOutWaitDone", "试管架已取出");
}
// 使用加液盘
private void lockLiquidPlate() {
var lockName = this.taskModel.id;
if ( "manual".equals(this.taskModel.mode) ) {
lockName = this.taskModel.batchNo;
}
var device = Device.getInstance();
this.updateTaskStatus("WaitForLiquidPlate", "等待加液盘空闲");
device.liquidAddition.lockLiquidPlate(lockName);
this.updateTaskStatus("WaitForLiquidPlate", "锁定加液盘");
}
// 释放加液盘
private void unlockLiquidPlate() {
var lockName = this.taskModel.id;
if ( "manual".equals(this.taskModel.mode) ) {
lockName = this.taskModel.batchNo;
}
var device = Device.getInstance();
this.updateTaskStatus("WaitForLiquidPlate", "释放加液盘");
device.liquidAddition.unlockLiquidPlate(lockName);
}
// 更新任务状态
private void updateTaskStatus(String status, String message) {
LOG.info("[Digestion Task : {}] ({}) {}", taskModel.id, status, message);

4
src/main/java/com/iflytop/digester/controller/HeatSlotController.java

@ -8,6 +8,8 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
import java.util.UUID;
@Controller
public class HeatSlotController extends UfApiControllerBase {
@Resource
@ -26,6 +28,7 @@ public class HeatSlotController extends UfApiControllerBase {
String tubeRackNo = (String)params.get("tubeRackNo");
try {
var slot = this.device.heatingTurntable.allocSlot(tubeRackNo);
this.device.liquidAddition.lockLiquidPlate(tubeRackNo);
return this.success(slot);
} catch ( Exception e ) {
return this.error(e.getMessage());
@ -38,6 +41,7 @@ public class HeatSlotController extends UfApiControllerBase {
Integer slotIndex = (Integer)params.get("slotIndex");
try {
var slot = this.device.heatingTurntable.getSlotByIndex(slotIndex);
this.device.liquidAddition.unlockLiquidPlate(slot.tubeRackNo);
slot.setTubeRackNo(null);
return this.success();
} catch ( Exception e ) {

2
src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableSlot.java

@ -1,11 +1,9 @@
package com.iflytop.digester.deviceinstance;
import com.iflytop.digester.underframework.UfActuatorCmdExecutor;
import com.iflytop.digester.underframework.UfCmdSnippetExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HeatingTurntableSlot {
// 槽位索引
public Integer index = -1;

48
src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java

@ -17,9 +17,12 @@ public class LiquidAdditionInstance {
private List<LiquidAdditionLiquid> liquids;
// lock for bucket empty
private final Object bucketEmptyLock = new Object();
// locks for liquid plate
private final List<String> liquidPlateLocks = new ArrayList<>();
// setup
public void setup() {
this.liquidPlateLocks.clear();
this.liquids = new ArrayList<>();
for (int i = 0; i < 8; i++) {
LiquidAdditionLiquid liquid = new LiquidAdditionLiquid();
@ -31,6 +34,43 @@ public class LiquidAdditionInstance {
}
}
// lock liquid plate
public void lockLiquidPlate( String lockName ) {
MdbRuntimeLog.log("LiquidPlateLock", "加液盘锁定等待 : %s", lockName);
this.liquidPlateLocks.add(lockName);
if ( 1 == this.liquidPlateLocks.size() ) {
MdbRuntimeLog.log("LiquidPlateLock", "加液盘锁定成功 : %s", lockName);
return ;
}
synchronized ( lockName ) {
try {
lockName.wait();
MdbRuntimeLog.log("LiquidPlateLock", "加液盘锁定成功 : %s", lockName);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// unlock liquid plate
public void unlockLiquidPlate( String lockName ) {
MdbRuntimeLog.log("LiquidPlateLock", "加液盘锁定解除 : %s", lockName);
String lock = null;
for ( String lockItem : this.liquidPlateLocks ) {
if ( lockItem.equals(lockName) ) {
lock = lockItem;
}
}
this.liquidPlateLocks.remove(lock);
if (this.liquidPlateLocks.isEmpty()) {
return ;
}
Object nextLock = this.liquidPlateLocks.remove(0);
synchronized ( nextLock ) {
nextLock.notify();
}
}
// get liquids
public List<LiquidAdditionLiquid> getLiquids() {
return this.liquids;
@ -95,6 +135,13 @@ public class LiquidAdditionInstance {
// 检查液体量
private void bucketVolumeCheck( Integer pumpIndex ) {
var env = UfApplication.getApp().getEnv();
Boolean bucketVolumeCheckEnable = env.getProperty("app.bucketVolumeCheckEnable", Boolean.class);
assert null != bucketVolumeCheckEnable;
if ( !bucketVolumeCheckEnable ) {
return ;
}
var liquid = liquids.get((0==pumpIndex%2) ? pumpIndex/2 : (pumpIndex-1)/2);
var stateStr = UfActuatorCmdExecutor.execute("LiquidBucketVolumeIO", "module_readio");
var state = Integer.parseInt(stateStr);
@ -108,7 +155,6 @@ public class LiquidAdditionInstance {
liquid.setVolume(0);
// 如果缺少的液体不是水 则需要发送通知手动补充
var env = UfApplication.getApp().getEnv();
Integer waterBucketIndex = env.getProperty("app.liquidWaterBucketIndex", Integer.class);
assert waterBucketIndex != null;
if (!waterBucketIndex.equals(liquid.bucketIndex)) {

4
src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java

@ -28,7 +28,9 @@ public class UfActiveRecord {
String tableName = UfActiveRecord.getTableNameFromModelClass(this.getClass());
Map<String,Object> data = UfActiveRecord.exportModelData(this);
if ( this.isNewRecord ) {
this.id = UUID.randomUUID().toString();
if ( null == this.id ) {
this.id = UUID.randomUUID().toString();
}
data.put("id", this.id);
mapper.insert(tableName, data);
this.isNewRecord = false;

Loading…
Cancel
Save