fix: s7地址解析
This commit is contained in:
@@ -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 和 1;VD4 → 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user