diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiApplicationRunner.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiApplicationRunner.java index e9ad9c6..2359b6d 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiApplicationRunner.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiApplicationRunner.java @@ -13,6 +13,7 @@ public class DiApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { this.device.getTaskManager().scanTaskClasses("com.my.graphiteDigesterBg.task"); + this.device.getTaskManager().scanTaskStepClasses("com.my.graphiteDigesterBg.step"); this.device.getResource().scanResourceManagerClasses("com.my.graphiteDigesterBg.resource"); } } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java index c663af0..520ad88 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java @@ -8,6 +8,11 @@ public interface DiTask { String getUUID(); // set device void setDevice(DiDevice device); + // get device + DiDevice getDevice(); // run void run(); + // stop + void stop(); + void setStatus(TaskStatus status); } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java index fb5ce3f..6bc3576 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java @@ -1,33 +1,35 @@ package com.my.graphiteDigesterBg.diframe; -import java.util.ArrayList; -import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; abstract public class DiTaskBase implements DiTask { + // logger + public static final Logger LOG = LoggerFactory.getLogger(DiTaskExecutor.class); // device private DiDevice device; // uuid private final String uuid; // status private TaskStatus status; - // steps - private List steps; - // step index - private Integer stepIndex; + // request task stop + private Boolean isRequestTaskStop = false; // constructor public DiTaskBase() { this.uuid = java.util.UUID.randomUUID().toString(); - this.steps = new ArrayList<>(); - this.stepIndex = 0; this.status = TaskStatus.NEW; } - // set status - protected void setStatus(TaskStatus status) { + @Override + public void setStatus(TaskStatus status) { this.status = status; + LOG.info("[Task #{}] Status => {}", this.getUUID(), this.getStatus()); + if ( TaskStatus.READY.equals(this.getStatus()) ) { + this.getDevice().getTaskManager().getExecutor().notifyTaskReady(); + } } - // get device - protected DiDevice getDevice() { + @Override + public DiDevice getDevice() { return this.device; } @@ -52,6 +54,16 @@ abstract public class DiTaskBase implements DiTask { this.status = TaskStatus.FINISHED; } + @Override + public void stop() { + this.isRequestTaskStop = true; + } + + // get request task stop + public Boolean getIsRequestTaskStop() { + return this.isRequestTaskStop; + } + // get manager public T getResourceManager( Class clazz ) { return this.getDevice().getResource().getManager(clazz); diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskExecutor.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskExecutor.java index 839d3c5..b627b1d 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskExecutor.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskExecutor.java @@ -68,7 +68,7 @@ public class DiTaskExecutor implements Runnable { // wait for new task synchronized ( this.taskList ) { try { - LOG.info("waiting for executable task"); + LOG.info("[Task Executor] waiting for executable task"); this.taskList.wait(); LOG.info("waiting for executable task waked up"); } catch (InterruptedException e) { @@ -119,6 +119,14 @@ public class DiTaskExecutor implements Runnable { return null; } + // notify task ready + public void notifyTaskReady() { + synchronized ( this.taskList ) { + this.taskList.notifyAll(); + } + } + + public void pause() {} public void resume() {} } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java index f11e6c9..d908d9a 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java @@ -15,6 +15,8 @@ public class DiTaskManager { private final DiDevice device; // task classes private final Map> taskClasses; + // task step classes + private final Map> taskStepClasses; // task executor private DiTaskExecutor executor; // executor thread @@ -24,6 +26,7 @@ public class DiTaskManager { public DiTaskManager(DiDevice device) { this.device = device; this.taskClasses = new HashMap<>(); + this.taskStepClasses = new HashMap<>(); this.executor = null; this.executorThread = null; } @@ -104,4 +107,23 @@ public class DiTaskManager { } return task; } + + // get scan task classes + public void scanTaskStepClasses( String packageName ) { + List> taskStepClasses = DiClassHelper.getAllClassesInPackage(packageName); + for ( Class taskStepClass : taskStepClasses ) { + if ( DiTaskStepBase.class.isAssignableFrom(taskStepClass) ) { + TaskStep taskStep = taskStepClass.getAnnotation(TaskStep.class); + if ( taskStep != null ) { + this.taskStepClasses.put(taskStep.name(), taskStepClass); + LOG.info("(Task Step) {} => {}", taskStep.name(), taskStepClass.getName()); + } + } + } + } + + // generate task + public Class getTaskStepClassByName( String name ) { + return this.taskStepClasses.get(name); + } } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStep.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStep.java index 2a24f50..239265f 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStep.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStep.java @@ -1,4 +1,17 @@ package com.my.graphiteDigesterBg.diframe; - +import com.fasterxml.jackson.databind.JsonNode; public interface DiTaskStep { + void run(); + + String getAction(); + + void setStepNode(JsonNode stepNode); + + JsonNode getStepNode(); + + void setTask(DiTask task); + + DiTask getTask(); + + T getTask( Class clazz ); } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepBase.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepBase.java new file mode 100644 index 0000000..311098f --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepBase.java @@ -0,0 +1,40 @@ +package com.my.graphiteDigesterBg.diframe; +import com.fasterxml.jackson.databind.JsonNode; +abstract public class DiTaskStepBase implements DiTaskStep { + // name of step action + public String action; + // step node + private JsonNode stepNode; + // task + private DiTask task; + + @Override + public void setTask(DiTask task) { + this.task = task; + } + + @Override + public DiTask getTask() { + return this.task; + } + + @Override + public T getTask( Class clazz ) { + return (T)this.task; + } + + @Override + public void setStepNode(JsonNode stepNode) { + this.stepNode = stepNode; + } + + @Override + public JsonNode getStepNode() { + return this.stepNode; + } + + @Override + public String getAction() { + return action; + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepTaskBase.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepTaskBase.java new file mode 100644 index 0000000..729dc40 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskStepTaskBase.java @@ -0,0 +1,80 @@ +package com.my.graphiteDigesterBg.diframe; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; +abstract public class DiTaskStepTaskBase extends DiTaskBase { + // logger + public static final Logger LOG = LoggerFactory.getLogger(DiTask.class); + // steps + public List steps; + // step index + public Integer stepIndex; + + // setup task + abstract protected void setup(); + + @Override + public void run() { + if ( null == this.stepIndex ) { + this.setup(); + this.stepIndex = 0; + } + + this.setStatus(TaskStatus.RUNNING); + + // execute steps + while ( this.stepIndex < this.steps.size() ) { + if ( this.getIsRequestTaskStop() ) { + this.setStatus(TaskStatus.CANCELLED); + break ; + } + + DiTaskStep step = this.steps.get(this.stepIndex); + this.executeStep(step); + this.stepIndex++; + if ( !TaskStatus.RUNNING.equals(this.getStatus()) ) { + break; + } + } + + // finish task + if ( TaskStatus.RUNNING.equals(this.getStatus()) ) { + this.setStatus(TaskStatus.FINISHED); + } + } + + // execute step + private void executeStep( DiTaskStep step ) { + LOG.info("[Task #{}] - Step {} => {}", this.getUUID(), step.getAction(), step.getStepNode().toString()); + step.run(); + } + + // load steps by json + protected void loadStepsByJson( String json ) { + ObjectMapper jsonMapper = new ObjectMapper(); + JsonNode stepJsonTree = null; + try { + stepJsonTree = jsonMapper.readTree(json); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + this.steps = new ArrayList<>(); + for ( JsonNode stepNode : stepJsonTree ) { + String name = stepNode.get("action").asText(); + + var stepClass = (Class)this.getDevice().getTaskManager().getTaskStepClassByName(name); + if ( stepClass == null ) { + throw new RuntimeException("step class not found: " + name); + } + DiTaskStep step = jsonMapper.convertValue(stepNode, stepClass); + step.setStepNode(stepNode); + step.setTask(this); + this.steps.add(step); + } + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/TaskStep.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/TaskStep.java new file mode 100644 index 0000000..871451a --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/TaskStep.java @@ -0,0 +1,9 @@ +package com.my.graphiteDigesterBg.diframe; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +@Retention(RetentionPolicy.RUNTIME) +@Target({java.lang.annotation.ElementType.TYPE}) +public @interface TaskStep { + String name(); +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/model/MdbDigestionTask.java b/src/src/main/java/com/my/graphiteDigesterBg/model/MdbDigestionTask.java new file mode 100644 index 0000000..b96e341 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/model/MdbDigestionTask.java @@ -0,0 +1,18 @@ +package com.my.graphiteDigesterBg.model; +import com.my.graphiteDigesterBg.diframe.ActiveRecordField; +import com.my.graphiteDigesterBg.diframe.DiActiveRecord; +public class MdbDigestionTask extends DiActiveRecord { + @ActiveRecordField + public Integer id; + + @ActiveRecordField + public String name; + + @ActiveRecordField + public String steps; + + // get table name + public static String getTableName() { + return "app_digestion_tasks"; + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/resource/ResHeatingTubeRackSlot.java b/src/src/main/java/com/my/graphiteDigesterBg/resource/ResHeatingTubeRackSlot.java index ebaa51c..7c51dfa 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/resource/ResHeatingTubeRackSlot.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/resource/ResHeatingTubeRackSlot.java @@ -1,6 +1,11 @@ package com.my.graphiteDigesterBg.resource; +import com.my.graphiteDigesterBg.diframe.DiTask; import com.my.graphiteDigesterBg.diframe.actuator.DiActServo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ResHeatingTubeRackSlot { + // logger + public static final Logger LOG = LoggerFactory.getLogger(ResHeatingTubeRackSlot.class); // index of slot private final Integer index; // is slot locked @@ -30,6 +35,20 @@ public class ResHeatingTubeRackSlot { this.isLocked = false; } + // heating on + public void heatingOn() { + LOG.info("[Resource TubeRackSlot#{}] Heating On", this.index); + // @TODO : 加热未实现 + LOG.error("开始加热未实现"); + } + + // heating off + public void heatingOff() { + LOG.info("[Resource TubeRackSlot#{}] Heating Off", this.index); + // @TODO : 加热未实现 + LOG.error("停止加热未实现"); + } + // get cover servo public DiActServo getCoverServo() { String servoKey = "heatSlot" + this.index.toString() + "CoverServo"; diff --git a/src/src/main/java/com/my/graphiteDigesterBg/step/StepHeating.java b/src/src/main/java/com/my/graphiteDigesterBg/step/StepHeating.java new file mode 100644 index 0000000..d9f9d35 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/step/StepHeating.java @@ -0,0 +1,41 @@ +package com.my.graphiteDigesterBg.step; +import com.my.graphiteDigesterBg.diframe.DiTask; +import com.my.graphiteDigesterBg.diframe.DiTaskStepBase; +import com.my.graphiteDigesterBg.diframe.TaskStep; +import com.my.graphiteDigesterBg.resource.ResHeatingTubeRackSlotManager; +import com.my.graphiteDigesterBg.task.TaskDigestion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Timer; +import java.util.TimerTask; +@TaskStep(name="Heating") +public class StepHeating extends DiTaskStepBase { + // logger + public static final Logger LOG = LoggerFactory.getLogger(StepHeating.class); + // temperature + public Integer temperature; + // duration in seconds + public Integer duration; + // timer + private Timer timer; + + @Override + public void run() { + var task = this.getTask(TaskDigestion.class); + var slotMan = task.getDevice().getResource().getManager(ResHeatingTubeRackSlotManager.class); + var slot = slotMan.getSlotByIndex(task.slotIndex); + + slot.heatingOn(); + task.setStatus(DiTask.TaskStatus.WAITING); + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + slot.heatingOff(); + task.setStatus(DiTask.TaskStatus.READY); + } + }; + + this.timer = new Timer(); + this.timer.schedule(timerTask, this.duration * 1000); + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/step/StepPump.java b/src/src/main/java/com/my/graphiteDigesterBg/step/StepPump.java new file mode 100644 index 0000000..c21616a --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/step/StepPump.java @@ -0,0 +1,17 @@ +package com.my.graphiteDigesterBg.step; +import com.my.graphiteDigesterBg.diframe.DiTaskStepBase; +import com.my.graphiteDigesterBg.diframe.TaskStep; +@TaskStep(name="Pump") +public class StepPump extends DiTaskStepBase { + // type + public String type; + // amount + public Integer amount; + // shake + public Integer shake; + + @Override + public void run() { + System.out.println("StepPump.run()"); + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java b/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java index 3265595..f2ee93f 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java @@ -1,11 +1,22 @@ package com.my.graphiteDigesterBg.task; -import com.my.graphiteDigesterBg.diframe.DiTaskBase; +import com.my.graphiteDigesterBg.diframe.DiActiveRecord; +import com.my.graphiteDigesterBg.diframe.DiTaskStepTaskBase; import com.my.graphiteDigesterBg.diframe.Task; +import com.my.graphiteDigesterBg.model.MdbDigestionTask; +import java.util.Map; @Task(name="Digestion") -public class TaskDigestion extends DiTaskBase { +public class TaskDigestion extends DiTaskStepTaskBase { + // name of digesting task + public String name; + // slot index + public Integer slotIndex; + @Override - public void run() { - System.out.println("TaskDigestion.run()"); - this.setStatus(TaskStatus.FINISHED); + protected void setup() { + var taskModel = DiActiveRecord.findOne(MdbDigestionTask.class, Map.of("name", this.name)); + if ( taskModel == null ) { + throw new RuntimeException("task [" + this.name + "] not found"); + } + this.loadStepsByJson(taskModel.steps); } } diff --git a/src/src/main/resources/application.yml b/src/src/main/resources/application.yml index dd42fd0..fbc315c 100644 --- a/src/src/main/resources/application.yml +++ b/src/src/main/resources/application.yml @@ -5,14 +5,14 @@ spring: password: 1 driver-class-name: org.sqlite.JDBC -mybatis: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +#mybatis: +# configuration: +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl device : connection : class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort - path : COM11 + path : COM1 baudRate : 921600 frameTimeout : 1000 mode : binary # text | hex | binary \ No newline at end of file diff --git a/src/src/main/resources/device.yml b/src/src/main/resources/device.yml index 2bb7baa..7eb612e 100644 --- a/src/src/main/resources/device.yml +++ b/src/src/main/resources/device.yml @@ -1,6 +1,6 @@ connection : class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort - path : COM11 + path : COM1 baudRate : 921600 frameTimeout : 100 callTimeout : 5000