fix: modbustcp读功能与测试
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package org.nl.iot.core.driver.protocol.modbustcp;
|
package org.nl.iot.core.driver.protocol.modbustcp;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nl.common.exception.CommonException;
|
import org.nl.common.exception.CommonException;
|
||||||
import org.nl.iot.core.driver.bo.AttributeBO;
|
import org.nl.iot.core.driver.bo.AttributeBO;
|
||||||
@@ -20,6 +21,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* modbus-tcp通信协议的驱动自定义服务实现类
|
* modbus-tcp通信协议的驱动自定义服务实现类
|
||||||
@@ -38,8 +40,9 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
private Map<String, ModbusMaster> connectMap;
|
private Map<String, ModbusMaster> connectMap;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@PostConstruct
|
||||||
public void initial() {
|
public void initial() {
|
||||||
|
connectMap = new ConcurrentHashMap<>(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -104,22 +107,25 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
int slaveId = pointConfig.get("slaveId").getValueByClass(Integer.class);
|
int slaveId = pointConfig.get("slaveId").getValueByClass(Integer.class);
|
||||||
int offset = pointConfig.get("offset").getValueByClass(Integer.class);
|
int offset = pointConfig.get("offset").getValueByClass(Integer.class);
|
||||||
int functionCode = getFunctionCode(offset);
|
int functionCode = getFunctionCode(offset);
|
||||||
|
|
||||||
|
// 计算实际的寄存器地址(Modbus协议地址从0开始)
|
||||||
|
int actualAddress = getActualAddress(offset, functionCode);
|
||||||
|
|
||||||
switch (functionCode) {
|
switch (functionCode) {
|
||||||
case 1:
|
case 1:
|
||||||
BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, offset);
|
BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, actualAddress);
|
||||||
Boolean coilValue = getMasterValue(modbusMaster, coilLocator);
|
Boolean coilValue = getMasterValue(modbusMaster, coilLocator);
|
||||||
return String.valueOf(coilValue);
|
return String.valueOf(coilValue);
|
||||||
case 2:
|
case 2:
|
||||||
BaseLocator<Boolean> inputLocator = BaseLocator.inputStatus(slaveId, offset);
|
BaseLocator<Boolean> inputLocator = BaseLocator.inputStatus(slaveId, actualAddress);
|
||||||
Boolean inputStatusValue = getMasterValue(modbusMaster, inputLocator);
|
Boolean inputStatusValue = getMasterValue(modbusMaster, inputLocator);
|
||||||
return String.valueOf(inputStatusValue);
|
return String.valueOf(inputStatusValue);
|
||||||
case 3:
|
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);
|
Number holdingValue = getMasterValue(modbusMaster, holdingLocator);
|
||||||
return String.valueOf(holdingValue);
|
return String.valueOf(holdingValue);
|
||||||
case 4:
|
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);
|
Number inputRegisterValue = getMasterValue(modbusMaster, inputRegister);
|
||||||
return String.valueOf(inputRegisterValue);
|
return String.valueOf(inputRegisterValue);
|
||||||
default:
|
default:
|
||||||
@@ -179,26 +185,58 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据Modbus地址偏移量获取对应的功能码
|
* 根据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)
|
* @param offset 地址偏移量(1-9999/10001-19999/30001-39999/40001-49999)
|
||||||
* @return 对应的功能码(1-4)
|
* @return 对应的功能码(1-4)
|
||||||
* @throws CommonException 当偏移量不在合法范围时抛出异常
|
* @throws CommonException 当偏移量不在合法范围时抛出异常
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static int getFunctionCode(int offset) {
|
public static int getFunctionCode(int offset) {
|
||||||
int functionCode;
|
int functionCode;
|
||||||
|
|
||||||
if (offset >= 1 && offset <= 9999) {
|
if (offset >= 1 && offset <= 9999) {
|
||||||
functionCode = 1;
|
functionCode = 1; // 线圈
|
||||||
} else if (offset >= 10001 && offset <= 19999) {
|
} else if (offset >= 10001 && offset <= 19999) {
|
||||||
functionCode = 2;
|
functionCode = 2; // 离散输入
|
||||||
} else if (offset >= 30001 && offset <= 39999) {
|
} else if (offset >= 30001 && offset <= 39999) {
|
||||||
functionCode = 3;
|
functionCode = 4; // 输入寄存器
|
||||||
} else if (offset >= 40001 && offset <= 49999) {
|
} else if (offset >= 40001 && offset <= 49999) {
|
||||||
functionCode = 4;
|
functionCode = 3; // 保持寄存器
|
||||||
} else {
|
} else {
|
||||||
throw new CommonException("无效的偏移量:" + offset);
|
throw new CommonException("无效的偏移量:" + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return functionCode;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,18 @@ package org.nl;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
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.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author: lyd
|
* @author: lyd
|
||||||
@@ -13,8 +22,61 @@ import org.springframework.test.context.junit4.SpringRunner;
|
|||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@SpringBootTest(classes = Application.class)
|
@SpringBootTest(classes = Application.class)
|
||||||
public class ApiTest {
|
public class ApiTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ModBusProtocolDriverImpl modBusProtocolDriver;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void modbusTest() {
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user