|
|
package com.xujie.sys.common.utils;
import com.ghgande.j2mod.modbus.facade.ModbusTCPMaster;import com.ghgande.j2mod.modbus.procimg.Register;import com.ghgande.j2mod.modbus.procimg.SimpleRegister;import com.ghgande.j2mod.modbus.util.BitVector;import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import java.util.*;import java.util.stream.Collectors;
public class ModbusUtils { private static final Logger log = LoggerFactory.getLogger(ModbusUtils.class);
/** Modbus TCP 套接字超时(毫秒),用于建连与读写;弱网或从站响应慢时可适当加大 */ private static final int MODBUS_TCP_TIMEOUT_MS = 20000;
/** * * @param highRegister 高 16 位所在寄存器的 {@code getValue()} * @param lowRegister 低 16 位所在寄存器的 {@code getValue()} */ public static float holdingRegistersToFloatBigEndian(int highRegister, int lowRegister) { int bits = (highRegister & 0xFFFF) << 16 | (lowRegister & 0xFFFF); return Float.intBitsToFloat(bits); }
/** * 读取单个保持寄存器值 * * @param ip 设备IP地址 * @param port 端口号(默认502) * @param unitId 单元ID(默认1) * @param ref 寄存器地址(从0开始) * @return 寄存器值,失败返回null */ public static Integer readSingleRegister(String ip, int port, int unitId, int ref) { ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS); master.connect(); Register[] registers = master.readMultipleRegisters(unitId, ref, 1); if (registers != null && registers.length > 0) { log.info("读取保持寄存器成功 - IP: {}, Port: {}, Ref: {}, Value: {}", ip, port, ref, registers[0].getValue()); return registers[0].getValue(); } } catch (Exception e) { log.error("读取单个寄存器失败 - IP: {}, Port: {}, Ref: {}, Error: {}", ip, port, ref, e.getMessage()); throw new RuntimeException("请重试,连接寄存器失败:"+e); } finally { try { master.disconnect(); } catch (Exception e) { log.error("断开连接失败", e); } } return null; }
/** * 读取多个保持寄存器值 * * @param ip 设备IP地址 * @param port 端口号 * @param ref 起始寄存器地址(从0开始) * @param count 读取数量 * @return 寄存器值列表,失败返回空列表 */ public static List<Integer> readMultipleRegisters(String ip, int port, int ref, int count) { ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS); master.connect(); Register[] registers = master.readMultipleRegisters(ref, count); if (registers != null) { return Arrays.stream(registers) .map(Register::getValue) .collect(Collectors.toList()); } } catch (Exception e) { log.error("读取多个寄存器失败 - IP: {}, Port: {}, Ref: {}, Count: {}, Error: {}", ip, port, ref, count, e.getMessage()); } finally { try { master.disconnect(); } catch (Exception e) { log.error("断开连接失败", e); } } return new ArrayList<>(); }
/** * 读取线圈状态 * * @param ip 设备IP地址 * @param port 端口号 * @param ref 起始线圈地址(从0开始) * @param count 读取数量 * @return BitVector对象,失败返回null */ public static BitVector readCoils(String ip, int port, int ref, int count) { ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS); master.connect(); return master.readCoils(ref, count); } catch (Exception e) { log.error("读取线圈失败 - IP: {}, Port: {}, Ref: {}, Count: {}, Error: {}", ip, port, ref, count, e.getMessage()); } finally { try { master.disconnect(); } catch (Exception e) { log.error("断开连接失败", e); } } return null; }
/** * 读取单个线圈状态 * * @param ip 设备IP地址 * @param port 端口号 * @param ref 线圈地址(从0开始) * @return true表示ON,false表示OFF,失败返回null */ public static Boolean readSingleCoil(String ip, int port, int ref) { BitVector coils = readCoils(ip, port, ref, 1); if (coils != null) { return coils.getBit(0); } return null; }
/** * 批量读取寄存器(分批读取,每批最多100个) * * @param ip 设备IP地址 * @param port 端口号 * @param startRef 起始地址 * @param totalCount 总数量 * @return 寄存器值列表 */ public static List<Integer> readRegistersBatch(String ip, int port, int startRef, int totalCount) { List<Integer> result = new ArrayList<>(); int batchSize = 100; // 每批最多读取100个
// 分批读取
for (int i = 0; i < totalCount / batchSize; i++) { int ref = startRef + i * batchSize; List<Integer> batch = readMultipleRegisters(ip, port, ref, batchSize); result.addAll(batch); }
// 读取剩余部分
int remainder = totalCount % batchSize; if (remainder > 0) { int ref = startRef + (totalCount / batchSize) * batchSize; List<Integer> batch = readMultipleRegisters(ip, port, ref, remainder); result.addAll(batch); }
// 验证读取数量
if (result.size() != totalCount) { log.warn("读取寄存器数量不匹配 - 期望: {}, 实际: {}", totalCount, result.size()); }
return result; }
public static Map<Integer, Integer> readHoldingRegisters(String ip, int port, int slaveId, int offset, int quantity) { Map<Integer, Integer> resultMap = new HashMap<>(); ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS);
// 开启连接
master.connect();
// 验证连接是否成功建立
if (!master.isConnected()) { log.error("连接失败 - IP: {}, Port: {}", ip, port); return resultMap; }
// 注意:j2mod 的 ref/address 一般从 0 开始;调用方需自行确保 offset 基准正确
Register[] registers = master.readMultipleRegisters(slaveId, offset, quantity); if (registers == null) { log.warn("读取保持寄存器返回null - IP: {}, Port: {}, offset: {}, quantity: {}", ip, port, offset, quantity); return resultMap; }
for (int i = 0; i < registers.length; i++) { resultMap.put(offset + i, registers[i].getValue()); }
} catch (Exception e) { log.error("读取保持寄存器失败 - IP: {}, Port: {}, offset: {}, quantity: {}, Error: {}", ip, port, offset, quantity, e.getMessage(), e); } finally { try { if (master.isConnected()) { master.disconnect(); } } catch (Exception e) { log.error("断开连接失败", e); } }
return resultMap; }
/** * 连续读取多字保持寄存器,按批拆分后合并。 * Modbus FC03 单次请求的字数超过从站允许上限(常见 100~125)时,从站会返回异常码 0x03 Illegal Data Value。 */ public static Map<Integer, Integer> readHoldingRegistersBatched(String ip, int port, int slaveId, int offset, int quantity) { final int maxPerRequest = 100; Map<Integer, Integer> merged = new HashMap<>(); int pos = offset; int left = quantity; while (left > 0) { int chunk = Math.min(maxPerRequest, left); Map<Integer, Integer> part = readHoldingRegisters(ip, port, slaveId, pos, chunk); if (part == null || part.isEmpty()) { log.warn("分批读取保持寄存器中断 - offset={}, 本批 quantity={}, 已合并 {} 字", pos, chunk, merged.size()); break; } merged.putAll(part); pos += chunk; left -= chunk; } if (merged.size() < quantity) { log.warn("分批读取保持寄存器未凑满 - 期望 {} 字, 实际 {} 字", quantity, merged.size()); } return merged; }
public static Map<Integer, Float> readFloatHoldingRegisters(String ip, int port, int slaveId, int offset, int quantity) { Map<Integer, Float> resultMap = new HashMap<>(); ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS);
// 开启连接
master.connect();
// 验证连接是否成功建立
if (!master.isConnected()) { log.error("连接失败 - IP: {}, Port: {}", ip, port); return resultMap; }
// 注意:j2mod 的 ref/address 一般从 0 开始;调用方需自行确保 offset 基准正确
Register[] registers = master.readMultipleRegisters(slaveId, offset, quantity); if (registers == null) { log.warn("读取保持寄存器返回null - IP: {}, Port: {}, offset: {}, quantity: {}", ip, port, offset, quantity); return resultMap; }
for (int i = 0; i < registers.length; i++) { resultMap.put(offset + i, Float.valueOf(registers[i].getValue())); }
} catch (Exception e) { log.error("读取保持寄存器失败 - IP: {}, Port: {}, offset: {}, quantity: {}, Error: {}", ip, port, offset, quantity, e.getMessage(), e); } finally { try { if (master.isConnected()) { master.disconnect(); } } catch (Exception e) { log.error("断开连接失败", e); } }
return resultMap; }
public static boolean writeSingleHoldingRegister(String ip, int port, int unitId, int ref, int value) { ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS); master.connect(); if (!master.isConnected()) { log.error("连接失败 - IP: {}, Port: {}", ip, port); return false; } master.writeSingleRegister(unitId, ref, new SimpleRegister(value)); return true; } catch (Exception e) { log.error("写入保持寄存器失败 - IP: {}, Port: {}, ref: {}, value: {}, Error: {}", ip, port, ref, value, e.getMessage(), e); return false; } finally { try { if (master.isConnected()) { master.disconnect(); } } catch (Exception e) { log.error("断开连接失败", e); } } }
public static void resetRegisters(String ip, int port, int unitId, List<Integer> refs) { if (refs == null || refs.isEmpty()) { return; } ModbusTCPMaster master = new ModbusTCPMaster(ip, port); try { master.setTimeout(MODBUS_TCP_TIMEOUT_MS); master.connect(); if (!master.isConnected()) { log.error("连接失败 - IP: {}, Port: {}", ip, port); return; } for (Integer ref : refs) { if (ref != null) { master.writeSingleRegister(unitId, ref, new SimpleRegister(0)); } } } catch (Exception e) { log.error("批量复位寄存器失败 - IP: {}, Port: {}, refs: {}, Error: {}", ip, port, refs, e.getMessage(), e); } finally { try { if (master.isConnected()) { master.disconnect(); } } catch (Exception e) { log.error("断开连接失败", e); } } }}
|