fix: s7地址解析

This commit is contained in:
2026-03-11 10:34:35 +08:00
parent 12e8483804
commit ffb0947e32

View File

@@ -214,14 +214,122 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
*/
private PlcS7PointVariable getPointVariable(IotConfig config, String type) {
log.debug("Plc S7 Point Attribute Config {}", config);
// todo: DB 块地址解析
// return new PlcS7PointVariable(
// config.get("dbNum").getValueByClass(Integer.class),
// config.get("byteOffset").getValueByClass(Integer.class),
// config.get("bitOffset").getValueByClass(Integer.class),
// config.get("blockSize").getValueByClass(Integer.class),
// type);
return null;
// DB 块地址解析
return parseS7Address(config.getRegisterAddress(), type);
}
// 通用解析方法支持DB格式DB1.DBX10.3和S7-200格式VB1、VD4、V1.3
public static PlcS7PointVariable parseS7Address(String address, String type) {
if (address == null || address.trim().isEmpty()) {
throw new IllegalArgumentException("S7地址不能为空");
}
String cleanAddress = address.trim().toUpperCase();
int dbNum = 0;
String area = "";
int byteOffset = -1;
int bitOffset = -1;
int size = -1;
// ========== 分支1解析S7-1200/1500的DB格式DB1.DBX10.3、DB2.DBD5 ==========
if (cleanAddress.startsWith("DB")) {
area = "DB";
// 拆分DB编号和地址主体DB1.DBX10.3 → DB1 和 DBX10.3
String[] dbAndAddress = cleanAddress.split("\\.DB", 2);
if (dbAndAddress.length != 2) {
throw new IllegalArgumentException("DB地址格式错误" + address);
}
// 解析DB编号
String dbNumStr = dbAndAddress[0].replace("DB", "");
try {
dbNum = Integer.parseInt(dbNumStr);
if (dbNum < 1) throw new IllegalArgumentException("DB编号必须≥1" + dbNumStr);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("DB编号不是有效数字" + dbNumStr, e);
}
// 解析类型和偏移DBX10.3 → X10.3
String addressBody = "DB" + dbAndAddress[1];
char typeSuffix = addressBody.charAt(2);
String offsetStr = addressBody.substring(3);
// 按类型解析
switch (typeSuffix) {
case 'X': // BOOL
String[] byteBit = offsetStr.split("\\.");
if (byteBit.length != 2) throw new IllegalArgumentException("BOOL地址需包含位偏移" + address);
byteOffset = parseIntCheck(byteBit[0], "字节偏移");
bitOffset = parseIntCheck(byteBit[1], "位偏移");
if (bitOffset < 0 || bitOffset > 7) throw new IllegalArgumentException("位偏移需0-7" + bitOffset);
size = 1;
break;
case 'B': // BYTE
byteOffset = parseIntCheck(offsetStr, "字节偏移");
size = 1;
break;
case 'W': // WORD
byteOffset = parseIntCheck(offsetStr, "字节偏移");
size = 2;
break;
case 'D': // DWORD/REAL
byteOffset = parseIntCheck(offsetStr, "字节偏移");
size = 4;
break;
case 'R': // REAL
byteOffset = parseIntCheck(offsetStr, "字节偏移");
size = 4;
break;
default:
throw new IllegalArgumentException("不支持的DB类型后缀" + typeSuffix);
}
// ========== 分支2解析S7-200的VB/VD/V1.3格式 ==========
} else {
// 第一步判断是BOOL位V1.3、I0.1)还是字节/双字VB1、VD4
if (cleanAddress.contains(".")) {
// 处理BOOL位V1.3、I0.1、M2.5
String[] areaByteBit = cleanAddress.split("\\.");
if (areaByteBit.length != 2) throw new IllegalArgumentException("S7-200 BOOL地址格式错误" + address);
// 拆分存储区和字节偏移V1 → V 和 1
String areaByteStr = areaByteBit[0];
area = areaByteStr.substring(0, 1); // 取第一个字符V/I/Q/M/SM
String byteOffsetStr = areaByteStr.substring(1);
// 校验存储区合法性
if (!"VIQMSM".contains(area)) throw new IllegalArgumentException("不支持的S7-200存储区" + area);
// 解析字节和位偏移
byteOffset = parseIntCheck(byteOffsetStr, "字节偏移");
bitOffset = parseIntCheck(areaByteBit[1], "位偏移");
if (bitOffset < 0 || bitOffset > 7) throw new IllegalArgumentException("位偏移需0-7" + bitOffset);
size = 1; // BOOL占1字节
} else {
// 处理字节/双字VB1、VD4、IW2、MB3
// 拆分存储区+类型 和 地址VB1 → VB 和 1VD4 → VD 和 4
char typeSuffix = cleanAddress.charAt(1); // 第二个字符是类型B/W/D
area = cleanAddress.substring(0, 1); // 第一个字符是存储区V/I/Q/M/SM
String offsetStr = cleanAddress.substring(2);
// 校验存储区和类型
if (!"VIQMSM".contains(area)) throw new IllegalArgumentException("不支持的S7-200存储区" + area);
if (!"BWD".contains(String.valueOf(typeSuffix))) throw new IllegalArgumentException("不支持的S7-200类型后缀" + typeSuffix);
// 解析字节偏移和大小
byteOffset = parseIntCheck(offsetStr, "字节偏移");
switch (typeSuffix) {
case 'B': size = 1; break; // BYTE
case 'W': size = 2; break; // WORD
case 'D': size = 4; break; // DWORD/REAL
}
}
}
// 校验字节偏移合法性
if (byteOffset < 0) throw new IllegalArgumentException("字节偏移不能为负数:" + byteOffset);
return new PlcS7PointVariable(dbNum, byteOffset, bitOffset, size, type);
}
// 工具方法:解析数字并捕获异常
private static int parseIntCheck(String str, String fieldName) {
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(fieldName + "不是有效数字:" + str, e);
}
}
/**