diff --git a/src/pom.xml b/src/pom.xml
index 9dab566..a54e55a 100644
--- a/src/pom.xml
+++ b/src/pom.xml
@@ -29,6 +29,11 @@
jSerialComm
2.6.2
+
+ org.java-websocket
+ Java-WebSocket
+ 1.5.4
+
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 8a0baa6..aa0968b 100644
--- a/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java
+++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java
@@ -1,11 +1,11 @@
package com.my.graphiteDigesterBg.diframe;
+import com.my.graphiteDigesterBg.diframe.util.DiByteBuffer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
@@ -15,7 +15,6 @@ import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-
@Component
public class DiDevice {
@Resource
@@ -76,7 +75,7 @@ public class DiDevice {
// setup connection
private void setupConnection() {
- String connectionClassName = this.env.getProperty("device.connection.class");
+ String connectionClassName = this.getConfig("connection.class");
Class> connectionClass = null;
try {
connectionClass = Class.forName(connectionClassName);
@@ -175,6 +174,8 @@ public class DiDevice {
request = this.buildCommandRequestForTextMode(cmd, mid, args);
} else if ("binary".equals(cmdMode) ) {
request = this.buildCommandRequestForBinaryMode(cmd, mid, args);
+ } else if ("hex".equals(cmdMode)) {
+ request = this.buildCommandRequestForHexMode(cmd, mid, args);
} else {
throw new RuntimeException("Unknown command mode: " + cmdMode);
}
@@ -239,4 +240,13 @@ public class DiDevice {
return request;
}
+
+ // build command buffer for hex mode
+ private DiCommandRequest buildCommandRequestForHexMode(DiCommand cmd, Integer mid, Object... args) {
+ DiCommandRequest request = this.buildCommandRequestForBinaryMode(cmd, mid, args);
+ String hex = DiByteBuffer.toHex(request.parameter);
+ hex = hex.replace(" ","");
+ request.parameter = ByteBuffer.wrap(hex.getBytes());
+ return request;
+ }
}
\ No newline at end of file
diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocket.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocket.java
new file mode 100644
index 0000000..039876c
--- /dev/null
+++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocket.java
@@ -0,0 +1,144 @@
+package com.my.graphiteDigesterBg.diframe.connection;
+import com.my.graphiteDigesterBg.diframe.DiCommandRequest;
+import com.my.graphiteDigesterBg.diframe.DiDevice;
+import com.my.graphiteDigesterBg.diframe.DiDeviceConnection;
+import com.my.graphiteDigesterBg.diframe.util.DiByteBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+public class DiConWebsocket implements DiDeviceConnection {
+ // logger
+ public static final Logger LOG = LoggerFactory.getLogger(DiConWebsocket.class);
+ // device
+ private DiDevice device;
+ // client
+ private DiConWebsocketClient client;
+ // requests
+ private final List requests;
+
+ // constructor
+ public DiConWebsocket() {
+ this.requests = new ArrayList<>();
+ }
+
+ @Override
+ public void setDevice(DiDevice device) {
+ this.device = device;
+ }
+
+ @Override
+ public void connect() {
+ String wsUri = this.device.getConfig("connection.uri");
+ if ( null == wsUri ) {
+ throw new RuntimeException("device option 'device.connection.uri' is required.");
+ }
+ URI uri = null;
+ try {
+ uri = new URI(wsUri);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ this.client = new DiConWebsocketClient(uri);
+ this.client.connect();
+ this.client.setHolder(this);
+ }
+
+ @Override
+ public void call(DiCommandRequest request) {
+ this.requests.add(request);
+ String cmd = DiByteBuffer.toHex(request.parameter);
+ LOG.info("Command => {} : [{}]", request.parameterText, cmd);
+ cmd = cmd.replace(" ","");
+ this.client.send(cmd);
+ this.setupRequestTimeoutTimer(request);
+ synchronized ( request ) {
+ try {
+ request.wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ LOG.info("Command <= {}", DiByteBuffer.toHex(request.response));
+ }
+
+ // setup request timeout timer
+ private void setupRequestTimeoutTimer(DiCommandRequest request) {
+ TimerTask callTimeoutTimerTask = new TimerTask() {
+ @Override
+ public void run() {
+ DiConWebsocket.this.handleCallTimeout(request);
+ }
+ };
+ request.timeoutTimer = new Timer();
+ Integer callTimeout = this.device.getConfig("connection.callTimeout", Integer.class);
+ request.timeoutTimer.schedule(callTimeoutTimerTask, callTimeout);
+ }
+
+ // handle call timeout
+ private void handleCallTimeout(DiCommandRequest request) {
+ if ( request.isResponseReceived ) {
+ return ;
+ }
+
+ request.timeoutCount ++;
+ if ( request.timeoutCount > 3 ) {
+ synchronized ( request ) {
+ request.timeoutTimer = null;
+ request.errorCode = 8000;
+ request.notify();
+ }
+ return ;
+ }
+
+ String cmd = DiByteBuffer.toHex(request.parameter);
+ LOG.info("Command (Retry:{}) => {} : [{}]", request.timeoutCount, request.parameterText, cmd);
+ cmd = cmd.replace(" ","");
+ this.client.send(cmd);
+ this.setupRequestTimeoutTimer(request);
+ }
+
+ // handle on data
+ public void handleOnText(String text) {
+ ByteBuffer message = DiByteBuffer.fromHex(text);
+ message.order(ByteOrder.LITTLE_ENDIAN);
+ byte messageType = message.get(5);
+ if ( 0x01 == messageType ) { // ack message
+ this.handleOnTextAckMessage(message);
+ } else if ( 0x02 == messageType ) { // error message
+ throw new RuntimeException("error message received: " + text);
+ } else {
+ throw new RuntimeException("unknown message type : " + messageType + " <= " + text);
+ }
+ }
+
+ // handle on data timeout for binary mode ack message
+ private void handleOnTextAckMessage(ByteBuffer message) {
+ short messageId = message.getShort(0);
+ DiCommandRequest request = null;
+ for ( DiCommandRequest requestItem : this.requests ) {
+ if ( requestItem.id == messageId ) {
+ request = requestItem;
+ break;
+ }
+ }
+ if ( null == request ) {
+ return ; // 可能是超时了, 已经被处理掉了 ~~~
+ }
+ request.response = message;
+ request.isResponseReceived = true;
+ if ( null != request.timeoutTimer ) {
+ request.timeoutTimer.cancel();
+ request.timeoutTimer = null;
+ }
+ synchronized ( request ) {
+ request.notify();
+ }
+ }
+}
diff --git a/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocketClient.java b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocketClient.java
new file mode 100644
index 0000000..9718240
--- /dev/null
+++ b/src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocketClient.java
@@ -0,0 +1,49 @@
+package com.my.graphiteDigesterBg.diframe.connection;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.net.URI;
+public class DiConWebsocketClient extends WebSocketClient {
+ // logger
+ public static final Logger LOG = LoggerFactory.getLogger(DiConWebsocketClient.class);
+
+ // holder
+ private DiConWebsocket holder;
+
+ // constructor
+ public DiConWebsocketClient(URI uri) {
+ super(uri);
+ }
+
+ // set holder
+ public void setHolder(DiConWebsocket holder) {
+ this.holder = holder;
+ }
+
+ /**
+ * event handler for receiving text message from device
+ * @param text message from device
+ */
+ @Override
+ public void onMessage(String text) {
+ this.holder.handleOnText(text);
+ }
+
+ @Override
+ public void onOpen(ServerHandshake serverHandshake) {
+ LOG.info("device connected : {}", this.uri);
+ }
+
+ @Override
+ public void onClose(int i, String s, boolean b) {
+ LOG.info("close");
+ throw new RuntimeException("device connection closed");
+ }
+
+ @Override
+ public void onError(Exception e) {
+ LOG.error("error", e);
+ throw new RuntimeException(e);
+ }
+}
diff --git a/src/src/main/resources/application.yml b/src/src/main/resources/application.yml
index fbc315c..d3184d9 100644
--- a/src/src/main/resources/application.yml
+++ b/src/src/main/resources/application.yml
@@ -8,11 +8,3 @@ spring:
#mybatis:
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-
-device :
- connection :
- class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort
- 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 7eb612e..a700727 100644
--- a/src/src/main/resources/device.yml
+++ b/src/src/main/resources/device.yml
@@ -1,10 +1,14 @@
connection :
- class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort
- path : COM1
- baudRate : 921600
- frameTimeout : 100
- callTimeout : 5000
- mode : binary # text | hex | binary
+# class : com.my.graphiteDigesterBg.diframe.connection.DiConSerialPort
+# path : COM1
+# baudRate : 921600
+# frameTimeout : 100
+# callTimeout : 5000
+# mode : binary # text | hex | binary
+ class : com.my.graphiteDigesterBg.diframe.connection.DiConWebsocket
+ uri : ws://127.0.0.1:8899/device
+ mode : hex
+ callTimeout : 3000
# device registers
registers :
# 加液电机