啊鑫
2025-07-28 1b3d57f133b494114c1cdd30627c7057eecdf1b1
UniversalModbusManager.cs
@@ -501,7 +501,23 @@
        /// <param name="groupName">组名称(用于日志)</param>
        private async Task ReadFieldGroup(DynamicModbusData dynamicData, Dictionary<string, DataField> fieldGroup, string groupName)
        {
            if (_modbusClient == null) return;
            if (_modbusClient == null)
            {
                LogWarning($"Modbus客户端为null,无法读取 {groupName}");
                return;
            }
            if (!_isConnected)
            {
                LogWarning($"Modbus未连接,无法读取 {groupName}");
                return;
            }
            if (fieldGroup == null || fieldGroup.Count == 0)
            {
                LogDebug($"{groupName} 没有配置字段,跳过读取");
                return;
            }
            foreach (var kvp in fieldGroup)
            {
@@ -510,14 +526,43 @@
                try
                {
                    // 检查Modbus客户端状态
                    if (_modbusClient == null || !_modbusClient.Connected)
                    {
                        LogWarning($"Modbus客户端未连接,跳过字段 '{fieldName}'");
                        continue;
                    }
                    // 读取原始寄存器数据
                    var registers = await Task.Run(() => 
                        _modbusClient.ReadHoldingRegisters(fieldConfig.Address, fieldConfig.Length));
                    // 验证寄存器读取结果的有效性
                    ValidateRegisterData(fieldName, fieldConfig, registers);
                    // 检查读取结果是否为null
                    if (registers == null)
                    {
                        LogWarning($"字段 '{fieldName}' 读取结果为null,地址: {fieldConfig.Address}, 长度: {fieldConfig.Length}");
                        continue;
                    }
                    // 记录原始寄存器数据用于调试
                    LogDebug($"[RAW-DATA] 字段 '{fieldName}' 原始寄存器: [{string.Join(", ", registers)}] (十六进制: [{string.Join(", ", registers.Select(r => $"0x{r:X4}"))}])");
                    // 详细记录每个寄存器的字节分解
                    for (int i = 0; i < registers.Length; i++)
                    {
                        var reg = registers[i];
                        var highByte = (byte)((reg >> 8) & 0xFF);
                        var lowByte = (byte)(reg & 0xFF);
                        LogDebug($"[RAW-DATA] 寄存器{i}: {reg} (0x{reg:X4}) → 高字节:{highByte}('{(char)highByte}') 低字节:{lowByte}('{(char)lowByte}')");
                    }
                    // 验证数据长度
                    if (!ModbusDataParser.ValidateRegisterLength(registers, fieldConfig))
                    {
                        LogWarning($"字段 '{fieldName}' 的数据长度不足:期望{fieldConfig.Length},实际{registers.Length}");
                        LogWarning($"字段 '{fieldName}' 的数据长度不足:期望{fieldConfig.Length},实际{registers?.Length ?? 0}");
                        continue;
                    }
@@ -532,6 +577,14 @@
                catch (Exception ex)
                {
                    LogError($"读取字段 '{fieldName}' 失败: {ex.Message}");
                    // 记录详细错误信息
                    await _databaseManager?.LogErrorAsync(
                        "FieldReadError",
                        $"读取字段 '{fieldName}' 失败: {ex.Message}",
                        ex,
                        ErrorSeverity.Medium)!;
                    // 继续读取其他字段
                }
            }
@@ -563,6 +616,98 @@
        #endregion
        #region 数据验证方法
        /// <summary>
        /// 验证寄存器数据的有效性
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <param name="fieldConfig">字段配置</param>
        /// <param name="registers">读取的寄存器数据</param>
        private void ValidateRegisterData(string fieldName, DataField fieldConfig, int[]? registers)
        {
            if (registers == null)
            {
                LogWarning($"[VALIDATE] 字段 '{fieldName}' 寄存器数据为null");
                return;
            }
            LogDebug($"[VALIDATE] 字段 '{fieldName}' 原始数据验证:");
            LogDebug($"[VALIDATE] - 地址: {fieldConfig.Address}, 期望长度: {fieldConfig.Length}, 实际长度: {registers.Length}");
            LogDebug($"[VALIDATE] - 数据类型: {fieldConfig.DataType}");
            // 检查数据长度
            if (registers.Length != fieldConfig.Length)
            {
                LogWarning($"[VALIDATE] 字段 '{fieldName}' 数据长度不匹配: 期望{fieldConfig.Length}, 实际{registers.Length}");
            }
            // 检查是否包含有效数据
            var hasNonZeroData = registers.Any(r => r != 0);
            if (!hasNonZeroData)
            {
                LogWarning($"[VALIDATE] 字段 '{fieldName}' 所有寄存器都为0,可能是无效数据");
            }
            // 检查数据范围(16位有符号整数范围)
            var outOfRangeCount = registers.Count(r => r < -32768 || r > 32767);
            if (outOfRangeCount > 0)
            {
                LogWarning($"[VALIDATE] 字段 '{fieldName}' 有{outOfRangeCount}个寄存器值超出16位有符号整数范围");
            }
            // 特殊数据模式检测
            DetectSpecialDataPatterns(fieldName, registers);
        }
        /// <summary>
        /// 检测特殊的数据模式
        /// </summary>
        /// <param name="fieldName">字段名</param>
        /// <param name="registers">寄存器数据</param>
        private void DetectSpecialDataPatterns(string fieldName, int[] registers)
        {
            // 检测全FF模式(通信错误)
            if (registers.All(r => r == -1 || r == 0xFFFF))
            {
                LogWarning($"[PATTERN] 字段 '{fieldName}' 检测到全FF模式,可能是通信错误");
            }
            // 检测常见的错误码模式
            if (registers.Length >= 2)
            {
                var combined = ((long)(registers[0] & 0xFFFF) << 16) | (registers[1] & 0xFFFF);
                if (combined == 0xE2400001)
                {
                    LogInfo($"[PATTERN] 字段 '{fieldName}' 检测到已知的无效数据标识 0xE2400001");
                }
            }
            // 检测ASCII字符模式(用于字符串和时间戳字段)
            if (registers.Any(r => IsLikelyAsciiData(r)))
            {
                LogDebug($"[PATTERN] 字段 '{fieldName}' 包含可能的ASCII字符数据");
            }
        }
        /// <summary>
        /// 检查寄存器值是否可能包含ASCII字符
        /// </summary>
        /// <param name="register">寄存器值</param>
        /// <returns>是否可能是ASCII数据</returns>
        private bool IsLikelyAsciiData(int register)
        {
            if (register == 0) return false;
            var highByte = (byte)((register >> 8) & 0xFF);
            var lowByte = (byte)(register & 0xFF);
            // 检查是否为可打印ASCII字符范围(32-126)
            return (highByte >= 32 && highByte <= 126) || (lowByte >= 32 && lowByte <= 126);
        }
        #endregion
        #region 数据发送方法
        /// <summary>