sige 1 year ago
parent
commit
41a1b71ec1
  1. BIN
      app.db
  2. 248
      src/main/java/com/iflytop/digester/StartResetTaskThread.java
  3. 31
      src/main/java/com/iflytop/digester/controller/DeviceController.java
  4. 21
      src/main/java/com/iflytop/digester/controller/HeatSlotController.java
  5. 21
      src/main/java/com/iflytop/digester/controller/LiquidController.java
  6. 19
      src/main/java/com/iflytop/digester/deviceinstance/Device.java
  7. 5
      src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java
  8. 8
      src/main/java/com/iflytop/digester/deviceinstance/LiquidAdditionInstance.java
  9. 17
      src/main/java/com/iflytop/digester/underframework/controller/UfApiDictionary.java
  10. 18
      src/main/java/com/iflytop/digester/underframework/controller/UfApiRuntimeVariable.java
  11. 33
      src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbDictItem.java
  12. 67
      src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java
  13. 7
      src/main/java/com/iflytop/digester/underframework/dao/record/UfActiveRecord.java
  14. 2
      web

BIN
app.db

248
src/main/java/com/iflytop/digester/StartResetTaskThread.java

@ -0,0 +1,248 @@
package com.iflytop.digester;
import com.iflytop.digester.deviceinstance.Device;
import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable;
public class StartResetTaskThread extends Thread {
// 是否需要放置异常处理试管架
private Boolean isErrorTubeRackRequired = true;
@Override
public void run() {
var device = Device.getInstance();
device.setStatus("preparing");
this.setProgressMessage("设备初始化...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// this.getDevice().getIO().setValue("LightRed", 1);
//
// this.setProgressMessage("设备初始化 : 关闭设备门");
// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class);
// doorMotor.setEnable(true);
// MoveDoorClose.execute(this.getDevice());
//
// this.setProgressMessage("设备初始化 : 加液臂复位");
// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class);
// liquidMotor.setEnable(true);
// liquidMotor.reset();
// liquidMotor.moveTo("LiquidArmStandby");
//
// this.setProgressMessage("设备初始化 : 关闭夹爪");
// DiActServo transferClipServo = this.getActuator(MyDevice.ACT_TRANSFER_CLIP_SERVO, DiActServo.class);
// transferClipServo.setEnable(true);
// transferClipServo.moveTo("TransClipServoClose");
//
// this.setProgressMessage("设备初始化 : 搬运机械臂上下移动复位");
// DiActMotor transUdMotor = this.getActuator(MyDevice.ACT_TRANSFER_UD_MOTOR, DiActMotor.class);
// transUdMotor.setEnable(true);
// transUdMotor.reset();
// transUdMotor.moveTo("TransUdMotorStandby");
//
// this.setProgressMessage("设备初始化 : 搬运机械臂左右移动复位");
// DiActMotor transLrMotor = this.getActuator(MyDevice.ACT_TRANSFER_LR_MOTOR, DiActMotor.class);
// transLrMotor.setEnable(true);
// transLrMotor.reset();
// transLrMotor.setMoveOffset("TransLrMotorGlobalOffset");
// transLrMotor.moveTo("TransLrMotorStandby");
//
// // @TODO : http://127.0.0.1:5566/issues/39
// this.setProgressMessage("设备初始化 : 加液转盘复位");
// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class);
// liquidPlateMotor.setEnable(true);
// liquidPlateMotor.reset();
//
// // @TODO : http://127.0.0.1:5566/issues/40
// this.setProgressMessage("设备初始化 : 加热盘转盘复位");
// DiActMotor heatPlateMotor = this.getActuator(MyDevice.ACT_HEAT_PLATE_MOTOR, DiActMotor.class);
// heatPlateMotor.setEnable(true);
// heatPlateMotor.reset();
// heatPlateMotor.moveTo("HeatPlateStandby");
//
// this.setupHeatingSlotCover();
// this.setupPeristalticPump();
//
// this.setProgressMessage("设备初始化 : 相机");
// DiActCameraBasler camera = this.getActuator(MyDevice.ACT_CAMERA, DiActCameraBasler.class);
// camera.setEnable(true);
//
// this.setProgressMessage("设备初始化 : 定时刷新加热盘温度");
// var slotMan = this.getResourceManager(ResHeatingTubeRackSlotManager.class);
// slotMan.startTemperatureRefresh();
//
// if ( this.isErrorTubeRackRequired ) {
// this.setProgressMessage("设备初始化 : 放入异常处理试管架");
// doorMotor.reset(); // 打开设备门
// DiMdbNotification.taskAction(this, "TaskStartResetErrorTubeRackPutIn");
// this.waitAction("TaskStartResetErrorTubeRackPutIn");
// }
//
// this.getDevice().getIO().setValue("LightRed", 0);
// this.getDevice().getIO().setValue("LightGreen", 1);
this.setProgressMessage("设备初始化 : 完成");
device.setStatus("ready");
UfMdbRuntimeVariable.setString("设备已就绪","device.message");
}
//
// // 设置蠕动泵
// private void setupPeristalticPump() {
// int peristalticPumpCount = 1;
// var actuators = this.getDevice().getActuators().getAll();
// for ( var actuator : actuators ) {
// if (actuator instanceof DiActPeristalticPump pump) {
// this.setProgressMessage("设备初始化 : 蠕动泵复位 " + peristalticPumpCount + "/16");
// pump.setEnable(true);
// peristalticPumpCount++;
// }
// }
//
// Boolean enableSetup = this.getDevice().getEnv().getProperty("app.liquidPeristalticPumpPipeSetupEnable",Boolean.class);
// assert enableSetup != null;
// if ( !enableSetup ) {
// return ;
// }
//
// DiActMotor liquidPlateMotor = this.getActuator(MyDevice.ACT_LIQUID_PLATE_MOTOR, DiActMotor.class);
// DiActMotor liquidMotor = this.getActuator(MyDevice.ACT_LIQUID_MOTOR, DiActMotor.class);
//
// this.setProgressMessage("设备初始化 : 初始化加液管路");
// MoveDoorOpen.execute(this.getDevice());
// DiMdbNotification.taskAction(this, "TaskStartResetPumpPipeSetupTubeRankPutIn");
// this.waitAction("TaskStartResetPumpPipeSetupTubeRankPutIn");
// MoveDoorClose.execute(this.getDevice());
//
// // 加液管充满
// for ( int i=0; i<8; i++ ) {
// this.setProgressMessage("设备初始化 : 初始化加液管路 " + (i+1) + "/8");
// if ( 0 == i%2 ) {
// liquidMotor.moveTo("LiquidArmPumpGroupOut");
// liquidPlateMotor.moveTo("LiquidPlateSlotPumpOutGroup",i/2);
// } else {
// liquidMotor.moveTo("LiquidArmPumpGroupIn");
// liquidPlateMotor.moveTo("LiquidPlateSlotPumpInGroup", i/2);
// }
//
// var pump0 = this.getActuator("LiquidPeristalticPump_"+i+"_0", DiActPeristalticPump.class);
// var pump1 = this.getActuator("LiquidPeristalticPump_"+i+"_1", DiActPeristalticPump.class);
// var pipeVolumeCircle0 = pump1.getLocationValue("LiquidPeristalticPumpPipeVolumeCircle",i, 0);
// var pipeVolumeCircle1 = pump1.getLocationValue("LiquidPeristalticPumpPipeVolumeCircle",i, 1);
// this.batchExecute(List.of(
// () -> pump0.moveBy(pipeVolumeCircle0),
// () -> pump1.moveBy(pipeVolumeCircle1)
// ));
// pump0.retract();
// pump1.retract();
// }
//
// liquidMotor.moveTo("LiquidArmStandby");
//
// // 加液管充满, 需要取出试管架
// MoveDoorOpen.execute(this.getDevice());
// DiMdbNotification.taskAction(this, "TaskStartResetPumpPipeSetupTubeRankTakeOut");
// this.waitAction("TaskStartResetPumpPipeSetupTubeRankTakeOut");
// MoveDoorClose.execute(this.getDevice());
// }
//
// /**
// * 清理试管架
// * @issue : <a href="http://127.0.0.1:5566/issues/85">无法获取加液位置是否存在试管架</a>
// */
// private void setupHeatingSlotCover() {
// boolean isDoorOpen = false;
// Integer errorSlotIndex = this.getDevice().getEnv().getProperty("app.errorSlotIndex",Integer.class);
//
// for ( int i=0; i<5; i++ ) {
// this.setProgressMessage("设备初始化 : 检查试管架 " + (i+1) + "/5");
// String key = "HeatingPlateMotorSlotCover_" + i;
// DiActServo heatSlotCoverServo = this.getActuator(key, DiActServo.class);
// heatSlotCoverServo.setEnable(true);
// var currentPos = heatSlotCoverServo.getCurrentPos();
// LOG.info("HeatingPlateMotorSlotCover #{} : current pos = {}", i, currentPos);
//
// // 如果是空的则初始化位置后继续下一步
// var rackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverRackExists");
// if ( currentPos > rackExistsPos ) {
// heatSlotCoverServo.setCurrentPosAsMiddle();
// continue;
// }
//
// // 如果是空试管架 又是异常区域则不处理 因为异常区域始终要有个试管架
// var emptyRackExistsPos = heatSlotCoverServo.getLocationValue("HeatingPlateMotorSlotCoverEmptyRackExists");
// if ( currentPos > emptyRackExistsPos && null != errorSlotIndex && errorSlotIndex == i ) { // 异常区域存在空试管架
// this.isErrorTubeRackRequired = false;
// continue;
// }
//
// var moveToLiquidPlate = new MoveMoveTubeRackFromHeatPlateToLiquidPlate();
// moveToLiquidPlate.setDevice(this.getDevice());
// moveToLiquidPlate.slotIndex = i;
// moveToLiquidPlate.updateSlotStatus = false;
// moveToLiquidPlate.run();
//
// if ( !isDoorOpen ) {
// MoveDoorOpen.execute(this.getDevice());
// isDoorOpen = true;
// }
//
// heatSlotCoverServo.moveTo("HeatingPlateMotorSlotCoverEmpty");
// heatSlotCoverServo.setEnable(false);
//
// // 等待取出试管架
// DiMdbNotification.taskAction(this, "TaskStartResetErrorTubeRackTakeOut");
// this.waitAction("TaskStartResetErrorTubeRackTakeOut");
// LOG.info("HeatingPlateMotorSlotCover #{} : take out", i);
//
// heatSlotCoverServo.setEnable(true);
// heatSlotCoverServo.setCurrentPosAsMiddle();
// }
//
// if ( isDoorOpen ) {
// MoveDoorClose.execute(this.getDevice());
// }
// }
//
// // 异常处理位试管架取出
// public void actionErrorTubeRackTakeOut() {
// var action = this.getAction("TaskStartResetErrorTubeRackTakeOut");
// action.finish();
// }
//
// // 放入异常处理位试管架
// public void actionErrorTubeRackPutIn() {
// var slotMan = this.getResourceManager(ResHeatingTubeRackSlotManager.class);
// var slot = slotMan.getErrorSlot();
//
// // 关闭设备门
// DiActMotor doorMotor = this.getActuator(MyDevice.ACT_DOOR_MOTOR, DiActMotor.class);
// doorMotor.moveToIO(1, 1);
//
// var move = new MoveMoveTubeRackFromLiquidPlateToHeatPlate();
// move.slotIndex = slot.index;
// move.setDevice(this.getDevice());
// move.run();
// slot.lock();
//
// var action = this.getAction("TaskStartResetErrorTubeRackPutIn");
// action.finish();
// }
//
// // 蠕动泵管路初始化
// public void actionPumpPipeSetupTubeRankPutIn() {
// var action = this.getAction("TaskStartResetPumpPipeSetupTubeRankPutIn");
// action.finish();
// }
//
// // 蠕动泵管路初始化
// public void actionPumpPipeSetupTubeRankTakeOut() {
// var action = this.getAction("TaskStartResetPumpPipeSetupTubeRankTakeOut");
// action.finish();
// }
// set progress message
private void setProgressMessage(String message) {
UfMdbRuntimeVariable.setString(message, "device.start.message");
}
}

31
src/main/java/com/iflytop/digester/controller/DeviceController.java

@ -0,0 +1,31 @@
package com.iflytop.digester.controller;
import com.iflytop.digester.StartResetTaskThread;
import com.iflytop.digester.deviceinstance.Device;
import com.iflytop.digester.underframework.controller.UfApiControllerBase;
import com.iflytop.digester.underframework.controller.UfApiResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DeviceController extends UfApiControllerBase {
@Resource
private Device device;
@ResponseBody
@PostMapping("/api/device/start")
public UfApiResponse start() {
if (!"new".equals(this.device.getStatus())) {
return this.error("当前设备无法执行启动操作");
}
var startReset = new StartResetTaskThread();
startReset.start();
return this.success();
}
@ResponseBody
@PostMapping("/api/device/status-get")
public UfApiResponse statusGet() {
return this.success(this.device.getStatus());
}
}

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

@ -0,0 +1,21 @@
package com.iflytop.digester.controller;
import com.iflytop.digester.deviceinstance.Device;
import com.iflytop.digester.underframework.controller.UfApiControllerBase;
import com.iflytop.digester.underframework.controller.UfApiResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
@Controller
public class HeatSlotController extends UfApiControllerBase {
@Resource
private Device device;
@ResponseBody
@PostMapping("/api/heat-slot/list")
public UfApiResponse list() {
var heatSlots = this.device.heatingTurntable.getSlots();
return this.success(Map.of("slots", heatSlots));
}
}

21
src/main/java/com/iflytop/digester/controller/LiquidController.java

@ -0,0 +1,21 @@
package com.iflytop.digester.controller;
import com.iflytop.digester.deviceinstance.Device;
import com.iflytop.digester.underframework.controller.UfApiControllerBase;
import com.iflytop.digester.underframework.controller.UfApiResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
@Controller
public class LiquidController extends UfApiControllerBase {
@Resource
private Device device;
@ResponseBody
@PostMapping("/api/liquid/list")
public UfApiResponse list() {
var liquids = this.device.liquidAddition.getLiquids();
return this.success(Map.of("liquids", liquids));
}
}

19
src/main/java/com/iflytop/digester/deviceinstance/Device.java

@ -1,9 +1,14 @@
package com.iflytop.digester.deviceinstance;
import com.iflytop.digester.DigestionTaskThread;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class Device {
// logger
public static final Logger LOG = LoggerFactory.getLogger(Device.class);
// device instance
private static Device instance = null;
@ -22,6 +27,9 @@ public class Device {
@Resource
public Camera camera;
// device status
private String status = "new"; // new, preparing, ready, running, stopping, stopped
// get device instance
public static Device getInstance() {
return instance;
@ -31,4 +39,15 @@ public class Device {
public void init() {
instance = this;
}
// start device
public String getStatus() {
return status;
}
// set device status
public void setStatus(String status) {
LOG.info("[Device Status] {} => {}", this.status, status);
this.status = status;
}
}

5
src/main/java/com/iflytop/digester/deviceinstance/HeatingTurntableInstance.java

@ -17,6 +17,11 @@ public class HeatingTurntableInstance {
}
}
// 获取槽位列表
public List<HeatingTurntableSlot> getSlots() {
return slots;
}
// 分配加热位
synchronized public HeatingTurntableSlot allocSlot( String tubeRackNo ) {
for (HeatingTurntableSlot slot : slots) {

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

@ -17,13 +17,19 @@ public class LiquidAdditionInstance {
LiquidAdditionLiquid liquid = new LiquidAdditionLiquid();
// @TODO : 测试用要删除
liquid.type = "盐酸";
liquid.type = "hydrochloric";
liquid.volume = 100;
liquids.add(liquid);
}
}
// get liquids
public List<LiquidAdditionLiquid> getLiquids() {
return this.liquids;
}
// 针对试管加液
public void addLiquidToTubes(List<Integer> tubes, String type, int volume ) {
var pumpIndexes = this.getPumpIndexForGroupOutAndIn(type);

17
src/main/java/com/iflytop/digester/underframework/controller/UfApiDictionary.java

@ -0,0 +1,17 @@
package com.iflytop.digester.underframework.controller;
import com.iflytop.digester.underframework.dao.model.UfMdbDictItem;
import org.springframework.stereotype.Controller;
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;
@Controller
public class UfApiDictionary extends UfApiControllerBase {
@ResponseBody
@PostMapping("/api/dictionary/list-by-group")
public UfApiResponse listByGroup(@RequestBody Map<String, Object> params ) {
var group = (String)params.get("group");
var items = UfMdbDictItem.getItems(group);
return success(items);
}
}

18
src/main/java/com/iflytop/digester/underframework/controller/UfApiRuntimeVariable.java

@ -0,0 +1,18 @@
package com.iflytop.digester.underframework.controller;
import com.iflytop.digester.underframework.dao.model.UfMdbRuntimeVariable;
import org.springframework.stereotype.Controller;
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;
@Controller
public class UfApiRuntimeVariable extends UfApiControllerBase {
@ResponseBody
@PostMapping("/api/runtime-variable/get")
public UfApiResponse get(@RequestBody Map<String, Object> params ) {
String key = (String)params.get("key");
var value = UfMdbRuntimeVariable.getString(key);
assert value != null;
return success(Map.of("value", value));
}
}

33
src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbDictItem.java

@ -0,0 +1,33 @@
package com.iflytop.digester.underframework.dao.model;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.dao.record.UfActiveRecordField;
import java.util.List;
import java.util.Map;
public class UfMdbDictItem extends UfActiveRecord {
@UfActiveRecordField
public String groupKey;
@UfActiveRecordField
public String groupName;
@UfActiveRecordField
public String itemKey;
@UfActiveRecordField
public String itemName;
@UfActiveRecordField
public String itemValue;
// get table name
public static String getTableName() {
return "app_dict_items";
}
// get items
public static List<UfMdbDictItem> getItems(String groupKey) {
return UfActiveRecord.find(UfMdbDictItem.class, Map.of("groupKey", groupKey));
}
}

67
src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbRuntimeVariable.java

@ -0,0 +1,67 @@
package com.iflytop.digester.underframework.dao.model;
import com.iflytop.digester.underframework.dao.record.UfActiveRecord;
import com.iflytop.digester.underframework.dao.record.UfActiveRecordField;
import java.util.Map;
public class UfMdbRuntimeVariable extends UfActiveRecord {
@UfActiveRecordField
public String key;
@UfActiveRecordField
public String value;
// get table name
public static String getTableName() {
return "app_runtime_variables";
}
// build key
private static String buildKey(String key, Object ... args) {
StringBuilder keyBuilder = new StringBuilder(key);
for (Object arg : args) {
keyBuilder.append(".").append(arg.toString());
}
return keyBuilder.toString();
}
// get location value
public static UfMdbRuntimeVariable getVariable(String key, Object ... args ) {
key = UfMdbRuntimeVariable.buildKey(key, args);
return UfActiveRecord.findOne(UfMdbRuntimeVariable.class, Map.of("key", key));
}
// get string
public static String getString(String name, Object ... args ) {
var variable = UfMdbRuntimeVariable.getVariable(name, args);
return null == variable ? null : variable.value;
}
// get integer
public static Integer getInteger(String name, Object ... args ) {
var variable = UfMdbRuntimeVariable.getVariable(name, args);
return null == variable ? null : Integer.parseInt(variable.value);
}
// set string
public static void setString(String value, String name, Object ... args ) {
var variable = UfMdbRuntimeVariable.getVariable(name, args);
if ( null == variable ) {
variable = new UfMdbRuntimeVariable();
variable.key = UfMdbRuntimeVariable.buildKey(name, args);
}
variable.value = value;
variable.save();
}
// set integer
public static void setInteger(Integer value, String name, Object ... args ) {
UfMdbRuntimeVariable.setString(value.toString(), name, args);
}
// remove
public static void remove(String name, Object ... args ) {
var variable = UfMdbRuntimeVariable.getVariable(name);
if ( null != variable ) {
variable.delete();
}
}
}

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

@ -103,6 +103,13 @@ public class UfActiveRecord {
return mapper.count(criteria);
}
// find by conditions
public static <T extends UfActiveRecord> List<T> find(Class<T> modelClass, Map<String,Object> conditions) {
var criteria = new UfActiveRecordCriteria();
criteria.conditions = conditions;
return UfActiveRecord.find(modelClass, criteria);
}
// find all by criteria
public static <T extends UfActiveRecord> List<T> find(Class<T> modelClass, UfActiveRecordCriteria criteria ) {
criteria.tableName = UfActiveRecord.getTableNameFromModelClass(modelClass);

2
web

@ -1 +1 @@
Subproject commit 1281f43be8a5de2f98d83c2a32506bb878eb5495
Subproject commit 7f4d0b8bfe683b41e75233368ed1ec1e98c8c350
Loading…
Cancel
Save