From c8e4c68985aebe1afeee51356b7ead1bb94164ac Mon Sep 17 00:00:00 2001 From: shenzhouyu Date: Fri, 22 May 2026 20:00:53 +0800 Subject: [PATCH] =?UTF-8?q?=E8=83=B6=E6=B0=B4=E9=87=87=E9=9B=8617.?= =?UTF-8?q?=E5=87=A0=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xujie/sys/common/utils/ModbusUtils.java | 35 +++++++-- .../pms/service/Impl/QcServiceImpl.java | 74 ++++++++++++------- 2 files changed, 77 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java b/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java index d4621ef5..ab9156ed 100644 --- a/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java +++ b/src/main/java/com/xujie/sys/common/utils/ModbusUtils.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; @@ -15,7 +16,7 @@ public class ModbusUtils { private static final Logger log = LoggerFactory.getLogger(ModbusUtils.class); /** Modbus TCP 套接字超时(毫秒),用于建连与读写;弱网或从站响应慢时可适当加大 */ - private static final int MODBUS_TCP_TIMEOUT_MS = 20000; + private static final int MODBUS_TCP_TIMEOUT_MS = 30000; /** * 与 {@code ModbusCommunicateServiceImpl#getResponseMessage} 一致:首寄存器为高 16 位,次寄存器为低 16 位。 @@ -53,29 +54,49 @@ public class ModbusUtils { return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString(); } + /** 入库用:四舍五入保留 4 位小数 */ + public static String formatFloat4Decimals(float value) { + if (Float.isNaN(value) || Float.isInfinite(value)) { + return "0.0000"; + } + return BigDecimal.valueOf(value).setScale(4, RoundingMode.HALF_UP).toPlainString(); + } + private static float pickAbnormalFloatCandidate(float highWordFirst, float lowWordFirst) { int scoreHigh = scoreAbnormalFloat(highWordFirst); int scoreLow = scoreAbnormalFloat(lowWordFirst); if (scoreLow > scoreHigh) { return lowWordFirst; } + if (scoreHigh > scoreLow) { + return highWordFirst; + } + if (scoreHigh < 0) { + return 0f; + } return highWordFirst; } - /** 值越大越可信:占位值 -99999.9 > 正常测量 > 0 > 字序错误的极小值 */ + /** + * 值越大越可信:设备占位约 ±99999 > 正常测量(如 17.x)> 0; + * 字序/地址偏差产生的 ±1e8、2.7E23、E-41 等极低或极高值判为不可信。 + */ private static int scoreAbnormalFloat(float value) { if (Float.isNaN(value) || Float.isInfinite(value)) { - return -100; + return -1000; } if (value == 0f) { return 0; } float abs = Math.abs(value); - if (abs >= 10000f) { - return 100; + if (abs >= 99900f && abs <= 100100f) { + return 1000; + } + if (abs >= 1e6f || abs < 1e-4f) { + return -1000; } - if (abs >= 1e-6f) { - return 50; + if (abs <= 50000f) { + return 500; } return -100; } diff --git a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java index b1c6727f..4802f94d 100644 --- a/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/pms/service/Impl/QcServiceImpl.java @@ -4815,6 +4815,7 @@ public class QcServiceImpl implements QcService { } @Override + @Transactional(rollbackFor = Exception.class) public ArrayList getCollectorDataByItem(QcFAIRecordData data) throws Exception{ EquipmentFolderLocation location = getCollectorLocation(data.getSite()); int port = location.getPort(); @@ -4834,7 +4835,7 @@ public class QcServiceImpl implements QcService { } ArrayList abnormalRows = getAbnormalCollectorData(ip, port, unitId, data); - resetCollectorAbnormalRegisters(ip, port, unitId); + //resetCollectorAbnormalRegisters(ip, port, unitId); return abnormalRows; }else{ logger.info(port+","+ip+","+unitId+","+baseAddr+","+groups+","); @@ -4935,6 +4936,14 @@ public class QcServiceImpl implements QcService { return v == null ? -1 : (v & 0xFFFF); } + private static String hexReg(Map raw, int ref) { + Integer v = raw.get(ref); + if (v == null) { + return "null"; + } + return String.format(Locale.ROOT, "%04X", v & 0xFFFF); + } + private EquipmentFolderLocation getCollectorLocation(String site) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(EquipmentFolderLocation::getEquipmentNo, "J001"); @@ -5187,7 +5196,7 @@ public class QcServiceImpl implements QcService { }*/ private ArrayList getAbnormalCollectorData(String ip, int port, int unitId, QcFAIRecordData data) throws Exception { int readStartAddr = 400; - int readCount = 195; // 覆盖 400~594(单次 FC03 字数不宜超过从站上限,需分批读) + int readCount = 196; // 覆盖 400~595(第10组第5路float需595,单次FC03需分批) Map raw = ModbusUtils.readHoldingRegistersBatched(ip, port, unitId, readStartAddr, readCount); ArrayList subDetailValues = new ArrayList<>(); if (raw == null || raw.isEmpty()) { @@ -5205,20 +5214,32 @@ public class QcServiceImpl implements QcService { timeParts.add(timeValue == null ? 0 : (timeValue & 0xFFFF)); } - // 异常数据地址按32位float读取(高字在前):406/408/410/412/414 ... + // 异常 float:高/低字在前自动择优(屏显地址与 PDU ref 可能差 1,不能固定低字在前) List abnormalValues = new ArrayList<>(); for (int i = 0; i < 5; i++) { - int highRef = abnormalStartAddr + (i * 2); - int lowRef = highRef + 1; - Integer high = raw.get(highRef); - Integer low = raw.get(lowRef); - if (high != null && low != null) { - int bits = (high << 16) | (low & 0xFFFF); - abnormalValues.add(Float.intBitsToFloat(bits)); + int regRef = abnormalStartAddr + (i * 2); + int regRefNext = regRef + 1; + Integer reg0 = raw.get(regRef); + Integer reg1 = raw.get(regRefNext); + if (reg0 != null && reg1 != null) { + abnormalValues.add(ModbusUtils.parseAbnormalCollectorFloat(reg0, reg1)); } else { abnormalValues.add(0F); } } + if (groupIdx == 0) { + logger.info("异常区原始寄存器(屏显约40406起): r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}, r{}=0x{}", + abnormalStartAddr, hexReg(raw, abnormalStartAddr), + abnormalStartAddr + 1, hexReg(raw, abnormalStartAddr + 1), + abnormalStartAddr + 2, hexReg(raw, abnormalStartAddr + 2), + abnormalStartAddr + 3, hexReg(raw, abnormalStartAddr + 3), + abnormalStartAddr + 4, hexReg(raw, abnormalStartAddr + 4), + abnormalStartAddr + 5, hexReg(raw, abnormalStartAddr + 5), + abnormalStartAddr + 6, hexReg(raw, abnormalStartAddr + 6), + abnormalStartAddr + 7, hexReg(raw, abnormalStartAddr + 7), + abnormalStartAddr + 8, hexReg(raw, abnormalStartAddr + 8), + abnormalStartAddr + 9, hexReg(raw, abnormalStartAddr + 9)); + } logger.info("获取到的数据:{},时间:{}",abnormalValues.toString(),timeParts.toString()); boolean hasAbnormal = abnormalValues.stream().anyMatch(v -> v != 0F); @@ -5239,7 +5260,7 @@ public class QcServiceImpl implements QcService { detailValues.setIsSubmit("N"); detailValues.setSite(data.getSite()); detailValues.setNum(1); - detailValues.setSubDetailValue(String.valueOf(abnormalValues.get(i))); + detailValues.setSubDetailValue(ModbusUtils.formatFloat4Decimals(abnormalValues.get(i))); detailValues.setSubDetailValueB(collectedTime); detailValues.setSamplingLocationB(collectedTime); subDetailValues.add(detailValues); @@ -5250,21 +5271,24 @@ public class QcServiceImpl implements QcService { return subDetailValues; } + /** + * 无工单异常采集复位:300/301/302 + 10 组时间(6 寄存器)与异常 float 高字寄存器(5 路×2 字取高字地址)。 + */ private void resetCollectorAbnormalRegisters(String ip, int port, int unitId) { - List resetAddrs = new ArrayList<>(Arrays.asList( - 302, - 406, 408, 410, 412, 414, - 426, 428, 430, 432, 434, - 446, 448, 450, 452, 454, - 466, 468, 470, 472, 474, - 486, 488, 490, 492, 494, - 506, 508, 510, 512, 514, - 526, 528, 530, 532, 534, - 546, 548, 550, 552, 554, - 566, 568, 570, 572, 574, - 586, 588, 590, 592, 594 - )); - logger.info("开始复位"); + List resetAddrs = new ArrayList<>(); + resetAddrs.add(301); + resetAddrs.add(302); + for (int groupIdx = 0; groupIdx < 10; groupIdx++) { + int timeStartAddr = 400 + (groupIdx * 20); + for (int i = 0; i < 6; i++) { + resetAddrs.add(timeStartAddr + i); + } + int abnormalStartAddr = 406 + (groupIdx * 20); + for (int i = 0; i < 5; i++) { + resetAddrs.add(abnormalStartAddr + (i * 2)); + } + } + logger.info("开始复位, 共 {} 个寄存器", resetAddrs.size()); ModbusUtils.resetRegisters(ip, port, unitId, resetAddrs); logger.info("复位结束"); }