智慧水务管理系统 - 精河县供水工程综合管理平台

ModbusTcpAdapter.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package com.water.iot.adapter.impl;
  2. import com.water.iot.adapter.AdapterInfo;
  3. import com.water.iot.adapter.AdapterStatus;
  4. import com.water.iot.adapter.DeviceAdapter;
  5. import com.water.iot.model.DeviceCommand;
  6. import com.water.iot.model.DeviceInfo;
  7. import java.io.IOException;
  8. import java.net.InetAddress;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. /**
  12. * Modbus TCP 协议适配器
  13. */
  14. public class ModbusTcpAdapter implements DeviceAdapter {
  15. private String host;
  16. private int port;
  17. private AdapterStatus status = AdapterStatus.DISCONNECTED;
  18. private long connectionTime;
  19. private Map<String, DeviceInfo> connectedDevices = new HashMap<>();
  20. public ModbusTcpAdapter(String host, int port) {
  21. this.host = host;
  22. this.port = port;
  23. }
  24. @Override
  25. public String getProtocol() {
  26. return "modbus_tcp";
  27. }
  28. @Override
  29. public void onMessage(byte[] payload) {
  30. System.out.println("Modbus TCP 接收到设备数据: " + bytesToHex(payload));
  31. try {
  32. // 解析Modbus TCP帧
  33. if (payload.length >= 7) {
  34. int transactionId = ((payload[0] & 0xFF) << 8) | (payload[1] & 0xFF);
  35. int protocolId = ((payload[2] & 0xFF) << 8) | (payload[3] & 0xFF);
  36. int length = ((payload[4] & 0xFF) << 8) | (payload[5] & 0xFF);
  37. int unitId = payload[6];
  38. System.out.printf("Modbus TCP: Transaction=%d, Protocol=%d, Length=%d, UnitId=%d%n",
  39. transactionId, protocolId, length, unitId);
  40. // 处理Modbus请求
  41. if (protocolId == 0 && length > 0) {
  42. processModbusRequest(payload, unitId);
  43. }
  44. }
  45. } catch (Exception e) {
  46. System.err.println("处理Modbus TCP消息时出错: " + e.getMessage());
  47. }
  48. }
  49. private void processModbusRequest(byte[] payload, int unitId) {
  50. if (payload.length >= 8) {
  51. int functionCode = payload[7] & 0xFF;
  52. switch (functionCode) {
  53. case 0x01: // 读线圈状态
  54. handleReadCoils(payload, unitId);
  55. break;
  56. case 0x02: // 读离散输入
  57. handleReadDiscreteInputs(payload, unitId);
  58. break;
  59. case 0x03: // 保持寄存器
  60. handleReadHoldingRegisters(payload, unitId);
  61. break;
  62. case 0x04: // 输入寄存器
  63. handleReadInputRegisters(payload, unitId);
  64. break;
  65. case 0x05: // 写单个线圈
  66. handleWriteSingleCoil(payload, unitId);
  67. break;
  68. case 0x06: // 写单个寄存器
  69. handleWriteSingleRegister(payload, unitId);
  70. break;
  71. case 0x0F: // 写多个线圈
  72. handleWriteMultipleCoils(payload, unitId);
  73. break;
  74. case 0x10: // 写多个寄存器
  75. handleWriteMultipleRegisters(payload, unitId);
  76. break;
  77. default:
  78. System.out.println("未处理的Modbus功能码: 0x" + Integer.toHexString(functionCode));
  79. }
  80. }
  81. }
  82. private void handleReadHoldingRegisters(byte[] payload, int unitId) {
  83. if (payload.length >= 12) {
  84. int startAddress = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF);
  85. int quantity = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF);
  86. System.out.printf("读取保持寄存器: 起始地址=%d, 数量=%d%n", startAddress, quantity);
  87. // 这里应该实际读取设备数据,这里返回模拟数据
  88. byte[] response = generateModbusResponse(0x03, unitId, startAddress, quantity);
  89. // 在实际实现中,这里应该发送响应给设备
  90. }
  91. }
  92. private void handleReadInputRegisters(byte[] payload, int unitId) {
  93. if (payload.length >= 12) {
  94. int startAddress = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF);
  95. int quantity = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF);
  96. System.out.printf("读取输入寄存器: 起始地址=%d, 数量=%d%n", startAddress, quantity);
  97. }
  98. }
  99. private void handleWriteSingleRegister(byte[] payload, int unitId) {
  100. if (payload.length >= 12) {
  101. int address = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF);
  102. int value = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF);
  103. System.out.printf("写入单个寄存器: 地址=%d, 值=%d%n", address, value);
  104. }
  105. }
  106. private byte[] generateModbusResponse(int functionCode, int unitId, int startAddress, int quantity) {
  107. // 模拟生成Modbus响应
  108. byte[] response = new byte[9 + quantity * 2];
  109. response[0] = (byte) (functionCode + 0x80); // 响应
  110. response[1] = (byte) unitId;
  111. response[2] = (byte) (quantity * 2 >> 8);
  112. response[3] = (byte) (quantity * 2);
  113. // 填充模拟数据
  114. for (int i = 0; i < quantity; i++) {
  115. int index = 5 + i * 2;
  116. response[index] = (byte) (i * 100 >> 8);
  117. response[index + 1] = (byte) (i * 100 & 0xFF);
  118. }
  119. return response;
  120. }
  121. @Override
  122. public void sendCommand(String deviceSn, DeviceCommand cmd) {
  123. System.out.println("发送Modbus命令到设备 " + deviceSn + ": " + cmd.getCommandType());
  124. // 根据命令类型生成对应的Modbus请求
  125. switch (cmd.getCommandType()) {
  126. case "read":
  127. generateReadCommand(cmd);
  128. break;
  129. case "write":
  130. generateWriteCommand(cmd);
  131. break;
  132. case "control":
  133. generateControlCommand(cmd);
  134. break;
  135. default:
  136. System.err.println("不支持的命令类型: " + cmd.getCommandType());
  137. }
  138. }
  139. private void generateReadCommand(DeviceCommand cmd) {
  140. // 生成读寄存器命令
  141. int address = Integer.parseInt(cmd.getParameterKey());
  142. int quantity = Integer.parseInt(cmd.getParameterValue().toString());
  143. System.out.printf("生成读命令: 地址=%d, 数量=%d%n", address, quantity);
  144. }
  145. private void generateWriteCommand(DeviceCommand cmd) {
  146. // 生成写寄存器命令
  147. int address = Integer.parseInt(cmd.getParameterKey());
  148. int value = Integer.parseInt(cmd.getParameterValue().toString());
  149. System.out.printf("生成写命令: 地址=%d, 值=%d%n", address, value);
  150. }
  151. private void generateControlCommand(DeviceCommand cmd) {
  152. // 生成控制命令(如开关阀门)
  153. String action = cmd.getParameterKey();
  154. int address = Integer.parseInt(cmd.getParameterValue().toString());
  155. System.out.printf("生成控制命令: 动作=%s, 地址=%d%n", action, address);
  156. }
  157. @Override
  158. public DeviceInfo parseDeviceInfo(byte[] payload) {
  159. System.out.println("解析Modbus设备信息: " + bytesToHex(payload));
  160. // 根据Modbus协议解析设备信息
  161. DeviceInfo deviceInfo = new DeviceInfo("MODBUS_001", "Modbus设备", "flow_meter");
  162. deviceInfo.setManufacturer("Simatic");
  163. deviceInfo.setProtocolVersion("Modbus TCP");
  164. // 解析设备属性
  165. Map<String, Object> properties = new HashMap<>();
  166. properties.put("connectionType", "TCP");
  167. properties.put("baudRate", 115200);
  168. properties.put("parity", "even");
  169. deviceInfo.setProperties(properties);
  170. return deviceInfo;
  171. }
  172. @Override
  173. public AdapterStatus getStatus(String deviceSn) {
  174. return status;
  175. }
  176. @Override
  177. public boolean connect() {
  178. try {
  179. // 尝试连接到Modbus TCP服务器
  180. InetAddress address = InetAddress.getByName(host);
  181. if (address.isReachable(5000)) {
  182. status = AdapterStatus.CONNECTED;
  183. connectionTime = System.currentTimeMillis();
  184. System.out.println("Modbus TCP 适配器连接成功: " + host + ":" + port);
  185. return true;
  186. } else {
  187. status = AdapterStatus.ERROR;
  188. System.err.println("无法连接到Modbus TCP服务器: " + host + ":" + port);
  189. return false;
  190. }
  191. } catch (IOException e) {
  192. status = AdapterStatus.ERROR;
  193. System.err.println("Modbus TCP连接失败: " + e.getMessage());
  194. return false;
  195. }
  196. }
  197. @Override
  198. public void disconnect() {
  199. status = AdapterStatus.DISCONNECTED;
  200. connectedDevices.clear();
  201. System.out.println("Modbus TCP 适配器已断开连接");
  202. }
  203. @Override
  204. public AdapterInfo getAdapterInfo() {
  205. return new AdapterInfo("ModbusTCP适配器", "modbus_tcp", "1.0", "支持Modbus TCP协议的设备适配");
  206. }
  207. private String bytesToHex(byte[] bytes) {
  208. StringBuilder sb = new StringBuilder();
  209. for (byte b : bytes) {
  210. sb.append(String.format("%02X ", b));
  211. }
  212. return sb.toString();
  213. }
  214. }