diff --git a/app.db b/app.db index 14d9b3d..9beb63e 100644 Binary files a/app.db and b/app.db differ diff --git a/src/main/java/com/iflytop/digester/underframework/connection/UfModbusRTUOverTCP.java b/src/main/java/com/iflytop/digester/underframework/connection/UfModbusRTUOverTCP.java index 5562337..078a761 100644 --- a/src/main/java/com/iflytop/digester/underframework/connection/UfModbusRTUOverTCP.java +++ b/src/main/java/com/iflytop/digester/underframework/connection/UfModbusRTUOverTCP.java @@ -36,7 +36,7 @@ public class UfModbusRTUOverTCP extends UfConnectionBase { } @Override - public String execute(UfMdbActuatorCmd command) { + synchronized public String execute(UfMdbActuatorCmd command) { return ""; } diff --git a/src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java b/src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java index 914fe31..7201e59 100644 --- a/src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java +++ b/src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java @@ -1,6 +1,7 @@ package com.iflytop.digester.underframework.connection; import com.iflytop.digester.underframework.dao.model.TsMdbActuator; import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd; +import com.iflytop.digester.underframework.dao.record.UfActiveRecord; import com.iflytop.digester.underframework.util.TsByteBuffer; import com.iflytop.digester.underframework.util.UfClassHelper; import org.java_websocket.client.WebSocketClient; @@ -19,13 +20,17 @@ public class UfZcancmderWebsocket extends UfConnectionBase { // client private WebSocketClient client; // packet index - private int packetIndex = 0; + private int packetIndexCounter = 0; + // current packet index + private int currentPacketIndex = 0; // call lock private final Object callLock = new Object(); // response private ByteBuffer response; // response error private String responseError; + // timeout timer + private Timer timeoutTimer; @Override public void connect() { @@ -70,6 +75,8 @@ public class UfZcancmderWebsocket extends UfConnectionBase { returnValue = (String) UfClassHelper.invokeMethod(this, methodName, List.of(command)); } catch (NoSuchMethodException e) { returnValue = this.executeDeviceCommand(command); + } catch (Exception e) { + throw new RuntimeException(e); } if ( 1 == command.waitForFinish ) { @@ -80,18 +87,32 @@ public class UfZcancmderWebsocket extends UfConnectionBase { // execute device command private String executeDeviceCommand( UfMdbActuatorCmd actuatorCmd ) { - this.response = null; - this.responseError = null; - this.sendCommandRequest(actuatorCmd); - - synchronized (this.callLock) { - try { - this.callLock.wait(); - } catch (InterruptedException e) { - throw new RuntimeException(e); + // 超时重试3次 + for ( int i=0; i<3; i++ ) { + this.response = null; + this.responseError = null; + // 启动超时定时器 + this.startTimeoutTimer(); + // 发送数据 + this.sendCommandRequest(actuatorCmd); + // 等待数据响应或超时 + synchronized (this.callLock) { + try { + this.callLock.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + if ( null != this.response ) { + break ; } } + if ( null == this.response ) { + var actuator = UfActiveRecord.findOne(TsMdbActuator.class, actuatorCmd.actuatorId); + throw new RuntimeException(String.format("设备 [%s] 响应超时: %s", actuator.name, actuatorCmd.cmdKey)); + } + if ( null != this.responseError ) { throw new RuntimeException(this.responseError); } @@ -112,6 +133,22 @@ public class UfZcancmderWebsocket extends UfConnectionBase { } } + // start timeout timer + private void startTimeoutTimer() { + var timerTask = new TimerTask() { + @Override + public void run() { + LOG.info("[Command-Executor] timeout"); + UfZcancmderWebsocket.this.timeoutTimer = null; + synchronized (UfZcancmderWebsocket.this.callLock) { + UfZcancmderWebsocket.this.callLock.notifyAll(); + } + } + }; + this.timeoutTimer = new Timer(); + this.timeoutTimer.schedule(timerTask, 3000); + } + // send command request private void sendCommandRequest(UfMdbActuatorCmd actuatorCmd) { String cmd = this.buildCommand(actuatorCmd); @@ -150,7 +187,7 @@ public class UfZcancmderWebsocket extends UfConnectionBase { int bufferSize = 2 + 2 + 1 + 1 + 2 + 4 * paramList.size(); // PacketIndex - MainCmdId - SubCmdId - CmdType - ModuleId - Parameters ByteBuffer buffer = ByteBuffer.allocate(bufferSize); buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.putShort((short) this.packetIndex); // PacketIndex + buffer.putShort((short) this.packetIndexCounter); // PacketIndex buffer.putShort((short) mainCmdId); // MainCmdId buffer.put((byte) subCmdId); // SubCmdId buffer.put((byte) 0); // CmdType @@ -160,9 +197,10 @@ public class UfZcancmderWebsocket extends UfConnectionBase { buffer.putInt(Integer.parseInt(param)); } - this.packetIndex ++; - if ( this.packetIndex > 30000 ) { - this.packetIndex = 0; + this.currentPacketIndex = this.packetIndexCounter; + this.packetIndexCounter++; + if ( this.packetIndexCounter > 30000 ) { + this.packetIndexCounter = 0; } String cmd = TsByteBuffer.toHex(buffer); @@ -174,6 +212,16 @@ public class UfZcancmderWebsocket extends UfConnectionBase { private void handleOnTextMessage( String text ) { ByteBuffer message = TsByteBuffer.fromHex(text); message.order(ByteOrder.LITTLE_ENDIAN); + short packetIndex = message.getShort(0); + if ( packetIndex != this.currentPacketIndex ) { + return ; // 可能超时了, 所以忽略掉 ~~~ + } + + if ( null != this.timeoutTimer ) { + this.timeoutTimer.cancel(); + this.timeoutTimer = null; + } + byte messageType = message.get(5); if ( 0x01 == messageType ) { // ack message this.handleOnTextAckMessage(message); @@ -229,4 +277,33 @@ public class UfZcancmderWebsocket extends UfConnectionBase { } } while ( true ); } + + // cmd motor easy move to + public void cmdMotorEasyMoveTo(UfMdbActuatorCmd command) { + this.executeDeviceCommand(command); + this.waitForActuatorFinish(command); + + var actuator = UfActiveRecord.findOne(TsMdbActuator.class, command.actuatorId); + var encoderAvailable = actuator.getProperty("encoderAvailable"); + if ( null == encoderAvailable || !encoderAvailable.asBoolean() ) { + return ; + } + + var destValue = Integer.parseInt(command.parameters); + var encoderValue = this.getActuatorEncoderValue(command); + if ( Math.abs(encoderValue - destValue) > 10 ) { + throw new RuntimeException(String.format("电机 [%s] 移动失败,目标位置:%d,当前位置:%d", actuator.name, destValue, encoderValue)); + } + } + + // cmd motor read enc val + private Integer getActuatorEncoderValue(UfMdbActuatorCmd srcCmd) { + var command = new UfMdbActuatorCmd(); + command.actuatorId = srcCmd.actuatorId; + command.cmdId = "0219"; + command.cmdKey = "motor_read_enc_val"; + command.cmdFlags = srcCmd.cmdFlags; + String value = this.executeDeviceCommand(command); + return Integer.parseInt(value); + } } diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/TsMdbActuator.java b/src/main/java/com/iflytop/digester/underframework/dao/model/TsMdbActuator.java index 4efc50d..c6b81d1 100644 --- a/src/main/java/com/iflytop/digester/underframework/dao/model/TsMdbActuator.java +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/TsMdbActuator.java @@ -1,4 +1,8 @@ package com.iflytop.digester.underframework.dao.model; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iflytop.digester.deviceinstance.HeatingTurntableSlotTube; import com.iflytop.digester.underframework.dao.record.UfActiveRecord; import com.iflytop.digester.underframework.dao.record.UfActiveRecordField; /* @@ -14,8 +18,23 @@ public class TsMdbActuator extends UfActiveRecord { @UfActiveRecordField public String name; + @UfActiveRecordField + public String properties = "{}"; + // get table name public static String getTableName() { return "app_actuators"; } + + // get property + public JsonNode getProperty(String key) { + ObjectMapper jsonMapper = new ObjectMapper(); + JsonNode properties = null; + try { + properties = jsonMapper.readTree(this.properties); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return properties.get(key); + } } diff --git a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuatorCmd.java b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuatorCmd.java index f4a657e..c187d9a 100644 --- a/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuatorCmd.java +++ b/src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuatorCmd.java @@ -24,7 +24,7 @@ public class UfMdbActuatorCmd extends UfActiveRecord { public String fixedParameters; @UfActiveRecordField - public String parameters; + public String parameters = ""; @UfActiveRecordField public Integer waitForFinish; diff --git a/src/main/java/com/iflytop/digester/underframework/util/UfClassHelper.java b/src/main/java/com/iflytop/digester/underframework/util/UfClassHelper.java index 565803b..caf3448 100644 --- a/src/main/java/com/iflytop/digester/underframework/util/UfClassHelper.java +++ b/src/main/java/com/iflytop/digester/underframework/util/UfClassHelper.java @@ -54,8 +54,10 @@ public class UfClassHelper { } else { return method.invoke(obj, args.toArray()); } - } catch (IllegalAccessException | InvocationTargetException e) { + } catch (IllegalAccessException e) { throw new RuntimeException(e); + } catch ( InvocationTargetException e ) { + throw new RuntimeException(e.getCause().getMessage()); } }