diff --git a/src/pom.xml b/src/pom.xml index 5a8dd12..5bdcb6a 100644 --- a/src/pom.xml +++ b/src/pom.xml @@ -27,6 +27,12 @@ spring-boot-starter-test test + + + com.fazecast + jSerialComm + 2.6.2 + diff --git a/src/src/main/java/com/my/graphiteDigesterBg/MyApplicationRunner.java b/src/src/main/java/com/my/graphiteDigesterBg/MyApplicationRunner.java index cc2b6e0..3757f3f 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/MyApplicationRunner.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/MyApplicationRunner.java @@ -4,6 +4,7 @@ import com.my.graphiteDigesterBg.diframe.DiDeviceActuatorManager; import com.my.graphiteDigesterBg.diframe.DiDeviceIO; import com.my.graphiteDigesterBg.diframe.DiDeviceIOManager; import com.my.graphiteDigesterBg.diframe.actuator.DiActMotor; +import com.my.graphiteDigesterBg.diframe.actuator.DiActPeristalticPump; import jakarta.annotation.Resource; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; @@ -70,7 +71,7 @@ public class MyApplicationRunner implements ApplicationRunner { actuators.register(MyDevice.ACT_LIQUID_PLATE_MOTOR, new DiActMotor(){{ mid = 51; }}); - actuators.register(MyDevice.ACT_LIQUID_PERISTALTIC_PUMP, new DiActMotor(){{ + actuators.register(MyDevice.ACT_LIQUID_PERISTALTIC_PUMP, new DiActPeristalticPump(){{ mid = 61; }}); } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuator.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuator.java index 5479614..1a1e421 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuator.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuator.java @@ -1,4 +1,5 @@ package com.my.graphiteDigesterBg.diframe; public interface DiActuator { - + // set device + void setDevice( DiDevice device ); } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java index b8c22a9..6d476aa 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java @@ -1,8 +1,40 @@ package com.my.graphiteDigesterBg.diframe; - -import com.my.graphiteDigesterBg.diframe.DiActuator; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; abstract public class DiActuatorBase implements DiActuator { + // device + private DiDevice device; // mid protected Integer mid; + + @Override + public void setDevice( DiDevice device ) { + this.device = device; + } + + // execute device command + protected DiCommandResponse call( DiCommand cmd, Object... args ) { + ByteBuffer buffer = null; + String cmdMode = this.device.getEnv().getProperty("device.command.mode"); + if ("text".equals(cmdMode)) { + buffer = this.buildCommandBufferForTextMode(cmd, args); + } else { + throw new RuntimeException("Unknown command mode: " + cmdMode); + } + ByteBuffer response = this.device.getConnection().call(buffer); + return new DiCommandResponse(response); + } + + // build command buffer for text mode + private ByteBuffer buildCommandBufferForTextMode(DiCommand cmd, Object... args) { + List parts = new ArrayList<>(); + parts.add(cmd.getName()); + for ( Object arg : args ) { + parts.add(arg.toString()); + } + String command = String.join(" ", parts); + return ByteBuffer.wrap(command.getBytes()); + } } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java new file mode 100644 index 0000000..2d4c810 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java @@ -0,0 +1,25 @@ +package com.my.graphiteDigesterBg.diframe; +public enum DiCommand { + MOTOR_EASY_MOVE_BY("motor_easy_move_by", 0x0212); + + // command name + private final String name; + // command id + private final int cmdId; + + // constructor + DiCommand(String name, int cmdId) { + this.name = name; + this.cmdId = cmdId; + } + + // get command name + public String getName() { + return this.name; + } + + // get command id + public int getCmdId() { + return this.cmdId; + } +} \ No newline at end of file diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandResponse.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandResponse.java new file mode 100644 index 0000000..fc238fb --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandResponse.java @@ -0,0 +1,16 @@ +package com.my.graphiteDigesterBg.diframe; +import java.nio.ByteBuffer; +public class DiCommandResponse { + // response + private final ByteBuffer response; + + // constructor + public DiCommandResponse(ByteBuffer response) { + this.response = response; + } + + // read integer + public Integer readInteger( Integer index ) { + return this.response.getInt(index); + } +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java index dbaabdf..c32eba4 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java @@ -1,8 +1,19 @@ package com.my.graphiteDigesterBg.diframe; +import com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort; import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + @Component public class DiDevice { + @Resource + private Environment env; + // connection + private DiDeviceConnection connection; // io manager private DiDeviceIOManager io; // actuator manager @@ -12,11 +23,38 @@ public class DiDevice { @PostConstruct public void init() { + this.setupConnection(); this.io = new DiDeviceIOManager(this); this.actuators = new DiDeviceActuatorManager(this); this.taskManager = new DiTaskManager(this); } + // setup connection + private void setupConnection() { + String connectionClassName = this.env.getProperty("device.connection.class"); + Class connectionClass = null; + try { + connectionClass = Class.forName(connectionClassName); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + Constructor connectionConstructor = null; + try { + connectionConstructor = connectionClass.getDeclaredConstructor(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + + try { + this.connection = (DiDeviceConnection) connectionConstructor.newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + this.connection.setDevice(this); + this.connection.connect(); + } + // get io manager public DiDeviceIOManager getIO() { return this.io; @@ -31,4 +69,14 @@ public class DiDevice { public DiTaskManager getTaskManager() { return this.taskManager; } + + // get connection + public DiDeviceConnection getConnection() { + return this.connection; + } + + // get env + public Environment getEnv() { + return this.env; + } } \ No newline at end of file diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceActuatorManager.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceActuatorManager.java index b6fc1d9..27104c4 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceActuatorManager.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceActuatorManager.java @@ -15,11 +15,12 @@ public class DiDeviceActuatorManager { // register actuator public void register( String id, DiActuator actuator ) { - this.actuators.put( id, actuator ); + actuator.setDevice(this.device); + this.actuators.put(id, actuator); } // get actuator - public void get( String id ) { - this.actuators.get( id ); + public DiActuator get( String id ) { + return this.actuators.get( id ); } } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java new file mode 100644 index 0000000..03d1b14 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java @@ -0,0 +1,10 @@ +package com.my.graphiteDigesterBg.diframe; +import java.nio.ByteBuffer; +public interface DiDeviceConnection { + // set device + void setDevice(DiDevice device); + // connect to device + void connect(); + // call device with parameter and return result + ByteBuffer call(ByteBuffer parameter); +} 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 383cf7d..8364ea0 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTask.java @@ -6,6 +6,8 @@ public interface DiTask { TaskStatus getStatus(); // get UUID String getUUID(); + // set device + void setDevice(DiDevice device); // set parameter void setParameter(Object parameter); // run 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 f01f2e1..74ced70 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskBase.java @@ -1,8 +1,9 @@ package com.my.graphiteDigesterBg.diframe; import java.util.ArrayList; import java.util.List; -import java.util.Map; abstract public class DiTaskBase implements DiTask { + // device + private DiDevice device; // uuid private final String uuid; // status @@ -27,6 +28,11 @@ abstract public class DiTaskBase implements DiTask { this.status = status; } + // get device + protected DiDevice getDevice() { + return this.device; + } + @Override public String getUUID() { return this.uuid; @@ -38,6 +44,11 @@ abstract public class DiTaskBase implements DiTask { } @Override + public void setDevice(DiDevice device) { + this.device = device; + } + + @Override public void setParameter(Object parameter) { this.parameter = parameter; } 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 3d0c0af..8152df5 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiTaskManager.java @@ -11,9 +11,9 @@ public class DiTaskManager { // logger public static final Logger LOG = LoggerFactory.getLogger(DiTaskManager.class); // device - private DiDevice device; + private final DiDevice device; // task classes - private Map> taskClasses; + private final Map> taskClasses; // task executor private DiTaskExecutor executor; // executor thread @@ -75,6 +75,7 @@ public class DiTaskManager { throw new RuntimeException(e); } + task.setDevice(this.device); task.setParameter(parameter); return task; } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActPeristalticPump.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActPeristalticPump.java index 870fa7c..11c7d33 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActPeristalticPump.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/actuator/DiActPeristalticPump.java @@ -1,6 +1,8 @@ package com.my.graphiteDigesterBg.diframe.actuator; - import com.my.graphiteDigesterBg.diframe.DiActuatorBase; - +import com.my.graphiteDigesterBg.diframe.DiCommand; public class DiActPeristalticPump extends DiActuatorBase { + public void rotate() { + this.call(DiCommand.MOTOR_EASY_MOVE_BY, 1); + } } \ No newline at end of file diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiConsumable.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiConsumable.java similarity index 61% rename from src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiConsumable.java rename to src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiConsumable.java index 6dbf358..aee50c0 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiConsumable.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiConsumable.java @@ -1,4 +1,4 @@ package com.my.graphiteDigesterBg.diframe.api; -public class ApiConsumable { +public class DiApiConsumable { } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiDevice.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiDevice.java similarity index 94% rename from src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiDevice.java rename to src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiDevice.java index 19364f9..67dd71f 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiDevice.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiDevice.java @@ -7,7 +7,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller -public class ApiDevice extends DiApiControllerBase { +public class DiApiDevice extends DiApiControllerBase { @Resource private DiDevice device; diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiTask.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiTask.java similarity index 95% rename from src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiTask.java rename to src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiTask.java index 9c22de3..b47f267 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiTask.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiTask.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Map; @Controller -public class ApiTask extends DiApiControllerBase { +public class DiApiTask extends DiApiControllerBase { @Resource private DiDevice device; diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiUser.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiUser.java similarity index 80% rename from src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiUser.java rename to src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiUser.java index 483a5b6..21992ca 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/ApiUser.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/api/DiApiUser.java @@ -1,5 +1,5 @@ package com.my.graphiteDigesterBg.diframe.api; -public class ApiUser { +public class DiApiUser { public void login() {} public void logout() {} } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConSerialPort.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConSerialPort.java new file mode 100644 index 0000000..2eef350 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConSerialPort.java @@ -0,0 +1,72 @@ +package com.my.graphiteDigesterBg.diframe.connection; +import com.fazecast.jSerialComm.SerialPort; +import com.fazecast.jSerialComm.SerialPortDataListener; +import com.fazecast.jSerialComm.SerialPortEvent; +import com.my.graphiteDigesterBg.diframe.DiDevice; +import com.my.graphiteDigesterBg.diframe.DiDeviceConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import java.nio.ByteBuffer; +public class DiConSerialPort implements DiDeviceConnection { + // logger + public static final Logger LOG = LoggerFactory.getLogger(DiConSerialPort.class); + // device + private DiDevice device; + // serial port connection + private SerialPort connection; + + @Override + public void setDevice(DiDevice device) { + this.device = device; + } + + @Override + public void connect() { + Environment env = this.device.getEnv(); + String path = env.getProperty("device.connection.path"); + if ( null == path ) { + throw new RuntimeException("device option 'device.connection.path' is required."); + } + Integer baudRate = env.getProperty("device.connection.baudRate", Integer.class); + if ( null == baudRate ) { + throw new RuntimeException("device option 'device.connection.baudRate' is required."); + } + + this.connection = SerialPort.getCommPort(path); + this.connection.openPort(); + if ( !this.connection.isOpen() ) { + throw new RuntimeException("Failed to open serial port"); + } + + this.connection.setBaudRate(baudRate); + this.connection.addDataListener(new SerialPortDataListener() { + @Override + public int getListeningEvents() { + return SerialPort.LISTENING_EVENT_DATA_RECEIVED; + } + @Override + public void serialEvent(SerialPortEvent serialPortEvent) { + DiConSerialPort.this.handleOnData(serialPortEvent); + } + }); + LOG.info("Connecting to device: {}@{}", path, baudRate); + } + + // handle on data + private void handleOnData(SerialPortEvent serialPortEvent) { + byte[] data = serialPortEvent.getReceivedData(); + System.out.println("Received data of size: " + data.length); + for (byte b : data) { + System.out.print((char)b); + } + System.out.println("\n"); + } + + @Override + public ByteBuffer call(ByteBuffer parameter) { + byte[] data = parameter.array(); + this.connection.writeBytes(data, data.length); + return null; + } +} 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 ab60e61..b48cb76 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java @@ -1,10 +1,16 @@ package com.my.graphiteDigesterBg.task; +import com.my.graphiteDigesterBg.MyDevice; import com.my.graphiteDigesterBg.diframe.DiTaskBase; import com.my.graphiteDigesterBg.diframe.Task; +import com.my.graphiteDigesterBg.diframe.actuator.DiActPeristalticPump; + @Task(name="digestion") public class TaskDigestion extends DiTaskBase { @Override public void run() { + DiActPeristalticPump peristalticPump = (DiActPeristalticPump)this.getDevice().getActuators().get(MyDevice.ACT_LIQUID_PERISTALTIC_PUMP); + peristalticPump.rotate(); + System.out.println("TaskDigestion.run()"); this.setStatus(TaskStatus.FINISHED); } diff --git a/src/src/main/resources/application.properties b/src/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/src/main/resources/application.yml b/src/src/main/resources/application.yml new file mode 100644 index 0000000..29afcf1 --- /dev/null +++ b/src/src/main/resources/application.yml @@ -0,0 +1,7 @@ +device : + connection : + class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort + path : COM1 + baudRate : 9600 + command : + mode : text # text | hex | binary \ No newline at end of file