From 30a5f6890575ab4e097bfc73c7adced983a77c03 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Tue, 3 Mar 2026 14:26:23 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20modbustcp=E8=AF=BB=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E4=B8=8E=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modbustcp/ModBusProtocolDriverImpl.java | 58 ++++++++++++++--- nl-web-app/src/test/java/org/nl/ApiTest.java | 62 +++++++++++++++++++ 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java index e66f6e0..3f591c6 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java @@ -1,5 +1,6 @@ package org.nl.iot.core.driver.protocol.modbustcp; +import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.nl.common.exception.CommonException; import org.nl.iot.core.driver.bo.AttributeBO; @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; /** * modbus-tcp通信协议的驱动自定义服务实现类 @@ -38,8 +40,9 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { private Map connectMap; @Override + @PostConstruct public void initial() { - + connectMap = new ConcurrentHashMap<>(16); } @Override @@ -104,22 +107,25 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { int slaveId = pointConfig.get("slaveId").getValueByClass(Integer.class); int offset = pointConfig.get("offset").getValueByClass(Integer.class); int functionCode = getFunctionCode(offset); + + // 计算实际的寄存器地址(Modbus协议地址从0开始) + int actualAddress = getActualAddress(offset, functionCode); switch (functionCode) { case 1: - BaseLocator coilLocator = BaseLocator.coilStatus(slaveId, offset); + BaseLocator coilLocator = BaseLocator.coilStatus(slaveId, actualAddress); Boolean coilValue = getMasterValue(modbusMaster, coilLocator); return String.valueOf(coilValue); case 2: - BaseLocator inputLocator = BaseLocator.inputStatus(slaveId, offset); + BaseLocator inputLocator = BaseLocator.inputStatus(slaveId, actualAddress); Boolean inputStatusValue = getMasterValue(modbusMaster, inputLocator); return String.valueOf(inputStatusValue); case 3: - BaseLocator holdingLocator = BaseLocator.holdingRegister(slaveId, offset, getValueType(type)); + BaseLocator holdingLocator = BaseLocator.holdingRegister(slaveId, actualAddress, getValueType(type)); Number holdingValue = getMasterValue(modbusMaster, holdingLocator); return String.valueOf(holdingValue); case 4: - BaseLocator inputRegister = BaseLocator.inputRegister(slaveId, offset, getValueType(type)); + BaseLocator inputRegister = BaseLocator.inputRegister(slaveId, actualAddress, getValueType(type)); Number inputRegisterValue = getMasterValue(modbusMaster, inputRegister); return String.valueOf(inputRegisterValue); default: @@ -179,26 +185,58 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { /** * 根据Modbus地址偏移量获取对应的功能码 + * 注意:不同厂商对地址范围的定义可能不同,这里采用常见的约定: + * - 00001-09999: 功能码01 (线圈 Coil) + * - 10001-19999: 功能码02 (离散输入 Discrete Input) + * - 30001-39999: 功能码04 (输入寄存器 Input Register) + * - 40001-49999: 功能码03 (保持寄存器 Holding Register) + * * @param offset 地址偏移量(1-9999/10001-19999/30001-39999/40001-49999) * @return 对应的功能码(1-4) * @throws CommonException 当偏移量不在合法范围时抛出异常 */ - public static int getFunctionCode(int offset) { int functionCode; if (offset >= 1 && offset <= 9999) { - functionCode = 1; + functionCode = 1; // 线圈 } else if (offset >= 10001 && offset <= 19999) { - functionCode = 2; + functionCode = 2; // 离散输入 } else if (offset >= 30001 && offset <= 39999) { - functionCode = 3; + functionCode = 4; // 输入寄存器 } else if (offset >= 40001 && offset <= 49999) { - functionCode = 4; + functionCode = 3; // 保持寄存器 } else { throw new CommonException("无效的偏移量:" + offset); } return functionCode; } + + /** + * 根据Modbus地址偏移量和功能码计算实际的寄存器地址 + * Modbus协议中,寄存器地址从0开始,需要减去相应的偏移量 + * + * @param offset 地址偏移量(1-9999/10001-19999/30001-39999/40001-49999) + * @param functionCode 功能码(1-4) + * @return 实际的寄存器地址(从0开始) + */ + private int getActualAddress(int offset, int functionCode) { + switch (functionCode) { + case 1: + // 线圈状态:1-9999 -> 0-9998 + return offset - 1; + case 2: + // 离散输入:10001-19999 -> 0-9998 + return offset - 10001; + case 3: + // 保持寄存器:40001-49999 -> 0-9998 + return offset - 40001; + case 4: + // 输入寄存器:30001-39999 -> 0-9998 + return offset - 30001; + default: + return 0; + } + } } diff --git a/nl-web-app/src/test/java/org/nl/ApiTest.java b/nl-web-app/src/test/java/org/nl/ApiTest.java index 552b2fc..ca573f5 100644 --- a/nl-web-app/src/test/java/org/nl/ApiTest.java +++ b/nl-web-app/src/test/java/org/nl/ApiTest.java @@ -2,9 +2,18 @@ package org.nl; import org.junit.Test; import org.junit.runner.RunWith; +import org.nl.iot.core.driver.bo.AttributeBO; +import org.nl.iot.core.driver.entity.RValue; +import org.nl.iot.core.driver.protocol.modbustcp.ModBusProtocolDriverImpl; +import org.nl.iot.modular.iot.entity.IotConfig; +import org.nl.iot.modular.iot.entity.IotConnect; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import java.util.HashMap; +import java.util.Map; + /** * * @author: lyd @@ -13,8 +22,61 @@ import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class ApiTest { + + @Autowired + private ModBusProtocolDriverImpl modBusProtocolDriver; + @Test public void modbusTest() { + // 构建驱动配置(连接配置) + Map driverConfig = new HashMap<>(); + driverConfig.put("host", AttributeBO.builder().value("192.168.81.251").build()); + driverConfig.put("port", AttributeBO.builder().value("502").build()); + // 构建点位配置 + Map pointConfig = new HashMap<>(); + pointConfig.put("slaveId", AttributeBO.builder().value("1").build()); + pointConfig.put("offset", AttributeBO.builder().value("40001").build()); // 功能码3:保持寄存器 + pointConfig.put("data_type", AttributeBO.builder().value("int16").build()); + + // 构建连接对象 + IotConnect connect = IotConnect.builder() + .id(1) + .code("MODBUS_TCP_001") + .host("192.168.81.251") + .port(502) + .protocol("modbus-tcp") + .enabled(true) + .description("测试Modbus TCP连接") + .build(); + + // 构建配置对象 + IotConfig config = IotConfig.builder() + .id(1) + .connectId(1) + .alias("temperature") + .aliasName("温度传感器") + .registerAddress("40001") + .dataType("int16") + .readonly(true) + .enabled(true) + .description("测试温度读取") + .build(); + + try { + // 调用read方法进行测试 + RValue result = modBusProtocolDriver.read(driverConfig, pointConfig, connect, config); + + // 输出测试结果 + System.out.println("=== Modbus读取测试结果 ==="); + System.out.println("连接信息: " + result.getConnect()); + System.out.println("配置信息: " + result.getConfig()); + System.out.println("读取值: " + result.getValue()); + System.out.println("测试完成!"); + + } catch (Exception e) { + System.err.println("测试失败: " + e.getMessage()); + e.printStackTrace(); + } } }