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 6d476aa..29c6e20 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiActuatorBase.java @@ -1,9 +1,11 @@ package com.my.graphiteDigesterBg.diframe; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; - abstract public class DiActuatorBase implements DiActuator { + // message index + private static short messageIndex = 0; // device private DiDevice device; // mid @@ -14,27 +16,76 @@ abstract public class DiActuatorBase implements DiActuator { this.device = device; } + // set enable + public void setEnable( Boolean enable ) { + this.call(DiCommand.MODULE_ENABLE, enable ? 1 : 0); + } + // execute device command protected DiCommandResponse call( DiCommand cmd, Object... args ) { - ByteBuffer buffer = null; - String cmdMode = this.device.getEnv().getProperty("device.command.mode"); + DiCommandRequest request = null; + String cmdMode = this.device.getEnv().getProperty("device.connection.mode"); if ("text".equals(cmdMode)) { - buffer = this.buildCommandBufferForTextMode(cmd, args); + request = this.buildCommandRequestForTextMode(cmd, args); + } else if ("binary".equals(cmdMode) ) { + request = this.buildCommandRequestForBinaryMode(cmd, args); } else { throw new RuntimeException("Unknown command mode: " + cmdMode); } - ByteBuffer response = this.device.getConnection().call(buffer); - return new DiCommandResponse(response); + this.device.getConnection().call(request); + return new DiCommandResponse(request.response); } // build command buffer for text mode - private ByteBuffer buildCommandBufferForTextMode(DiCommand cmd, Object... args) { + private DiCommandRequest buildCommandRequestForTextMode(DiCommand cmd, Object... args) { List parts = new ArrayList<>(); parts.add(cmd.getName()); + parts.add(this.mid.toString()); for ( Object arg : args ) { parts.add(arg.toString()); } String command = String.join(" ", parts); - return ByteBuffer.wrap(command.getBytes()); + + DiCommandRequest request = new DiCommandRequest(); + request.parameter = ByteBuffer.wrap(command.getBytes()); + return request; + } + + // build command buffer for binary mode + private DiCommandRequest buildCommandRequestForBinaryMode(DiCommand cmd, Object... args) { + int length = 2/*PacketIndex*/ + 2/*MainCmdId*/ + 1/*SubCmdId*/ + 1/*CmdType*/ + 2/*ModuleId*/; + for ( Object param : args ) { + if ( param instanceof Integer ) { + length += 4; + } else { + throw new RuntimeException("param type error"); + } + } + int cmdId = cmd.getCmdId(); + int subCmdId = cmdId & 0xFF; + int mainCmdId = (cmdId >> 8) & 0xFFFF; + int moduleId = this.mid; + + DiCommandRequest request = new DiCommandRequest(); + request.id = DiActuatorBase.messageIndex; + request.parameter = ByteBuffer.allocate(length); + request.parameter.order(ByteOrder.LITTLE_ENDIAN); + request.parameter.putShort(DiActuatorBase.messageIndex); + request.parameter.putShort((short)mainCmdId); // main cmd id + request.parameter.put((byte)subCmdId); // sub cmd id + request.parameter.put((byte)0); // directive type + request.parameter.putShort((short)moduleId); // mid + for ( Object param : args ) { + if ( param instanceof Integer ) { + request.parameter.putInt((Integer)param); + } + } + + DiActuatorBase.messageIndex ++; + if ( DiActuatorBase.messageIndex > 30000 ) { + DiActuatorBase.messageIndex = 0; + } + + return request; } } diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java index 2d4c810..c70e9ce 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommand.java @@ -1,5 +1,6 @@ package com.my.graphiteDigesterBg.diframe; public enum DiCommand { + MODULE_ENABLE("module_enable", 0x0114), MOTOR_EASY_MOVE_BY("motor_easy_move_by", 0x0212); // command name diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandRequest.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandRequest.java new file mode 100644 index 0000000..90e3123 --- /dev/null +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiCommandRequest.java @@ -0,0 +1,16 @@ +package com.my.graphiteDigesterBg.diframe; +import java.nio.ByteBuffer; +public class DiCommandRequest { + // message id + public short id; + // parameter + public ByteBuffer parameter; + // response + public ByteBuffer response; + // error code + public Integer errorCode = 0; + // is response received + public Boolean isResponseReceived = false; + // timeout count + public Integer timeoutCount = 0; +} diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java index 03d1b14..6776532 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDeviceConnection.java @@ -6,5 +6,5 @@ public interface DiDeviceConnection { // connect to device void connect(); // call device with parameter and return result - ByteBuffer call(ByteBuffer parameter); + void call(DiCommandRequest request); } 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 11c7d33..2175a5d 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 @@ -3,6 +3,6 @@ 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); + this.call(DiCommand.MOTOR_EASY_MOVE_BY, 100 * 30); } } \ No newline at end of file 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 index 2eef350..6962698 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConSerialPort.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConSerialPort.java @@ -2,12 +2,17 @@ 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.DiCommandRequest; 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; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; public class DiConSerialPort implements DiDeviceConnection { // logger public static final Logger LOG = LoggerFactory.getLogger(DiConSerialPort.class); @@ -15,6 +20,19 @@ public class DiConSerialPort implements DiDeviceConnection { private DiDevice device; // serial port connection private SerialPort connection; + // requests + private final List requests; + // received data + private ByteBuffer receivedData; + // received data timer + private Timer receivedDataTimer; + + // constructor + public DiConSerialPort() { + this.requests = new ArrayList<>(); + this.receivedData = null; + this.receivedDataTimer = null; + } @Override public void setDevice(DiDevice device) { @@ -55,18 +73,83 @@ public class DiConSerialPort implements DiDeviceConnection { // handle on data private void handleOnData(SerialPortEvent serialPortEvent) { + if ( null != this.receivedDataTimer ) { + this.receivedDataTimer.cancel(); + this.receivedDataTimer = null; + } + + if ( null == this.receivedData ) { + this.receivedData = ByteBuffer.allocate(0); + } byte[] data = serialPortEvent.getReceivedData(); - System.out.println("Received data of size: " + data.length); - for (byte b : data) { - System.out.print((char)b); + ByteBuffer newBuffer = ByteBuffer.allocate(this.receivedData.capacity() + data.length); + newBuffer.put(this.receivedData).put(data); + this.receivedData = newBuffer; + + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + DiConSerialPort.this.handleOnDataTimeout(); + } + }; + this.receivedDataTimer = new Timer(); + Integer frameTimeout = this.device.getEnv().getProperty("device.connection.frameTimeout", Integer.class, 1000); + this.receivedDataTimer.schedule(timerTask, frameTimeout); + } + + // handle on data timeout + private void handleOnDataTimeout() { + String mode = this.device.getEnv().getProperty("device.connection.mode"); + if ( "binary".equals(mode) ) { + this.handleOnDataTimeoutForBinaryMode(); + } else { + throw new RuntimeException("Unknown command mode: " + mode); + } + } + + // handle on data timeout for binary mode + private void handleOnDataTimeoutForBinaryMode() { + byte messageType = this.receivedData.get(5); + if ( 0x01 == messageType ) { + this.handleOnDataTimeoutForBinaryModeAckMessage(); + } else { + throw new RuntimeException("unknown message type"); + } + } + + // handle on data timeout for binary mode ack message + private void handleOnDataTimeoutForBinaryModeAckMessage() { + short messageId = this.receivedData.getShort(0); + DiCommandRequest request = null; + for ( DiCommandRequest requestItem : this.requests ) { + if ( requestItem.id == messageId ) { + request = requestItem; + break; + } + } + if ( null == request ) { + throw new RuntimeException("unknown message id: " + messageId); + } + request.response = this.receivedData; + request.isResponseReceived = true; + this.receivedData = null; + synchronized ( request ) { + request.notify(); } - System.out.println("\n"); } @Override - public ByteBuffer call(ByteBuffer parameter) { - byte[] data = parameter.array(); + public void call(DiCommandRequest request) { + this.requests.add(request); + byte[] data = request.parameter.array(); this.connection.writeBytes(data, data.length); - return null; + synchronized ( request ) { + try { + request.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + LOG.info("Command response received: {}", request.response); } } 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 b48cb76..233cffc 100644 --- a/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java +++ b/src/src/main/java/com/my/graphiteDigesterBg/task/TaskDigestion.java @@ -9,6 +9,7 @@ public class TaskDigestion extends DiTaskBase { @Override public void run() { DiActPeristalticPump peristalticPump = (DiActPeristalticPump)this.getDevice().getActuators().get(MyDevice.ACT_LIQUID_PERISTALTIC_PUMP); + peristalticPump.setEnable(true); peristalticPump.rotate(); System.out.println("TaskDigestion.run()"); diff --git a/src/src/main/resources/application.yml b/src/src/main/resources/application.yml index 29afcf1..3fa8770 100644 --- a/src/src/main/resources/application.yml +++ b/src/src/main/resources/application.yml @@ -3,5 +3,5 @@ device : class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort path : COM1 baudRate : 9600 - command : - mode : text # text | hex | binary \ No newline at end of file + frameTimeout : 1000 + mode : binary # text | hex | binary \ No newline at end of file