|
@@ -85,6 +85,7 @@ public class DataParser {
|
|
|
|
|
|
|
|
logger.debug("消息通过所有校验");
|
|
logger.debug("消息通过所有校验");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 解析消息(支持历史记录帧0x31和结束通讯帧0x34,协议2.2.3)
|
|
* 解析消息(支持历史记录帧0x31和结束通讯帧0x34,协议2.2.3)
|
|
|
*/
|
|
*/
|
|
@@ -106,17 +107,18 @@ public class DataParser {
|
|
|
byte frameType = msgBytes[index++];
|
|
byte frameType = msgBytes[index++];
|
|
|
data.setDataType(String.format("0x%02X", frameType));
|
|
data.setDataType(String.format("0x%02X", frameType));
|
|
|
|
|
|
|
|
- // 4. 源地址长度 + 内容
|
|
|
|
|
- int srcLen = msgBytes[index++] & 0xFF;
|
|
|
|
|
- // 实际有些设备固定6字节地址,防止越界
|
|
|
|
|
- int srcAddrSize = Math.min(srcLen, 6);
|
|
|
|
|
|
|
+ // 4. 源地址:按规则计算长度(原地址标识转10进制,奇数+1后除2)
|
|
|
|
|
+ int srcLenFlag = msgBytes[index++] & 0xFF; // 源地址标识(10进制)
|
|
|
|
|
+ int srcAddrSize = calculateAddrLength(srcLenFlag); // 计算源地址字节长度
|
|
|
|
|
+ srcAddrSize = Math.min(srcAddrSize, 10); // 防止越界,最多10字节
|
|
|
byte[] srcAddr = Arrays.copyOfRange(msgBytes, index, index + srcAddrSize);
|
|
byte[] srcAddr = Arrays.copyOfRange(msgBytes, index, index + srcAddrSize);
|
|
|
data.setSourceAddr(parseBcdToStr(srcAddr));
|
|
data.setSourceAddr(parseBcdToStr(srcAddr));
|
|
|
index += srcAddrSize;
|
|
index += srcAddrSize;
|
|
|
|
|
|
|
|
- // 5. 目的地址长度 + 内容
|
|
|
|
|
- int dstLen = msgBytes[index++] & 0xFF;
|
|
|
|
|
- int dstAddrSize = Math.min(dstLen, 6);
|
|
|
|
|
|
|
+ // 5. 目的地址:按相同规则计算长度
|
|
|
|
|
+ int dstLenFlag = msgBytes[index++] & 0xFF; // 目的地址标识(10进制)
|
|
|
|
|
+ int dstAddrSize = calculateAddrLength(dstLenFlag); // 计算目的地址字节长度
|
|
|
|
|
+ dstAddrSize = Math.min(dstAddrSize, 10); // 防止越界,最多10字节
|
|
|
byte[] dstAddr = Arrays.copyOfRange(msgBytes, index, index + dstAddrSize);
|
|
byte[] dstAddr = Arrays.copyOfRange(msgBytes, index, index + dstAddrSize);
|
|
|
data.setDestAddr(parseBcdToStr(dstAddr));
|
|
data.setDestAddr(parseBcdToStr(dstAddr));
|
|
|
data.setDestAddrLength(String.valueOf(dstAddrSize));
|
|
data.setDestAddrLength(String.valueOf(dstAddrSize));
|
|
@@ -124,61 +126,95 @@ public class DataParser {
|
|
|
|
|
|
|
|
// 6. 帧类型 = 0x31
|
|
// 6. 帧类型 = 0x31
|
|
|
if (frameType == 0x31) {
|
|
if (frameType == 0x31) {
|
|
|
|
|
+ // 设备ID
|
|
|
data.setDeviceCode(String.format("%02X", msgBytes[index++]));
|
|
data.setDeviceCode(String.format("%02X", msgBytes[index++]));
|
|
|
|
|
+ // 功能码
|
|
|
data.setFunctionCode(String.format("%02X", msgBytes[index++]));
|
|
data.setFunctionCode(String.format("%02X", msgBytes[index++]));
|
|
|
|
|
|
|
|
- data.setReserve1(String.format("%02X%02X%02X%02X", msgBytes[index], msgBytes[index + 1], msgBytes[index + 2], msgBytes[index + 3]));
|
|
|
|
|
- index += 4;
|
|
|
|
|
- data.setReserve2(String.format("%02X%02X", msgBytes[index], msgBytes[index + 1]));
|
|
|
|
|
- index += 2;
|
|
|
|
|
|
|
+ // 预留6字节(原代码拆成了4+2,合并为6字节)
|
|
|
|
|
+ data.setReserve1(String.format("%02X%02X%02X%02X%02X%02X",
|
|
|
|
|
+ msgBytes[index], msgBytes[index+1], msgBytes[index+2],
|
|
|
|
|
+ msgBytes[index+3], msgBytes[index+4], msgBytes[index+5]));
|
|
|
|
|
+ index += 6;
|
|
|
|
|
|
|
|
|
|
+ // 记录数量
|
|
|
int recordCount = msgBytes[index++] & 0xFF;
|
|
int recordCount = msgBytes[index++] & 0xFF;
|
|
|
data.setRecordCount(String.valueOf(recordCount));
|
|
data.setRecordCount(String.valueOf(recordCount));
|
|
|
|
|
|
|
|
|
|
+ // 记录格式
|
|
|
int recordFormat = ((msgBytes[index] & 0xFF) << 8) | (msgBytes[index + 1] & 0xFF);
|
|
int recordFormat = ((msgBytes[index] & 0xFF) << 8) | (msgBytes[index + 1] & 0xFF);
|
|
|
data.setRecordFormat(String.format("%04X", recordFormat));
|
|
data.setRecordFormat(String.format("%04X", recordFormat));
|
|
|
index += 2;
|
|
index += 2;
|
|
|
|
|
|
|
|
|
|
+ // 电池电压(整型转浮点,除以100)
|
|
|
int powerVolt = ((msgBytes[index] & 0xFF) << 8) | (msgBytes[index + 1] & 0xFF);
|
|
int powerVolt = ((msgBytes[index] & 0xFF) << 8) | (msgBytes[index + 1] & 0xFF);
|
|
|
data.setPowerVoltage(String.format("%.2f", powerVolt / 100.0));
|
|
data.setPowerVoltage(String.format("%.2f", powerVolt / 100.0));
|
|
|
index += 2;
|
|
index += 2;
|
|
|
|
|
|
|
|
|
|
+ // 现场状态(解析D3位判断是否最后一包)
|
|
|
byte fieldStatus = msgBytes[index++];
|
|
byte fieldStatus = msgBytes[index++];
|
|
|
data.setFieldStatus(String.format("%02X", fieldStatus));
|
|
data.setFieldStatus(String.format("%02X", fieldStatus));
|
|
|
|
|
+ // D3位:0x08 对应二进制 00001000,按位与判断
|
|
|
data.setIsLastPacket((fieldStatus & 0x08) != 0);
|
|
data.setIsLastPacket((fieldStatus & 0x08) != 0);
|
|
|
|
|
|
|
|
|
|
+ // 协议版本(两个字节)
|
|
|
data.setProtocolVersion(String.format("%02X", msgBytes[index++]));
|
|
data.setProtocolVersion(String.format("%02X", msgBytes[index++]));
|
|
|
data.setParamVersion(String.format("%02X", msgBytes[index++]));
|
|
data.setParamVersion(String.format("%02X", msgBytes[index++]));
|
|
|
|
|
+ // 信号质量
|
|
|
data.setSignalQuality(String.valueOf(msgBytes[index++] & 0xFF));
|
|
data.setSignalQuality(String.valueOf(msgBytes[index++] & 0xFF));
|
|
|
|
|
|
|
|
|
|
+ // 预留3字节
|
|
|
data.setReserve3(String.format("%02X%02X%02X", msgBytes[index], msgBytes[index + 1], msgBytes[index + 2]));
|
|
data.setReserve3(String.format("%02X%02X%02X", msgBytes[index], msgBytes[index + 1], msgBytes[index + 2]));
|
|
|
index += 3;
|
|
index += 3;
|
|
|
|
|
|
|
|
// --- 历史记录部分 ---
|
|
// --- 历史记录部分 ---
|
|
|
if (recordCount > 0 && index + 4 <= msgBytes.length) {
|
|
if (recordCount > 0 && index + 4 <= msgBytes.length) {
|
|
|
|
|
+ // 数据采集时间(4字节)
|
|
|
int ts = ((msgBytes[index] & 0xFF) << 24) | ((msgBytes[index + 1] & 0xFF) << 16)
|
|
int ts = ((msgBytes[index] & 0xFF) << 24) | ((msgBytes[index + 1] & 0xFF) << 16)
|
|
|
| ((msgBytes[index + 2] & 0xFF) << 8) | (msgBytes[index + 3] & 0xFF);
|
|
| ((msgBytes[index + 2] & 0xFF) << 8) | (msgBytes[index + 3] & 0xFF);
|
|
|
LocalDateTime recordTime = ProtocolUtils.convertToDateTime(ts);
|
|
LocalDateTime recordTime = ProtocolUtils.convertToDateTime(ts);
|
|
|
data.setTimestampSince(recordTime);
|
|
data.setTimestampSince(recordTime);
|
|
|
index += 4;
|
|
index += 4;
|
|
|
|
|
|
|
|
- long net = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
- long pos = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
- long neg = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
- long flow = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
- long pressure = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
- long switchVal = bytesToUInt32(msgBytes, index); index += 4;
|
|
|
|
|
-
|
|
|
|
|
- data.setMeter1NetTotal(String.valueOf(net));
|
|
|
|
|
- data.setMeter1PositiveTotal(String.valueOf(pos));
|
|
|
|
|
- data.setMeter1NegativeTotal(String.valueOf(neg));
|
|
|
|
|
- data.setMeter1InstantFlow(String.valueOf(flow));
|
|
|
|
|
- data.setPressure(String.valueOf(pressure));
|
|
|
|
|
|
|
+ // 表1净累计(4字节浮点)
|
|
|
|
|
+ float netTotal = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 表1正累计(4字节浮点)
|
|
|
|
|
+ float posTotal = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 表1负累计(4字节浮点)
|
|
|
|
|
+ float negTotal = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 表1瞬时流量(4字节浮点)
|
|
|
|
|
+ float instantFlow = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 流速(4字节浮点)
|
|
|
|
|
+ float flowSpeed = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 压力(4字节浮点)
|
|
|
|
|
+ float pressure = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 温度(4字节浮点)
|
|
|
|
|
+ float temperature = bytesToFloat(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+ // 开关量(4字节整型)
|
|
|
|
|
+ long switchVal = bytesToUInt32(msgBytes, index);
|
|
|
|
|
+ index += 4;
|
|
|
|
|
+
|
|
|
|
|
+ // 设置浮点型数据(保留两位小数展示)
|
|
|
|
|
+ data.setMeter1NetTotal(String.format("%.2f", netTotal));
|
|
|
|
|
+ data.setMeter1PositiveTotal(String.format("%.2f", posTotal));
|
|
|
|
|
+ data.setMeter1NegativeTotal(String.format("%.2f", negTotal));
|
|
|
|
|
+ data.setMeter1InstantFlow(String.format("%.2f", instantFlow));
|
|
|
|
|
+ data.setFlowSpeed(String.format("%.2f", flowSpeed)); // 新增流速字段
|
|
|
|
|
+ data.setPressure(String.format("%.2f", pressure));
|
|
|
|
|
+ data.setTemperature(String.format("%.2f", temperature)); // 新增温度字段
|
|
|
data.setSwitchValue(String.format("%08X", switchVal));
|
|
data.setSwitchValue(String.format("%08X", switchVal));
|
|
|
|
|
|
|
|
|
|
+ // 格式化历史记录字符串
|
|
|
data.setHistoryRecords(String.format(
|
|
data.setHistoryRecords(String.format(
|
|
|
- "时间:%s,净累计:%d,正累计:%d,负累计:%d,瞬时流量:%d,压力:%d,开关量:%08X",
|
|
|
|
|
- recordTime, net, pos, neg, flow, pressure, switchVal));
|
|
|
|
|
|
|
+ "时间:%s,净累计:%.2f,正累计:%.2f,负累计:%.2f,瞬时流量:%.2f,流速:%.2f,压力:%.2f,温度:%.2f,开关量:%08X",
|
|
|
|
|
+ recordTime, netTotal, posTotal, negTotal, instantFlow, flowSpeed, pressure, temperature, switchVal));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -186,6 +222,37 @@ public class DataParser {
|
|
|
return data;
|
|
return data;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 计算地址字节长度:原地址标识转10进制,奇数+1后除2
|
|
|
|
|
+ * @param lenFlag 地址标识(10进制值)
|
|
|
|
|
+ * @return 地址字节长度
|
|
|
|
|
+ */
|
|
|
|
|
+ private static int calculateAddrLength(int lenFlag) {
|
|
|
|
|
+ int temp = lenFlag;
|
|
|
|
|
+ // 奇数则+1
|
|
|
|
|
+ if (temp % 2 != 0) {
|
|
|
|
|
+ temp += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 除2得到字节长度
|
|
|
|
|
+ return temp / 2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 4字节(高字节在前)转单精度浮点型(IEEE 754)
|
|
|
|
|
+ * @param data 字节数组
|
|
|
|
|
+ * @param offset 起始偏移量
|
|
|
|
|
+ * @return 单精度浮点值
|
|
|
|
|
+ */
|
|
|
|
|
+ private static float bytesToFloat(byte[] data, int offset) {
|
|
|
|
|
+ // 先将4字节转为int(高字节在前)
|
|
|
|
|
+ int intValue = ((data[offset] & 0xFF) << 24)
|
|
|
|
|
+ | ((data[offset + 1] & 0xFF) << 16)
|
|
|
|
|
+ | ((data[offset + 2] & 0xFF) << 8)
|
|
|
|
|
+ | (data[offset + 3] & 0xFF);
|
|
|
|
|
+ // 按IEEE 754规则转换为float
|
|
|
|
|
+ return Float.intBitsToFloat(intValue);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/** 工具方法:BCD转字符串 */
|
|
/** 工具方法:BCD转字符串 */
|
|
|
private static String parseBcdToStr(byte[] bytes) {
|
|
private static String parseBcdToStr(byte[] bytes) {
|
|
|
StringBuilder sb = new StringBuilder();
|
|
StringBuilder sb = new StringBuilder();
|
|
@@ -202,4 +269,4 @@ public class DataParser {
|
|
|
| ((long) (data[offset + 2] & 0xFF) << 8)
|
|
| ((long) (data[offset + 2] & 0xFF) << 8)
|
|
|
| ((long) (data[offset + 3] & 0xFF));
|
|
| ((long) (data[offset + 3] & 0xFF));
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+}
|