package com.water.iot.adapter.impl; import com.water.iot.adapter.AdapterInfo; import com.water.iot.adapter.AdapterStatus; import com.water.iot.adapter.DeviceAdapter; import com.water.iot.model.DeviceCommand; import com.water.iot.model.DeviceInfo; import java.io.IOException; import java.net.InetAddress; import java.util.HashMap; import java.util.Map; /** * Modbus TCP 协议适配器 */ public class ModbusTcpAdapter implements DeviceAdapter { private String host; private int port; private AdapterStatus status = AdapterStatus.DISCONNECTED; private long connectionTime; private Map connectedDevices = new HashMap<>(); public ModbusTcpAdapter(String host, int port) { this.host = host; this.port = port; } @Override public String getProtocol() { return "modbus_tcp"; } @Override public void onMessage(byte[] payload) { System.out.println("Modbus TCP 接收到设备数据: " + bytesToHex(payload)); try { // 解析Modbus TCP帧 if (payload.length >= 7) { int transactionId = ((payload[0] & 0xFF) << 8) | (payload[1] & 0xFF); int protocolId = ((payload[2] & 0xFF) << 8) | (payload[3] & 0xFF); int length = ((payload[4] & 0xFF) << 8) | (payload[5] & 0xFF); int unitId = payload[6]; System.out.printf("Modbus TCP: Transaction=%d, Protocol=%d, Length=%d, UnitId=%d%n", transactionId, protocolId, length, unitId); // 处理Modbus请求 if (protocolId == 0 && length > 0) { processModbusRequest(payload, unitId); } } } catch (Exception e) { System.err.println("处理Modbus TCP消息时出错: " + e.getMessage()); } } private void processModbusRequest(byte[] payload, int unitId) { if (payload.length >= 8) { int functionCode = payload[7] & 0xFF; switch (functionCode) { case 0x01: // 读线圈状态 handleReadCoils(payload, unitId); break; case 0x02: // 读离散输入 handleReadDiscreteInputs(payload, unitId); break; case 0x03: // 保持寄存器 handleReadHoldingRegisters(payload, unitId); break; case 0x04: // 输入寄存器 handleReadInputRegisters(payload, unitId); break; case 0x05: // 写单个线圈 handleWriteSingleCoil(payload, unitId); break; case 0x06: // 写单个寄存器 handleWriteSingleRegister(payload, unitId); break; case 0x0F: // 写多个线圈 handleWriteMultipleCoils(payload, unitId); break; case 0x10: // 写多个寄存器 handleWriteMultipleRegisters(payload, unitId); break; default: System.out.println("未处理的Modbus功能码: 0x" + Integer.toHexString(functionCode)); } } } private void handleReadHoldingRegisters(byte[] payload, int unitId) { if (payload.length >= 12) { int startAddress = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF); int quantity = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF); System.out.printf("读取保持寄存器: 起始地址=%d, 数量=%d%n", startAddress, quantity); // 这里应该实际读取设备数据,这里返回模拟数据 byte[] response = generateModbusResponse(0x03, unitId, startAddress, quantity); // 在实际实现中,这里应该发送响应给设备 } } private void handleReadInputRegisters(byte[] payload, int unitId) { if (payload.length >= 12) { int startAddress = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF); int quantity = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF); System.out.printf("读取输入寄存器: 起始地址=%d, 数量=%d%n", startAddress, quantity); } } private void handleWriteSingleRegister(byte[] payload, int unitId) { if (payload.length >= 12) { int address = ((payload[8] & 0xFF) << 8) | (payload[9] & 0xFF); int value = ((payload[10] & 0xFF) << 8) | (payload[11] & 0xFF); System.out.printf("写入单个寄存器: 地址=%d, 值=%d%n", address, value); } } private byte[] generateModbusResponse(int functionCode, int unitId, int startAddress, int quantity) { // 模拟生成Modbus响应 byte[] response = new byte[9 + quantity * 2]; response[0] = (byte) (functionCode + 0x80); // 响应 response[1] = (byte) unitId; response[2] = (byte) (quantity * 2 >> 8); response[3] = (byte) (quantity * 2); // 填充模拟数据 for (int i = 0; i < quantity; i++) { int index = 5 + i * 2; response[index] = (byte) (i * 100 >> 8); response[index + 1] = (byte) (i * 100 & 0xFF); } return response; } @Override public void sendCommand(String deviceSn, DeviceCommand cmd) { System.out.println("发送Modbus命令到设备 " + deviceSn + ": " + cmd.getCommandType()); // 根据命令类型生成对应的Modbus请求 switch (cmd.getCommandType()) { case "read": generateReadCommand(cmd); break; case "write": generateWriteCommand(cmd); break; case "control": generateControlCommand(cmd); break; default: System.err.println("不支持的命令类型: " + cmd.getCommandType()); } } private void generateReadCommand(DeviceCommand cmd) { // 生成读寄存器命令 int address = Integer.parseInt(cmd.getParameterKey()); int quantity = Integer.parseInt(cmd.getParameterValue().toString()); System.out.printf("生成读命令: 地址=%d, 数量=%d%n", address, quantity); } private void generateWriteCommand(DeviceCommand cmd) { // 生成写寄存器命令 int address = Integer.parseInt(cmd.getParameterKey()); int value = Integer.parseInt(cmd.getParameterValue().toString()); System.out.printf("生成写命令: 地址=%d, 值=%d%n", address, value); } private void generateControlCommand(DeviceCommand cmd) { // 生成控制命令(如开关阀门) String action = cmd.getParameterKey(); int address = Integer.parseInt(cmd.getParameterValue().toString()); System.out.printf("生成控制命令: 动作=%s, 地址=%d%n", action, address); } @Override public DeviceInfo parseDeviceInfo(byte[] payload) { System.out.println("解析Modbus设备信息: " + bytesToHex(payload)); // 根据Modbus协议解析设备信息 DeviceInfo deviceInfo = new DeviceInfo("MODBUS_001", "Modbus设备", "flow_meter"); deviceInfo.setManufacturer("Simatic"); deviceInfo.setProtocolVersion("Modbus TCP"); // 解析设备属性 Map properties = new HashMap<>(); properties.put("connectionType", "TCP"); properties.put("baudRate", 115200); properties.put("parity", "even"); deviceInfo.setProperties(properties); return deviceInfo; } @Override public AdapterStatus getStatus(String deviceSn) { return status; } @Override public boolean connect() { try { // 尝试连接到Modbus TCP服务器 InetAddress address = InetAddress.getByName(host); if (address.isReachable(5000)) { status = AdapterStatus.CONNECTED; connectionTime = System.currentTimeMillis(); System.out.println("Modbus TCP 适配器连接成功: " + host + ":" + port); return true; } else { status = AdapterStatus.ERROR; System.err.println("无法连接到Modbus TCP服务器: " + host + ":" + port); return false; } } catch (IOException e) { status = AdapterStatus.ERROR; System.err.println("Modbus TCP连接失败: " + e.getMessage()); return false; } } @Override public void disconnect() { status = AdapterStatus.DISCONNECTED; connectedDevices.clear(); System.out.println("Modbus TCP 适配器已断开连接"); } @Override public AdapterInfo getAdapterInfo() { return new AdapterInfo("ModbusTCP适配器", "modbus_tcp", "1.0", "支持Modbus TCP协议的设备适配"); } private String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); } return sb.toString(); } }