13 changed files with 289 additions and 54 deletions
-
BINapp.db
-
6src/main/java/com/iflytop/digester/underframework/UfActuatorCmdExecutor.java
-
2src/main/java/com/iflytop/digester/underframework/UfApplication.java
-
6src/main/java/com/iflytop/digester/underframework/connection/UfConnection.java
-
2src/main/java/com/iflytop/digester/underframework/connection/UfConnectionBase.java
-
27src/main/java/com/iflytop/digester/underframework/connection/UfConnectionManager.java
-
172src/main/java/com/iflytop/digester/underframework/connection/UfModbusRTUOverTCP.java
-
92src/main/java/com/iflytop/digester/underframework/connection/UfZcancmderWebsocket.java
-
6src/main/java/com/iflytop/digester/underframework/dao/model/UfMdbActuatorCmd.java
-
11src/main/java/com/iflytop/digester/underframework/util/UfClassHelper.java
-
11src/main/java/com/iflytop/digester/underframework/web/api/TsApiActuatorCommand.java
-
6src/main/resources/application.yml
-
2web
@ -1,7 +1,9 @@ |
|||||
package com.iflytop.digester.underframework; |
package com.iflytop.digester.underframework; |
||||
import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd; |
import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd; |
||||
public class UfActuatorCmdExecutor { |
public class UfActuatorCmdExecutor { |
||||
public static void execute(UfMdbActuatorCmd cmd) { |
|
||||
// @TODO : 这里要判断使用那种通讯方式进行执行, 所以待定一下 |
|
||||
|
// execute cmd |
||||
|
public static String execute(UfMdbActuatorCmd cmd) { |
||||
|
var con = UfApplication.getApp().connections.get(cmd.connectionKey); |
||||
|
return con.execute(cmd); |
||||
} |
} |
||||
} |
} |
@ -0,0 +1,172 @@ |
|||||
|
package com.iflytop.digester.underframework.connection; |
||||
|
import com.iflytop.digester.underframework.dao.model.UfMdbActuatorCmd; |
||||
|
|
||||
|
import java.io.DataOutputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.io.InputStream; |
||||
|
import java.net.Socket; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
public class UfModbusRTUOverTCP extends UfConnectionBase { |
||||
|
// connection |
||||
|
private Socket socket; |
||||
|
// writer |
||||
|
private DataOutputStream writer; |
||||
|
// reader |
||||
|
private InputStream reader; |
||||
|
// busy |
||||
|
private Boolean isBusy = false; |
||||
|
|
||||
|
// connections |
||||
|
private static final Map<String, UfModbusRTUOverTCP> connections = new HashMap<>(); |
||||
|
|
||||
|
// get connection |
||||
|
public static UfModbusRTUOverTCP getConnection(String host, Integer port) { |
||||
|
String key = host + ":" + port; |
||||
|
if ( connections.containsKey(key) ) { |
||||
|
return connections.get(key); |
||||
|
} |
||||
|
|
||||
|
UfModbusRTUOverTCP con = new UfModbusRTUOverTCP(); |
||||
|
con.connect(host, port); |
||||
|
connections.put(key, con); |
||||
|
return con; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String execute(UfMdbActuatorCmd command) { |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void connect() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// constructor |
||||
|
public UfModbusRTUOverTCP() { |
||||
|
this.isBusy = false; |
||||
|
} |
||||
|
|
||||
|
// connect |
||||
|
public void connect( String host, Integer port ) { |
||||
|
try { |
||||
|
this.socket = new Socket(host, port); |
||||
|
this.writer = new DataOutputStream(this.socket.getOutputStream()); |
||||
|
this.reader = this.socket.getInputStream(); |
||||
|
} catch (Exception e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// write holding register |
||||
|
public void writeHoldingRegister( Integer slaveId, Integer address, Integer value ) { |
||||
|
byte[] cmd = new byte[8]; |
||||
|
cmd[0] = (byte)(slaveId & 0xFF); // slave id |
||||
|
cmd[1] = 0x06; // function code |
||||
|
cmd[2] = (byte)(address >> 8); // address high |
||||
|
cmd[3] = (byte)(address & 0xFF); // address low |
||||
|
cmd[4] = (byte)(value >> 8); // value high |
||||
|
cmd[5] = (byte)(value & 0xFF); // value low |
||||
|
this.call(cmd); |
||||
|
} |
||||
|
|
||||
|
// read holding register |
||||
|
public Integer readHoldingRegister( Integer slaveId, Integer address ) { |
||||
|
byte[] cmd = new byte[8]; |
||||
|
cmd[0] = (byte)(slaveId & 0xFF); // slave id |
||||
|
cmd[1] = 0x03; // function code |
||||
|
cmd[2] = (byte)(address >> 8); // address high |
||||
|
cmd[3] = (byte)(address & 0xFF); // address low |
||||
|
cmd[4] = 0x00; // value high |
||||
|
cmd[5] = 0x01; // value low |
||||
|
var response = this.call(cmd); |
||||
|
if (response.isEmpty()) { |
||||
|
throw new RuntimeException("Modbus RTU over TCP: no response"); |
||||
|
} |
||||
|
return response.get(3) << 8 | response.get(4); |
||||
|
} |
||||
|
|
||||
|
// call |
||||
|
private List<Integer> call(byte[] cmd) { |
||||
|
if ( this.isBusy ) { |
||||
|
synchronized ( this ) { |
||||
|
try { |
||||
|
this.wait(); |
||||
|
} catch (InterruptedException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.isBusy = true; |
||||
|
this.writeCmd(cmd); |
||||
|
List<Integer> response = this.readCmdResponse(); |
||||
|
this.isBusy = false; |
||||
|
synchronized ( this ) { |
||||
|
this.notify(); |
||||
|
} |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
// write command |
||||
|
private void writeCmd(byte[] cmd) { |
||||
|
var size = cmd.length; |
||||
|
var crc = this.calculateCRC(cmd, size - 2); |
||||
|
cmd[size-2] = (byte)(crc & 0xFF); |
||||
|
cmd[size-1] = (byte)(crc >> 8); |
||||
|
|
||||
|
try { |
||||
|
this.writer.write(cmd); |
||||
|
this.writer.flush(); |
||||
|
} catch (IOException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
Thread.sleep(300); |
||||
|
} catch (InterruptedException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// read command response |
||||
|
private List<Integer> readCmdResponse ( ) { |
||||
|
try { |
||||
|
List<Integer> result = new ArrayList<>(); |
||||
|
while ( 0 < this.reader.available() ) { |
||||
|
result.add(this.reader.read()); |
||||
|
} |
||||
|
return result; |
||||
|
} catch (IOException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 计算输入数据的CRC16 (Modbus) |
||||
|
* @param data 要计算CRC的字节数组 |
||||
|
* @param length 数组中需要计算的长度 |
||||
|
* @return 计算出的CRC16值 |
||||
|
*/ |
||||
|
public int calculateCRC(byte[] data, int length) { |
||||
|
int crc = 0xFFFF; // CRC的初始值 |
||||
|
|
||||
|
for (int pos = 0; pos < length; pos++) { |
||||
|
crc ^= data[pos] & 0xFF; // 将数据与CRC寄存器异或 |
||||
|
for (int i = 8; i != 0; i--) { // 循环处理每个位 |
||||
|
if ((crc & 0x0001) != 0) { |
||||
|
crc >>= 1; |
||||
|
crc ^= 0xA001; // 0xA001是预设的多项式 |
||||
|
} else { |
||||
|
crc >>= 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 高低位不交换,直接返回 |
||||
|
return crc & 0xFFFF; |
||||
|
} |
||||
|
} |
@ -1 +1 @@ |
|||||
Subproject commit 6bacffe10495394dfa5cf3a793d2aa7a60ef164c |
|
||||
|
Subproject commit 54eb4327c3a74e6aae926d4752b18439f62091f0 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue