release 雷鸟测试程序 V1.3
authorSnickerSun <snickersun@163.com>
Sun, 7 Dec 2025 02:44:47 +0000 (10:44 +0800)
committerSnickerSun <snickersun@163.com>
Sun, 7 Dec 2025 02:44:47 +0000 (10:44 +0800)
优化录音检测,大于设定值,连续三个或者累计6个算通过
优化电池温度和充电检测,确定根据勾选做检查

config_manager.cpp
config_manager.h
mainwindow.cpp
mainwindow.h
mainwindow.ui
releasePackage/LN_Factorytool_V1.3.zip [new file with mode: 0644]
releasePackage/LN_Factorytool_V1.3/LeiNiaoFactoryTool.exe [new file with mode: 0644]
releasePackage/LN_Factorytool_V1.3/settings.json [new file with mode: 0644]

index 026d778..6a9f753 100644 (file)
-#include "config_manager.h"\r
-#include <QFile>\r
-#include <QFileInfo>\r
-#include <QJsonDocument>\r
-#include <QJsonArray>\r
-#include <QDebug>\r
-#include <QCoreApplication>\r
-#include <QDir>\r
-\r
-ConfigManager::ConfigManager()\r
-    : configLoaded(false)\r
-{\r
-    setDefaultConfig();\r
-}\r
-\r
-ConfigManager::~ConfigManager()\r
-{\r
-}\r
-\r
-void ConfigManager::setDefaultConfig()\r
-{\r
-    // 设置默认配置\r
-    QJsonObject defaultConfig;\r
-    \r
-    // 默认开机检测关键字\r
-    QJsonArray bootKeywords;\r
-    bootKeywords.append("BuildVer");\r
-    bootKeywords.append("NAND flash ID");\r
-    bootKeywords.append("NAND ID:");\r
-    defaultConfig["bootDetectionKeywords"] = bootKeywords;\r
-    \r
-    // 默认版本信息获取指令\r
-    QJsonArray versionCommands;\r
-    versionCommands.append("AT^CAT1GETVER");\r
-    versionCommands.append("AT^CAT1GETSIGNAL");\r
-    versionCommands.append("AT^FACTORY");\r
-    defaultConfig["versionInfoCommands"] = versionCommands;\r
-    \r
-    // 默认产测模式检测指令\r
-    defaultConfig["factoryModeCheckCommand"] = "AT^FACTORY";\r
-    \r
-    // 默认产测模式关键字\r
-    QJsonArray factoryKeywords;\r
-    factoryKeywords.append("FACTORY TEST MODE:");\r
-    defaultConfig["factoryModeKeywords"] = factoryKeywords;\r
-    \r
-    // 默认测试参数配置\r
-    QJsonObject testConfig;\r
-    testConfig["portName"] = "";\r
-    testConfig["audioVolume"] = "2.0";\r
-    testConfig["audioLevelStandard"] = "中";\r
-    testConfig["expectedModemVer"] = "";\r
-    testConfig["expectedPYVer"] = "";\r
-    testConfig["expectedVer"] = "";\r
-    testConfig["bluetoothAddress"] = "";\r
-    testConfig["bluetoothRSSI"] = "";\r
-    defaultConfig["testConfig"] = testConfig;\r
-    \r
-    // 默认测试项checkbox配置(默认全部选中)\r
-    QJsonObject testCheckboxes;\r
-    testCheckboxes["lcd"] = true;\r
-    testCheckboxes["vib"] = true;\r
-    testCheckboxes["btn"] = true;\r
-    testCheckboxes["mic"] = true;\r
-    testCheckboxes["charge"] = true;\r
-    testCheckboxes["ntc"] = true;\r
-    testCheckboxes["gsensor"] = true;\r
-    testCheckboxes["bt"] = true;\r
-    testCheckboxes["4g"] = true;\r
-    defaultConfig["testCheckboxes"] = testCheckboxes;\r
-    \r
-    configObject = defaultConfig;\r
-    configLoaded = true;\r
-}\r
-\r
-bool ConfigManager::loadConfig(const QString& configPath)\r
-{\r
-    QString filePath = configPath;\r
-    if (filePath.isEmpty()) {\r
-        // 默认路径:应用程序目录下的settings.json\r
-        QString appPath = QCoreApplication::applicationDirPath();\r
-        filePath = appPath + "/settings.json";\r
-    }\r
-    \r
-    QFile file(filePath);\r
-    if (!file.exists()) {\r
-        qDebug() << "配置文件不存在,使用默认配置并创建文件:" << filePath;\r
-        setDefaultConfig();\r
-        \r
-        // 创建配置文件目录(如果不存在)\r
-        QFileInfo fileInfo(filePath);\r
-        QDir dir = fileInfo.absoluteDir();\r
-        if (!dir.exists()) {\r
-            dir.mkpath(".");\r
-        }\r
-        \r
-        // 将默认配置保存到文件\r
-        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {\r
-            QJsonDocument doc(configObject);\r
-            file.write(doc.toJson());\r
-            file.close();\r
-            qDebug() << "已创建默认配置文件:" << filePath;\r
-            configLoaded = true;\r
-            return true;\r
-        } else {\r
-            qDebug() << "无法创建配置文件:" << filePath << "错误:" << file.errorString();\r
-            configLoaded = true; // 即使文件创建失败,也使用默认配置\r
-            return false;\r
-        }\r
-    }\r
-    \r
-    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {\r
-        qDebug() << "无法打开配置文件:" << filePath << "错误:" << file.errorString();\r
-        setDefaultConfig();\r
-        return false;\r
-    }\r
-    \r
-    QByteArray data = file.readAll();\r
-    file.close();\r
-    \r
-    QJsonParseError error;\r
-    QJsonDocument doc = QJsonDocument::fromJson(data, &error);\r
-    \r
-    if (error.error != QJsonParseError::NoError) {\r
-        qDebug() << "配置文件JSON解析错误:" << error.errorString();\r
-        setDefaultConfig();\r
-        return false;\r
-    }\r
-    \r
-    if (!doc.isObject()) {\r
-        qDebug() << "配置文件格式错误:不是JSON对象";\r
-        setDefaultConfig();\r
-        return false;\r
-    }\r
-    \r
-    configObject = doc.object();\r
-    configLoaded = true;\r
-    \r
-    // 合并默认配置(如果配置文件中缺少某些项,使用默认值)\r
-    QJsonObject defaultConfig;\r
-    setDefaultConfig();\r
-    defaultConfig = configObject;\r
-    \r
-    // 重新加载文件配置\r
-    doc = QJsonDocument::fromJson(data, &error);\r
-    configObject = doc.object();\r
-    \r
-    // 合并缺失的配置项\r
-    if (!configObject.contains("bootDetectionKeywords")) {\r
-        configObject["bootDetectionKeywords"] = defaultConfig["bootDetectionKeywords"];\r
-    }\r
-    if (!configObject.contains("versionInfoCommands")) {\r
-        configObject["versionInfoCommands"] = defaultConfig["versionInfoCommands"];\r
-    }\r
-    if (!configObject.contains("factoryModeCheckCommand")) {\r
-        configObject["factoryModeCheckCommand"] = defaultConfig["factoryModeCheckCommand"];\r
-    }\r
-    if (!configObject.contains("factoryModeKeywords")) {\r
-        configObject["factoryModeKeywords"] = defaultConfig["factoryModeKeywords"];\r
-    }\r
-    if (!configObject.contains("testConfig")) {\r
-        configObject["testConfig"] = defaultConfig["testConfig"];\r
-    } else {\r
-        // 合并testConfig中的缺失项\r
-        QJsonObject savedTestConfig = configObject["testConfig"].toObject();\r
-        QJsonObject defaultTestConfig = defaultConfig["testConfig"].toObject();\r
-        for (auto it = defaultTestConfig.begin(); it != defaultTestConfig.end(); ++it) {\r
-            if (!savedTestConfig.contains(it.key())) {\r
-                savedTestConfig[it.key()] = it.value();\r
-            }\r
-        }\r
-        configObject["testConfig"] = savedTestConfig;\r
-    }\r
-    \r
-    qDebug() << "配置文件加载成功:" << filePath;\r
-    return true;\r
-}\r
-\r
-QStringList ConfigManager::getBootDetectionKeywords() const\r
-{\r
-    QStringList keywords;\r
-    if (configObject.contains("bootDetectionKeywords") && \r
-        configObject["bootDetectionKeywords"].isArray()) {\r
-        QJsonArray array = configObject["bootDetectionKeywords"].toArray();\r
-        for (int i = 0; i < array.size(); ++i) {\r
-            if (array[i].isString()) {\r
-                keywords.append(array[i].toString());\r
-            }\r
-        }\r
-    }\r
-    return keywords;\r
-}\r
-\r
-QStringList ConfigManager::getVersionInfoCommands() const\r
-{\r
-    QStringList commands;\r
-    if (configObject.contains("versionInfoCommands") && \r
-        configObject["versionInfoCommands"].isArray()) {\r
-        QJsonArray array = configObject["versionInfoCommands"].toArray();\r
-        for (int i = 0; i < array.size(); ++i) {\r
-            if (array[i].isString()) {\r
-                commands.append(array[i].toString());\r
-            }\r
-        }\r
-    }\r
-    return commands;\r
-}\r
-\r
-QString ConfigManager::getFactoryModeCheckCommand() const\r
-{\r
-    if (configObject.contains("factoryModeCheckCommand") && \r
-        configObject["factoryModeCheckCommand"].isString()) {\r
-        return configObject["factoryModeCheckCommand"].toString();\r
-    }\r
-    return "AT^FACTORY";\r
-}\r
-\r
-QStringList ConfigManager::getFactoryModeKeywords() const\r
-{\r
-    QStringList keywords;\r
-    if (configObject.contains("factoryModeKeywords") && \r
-        configObject["factoryModeKeywords"].isArray()) {\r
-        QJsonArray array = configObject["factoryModeKeywords"].toArray();\r
-        for (int i = 0; i < array.size(); ++i) {\r
-            if (array[i].isString()) {\r
-                keywords.append(array[i].toString());\r
-            }\r
-        }\r
-    }\r
-    return keywords;\r
-}\r
-\r
-bool ConfigManager::isValid() const\r
-{\r
-    return configLoaded;\r
-}\r
-\r
-// 获取测试参数配置值\r
-QString ConfigManager::getTestConfig(const QString& key, const QString& defaultValue) const\r
-{\r
-    if (configObject.contains("testConfig") && configObject["testConfig"].isObject()) {\r
-        QJsonObject testConfig = configObject["testConfig"].toObject();\r
-        if (testConfig.contains(key) && testConfig[key].isString()) {\r
-            return testConfig[key].toString();\r
-        }\r
-    }\r
-    return defaultValue;\r
-}\r
-\r
-// 设置测试参数配置值\r
-void ConfigManager::setTestConfig(const QString& key, const QString& value)\r
-{\r
-    if (!configObject.contains("testConfig") || !configObject["testConfig"].isObject()) {\r
-        configObject["testConfig"] = QJsonObject();\r
-    }\r
-    QJsonObject testConfig = configObject["testConfig"].toObject();\r
-    testConfig[key] = value;\r
-    configObject["testConfig"] = testConfig;\r
-}\r
-\r
-// 保存配置到文件\r
-bool ConfigManager::saveConfig(const QString& configPath)\r
-{\r
-    QString filePath = configPath;\r
-    if (filePath.isEmpty()) {\r
-        // 默认路径:应用程序目录下的settings.json\r
-        QString appPath = QCoreApplication::applicationDirPath();\r
-        filePath = appPath + "/settings.json";\r
-    }\r
-    \r
-    // 创建配置文件目录(如果不存在)\r
-    QFileInfo fileInfo(filePath);\r
-    QDir dir = fileInfo.absoluteDir();\r
-    if (!dir.exists()) {\r
-        dir.mkpath(".");\r
-    }\r
-    \r
-    // 保存到文件\r
-    QFile file(filePath);\r
-    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {\r
-        qDebug() << "无法保存配置文件:" << filePath << "错误:" << file.errorString();\r
-        return false;\r
-    }\r
-    \r
-    QJsonDocument doc(configObject);\r
-    file.write(doc.toJson());\r
-    file.close();\r
-    \r
-    qDebug() << "配置文件已保存:" << filePath;\r
-    return true;\r
-}\r
-\r
-// 获取测试项checkbox状态\r
-bool ConfigManager::getTestCheckbox(const QString& key, bool defaultValue) const\r
-{\r
-    if (!configObject.contains("testCheckboxes")) {\r
-        return defaultValue;\r
-    }\r
-    \r
-    QJsonObject checkboxes = configObject["testCheckboxes"].toObject();\r
-    if (!checkboxes.contains(key)) {\r
-        return defaultValue;\r
-    }\r
-    \r
-    return checkboxes[key].toBool();\r
-}\r
-\r
-// 设置测试项checkbox状态\r
-void ConfigManager::setTestCheckbox(const QString& key, bool value)\r
-{\r
-    if (!configObject.contains("testCheckboxes")) {\r
-        configObject["testCheckboxes"] = QJsonObject();\r
-    }\r
-    \r
-    QJsonObject checkboxes = configObject["testCheckboxes"].toObject();\r
-    checkboxes[key] = value;\r
-    configObject["testCheckboxes"] = checkboxes;\r
-}\r
-\r
+#include "config_manager.h"
+#include <QFile>
+#include <QFileInfo>
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QDebug>
+#include <QCoreApplication>
+#include <QDir>
+
+ConfigManager::ConfigManager()
+    : configLoaded(false)
+{
+    setDefaultConfig();
+}
+
+ConfigManager::~ConfigManager()
+{
+}
+
+void ConfigManager::setDefaultConfig()
+{
+    // 设置默认配置
+    QJsonObject defaultConfig;
+    
+    // 默认开机检测关键字
+    QJsonArray bootKeywords;
+    bootKeywords.append("BuildVer");
+    bootKeywords.append("NAND flash ID");
+    bootKeywords.append("NAND ID:");
+    defaultConfig["bootDetectionKeywords"] = bootKeywords;
+    
+    // 默认版本信息获取指令
+    QJsonArray versionCommands;
+    versionCommands.append("AT^CAT1GETVER");
+    versionCommands.append("AT^CAT1GETSIGNAL");
+    versionCommands.append("AT^FACTORY");
+    defaultConfig["versionInfoCommands"] = versionCommands;
+    
+    // 默认产测模式检测指令
+    defaultConfig["factoryModeCheckCommand"] = "AT^FACTORY";
+    
+    // 默认产测模式关键字
+    QJsonArray factoryKeywords;
+    factoryKeywords.append("FACTORY TEST MODE:");
+    defaultConfig["factoryModeKeywords"] = factoryKeywords;
+    
+    // 默认测试参数配置
+    QJsonObject testConfig;
+    testConfig["portName"] = "";
+    testConfig["audioVolume"] = "2.0";
+    testConfig["audioLevelStandard"] = "中";
+    testConfig["expectedModemVer"] = "";
+    testConfig["expectedPYVer"] = "";
+    testConfig["expectedVer"] = "";
+    testConfig["bluetoothAddress"] = "";
+    testConfig["bluetoothRSSI"] = "";
+    defaultConfig["testConfig"] = testConfig;
+    
+    // 默认测试项checkbox配置(默认全部选中)
+    QJsonObject testCheckboxes;
+    testCheckboxes["lcd"] = true;
+    testCheckboxes["vib"] = true;
+    testCheckboxes["btn"] = true;
+    testCheckboxes["mic"] = true;
+    testCheckboxes["charge"] = true;
+    testCheckboxes["ntc"] = true;
+    testCheckboxes["gsensor"] = true;
+    testCheckboxes["bt"] = true;
+    testCheckboxes["4g"] = true;
+    defaultConfig["testCheckboxes"] = testCheckboxes;
+    
+    configObject = defaultConfig;
+    configLoaded = true;
+}
+
+bool ConfigManager::loadConfig(const QString& configPath)
+{
+    QString filePath = configPath;
+    if (filePath.isEmpty()) {
+        // 默认路径:应用程序目录下的settings.json
+        QString appPath = QCoreApplication::applicationDirPath();
+        filePath = appPath + "/settings.json";
+    }
+    
+    QFile file(filePath);
+    if (!file.exists()) {
+        qDebug() << "配置文件不存在,使用默认配置并创建文件:" << filePath;
+        setDefaultConfig();
+        
+        // 创建配置文件目录(如果不存在)
+        QFileInfo fileInfo(filePath);
+        QDir dir = fileInfo.absoluteDir();
+        if (!dir.exists()) {
+            dir.mkpath(".");
+        }
+        
+        // 将默认配置保存到文件
+        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+            QJsonDocument doc(configObject);
+            file.write(doc.toJson());
+            file.close();
+            qDebug() << "已创建默认配置文件:" << filePath;
+            configLoaded = true;
+            return true;
+        } else {
+            qDebug() << "无法创建配置文件:" << filePath << "错误:" << file.errorString();
+            configLoaded = true; // 即使文件创建失败,也使用默认配置
+            return false;
+        }
+    }
+    
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        qDebug() << "无法打开配置文件:" << filePath << "错误:" << file.errorString();
+        setDefaultConfig();
+        return false;
+    }
+    
+    QByteArray data = file.readAll();
+    file.close();
+    
+    QJsonParseError error;
+    QJsonDocument doc = QJsonDocument::fromJson(data, &error);
+    
+    if (error.error != QJsonParseError::NoError) {
+        qDebug() << "配置文件JSON解析错误:" << error.errorString();
+        setDefaultConfig();
+        return false;
+    }
+    
+    if (!doc.isObject()) {
+        qDebug() << "配置文件格式错误:不是JSON对象";
+        setDefaultConfig();
+        return false;
+    }
+    
+    configObject = doc.object();
+    configLoaded = true;
+    
+    // 合并默认配置(如果配置文件中缺少某些项,使用默认值)
+    QJsonObject defaultConfig;
+    setDefaultConfig();
+    defaultConfig = configObject;
+    
+    // 重新加载文件配置
+    doc = QJsonDocument::fromJson(data, &error);
+    configObject = doc.object();
+    
+    // 合并缺失的配置项
+    if (!configObject.contains("bootDetectionKeywords")) {
+        configObject["bootDetectionKeywords"] = defaultConfig["bootDetectionKeywords"];
+    }
+    if (!configObject.contains("versionInfoCommands")) {
+        configObject["versionInfoCommands"] = defaultConfig["versionInfoCommands"];
+    }
+    if (!configObject.contains("factoryModeCheckCommand")) {
+        configObject["factoryModeCheckCommand"] = defaultConfig["factoryModeCheckCommand"];
+    }
+    if (!configObject.contains("factoryModeKeywords")) {
+        configObject["factoryModeKeywords"] = defaultConfig["factoryModeKeywords"];
+    }
+    if (!configObject.contains("testConfig")) {
+        configObject["testConfig"] = defaultConfig["testConfig"];
+    } else {
+        // 合并testConfig中的缺失项
+        QJsonObject savedTestConfig = configObject["testConfig"].toObject();
+        QJsonObject defaultTestConfig = defaultConfig["testConfig"].toObject();
+        for (auto it = defaultTestConfig.begin(); it != defaultTestConfig.end(); ++it) {
+            if (!savedTestConfig.contains(it.key())) {
+                savedTestConfig[it.key()] = it.value();
+            }
+        }
+        configObject["testConfig"] = savedTestConfig;
+    }
+    
+    qDebug() << "配置文件加载成功:" << filePath;
+    return true;
+}
+
+QStringList ConfigManager::getBootDetectionKeywords() const
+{
+    QStringList keywords;
+    if (configObject.contains("bootDetectionKeywords") && 
+        configObject["bootDetectionKeywords"].isArray()) {
+        QJsonArray array = configObject["bootDetectionKeywords"].toArray();
+        for (int i = 0; i < array.size(); ++i) {
+            if (array[i].isString()) {
+                keywords.append(array[i].toString());
+            }
+        }
+    }
+    return keywords;
+}
+
+QStringList ConfigManager::getVersionInfoCommands() const
+{
+    QStringList commands;
+    if (configObject.contains("versionInfoCommands") && 
+        configObject["versionInfoCommands"].isArray()) {
+        QJsonArray array = configObject["versionInfoCommands"].toArray();
+        for (int i = 0; i < array.size(); ++i) {
+            if (array[i].isString()) {
+                commands.append(array[i].toString());
+            }
+        }
+    }
+    return commands;
+}
+
+QString ConfigManager::getFactoryModeCheckCommand() const
+{
+    if (configObject.contains("factoryModeCheckCommand") && 
+        configObject["factoryModeCheckCommand"].isString()) {
+        return configObject["factoryModeCheckCommand"].toString();
+    }
+    return "AT^FACTORY";
+}
+
+QStringList ConfigManager::getFactoryModeKeywords() const
+{
+    QStringList keywords;
+    if (configObject.contains("factoryModeKeywords") && 
+        configObject["factoryModeKeywords"].isArray()) {
+        QJsonArray array = configObject["factoryModeKeywords"].toArray();
+        for (int i = 0; i < array.size(); ++i) {
+            if (array[i].isString()) {
+                keywords.append(array[i].toString());
+            }
+        }
+    }
+    return keywords;
+}
+
+bool ConfigManager::isValid() const
+{
+    return configLoaded;
+}
+
+// 获取测试参数配置值
+QString ConfigManager::getTestConfig(const QString& key, const QString& defaultValue) const
+{
+    if (configObject.contains("testConfig") && configObject["testConfig"].isObject()) {
+        QJsonObject testConfig = configObject["testConfig"].toObject();
+        if (testConfig.contains(key) && testConfig[key].isString()) {
+            return testConfig[key].toString();
+        }
+    }
+    return defaultValue;
+}
+
+// 设置测试参数配置值
+void ConfigManager::setTestConfig(const QString& key, const QString& value)
+{
+    if (!configObject.contains("testConfig") || !configObject["testConfig"].isObject()) {
+        configObject["testConfig"] = QJsonObject();
+    }
+    QJsonObject testConfig = configObject["testConfig"].toObject();
+    testConfig[key] = value;
+    configObject["testConfig"] = testConfig;
+}
+
+// 保存配置到文件
+bool ConfigManager::saveConfig(const QString& configPath)
+{
+    QString filePath = configPath;
+    if (filePath.isEmpty()) {
+        // 默认路径:应用程序目录下的settings.json
+        QString appPath = QCoreApplication::applicationDirPath();
+        filePath = appPath + "/settings.json";
+    }
+    
+    // 创建配置文件目录(如果不存在)
+    QFileInfo fileInfo(filePath);
+    QDir dir = fileInfo.absoluteDir();
+    if (!dir.exists()) {
+        dir.mkpath(".");
+    }
+    
+    // 保存到文件
+    QFile file(filePath);
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+        qDebug() << "无法保存配置文件:" << filePath << "错误:" << file.errorString();
+        return false;
+    }
+    
+    QJsonDocument doc(configObject);
+    file.write(doc.toJson());
+    file.close();
+    
+    qDebug() << "配置文件已保存:" << filePath;
+    return true;
+}
+
+// 获取测试项checkbox状态
+bool ConfigManager::getTestCheckbox(const QString& key, bool defaultValue) const
+{
+    if (!configObject.contains("testCheckboxes")) {
+        return defaultValue;
+    }
+    
+    QJsonObject checkboxes = configObject["testCheckboxes"].toObject();
+    if (!checkboxes.contains(key)) {
+        return defaultValue;
+    }
+    
+    return checkboxes[key].toBool();
+}
+
+// 设置测试项checkbox状态
+void ConfigManager::setTestCheckbox(const QString& key, bool value)
+{
+    if (!configObject.contains("testCheckboxes")) {
+        configObject["testCheckboxes"] = QJsonObject();
+    }
+    
+    QJsonObject checkboxes = configObject["testCheckboxes"].toObject();
+    checkboxes[key] = value;
+    configObject["testCheckboxes"] = checkboxes;
+}
+
index 709f976..a6476c9 100644 (file)
@@ -1,44 +1,44 @@
-#ifndef CONFIG_MANAGER_H\r
-#define CONFIG_MANAGER_H\r
-\r
-#include <QString>\r
-#include <QStringList>\r
-#include <QJsonObject>\r
-\r
-class ConfigManager\r
-{\r
-public:\r
-    ConfigManager();\r
-    ~ConfigManager();\r
-    \r
-    // 加载配置文件\r
-    bool loadConfig(const QString& configPath = QString());\r
-    \r
-    // 获取配置项\r
-    QStringList getBootDetectionKeywords() const;\r
-    QStringList getVersionInfoCommands() const;\r
-    QString getFactoryModeCheckCommand() const;\r
-    QStringList getFactoryModeKeywords() const;\r
-    \r
-    // 测试参数配置相关方法\r
-    QString getTestConfig(const QString& key, const QString& defaultValue = "") const;\r
-    void setTestConfig(const QString& key, const QString& value);\r
-    bool saveConfig(const QString& configPath = QString());  // 保存配置到文件\r
-    \r
-    // 测试项checkbox配置相关方法\r
-    bool getTestCheckbox(const QString& key, bool defaultValue = true) const;\r
-    void setTestCheckbox(const QString& key, bool value);\r
-    \r
-    // 检查配置是否有效\r
-    bool isValid() const;\r
-\r
-private:\r
-    QJsonObject configObject;\r
-    bool configLoaded;\r
-    \r
-    // 默认配置\r
-    void setDefaultConfig();\r
-};\r
-\r
-#endif // CONFIG_MANAGER_H\r
-\r
+#ifndef CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <QString>
+#include <QStringList>
+#include <QJsonObject>
+
+class ConfigManager
+{
+public:
+    ConfigManager();
+    ~ConfigManager();
+    
+    // 加载配置文件
+    bool loadConfig(const QString& configPath = QString());
+    
+    // 获取配置项
+    QStringList getBootDetectionKeywords() const;
+    QStringList getVersionInfoCommands() const;
+    QString getFactoryModeCheckCommand() const;
+    QStringList getFactoryModeKeywords() const;
+    
+    // 测试参数配置相关方法
+    QString getTestConfig(const QString& key, const QString& defaultValue = "") const;
+    void setTestConfig(const QString& key, const QString& value);
+    bool saveConfig(const QString& configPath = QString());  // 保存配置到文件
+    
+    // 测试项checkbox配置相关方法
+    bool getTestCheckbox(const QString& key, bool defaultValue = true) const;
+    void setTestCheckbox(const QString& key, bool value);
+    
+    // 检查配置是否有效
+    bool isValid() const;
+
+private:
+    QJsonObject configObject;
+    bool configLoaded;
+    
+    // 默认配置
+    void setDefaultConfig();
+};
+
+#endif // CONFIG_MANAGER_H
+
index 88fe677..18ff20b 100644 (file)
@@ -27,7 +27,7 @@ MainWindow::MainWindow(QWidget *parent)
     , ui(new Ui::MainWindow)
 {
     ui->setupUi(this);
-    setWindowTitle("雷鸟产测工具 V1.2");
+    setWindowTitle("雷鸟产测工具 V1.3");
     
     // 确保控制台输出使用UTF-8编码
     QTextCodec *utf8Codec = QTextCodec::codecForName("UTF-8");
@@ -92,6 +92,7 @@ MainWindow::MainWindow(QWidget *parent)
     audioFailButton = nullptr;
     audioRetestButton = nullptr;
     audioMicMiddleConsecutiveCount = 0;
+    audioMicTotalPassCount = 0;
     audioTestFinished = false;
     bluetoothTestTimer = new QTimer(this);
     bluetoothAddresses.clear();
@@ -3351,6 +3352,7 @@ void MainWindow::performAudioTest()
 
     // 重置录音测试相关状态
     audioMicMiddleConsecutiveCount = 0;
+    audioMicTotalPassCount = 0;
     audioTestFinished = false;
     
     // 获取音频测试通过标准(从UI中读取)
@@ -3646,9 +3648,15 @@ void MainWindow::onAudioRecordTimer()
         return;
     }
 
-    // 8秒内未检测到连续3个设置的标准Level,判定录音测试失败
-    qDebug() << QString("录音测试8秒超时,未检测到连续3个\"fac:mic level:%1\",测试失败").arg(audioLevelStandard);
-    ui->statusbar->showMessage(QString("录音测试失败:8秒内未检测到连续3个\"fac:mic level:%1\"").arg(audioLevelStandard), 3000);
+    // 8秒内未检测到连续3个或累计6个满足要求的Level,判定录音测试失败
+    qDebug() << QString("录音测试8秒超时,连续计数: %1,累计计数: %2,未达到通过标准(连续3次或累计6次),测试失败")
+                .arg(audioMicMiddleConsecutiveCount)
+                .arg(audioMicTotalPassCount);
+    ui->statusbar->showMessage(QString("录音测试失败:8秒内未达到通过标准(连续3次或累计6次满足要求 >= %1)").arg(audioLevelStandard), 3000);
+    ui->recvTextEdit->append(QString(">>> 音频测试超时失败: 连续 %1 次,累计 %2 次 (要求: 连续3次或累计6次 >= %3)")
+                             .arg(audioMicMiddleConsecutiveCount)
+                             .arg(audioMicTotalPassCount)
+                             .arg(audioLevelStandard));
     updateTestStatus("audio", STATUS_FAILED);
 
     audioTestFinished = true;
@@ -3662,6 +3670,76 @@ void MainWindow::onAudioRecordTimer()
     skipToNextEnabledTest();
 }
 
+// 解析音频等级(从文字或rms_db数值)
+QString MainWindow::parseAudioLevel(const QString& data)
+{
+    // 尝试从 "fac:mic level:" 后面提取值
+    QRegExp levelPattern("fac:mic level:(.+)");
+    if (levelPattern.indexIn(data) != -1) {
+        QString levelStr = levelPattern.cap(1).trimmed();
+        
+        // 如果是数字(rms_db值),转换为等级文字
+        bool ok;
+        double rms_db = levelStr.toDouble(&ok);
+        if (ok) {
+            // 根据rms_db值转换为等级
+            if (rms_db < -60.0) {
+                return "静音";
+            } else if (rms_db < -40.0) {
+                return "极低";
+            } else if (rms_db < -20.0) {
+                return "低";
+            } else if (rms_db < -6.0) {
+                return "中";
+            } else if (rms_db < 0.0) {
+                return "高";
+            } else {
+                return "最大";
+            }
+        } else {
+            // 已经是文字,直接返回(去除可能的空格和换行)
+            return levelStr;
+        }
+    }
+    
+    return "";
+}
+
+// 获取音频等级数值(用于比较)
+// 返回值:静音=0, 极低=1, 低=2, 中=3, 高=4, 最大=5
+int MainWindow::getAudioLevelValue(const QString& level)
+{
+    if (level == "静音") {
+        return 0;
+    } else if (level == "极低") {
+        return 1;
+    } else if (level == "低") {
+        return 2;
+    } else if (level == "中") {
+        return 3;
+    } else if (level == "高") {
+        return 4;
+    } else if (level == "最大") {
+        return 5;
+    }
+    return -1; // 未知等级
+}
+
+// 判断检测到的等级是否满足要求
+// 如果设置"低",那么"低"、"中"、"高"、"最大"都可以通过,但"极低"和"静音"不能通过
+bool MainWindow::isAudioLevelPass(const QString& detectedLevel, const QString& requiredLevel)
+{
+    int detectedValue = getAudioLevelValue(detectedLevel);
+    int requiredValue = getAudioLevelValue(requiredLevel);
+    
+    if (detectedValue == -1 || requiredValue == -1) {
+        return false; // 未知等级,不通过
+    }
+    
+    // 检测到的等级值 >= 要求的等级值,则通过
+    return detectedValue >= requiredValue;
+}
+
 // 检查录音测试结果
 void MainWindow::checkAudioTestResult(const QString& data)
 {
@@ -3673,24 +3751,65 @@ void MainWindow::checkAudioTestResult(const QString& data)
 
     // 只在录音测试过程中统计"fac:mic level:"的值
     if (data.contains("fac:mic level:")) {
-        // 构建要检测的字符串
-        QString targetLevel = QString("fac:mic level:%1").arg(audioLevelStandard);
+        // 解析检测到的音频等级
+        QString detectedLevel = parseAudioLevel(data);
+        
+        if (detectedLevel.isEmpty()) {
+            qDebug() << "无法解析音频等级,跳过";
+            return;
+        }
+        
+        qDebug() << QString("解析到音频等级: %1 (要求: >= %2)").arg(detectedLevel).arg(audioLevelStandard);
         
-        if (data.contains(targetLevel)) {
+        // 判断是否满足要求
+        bool isPass = isAudioLevelPass(detectedLevel, audioLevelStandard);
+        
+        if (isPass) {
+            // 满足要求,连续计数和累计计数都增加
             audioMicMiddleConsecutiveCount++;
-            qDebug() << QString("检测到 \"fac:mic level:%1\" ,当前连续计数: %2")
+            audioMicTotalPassCount++;
+            
+            qDebug() << QString("检测到满足要求的等级 \"%1\" (>= %2),连续计数: %3,累计计数: %4")
+                        .arg(detectedLevel)
                         .arg(audioLevelStandard)
-                        .arg(audioMicMiddleConsecutiveCount);
+                        .arg(audioMicMiddleConsecutiveCount)
+                        .arg(audioMicTotalPassCount);
+            
+            ui->recvTextEdit->append(QString(">>> 音频测试: 检测到等级 %1 (>= %2),连续 %3 次,累计 %4 次")
+                                     .arg(detectedLevel)
+                                     .arg(audioLevelStandard)
+                                     .arg(audioMicMiddleConsecutiveCount)
+                                     .arg(audioMicTotalPassCount));
         } else {
-            // 遇到其他 mic level 打印,连续计数清零
-            qDebug() << "检测到其他 mic level 打印,重置连续计数";
+            // 不满足要求,连续计数清零,但累计计数不变
+            qDebug() << QString("检测到不满足要求的等级 \"%1\" (< %2),重置连续计数")
+                        .arg(detectedLevel)
+                        .arg(audioLevelStandard);
             audioMicMiddleConsecutiveCount = 0;
+            
+            ui->recvTextEdit->append(QString(">>> 音频测试: 检测到等级 %1 (< %2,不满足要求),连续计数已重置")
+                                     .arg(detectedLevel)
+                                     .arg(audioLevelStandard));
         }
 
-        // 达到连续3次设置的标准Level视为录音测试通过
-        if (!audioTestFinished && audioMicMiddleConsecutiveCount >= 3) {
-            qDebug() << QString("录音测试通过:已检测到连续3个 \"fac:mic level:%1\"").arg(audioLevelStandard);
-            ui->statusbar->showMessage(QString("录音测试通过:检测到连续3个\"fac:mic level:%1\"").arg(audioLevelStandard), 3000);
+        // 判断是否通过:
+        // 1. 连续3次满足要求,或者
+        // 2. 累计6次满足要求(即使不是连续的)
+        bool testPassed = false;
+        QString passReason;
+        
+        if (audioMicMiddleConsecutiveCount >= 3) {
+            testPassed = true;
+            passReason = QString("连续 %1 次满足要求").arg(audioMicMiddleConsecutiveCount);
+        } else if (audioMicTotalPassCount >= 6) {
+            testPassed = true;
+            passReason = QString("累计 %1 次满足要求").arg(audioMicTotalPassCount);
+        }
+        
+        if (!audioTestFinished && testPassed) {
+            qDebug() << QString("录音测试通过:%1 (要求: >= %2)").arg(passReason).arg(audioLevelStandard);
+            ui->statusbar->showMessage(QString("录音测试通过:%1").arg(passReason), 3000);
+            ui->recvTextEdit->append(QString(">>> 音频测试通过: %1").arg(passReason));
             updateTestStatus("audio", STATUS_SUCCESS);
 
             audioTestFinished = true;
@@ -3703,6 +3822,7 @@ void MainWindow::checkAudioTestResult(const QString& data)
             // 发送结束音频测试指令
             QString audioEndCmd = "AT^AUDIOTEST=6\r\n";
             serial->write(audioEndCmd.toUtf8());
+            ui->recvTextEdit->append(">>> 发送指令: AT^AUDIOTEST=6 (结束音频测试)");
             qDebug() << "发送结束音频测试指令:" << audioEndCmd.trimmed();
 
             // 继续后续测试
@@ -3755,13 +3875,21 @@ void MainWindow::checkBatteryTestResult(const QString& data)
     }
     
     qDebug() << "电池测试收到数据:" << data.trimmed();
+    ui->recvTextEdit->append(QString(">>> 电池测试原始数据: %1").arg(data.trimmed()));
 
     // 解析电池数据,支持多种格式:
     // 1. 目标格式:fac:voltage : 3.800 , percent 85 , temp : 25.500, charge : 1
     // 2. 原有格式1:fac:voltage : 3.8 , percent 85 , charge : 1(无温度)
     // 3. 原有格式2:Battery: 3.8V
     // 4. 原有格式3:3.8V
-    QRegExp facVoltagePattern("fac:voltage\\s*:\\s*(\\d+\\.\\d+)\\s*,\\s*percent\\s*(\\d+)\\s*(,\\s*temp\\s*:\\s*(\\d+\\.\\d+))?\\s*,\\s*charge\\s*:\\s*(\\d+)");
+    // 增强的正则表达式,支持更多格式变体
+    QRegExp facVoltagePattern1("fac:voltage\\s*:\\s*(\\d+\\.\\d+)\\s*,\\s*percent\\s*(\\d+)\\s*(,\\s*temp\\s*:\\s*(\\d+\\.\\d+))?\\s*,\\s*charge\\s*:\\s*(\\d+)");
+    QRegExp facVoltagePattern2("fac:voltage\\s*:\\s*(\\d+\\.\\d+)\\s*,\\s*percent\\s*(\\d+)\\s*(,\\s*temp\\s*:\\s*(\\d+\\.\\d+))?\\s*,\\s*charge\\s*=\\s*(\\d+)");
+    QRegExp facVoltagePattern3("fac:voltage\\s*:\\s*(\\d+\\.\\d+)\\s*,\\s*percent\\s*(\\d+)\\s*(,\\s*temp\\s*:\\s*(\\d+\\.\\d+))?\\s*charge\\s*:\\s*(\\d+)");
+    // 单独提取charge字段的备用正则(如果主正则失败)
+    QRegExp chargePattern1("charge\\s*:\\s*(\\d+)");
+    QRegExp chargePattern2("charge\\s*=\\s*(\\d+)");
+    QRegExp chargePattern3("charge\\s+(\\d+)");
     QRegExp batteryPattern("Battery.*?(\\d+\\.\\d+)V?");
     QRegExp voltagePattern("(\\d+\\.\\d+)V");
 
@@ -3770,30 +3898,45 @@ void MainWindow::checkBatteryTestResult(const QString& data)
     double temp = -1.0;  // -1.0表示未检测到温度
     int charge = -1;     // -1表示未检测到充电状态
     bool voltageFound = false;
+    bool chargeFound = false;
     // 温度正常范围(可根据实际电池规格调整,此处为常见NTC有效范围)
     const double MIN_NORMAL_TEMP = 0.0;   // 最低正常温度:0℃
     const double MAX_NORMAL_TEMP = 60.0;  // 最高正常温度:60℃
 
-    if (facVoltagePattern.indexIn(data) != -1) {
-        // 解析支持「带温度」和「不带温度」的两种fac格式
-        voltage = facVoltagePattern.cap(1).toDouble();
-        percent = facVoltagePattern.cap(2).toInt();
-        if (!facVoltagePattern.cap(4).isEmpty()) {
-            temp = facVoltagePattern.cap(4).toDouble();
+    // 尝试多种fac:voltage格式
+    if (facVoltagePattern1.indexIn(data) != -1) {
+        // 格式1:fac:voltage : 3.800 , percent 85 , temp : 25.500, charge : 1
+        voltage = facVoltagePattern1.cap(1).toDouble();
+        percent = facVoltagePattern1.cap(2).toInt();
+        if (!facVoltagePattern1.cap(4).isEmpty()) {
+            temp = facVoltagePattern1.cap(4).toDouble();
         }
-        charge = facVoltagePattern.cap(5).toInt();
+        charge = facVoltagePattern1.cap(5).toInt();
+        chargeFound = true;
         voltageFound = true;
-
-        // 日志区分是否有温度
-        if (temp != -1.0) {
-            qDebug() << "使用fac:voltage(带温度)格式解析到:"
-                     << "电压:" << voltage << "V, 电量:" << percent << "%, "
-                     << "温度:" << temp << "℃, 充电状态:" << charge;
-        } else {
-            qDebug() << "使用fac:voltage(无温度)格式解析到:"
-                     << "电压:" << voltage << "V, 电量:" << percent << "%, "
-                     << "充电状态:" << charge;
-        }
+        qDebug() << "使用fac:voltage格式1解析成功";
+    } else if (facVoltagePattern2.indexIn(data) != -1) {
+        // 格式2:fac:voltage : 3.800 , percent 85 , temp : 25.500, charge = 1
+        voltage = facVoltagePattern2.cap(1).toDouble();
+        percent = facVoltagePattern2.cap(2).toInt();
+        if (!facVoltagePattern2.cap(4).isEmpty()) {
+            temp = facVoltagePattern2.cap(4).toDouble();
+        }
+        charge = facVoltagePattern2.cap(5).toInt();
+        chargeFound = true;
+        voltageFound = true;
+        qDebug() << "使用fac:voltage格式2解析成功(charge=格式)";
+    } else if (facVoltagePattern3.indexIn(data) != -1) {
+        // 格式3:fac:voltage : 3.800 , percent 85 , temp : 25.500 charge : 1(缺少逗号)
+        voltage = facVoltagePattern3.cap(1).toDouble();
+        percent = facVoltagePattern3.cap(2).toInt();
+        if (!facVoltagePattern3.cap(4).isEmpty()) {
+            temp = facVoltagePattern3.cap(4).toDouble();
+        }
+        charge = facVoltagePattern3.cap(5).toInt();
+        chargeFound = true;
+        voltageFound = true;
+        qDebug() << "使用fac:voltage格式3解析成功(缺少逗号)";
     } else if (batteryPattern.indexIn(data) != -1) {
         voltage = batteryPattern.cap(1).toDouble();
         voltageFound = true;
@@ -3803,6 +3946,48 @@ void MainWindow::checkBatteryTestResult(const QString& data)
         voltageFound = true;
         qDebug() << "使用通用电压格式解析到电压:" << voltage << "V(无电量、温度、充电状态)";
     }
+    
+    // 如果主正则没有匹配到charge,尝试单独提取charge字段
+    if (!chargeFound && data.contains("charge", Qt::CaseInsensitive)) {
+        if (chargePattern1.indexIn(data) != -1) {
+            charge = chargePattern1.cap(1).toInt();
+            chargeFound = true;
+            qDebug() << "使用备用charge格式1解析成功(charge: 格式)";
+        } else if (chargePattern2.indexIn(data) != -1) {
+            charge = chargePattern2.cap(1).toInt();
+            chargeFound = true;
+            qDebug() << "使用备用charge格式2解析成功(charge= 格式)";
+        } else if (chargePattern3.indexIn(data) != -1) {
+            charge = chargePattern3.cap(1).toInt();
+            chargeFound = true;
+            qDebug() << "使用备用charge格式3解析成功(charge 格式)";
+        }
+    }
+    
+    // 详细日志输出
+    if (voltageFound) {
+        QString parseLog = QString("解析结果 - 电压:%1V").arg(voltage);
+        if (percent > 0) parseLog += QString(", 电量:%1%").arg(percent);
+        if (temp != -1.0) {
+            parseLog += QString(", 温度:%1℃").arg(temp);
+        } else {
+            parseLog += ", 温度:未检测到";
+        }
+        if (chargeFound) {
+            parseLog += QString(", 充电状态:%1").arg(charge);
+            qDebug() << parseLog << "(charge字段解析成功)";
+        } else {
+            parseLog += ", 充电状态:未检测到";
+            qDebug() << parseLog << "(charge字段解析失败,尝试查找charge关键字)";
+            // 如果包含charge关键字但未解析成功,输出原始数据片段
+            int chargePos = data.indexOf("charge", 0, Qt::CaseInsensitive);
+            if (chargePos != -1) {
+                QString chargeContext = data.mid(qMax(0, chargePos - 20), 40);
+                qDebug() << "charge关键字上下文:" << chargeContext;
+                ui->recvTextEdit->append(QString(">>> 警告: 检测到charge关键字但解析失败,上下文: %1").arg(chargeContext));
+            }
+        }
+    }
 
     if (voltageFound) {
         // 停止超时检测
@@ -3811,37 +3996,96 @@ void MainWindow::checkBatteryTestResult(const QString& data)
             qDebug() << "电池测试收到响应,停止超时检测";
         }
 
+        // 充电状态检查(根据checkbox决定是否判定)
+        // 注意:充电状态每次都解析,但只有charge checkbox选中时才用充电状态来判断是否通过
+        bool chargeCheckEnabled = isTestItemEnabled("charge");
+        bool ntcCheckEnabled = isTestItemEnabled("ntc");
+        
         // 拼接检测结果日志(包含所有已获取的字段)
+        // 注意:充电状态和温度数据每次都解析并记录,无论checkbox是否选中
         QString resultLog = QString("检测到电池电压:%1V").arg(voltage);
         if (percent > 0) resultLog += QString(", 电量:%1%").arg(percent);
-        if (temp != -1.0) resultLog += QString(", 温度:%1℃").arg(temp);
-        if (charge != -1) resultLog += QString(", 充电状态:%1").arg(charge == 1 ? "充电中" : "未充电");
+        if (temp != -1.0) {
+            resultLog += QString(", 温度:%1℃").arg(temp);
+            // 如果NTC未启用,在日志中说明温度数据已解析但不用于判定
+            if (!ntcCheckEnabled) {
+                resultLog += "(NTC未启用,不用于判定)";
+            }
+        }
+        if (chargeFound && charge != -1) {
+            QString chargeStatusText;
+            if (charge == 1) {
+                chargeStatusText = "充电中";
+            } else if (charge == 0) {
+                chargeStatusText = "未充电";
+            } else {
+                chargeStatusText = QString("未知值(%1)").arg(charge);
+            }
+            resultLog += QString(", 充电状态:%1").arg(chargeStatusText);
+            // 如果充电检查未启用,在日志中说明充电状态已解析但不用于判定
+            if (!chargeCheckEnabled) {
+                resultLog += "(充电检查未启用,不用于判定)";
+            }
+        } else if (chargeFound && charge == -1) {
+            resultLog += ", 充电状态:解析失败";
+            qDebug() << "警告: charge字段存在但值为-1,可能解析有问题";
+        } else {
+            resultLog += ", 充电状态:未检测到";
+        }
         qDebug() << resultLog;
-
-        // 充电状态检查(根据checkbox决定是否判定)
-        bool chargeCheckEnabled = isTestItemEnabled("charge");
-        bool ntcCheckEnabled = isTestItemEnabled("ntc");
+        ui->recvTextEdit->append(QString(">>> 电池测试: %1").arg(resultLog));
         
         bool chargePassed = true;  // 默认通过(如果未启用检查)
         bool ntcPassed = true;     // 默认通过(如果未启用检查)
         
+        // 充电状态每次都解析(已经在上面解析了),这里只判断是否满足条件
         if (chargeCheckEnabled) {
-            if (charge == 0) {
-                qDebug() << "充电检查失败:设备未充电";
+            // charge checkbox选中,需要判断充电状态
+            if (chargeFound && charge == 1) {
+                // 充电中,通过
+                chargePassed = true;
+                updateTestStatus("charge", STATUS_SUCCESS);
+                qDebug() << "充电检查通过:设备正在充电 (charge=1)";
+                ui->recvTextEdit->append(">>> 充电检查通过:设备正在充电");
+            } else if (chargeFound && charge == 0) {
+                // 未充电,不通过
                 chargePassed = false;
+                updateTestStatus("charge", STATUS_FAILED);
+                qDebug() << "充电检查失败:设备未充电 (charge=0)";
                 ui->statusbar->showMessage("充电检查失败 - 设备未充电", 2000);
+                ui->recvTextEdit->append(">>> 充电检查失败:设备未充电");
+                
+                // 显示充电失败对话框(每次失败都显示,让用户可以选择重试)
                 showBatteryChargeFailDialog();
-                // 如果充电检查失败,直接返回,不继续测试
-                updateTestStatus("charge", STATUS_FAILED);
-                if (ntcCheckEnabled) {
-                    updateTestStatus("ntc", STATUS_UNTESTED);
+                
+                // 注意:不直接返回,继续检查NTC(如果启用),然后根据所有检查结果来决定是否通过
+            } else if (chargeFound && charge != -1 && charge != 0 && charge != 1) {
+                // 检测到charge字段但值不是0或1,可能是异常值
+                qDebug() << QString("充电检查:检测到异常charge值 %1,期望0或1").arg(charge);
+                ui->recvTextEdit->append(QString(">>> 警告: 充电状态值异常: %1 (期望0或1)").arg(charge));
+                QMessageBox msgBox(this);
+                msgBox.setWindowTitle("充电状态异常");
+                msgBox.setText(QString("检测到异常的充电状态值: %1").arg(charge));
+                msgBox.setInformativeText("期望值为0(未充电)或1(充电中),\n但检测到的值不符合预期,是否继续测试?");
+                msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+                msgBox.setDefaultButton(QMessageBox::Yes);
+                msgBox.setIcon(QMessageBox::Warning);
+
+                int ret = msgBox.exec();
+                if (ret == QMessageBox::No) {
+                    updateTestStatus("charge", STATUS_FAILED);
+                    chargePassed = false;
+                } else {
+                    // 用户选择继续,认为充电检查通过
+                    chargePassed = true;
+                    updateTestStatus("charge", STATUS_SUCCESS);
                 }
-                return;
-            } else if (charge == -1) {
-                qDebug() << "未检测到充电状态信息";
-                ui->statusbar->showMessage("电池测试 - 未检测到充电状态", 2000);
+            } else {
+                // 未检测到充电状态(chargeFound=false 或 charge=-1),如果启用了充电检查,需要提示
+                qDebug() << "充电检查:未检测到充电状态信息";
+                ui->recvTextEdit->append(">>> 警告: 未检测到充电状态信息");
                 QMessageBox msgBox(this);
-                msgBox.setWindowTitle("充电状态提醒");
+                msgBox.setWindowTitle("å\85\85ç\94µç\8a¶æ\80\81æ£\80æ\9f¥æ\8f\90é\86\92");
                 msgBox.setText("未检测到设备的充电状态信息");
                 msgBox.setInformativeText("系统未能检测到设备的充电状态信息,\n但电压检测正常,是否继续测试?");
                 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
@@ -3851,32 +4095,48 @@ void MainWindow::checkBatteryTestResult(const QString& data)
                 int ret = msgBox.exec();
                 if (ret == QMessageBox::No) {
                     updateTestStatus("charge", STATUS_FAILED);
-                    if (ntcCheckEnabled) {
-                        updateTestStatus("ntc", STATUS_UNTESTED);
-                    }
-                    return;
+                    chargePassed = false;
+                } else {
+                    // 用户选择继续,认为充电检查通过
+                    chargePassed = true;
+                    updateTestStatus("charge", STATUS_SUCCESS);
+                }
+            }
+        } else {
+            // 充电检查未启用,不判定(但充电状态仍然已解析)
+            chargePassed = true;
+            QString chargeStatusDesc = "未检测到";
+            if (chargeFound) {
+                if (charge == 1) {
+                    chargeStatusDesc = "充电中";
+                } else if (charge == 0) {
+                    chargeStatusDesc = "未充电";
+                } else {
+                    chargeStatusDesc = QString("值%1").arg(charge);
                 }
-                // 用户选择继续,认为充电检查通过
-                chargePassed = true;
-            } else if (charge == 1) {
-                chargePassed = true;
             }
+            qDebug() << QString("充电检查未启用,充电状态已解析: %1(但不用于判定)").arg(chargeStatusDesc);
         }
 
         // NTC温度检查(根据checkbox决定是否判定)
+        // 注意:温度数据每次都解析,但只有NTC checkbox选中时才用温度>0来判断是否通过
         bool isVoltageNormal = (voltage >= 3.3 && voltage <= 4.4);
         bool isTempNormal = true;  // 默认温度正常(未检测到温度时不影响结果)
+        
+        // 温度数据每次都解析(已经在上面解析了),这里只判断是否满足条件
         if (ntcCheckEnabled) {
+            // NTC checkbox选中,需要判断温度是否>0
             if (temp != -1.0) {
-                isTempNormal = (temp >= MIN_NORMAL_TEMP && temp <= MAX_NORMAL_TEMP);
+                // 判断条件:temp > 0.0
+                isTempNormal = (temp > 0.0);
                 if (!isTempNormal) {
                     ntcPassed = false;
-                    qDebug() << QString("NTC检查失败:温度异常(%1℃,正常范围%2℃-%3℃)").arg(temp).arg(MIN_NORMAL_TEMP).arg(MAX_NORMAL_TEMP);
+                    qDebug() << QString("NTC检查失败:温度 %1℃ 不满足要求(需要 > 0℃)").arg(temp);
                     updateTestStatus("ntc", STATUS_FAILED);
                 } else {
                     ntcPassed = true;
                     updateTestStatus("ntc", STATUS_SUCCESS);
-                    qDebug() << QString("NTC检查通过:温度正常(%1℃)").arg(temp);
+                    qDebug() << QString("NTC检查通过:温度 %1℃ 满足要求(> 0℃)").arg(temp);
                 }
             } else {
                 // 未检测到温度,如果启用了NTC检查,需要提示
@@ -3899,8 +4159,9 @@ void MainWindow::checkBatteryTestResult(const QString& data)
                 updateTestStatus("ntc", STATUS_SUCCESS);
             }
         } else {
-            // NTC检查未启用,不判定
+            // NTC检查未启用,不判定(但温度数据仍然已解析)
             ntcPassed = true;
+            qDebug() << QString("NTC检查未启用,温度数据已解析: %1℃(但不用于判定)").arg(temp != -1.0 ? QString::number(temp) : "未检测到");
         }
 
         // 更新充电状态(用于判定,不显示在UI)
@@ -4880,13 +5141,31 @@ void MainWindow::showBatteryChargeFailDialog()
     } else if (chargeFailDialog.clickedButton() == retryButton) {
         qDebug() << "用户选择重新获取电池信息";
         ui->statusbar->showMessage("重新获取电池信息...", 2000);
-        
-        // 重新发送电池测试指令
-        serial->write("AT^GETCYWEEID\r\n");
-        qDebug() << "重新发送电池测试指令: AT^GETCYWEEID";
-        
-        // 重新启动超时检测
-        testTimeoutTimer->start(10000);
+        ui->recvTextEdit->append(">>> 用户选择重新获取电池信息,重新发送测试指令");
+        
+        // 重置充电失败对话框标志,允许下次失败时再次显示
+        // 使用静态变量来跟踪,但通过重置状态来允许重试
+        // 注意:这里不直接操作静态变量,而是通过重置测试状态来允许新的检查
+        
+        // 重置充电测试状态,确保可以重新检测
+        updateTestStatus("charge", STATUS_TESTING);
+        updateTestStatus("battery", STATUS_TESTING);
+        
+        // 延迟100ms后重新发送电池测试指令,确保串口已准备好
+        QTimer::singleShot(100, this, [this]() {
+            if (isProductionTestRunning && currentTestStep == TEST_BATTERY && serial && serial->isOpen()) {
+                // 重新发送电池电量查询指令(正确的指令)
+                serial->write("AT^GETPOWER\r\n");
+                qDebug() << "重新发送电池测试指令: AT^GETPOWER";
+                ui->recvTextEdit->append(">>> 发送指令: AT^GETPOWER (重新获取电池信息)");
+                
+                // 重新启动超时检测
+                testTimeoutTimer->start(10000);
+            } else {
+                qDebug() << "电池测试重试:串口未打开或产测已停止,无法发送指令";
+                ui->recvTextEdit->append(">>> 警告: 串口未打开或产测已停止,无法重试");
+            }
+        });
     }
 }
 
index 552257d..6caa716 100644 (file)
@@ -83,6 +83,9 @@ private slots:
     void showAudioTestDialog(); // 显示录音测试弹窗
     void onAudioRecordTimer(); // 录音测试定时器(3秒录音)
     void checkAudioTestResult(const QString& data); // 检查录音测试结果
+    QString parseAudioLevel(const QString& data); // 解析音频等级(从文字或rms_db数值)
+    int getAudioLevelValue(const QString& level); // 获取音频等级数值(用于比较)
+    bool isAudioLevelPass(const QString& detectedLevel, const QString& requiredLevel); // 判断检测到的等级是否满足要求
     void performBatteryTest(); // 执行电池测试
     void checkBatteryTestResult(const QString& data); // 检查电池测试结果
     void performGsensorTest(); // 执行G-sensor测试
@@ -173,6 +176,7 @@ private:
     QPushButton *audioFailButton;      // 录音失败按钮
     QPushButton *audioRetestButton;    // 重新测试按钮
     int audioMicMiddleConsecutiveCount; // 连续检测到设置的标准Level的次数
+    int audioMicTotalPassCount;         // 累计检测到满足要求的Level的次数(包括非连续的)
     QString audioLevelStandard;         // 音频测试通过标准("中"或"低"等)
     bool audioTestFinished;             // 录音测试是否已完成(成功或失败)
     QSet<QString> bluetoothAddresses;  // 蓝牙测试检测到的不同蓝牙地址集合
index 07c79ee..cc78c40 100644 (file)
@@ -1200,7 +1200,7 @@ background-color: #F57C00;
             <item row="3" column="1">
              <widget class="QCheckBox" name="checkBox_ntc">
               <property name="text">
-               <string>NTC</string>
+               <string>电池温度</string>
               </property>
              </widget>
             </item>
diff --git a/releasePackage/LN_Factorytool_V1.3.zip b/releasePackage/LN_Factorytool_V1.3.zip
new file mode 100644 (file)
index 0000000..e29c653
Binary files /dev/null and b/releasePackage/LN_Factorytool_V1.3.zip differ
diff --git a/releasePackage/LN_Factorytool_V1.3/LeiNiaoFactoryTool.exe b/releasePackage/LN_Factorytool_V1.3/LeiNiaoFactoryTool.exe
new file mode 100644 (file)
index 0000000..a7b8050
Binary files /dev/null and b/releasePackage/LN_Factorytool_V1.3/LeiNiaoFactoryTool.exe differ
diff --git a/releasePackage/LN_Factorytool_V1.3/settings.json b/releasePackage/LN_Factorytool_V1.3/settings.json
new file mode 100644 (file)
index 0000000..b7ef5ee
--- /dev/null
@@ -0,0 +1,36 @@
+{\r
+    "bootDetectionKeywords": [\r
+        "BuildVer",\r
+        "NAND flash ID",\r
+        "NAND ID:"\r
+    ],\r
+    "factoryModeCheckCommand": "AT^FACTORY",\r
+    "factoryModeKeywords": [\r
+        "FACTORY TEST MODE:"\r
+    ],\r
+    "testCheckboxes": {\r
+        "4g": true,\r
+        "bt": true,\r
+        "btn": true,\r
+        "charge": true,\r
+        "lcd": true,\r
+        "mic": true,\r
+        "ntc": true,\r
+        "vib": true\r
+    },\r
+    "testConfig": {\r
+        "audioLevelStandard": "静音",\r
+        "audioVolume": "2.0",\r
+        "bluetoothAddress": "",\r
+        "bluetoothRSSI": "",\r
+        "expectedModemVer": "EG800AKCN91LCR07A01M04_OCPU_QPY_BETA1022",\r
+        "expectedPYVer": "PY_SRV_V27",\r
+        "expectedVer": "V1.0.13_20251205_072113",\r
+        "portName": "COM42 (USB-Enhanced-SERIAL CH343)"\r
+    },\r
+    "versionInfoCommands": [\r
+        "AT^CAT1GETVER",\r
+        "AT^CAT1GETSIGNAL",\r
+        "AT^FACTORY"\r
+    ]\r
+}\r