fix: modbustcp读功能与测试

This commit is contained in:
2026-03-03 14:26:23 +08:00
parent 800736caf8
commit 30a5f68905
2 changed files with 110 additions and 10 deletions

View File

@@ -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<String, ModbusMaster> 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<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, offset);
BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, actualAddress);
Boolean coilValue = getMasterValue(modbusMaster, coilLocator);
return String.valueOf(coilValue);
case 2:
BaseLocator<Boolean> inputLocator = BaseLocator.inputStatus(slaveId, offset);
BaseLocator<Boolean> inputLocator = BaseLocator.inputStatus(slaveId, actualAddress);
Boolean inputStatusValue = getMasterValue(modbusMaster, inputLocator);
return String.valueOf(inputStatusValue);
case 3:
BaseLocator<Number> holdingLocator = BaseLocator.holdingRegister(slaveId, offset, getValueType(type));
BaseLocator<Number> holdingLocator = BaseLocator.holdingRegister(slaveId, actualAddress, getValueType(type));
Number holdingValue = getMasterValue(modbusMaster, holdingLocator);
return String.valueOf(holdingValue);
case 4:
BaseLocator<Number> inputRegister = BaseLocator.inputRegister(slaveId, offset, getValueType(type));
BaseLocator<Number> 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;
}
}
}

View File

@@ -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<String, AttributeBO> driverConfig = new HashMap<>();
driverConfig.put("host", AttributeBO.builder().value("192.168.81.251").build());
driverConfig.put("port", AttributeBO.builder().value("502").build());
// 构建点位配置
Map<String, AttributeBO> 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();
}
}
}