--- /dev/null
+#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
+ 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
--- /dev/null
+#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
+ // 检查配置是否有效\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
# 源文件列表
SOURCES += \
main.cpp \
- mainwindow.cpp
+ mainwindow.cpp \
+ config_manager.cpp
# 头文件列表
HEADERS += \
- mainwindow.h
+ mainwindow.h \
+ config_manager.h
# UI 文件列表(关键:必须包含 mainwindow.ui)
FORMS += \
#include "mainwindow.h"
#include "ui_mainwindow.h"
+#include "config_manager.h"
#include <QMessageBox>
#include <QDateTime>
#include <QDebug>
QTextCodec::setCodecForCStrings(utf8Codec);
QTextCodec::setCodecForTr(utf8Codec);
#endif
-
+
// 初始化串口对象
serial = new QSerialPort(this);
connect(serial, &QSerialPort::readyRead, this, &MainWindow::readSerialData);
// 初始刷新串口列表
updateSerialPorts();
+
+ // 从settings.json加载测试参数
+ loadTestConfigFromSettings();
// 初始化按钮样式(可选:设置默认样式)
ui->openButton->setStyleSheet("QPushButton { padding: 5px 10px; }");
testLogFile = nullptr;
testLogStream = nullptr;
testLogFilePath = "";
+ // 初始化配置管理器
+ configManager.loadConfig();
+ // 初始化开机检测相关变量
+ bootDetected = false;
+ factoryModeChecked = false;
+ versionInfoFetched = false;
+ // 初始化版本信息获取相关变量
+ versionCommandQueue.clear();
+ currentVersionCommandIndex = -1;
+ versionCommandTimer = new QTimer(this);
+ connect(versionCommandTimer, &QTimer::timeout, this, &MainWindow::onVersionCommandTimeout);
+
+ // 从settings.json加载测试参数
+ loadTestConfigFromSettings();
// 初始化按键测试状态
for (int i = 0; i < 4; i++) {
MainWindow::~MainWindow()
{
+ // 保存测试参数到settings.json
+ saveTestConfigToSettings();
+
// 关闭日志文件
closeTestLogFile();
ui->openButton->setStyleSheet("QPushButton { padding: 5px 10px; }");
return;
}
-
+
// 检查是否选择了串口
if (ui->portNameBox->currentText().isEmpty()) {
QMessageBox::warning(this, "警告", "请先选择串口");
return;
}
-
+
// 配置串口参数(固定值)
QString portText = ui->portNameBox->currentText();
QString portName = portText.left(portText.indexOf(" ("));
QMessageBox::warning(this, "警告", "请先打开串口");
return;
}
-
+
// 获取发送区文本
QString sendStr = ui->sendTextEdit->toPlainText();
if (sendStr.isEmpty()) return;
// 提取IMEI信息
imeiInfo = data.mid(start, end - start).trimmed();
qDebug() << "使用imei:格式提取IMEI:" << imeiInfo;
- } else {
+ } else {
qDebug() << "未找到任何IMEI格式,数据:" << data.trimmed();
return;
}
if (modemPattern.indexIn(data) != -1) {
modemVerInfo = modemPattern.cap(1);
qDebug() << "使用括号格式提取Modem Version:" << modemVerInfo;
- } else {
+ } else {
qDebug() << "未找到Modem Version信息,数据格式:" << data.trimmed();
- return;
+ return;
+ }
}
- }
}
// 验证Modem Version是否有效(不为空即可)
if (recvData.isEmpty()) {
return;
}
-
+
// 将新接收的数据追加到缓存
recvBuffer += QString::fromUtf8(recvData);
if (line.startsWith("fac:")) {
appendToLogFile(processLine);
}
+
+ // 开机检测(仅在未检测到开机时执行)
+ // 同时检查原始行和去掉fac:前缀的行,确保能匹配到关键字
+ if (!bootDetected && !isProductionTestRunning) {
+ checkBootDetection(line);
+ // 如果原始行没匹配到,也检查去掉fac:前缀的行
+ if (!bootDetected && processLine != line) {
+ checkBootDetection(processLine);
+ }
+ }
+
+ // 产测模式检测(在检测到开机后执行)
+ if (bootDetected && !factoryModeChecked && !isProductionTestRunning) {
+ checkFactoryMode(line);
+ }
+
+ // 版本信息获取:当正在获取版本信息时,接收到数据后继续发送下一条指令
+ if (versionInfoFetched && currentVersionCommandIndex >= 0 &&
+ currentVersionCommandIndex < versionCommandQueue.size() &&
+ !isProductionTestRunning) {
+ // 如果当前指令的响应已收到(通过超时或检测到响应),继续下一条
+ // 这里主要通过超时机制来推进,但也可以检测到特定响应后立即推进
+ // 暂时依赖超时机制,如果需要可以添加响应检测逻辑
+ }
// 处理所有数据提取(不管是否以fac:开头)(大小写不敏感)
if (processLine.indexOf("BuildVer:", 0, Qt::CaseInsensitive) != -1) {
parseWstpPrintData(line);
}
+ // 检测FACTORY TEST MODE状态(wstp_print格式)
+ if (line.contains("FACTORY TEST MODE:", Qt::CaseInsensitive)) {
+ qDebug() << "检测到FACTORY TEST MODE信息:" << line.trimmed();
+ appendToLogFile(QString("检测到FACTORY TEST MODE信息: %1\n").arg(line.trimmed()));
+
+ if (line.contains("FACTORY TEST MODE: ENABLED", Qt::CaseInsensitive)) {
+ // 产测模式已开启
+ ui->factoryModeLineEdit->setText("是");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ffcccc;"); // 红底
+ qDebug() << "产测模式: 已开启";
+ appendToLogFile(QString("=== 产测模式状态: 已开启 ===\n"));
+
+ // 如果还未标记为已检测,标记并开始获取版本信息
+ if (!factoryModeChecked) {
+ factoryModeChecked = true;
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+ }
+ } else if (line.contains("FACTORY TEST MODE: DISABLED", Qt::CaseInsensitive)) {
+ // 产测模式已关闭
+ ui->factoryModeLineEdit->setText("否");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ccffcc;"); // 绿底
+ qDebug() << "产测模式: 已关闭";
+ appendToLogFile(QString("=== 产测模式状态: 已关闭 ===\n"));
+
+ // 如果还未标记为已检测,标记并开始获取版本信息
+ if (!factoryModeChecked) {
+ factoryModeChecked = true;
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+ }
+ }
+ }
+
// 检测设备信息数据(去掉[PPP_INFO]限制,支持多种格式)(大小写不敏感)
// 检测包含@sim:的数据(可能是IMEI数据和4G信号数据)
if (line.contains("@sim:") || processLine.contains("@sim:")) {
QString colorName;
int colorCommand;
switch (currentLcdColor) {
- case 1:
+ case 1:
colorName = "红色";
colorCommand = 6; // AT^LCDTEST=6 红色
- break;
- case 2:
+ break;
+ case 2:
colorName = "绿色";
colorCommand = 3; // AT^LCDTEST=3 绿色
- break;
- case 3:
+ break;
+ case 3:
colorName = "蓝色";
colorCommand = 4; // AT^LCDTEST=4 蓝色
- break;
- default:
+ break;
+ default:
colorName = "未知";
colorCommand = 6;
- break;
+ break;
}
ui->statusbar->showMessage("LCD测试中 - " + colorName + " (1秒)", 1000);
qDebug() << "currentTestStep:" << currentTestStep << "期望:" << TEST_MOTOR;
return;
}
-
+
qDebug() << "开始马达测试";
// 重置马达测试状态
qDebug() << "4G测试跳过 - 产测未运行";
return;
}
-
+
initRetry4GCount++;
qDebug() << "4G测试 - 初始化尝试次数:" << initRetry4GCount;
qDebug() << "LCD确认弹窗已显示过,跳过";
return;
}
-
+
qDebug() << "显示LCD测试确认弹窗";
// 标记弹窗已显示,避免重复弹出
for (int i = 0; i < 4; i++) {
if (keyTestStatus[i] == 0) {
allKeysTested = false;
- break;
+ break;
}
}
statusText = "未测试";
iconColor = "#888888";
textColor = "#888888";
- break;
+ break;
case STATUS_TESTING:
iconText = "●";
statusText = "测试中";
overallIcon = "✓";
overallText = "通过";
overallColor = "#4CAF50";
- } else {
+ } else {
// 任何其他情况(失败、测试中、等待开始等)都显示为未通过
overallIcon = "✗";
overallText = "未通过";
finalContent += "开始时间,结束时间,测试耗时,软件版本,IMEI,ICCID,Modem版本,PYVER版本,LCD测试,马达测试,按键测试,录音测试,电池测试,G-sensor测试,蓝牙测试,4G测试,整体结果\n";
finalContent += newDataLine;
qDebug() << "创建新的CSV文件:" << csvFilePath;
- } else {
+ } else {
// 现有文件,需要检查ICCID是否重复
QFile existingFile(csvFilePath);
if (!existingFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
finalContent += newDataLine;
iccidFound = true;
qDebug() << "找到相同ICCID,替换记录:" << iccid;
- } else {
+ } else {
// 保留不同ICCID的记录
finalContent += line + "\n";
}
QDateTime endTime = QDateTime::currentDateTime();
*testLogStream << QString("=== 测试结束时间: %1 ===\n").arg(endTime.toString("yyyy-MM-dd hh:mm:ss"));
*testLogStream << QString("测试记录已保存: %1\n").arg(csvFileName);
+
+ // 将recvTextEdit的内容追加到测试日志文件
+ QString recvContent = ui->recvTextEdit->toPlainText();
+ if (!recvContent.isEmpty()) {
+ *testLogStream << "\n=== UI日志内容 ===\n";
+ *testLogStream << recvContent;
+ *testLogStream << "\n=== UI日志结束 ===\n";
+ }
+
testLogStream->flush();
}
closeTestLogFile();
+ // 保存UI日志到独立文件(如果有效)
+ saveRecvTextEditToLog();
+
+ // 清除UI中的日志内容,防止重复保存
+ ui->recvTextEdit->clear();
+
// 返回文件名供外部使用
return csvFileName;
}
// 将signal值显示到界面
appendToLogFile(QString("Signal值: %1\n").arg(signalValue));
ui->statusbar->showMessage(QString("检测到Signal值: %1").arg(signalValue), 2000);
- } else {
+ } else {
qDebug() << "未找到signal值";
return;
}
// 显示最终测试结果弹窗
showFinalTestResult();
- }
- } else {
+ }
+ } else {
// 测试失败
QString failReason;
if (simValue != 1) {
// 启动5秒超时定时器,等待PPPINFO回复
test4GTimer->start(5000);
qDebug() << "启动5秒超时定时器,等待PPPINFO回复";
- } else {
+ } else {
// 超过3次后,改为等待signal和sim数据
qDebug() << "PPP数据已等待3次,改为等待signal和sim数据";
ui->statusbar->showMessage("4G测试中 - 等待signal和sim数据...", 5000);
if (success) {
qDebug() << "成功打开文件夹:" << saveDir;
ui->statusbar->showMessage("已打开产测记录文件夹", 2000);
- } else {
+ } else {
qDebug() << "打开文件夹失败:" << saveDir;
QMessageBox::warning(this, "打开失败",
QString("无法打开文件夹:\n%1\n请检查路径是否存在或权限是否足够").arg(saveDir));
hasReceivedSignalSim = false;
hasReceivedPppInfo = false;
+ // 在开始新测试前,检查是否需要保存当前UI日志
+ QString currentLogContent = ui->recvTextEdit->toPlainText();
+ QString currentImei = ui->IMEIlineEdit->text().trimmed();
+ QString currentIccid = ui->ICCIDlineEdit->text().trimmed();
+
+ // 如果UI有日志内容且IMEI/ICCID已知,则保存日志
+ if (!currentLogContent.trimmed().isEmpty() &&
+ !currentImei.isEmpty() && currentImei != "未获取" &&
+ !currentIccid.isEmpty() && currentIccid != "未获取") {
+ qDebug() << "开始新测试前,保存当前UI日志";
+ saveRecvTextEditToLog();
+ } else {
+ qDebug() << "UI日志为空或IMEI/ICCID未知,放弃保存,直接清空UI";
+ }
+
// 创建测试日志文件
createTestLogFile();
ui->sendTextEdit->clear(); // 清空发送文本框
ui->statusbar->clearMessage(); // 清空状态栏
+ // 重置开机检测状态
+ bootDetected = false;
+ factoryModeChecked = false;
+ versionInfoFetched = false;
+
// 清空设备信息
ui->VerlineEdit->clear(); // 清空版本信息
ui->IMEIlineEdit->clear(); // 清空IMEI
// 重置录音测试相关状态
audioMicMiddleConsecutiveCount = 0;
audioTestFinished = false;
+
+ // 获取音频测试通过标准(从UI中读取)
+ audioLevelStandard = "中"; // 默认值
+ if (ui->recordVolumelineEdit) {
+ QString levelText = ui->recordVolumelineEdit->text().trimmed();
+ if (!levelText.isEmpty()) {
+ audioLevelStandard = levelText;
+ }
+ }
+ qDebug() << "音频测试通过标准设置为:" << audioLevelStandard;
// 发送录音测试指令:先 AT^AUDIOTEST=5 再 AT^AUDIOTEST=7 <音量>
QString audioCmd1 = "AT^AUDIOTEST=5\r\n";
float v = volumeStr.toFloat(&ok);
if (ok && v >= 0) {
volume = v;
- } else {
+ } else {
qDebug() << "音量文本框内容非法,使用默认音量 2,原始值:" << volumeStr;
}
} else {
return;
}
- // 8秒内未检测到连续5个"fac:mic level:中",判定录音测试失败
- qDebug() << "录音测试8秒超时,未检测到连续5个\"fac:mic level:中\",测试失败";
- ui->statusbar->showMessage("录音测试失败:8秒内未检测到连续5个\"fac:mic level:中\"", 3000);
+ // 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);
updateTestStatus("audio", STATUS_FAILED);
audioTestFinished = true;
return;
}
- qDebug() << "录音测试收到数据:" << data.trimmed();
-
qDebug() << "录音测试收到数据:" << data.trimmed();
- // 只在录音测试过程中统计“fac:mic level:中”
+ // 只在录音测试过程中统计"fac:mic level:"的值
if (data.contains("fac:mic level:")) {
- if (data.contains("fac:mic level:中")) {
+ // 构建要检测的字符串
+ QString targetLevel = QString("fac:mic level:%1").arg(audioLevelStandard);
+
+ if (data.contains(targetLevel)) {
audioMicMiddleConsecutiveCount++;
- qDebug() << "检测到 \"fac:mic level:中\" ,当前连续计数:"
- << audioMicMiddleConsecutiveCount;
+ qDebug() << QString("检测到 \"fac:mic level:%1\" ,当前连续计数: %2")
+ .arg(audioLevelStandard)
+ .arg(audioMicMiddleConsecutiveCount);
} else {
// 遇到其他 mic level 打印,连续计数清零
qDebug() << "检测到其他 mic level 打印,重置连续计数";
audioMicMiddleConsecutiveCount = 0;
}
- // 达到连续5次"fac:mic level:中"视为录音测试通过
+ // 达到连续3次设置的标准Level视为录音测试通过
if (!audioTestFinished && audioMicMiddleConsecutiveCount >= 3) {
- qDebug() << "录音测试通过:已检测到连续5个 \"fac:mic level:中\"";
- ui->statusbar->showMessage("录音测试通过:检测到连续3个\"fac:mic level:中\"", 3000);
+ qDebug() << QString("录音测试通过:已检测到连续3个 \"fac:mic level:%1\"").arg(audioLevelStandard);
+ ui->statusbar->showMessage(QString("录音测试通过:检测到连续3个\"fac:mic level:%1\"").arg(audioLevelStandard), 3000);
updateTestStatus("audio", STATUS_SUCCESS);
audioTestFinished = true;
if (!isProductionTestRunning || currentTestStep != TEST_BATTERY) {
return;
}
-
+
qDebug() << "电池测试收到数据:" << data.trimmed();
// 解析电池数据,支持多种格式:
int ret = msgBox.exec();
if (ret == QMessageBox::No) {
updateTestStatus("battery", STATUS_FAILED);
- return;
+ return;
}
}
qDebug() << successMsg;
ui->statusbar->showMessage(successMsg, 2000);
updateTestStatus("battery", STATUS_SUCCESS);
- } else {
+ } else {
// 电压或温度异常
QString failMsg = QString("电池测试失败 - %1").arg(failReason);
if (temp == -1.0 && !isVoltageNormal) {
perform4GTest();
}
});
- } else {
+ } else {
qDebug() << "RSSI不满足要求:" << rssi << "<" << rssiThreshold;
ui->statusbar->showMessage(QString("蓝牙测试:检测到地址 %1,但RSSI %2 小于阈值 %3").arg(address).arg(rssi).arg(rssiThreshold), 2000);
}
if (bluetoothTestFinished) {
qDebug() << "蓝牙测试已在10秒内完成,不再处理超时";
- return;
- }
+ return;
+ }
// 检查是否使用指定地址+RSSI模式
QString targetAddress = ui->bluetoothAddressLineEdit->text().trimmed().toUpper();
// signal=99不计入平均值计算
qDebug() << "CAT1信号值为99,无效信号次数:" << cat1Signal99Count << "/" << cat1SignalReceivedCount;
ui->statusbar->showMessage(QString("CAT1信号测试 (%1/5) 信号值:99 (无效信号)").arg(cat1SignalReceivedCount), 2000);
- } else {
+ } else {
// 累加有效信号值用于计算平均值
cat1SignalTotalValue += signalValue;
if (signalValue > 25) {
qDebug() << "CAT1信号值" << signalValue << ",累计总和:" << cat1SignalTotalValue << ",当前平均值:" << averageSignal << ",有效次数:" << validCount << "/" << cat1SignalReceivedCount;
ui->statusbar->showMessage(QString("CAT1信号测试 (%1/5) 信号值:%2 平均值:%3").arg(cat1SignalReceivedCount).arg(signalValue).arg(averageSignal, 0, 'f', 1), 2000);
- }
- } else {
+ }
+ } else {
qDebug() << "CAT1信号测试未能解析signal值,数据:" << data.trimmed();
}
}
// 显示最终测试结果弹窗
showFinalTestResult();
}
- } else {
+ } else {
// 平均信号值小于25或没有有效数据,判定为失败
QString failReason;
if (validCount == 0) {
"}"
);
- // 设置弹窗样式
+ // 设置弹窗样式和字体(14号字,与UI一致)
+ QFont dialogFont = resultDialog.font();
+ dialogFont.setPointSize(14);
+ resultDialog.setFont(dialogFont);
+
resultDialog.setStyleSheet(
"QMessageBox { "
"background-color: #f8f9fa; "
+ "font-size: 14pt; "
"}"
"QMessageBox QLabel { "
- "font-size: 14px; "
+ "font-size: 14pt; "
"line-height: 1.4; "
"}"
);
default:
qDebug() << "未知的测试步骤超时:" << currentTestStep;
return;
- }
-
+ }
+
qDebug() << testDescription << "超时,10秒内未收到响应";
// 弹出超时提示对话框
break;
}
- } else {
+ } else {
// 用户选择停止测试
qDebug() << "用户选择停止测试";
ui->statusbar->showMessage("测试已停止", 2000);
serial->write("AT^FACTORY=3\r\n");
}
+// 检测设备开机
+void MainWindow::checkBootDetection(const QString& data)
+{
+ if (bootDetected) {
+ return; // 已经检测到开机,不再重复检测
+ }
+
+ QStringList keywords = configManager.getBootDetectionKeywords();
+ if (keywords.isEmpty()) {
+ qDebug() << "警告:bootDetectionKeywords 为空,无法进行开机检测";
+ return;
+ }
+
+ for (const QString& keyword : keywords) {
+ if (data.contains(keyword, Qt::CaseInsensitive)) {
+ qDebug() << "检测到设备开机关键字:" << keyword << ",数据片段:" << data.left(100);
+ appendToLogFile(QString("=== 检测到设备开机: %1 ===\n").arg(keyword));
+
+ bootDetected = true;
+
+ // 延迟1秒后自动发送产测模式检测指令(无论是否有日志,都要检测)
+ QTimer::singleShot(1000, this, [this]() {
+ if (!factoryModeChecked && serial->isOpen()) {
+ QString cmd = configManager.getFactoryModeCheckCommand();
+ if (!cmd.isEmpty()) {
+ // 如果是查询指令,确保使用 ? 参数
+ if (!cmd.contains("?") && !cmd.contains("=")) {
+ cmd = cmd + "?";
+ }
+ serial->write((cmd + "\r\n").toUtf8());
+ qDebug() << "检测到开机,自动发送产测模式检测指令:" << cmd;
+ appendToLogFile(QString("=== 检测到开机,自动发送产测模式检测指令: %1 ===\n").arg(cmd));
+ } else {
+ qDebug() << "产测模式检测指令为空,跳过检测";
+ appendToLogFile(QString("=== 产测模式检测指令为空,跳过检测 ===\n"));
+ // 如果指令为空,直接标记为已检测,并开始获取版本信息
+ factoryModeChecked = true;
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+ }
+ } else {
+ if (!serial->isOpen()) {
+ qDebug() << "串口未打开,无法发送产测模式检测指令";
+ } else {
+ qDebug() << "产测模式已检测过,跳过发送检测指令";
+ }
+ }
+ });
+
+ break;
+ }
+ }
+}
+
+// 检测产测模式
+void MainWindow::checkFactoryMode(const QString& data)
+{
+ if (factoryModeChecked) {
+ return; // 已经检测过,不再重复检测
+ }
+
+ QStringList keywords = configManager.getFactoryModeKeywords();
+ bool found = false;
+ for (const QString& keyword : keywords) {
+ if (data.contains(keyword, Qt::CaseInsensitive)) {
+ qDebug() << "检测到产测模式关键字:" << keyword;
+ appendToLogFile(QString("=== 检测到产测模式: %1 ===\n").arg(keyword));
+
+ factoryModeChecked = true;
+ found = true;
+
+ // 解析产测模式状态并更新UI
+ if (data.contains("FACTORY TEST MODE: ENABLED", Qt::CaseInsensitive)) {
+ ui->factoryModeLineEdit->setText("是");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ffcccc;"); // 红底
+ qDebug() << "产测模式: 已开启";
+ } else if (data.contains("FACTORY TEST MODE: DISABLED", Qt::CaseInsensitive)) {
+ ui->factoryModeLineEdit->setText("否");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ccffcc;"); // 绿底
+ qDebug() << "产测模式: 已关闭";
+ }
+
+ // 延迟1秒后开始获取版本信息
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+
+ break;
+ }
+ }
+
+ // 如果没有检测到产测模式关键字,但收到了产测模式检测指令的响应(可能是OK或ERROR)
+ // 解析 AT^FACTORY 或 AT^FACTORY? 的响应
+ if (!found) {
+ // 检查是否是 AT^FACTORY 相关指令的响应
+ // AT^FACTORY? 的响应可能是:+FACTORY: 1 或 +FACTORY: 0
+ QRegExp factoryResponsePattern("\\+FACTORY:\\s*(\\d+)", Qt::CaseInsensitive);
+ if (factoryResponsePattern.indexIn(data) != -1) {
+ int factoryValue = factoryResponsePattern.cap(1).toInt();
+ qDebug() << "解析到产测模式响应值:" << factoryValue;
+ appendToLogFile(QString("=== 产测模式检测响应: %1 ===\n").arg(factoryValue));
+
+ factoryModeChecked = true;
+
+ // 更新UI
+ if (factoryValue == 1) {
+ ui->factoryModeLineEdit->setText("是");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ffcccc;"); // 红底
+ qDebug() << "产测模式: 已开启 (响应值=1)";
+ } else {
+ ui->factoryModeLineEdit->setText("否");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ccffcc;"); // 绿底
+ qDebug() << "产测模式: 已关闭 (响应值=0)";
+ }
+
+ // 延迟1秒后开始获取版本信息
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+ }
+ // 如果响应是OK,可能是 AT^FACTORY 的确认响应(进入产测模式)
+ else if (data.contains("OK", Qt::CaseInsensitive) &&
+ (data.contains("FACTORY", Qt::CaseInsensitive) ||
+ data.contains("AT^FACTORY", Qt::CaseInsensitive))) {
+ qDebug() << "产测模式检测指令返回OK,认为已进入产测模式";
+ appendToLogFile(QString("=== 产测模式检测指令返回OK,认为已进入产测模式 ===\n"));
+
+ factoryModeChecked = true;
+
+ // 更新UI(假设OK表示已开启)
+ ui->factoryModeLineEdit->setText("是");
+ ui->factoryModeLineEdit->setStyleSheet("background-color: #ffcccc;"); // 红底
+
+ // 延迟1秒后开始获取版本信息
+ QTimer::singleShot(1000, this, [this]() {
+ if (!versionInfoFetched) {
+ startVersionInfoFetch();
+ }
+ });
+ }
+ // 记录其他响应用于调试
+ else if (data.contains("ERROR", Qt::CaseInsensitive) ||
+ data.contains("+CME ERROR", Qt::CaseInsensitive) ||
+ data.contains("OK", Qt::CaseInsensitive)) {
+ qDebug() << "产测模式检测指令响应:" << data.trimmed();
+ appendToLogFile(QString("产测模式检测指令响应: %1\n").arg(data.trimmed()));
+ }
+ }
+}
+
+// 开始获取版本信息
+void MainWindow::startVersionInfoFetch()
+{
+ if (versionInfoFetched && currentVersionCommandIndex >= 0) {
+ qDebug() << "版本信息获取正在进行中,跳过重复请求";
+ return; // 正在获取中,不再重复获取
+ }
+
+ versionCommandQueue = configManager.getVersionInfoCommands();
+ if (versionCommandQueue.isEmpty()) {
+ qDebug() << "版本信息指令列表为空";
+ appendToLogFile(QString("=== 版本信息指令列表为空 ===\n"));
+ return;
+ }
+
+ qDebug() << "开始获取版本信息,共" << versionCommandQueue.size() << "条指令";
+ appendToLogFile(QString("=== 开始获取版本信息,共%1条指令 ===\n").arg(versionCommandQueue.size()));
+
+ currentVersionCommandIndex = 0;
+ versionInfoFetched = true;
+
+ // 延迟500ms后发送第一条指令,确保串口就绪
+ QTimer::singleShot(500, this, [this]() {
+ if (serial->isOpen()) {
+ sendNextVersionCommand();
+ } else {
+ qDebug() << "串口未打开,无法发送版本信息指令";
+ appendToLogFile(QString("=== 串口未打开,无法获取版本信息 ===\n"));
+ versionInfoFetched = false;
+ currentVersionCommandIndex = -1;
+ }
+ });
+}
+
+// 发送下一个版本信息指令
+void MainWindow::sendNextVersionCommand()
+{
+ if (currentVersionCommandIndex < 0 || currentVersionCommandIndex >= versionCommandQueue.size()) {
+ qDebug() << "版本信息获取完成";
+ appendToLogFile(QString("=== 版本信息获取完成 ===\n"));
+ versionCommandTimer->stop();
+ return;
+ }
+
+ QString cmd = versionCommandQueue[currentVersionCommandIndex];
+ if (serial->isOpen()) {
+ serial->write((cmd + "\r\n").toUtf8());
+ qDebug() << "发送版本信息指令[" << (currentVersionCommandIndex + 1) << "/" << versionCommandQueue.size() << "]:" << cmd;
+ appendToLogFile(QString("发送版本信息指令: %1\n").arg(cmd));
+
+ // 启动超时定时器(每个指令等待2秒)
+ versionCommandTimer->start(2000);
+ currentVersionCommandIndex++;
+ }
+}
+
+// 版本信息指令超时处理
+void MainWindow::onVersionCommandTimeout()
+{
+ versionCommandTimer->stop();
+
+ // 继续发送下一条指令
+ if (currentVersionCommandIndex < versionCommandQueue.size()) {
+ sendNextVersionCommand();
+ } else {
+ qDebug() << "所有版本信息指令已发送完成";
+ appendToLogFile(QString("=== 所有版本信息指令已发送完成 ===\n"));
+ // 重置状态,允许再次获取
+ versionInfoFetched = false;
+ currentVersionCommandIndex = -1;
+ }
+}
+
+// 获取版本信息按钮点击事件
+void MainWindow::on_getVersionInfoButton_clicked()
+{
+ // 检查串口是否已打开
+ if (!serial->isOpen()) {
+ QMessageBox::warning(this, "警告", "请先打开串口连接");
+ return;
+ }
+
+ // 重置版本信息获取状态
+ versionInfoFetched = false;
+ currentVersionCommandIndex = -1;
+ versionCommandQueue.clear();
+
+ // 开始获取版本信息
+ startVersionInfoFetch();
+}
+
+// 保存测试参数到settings.json
+void MainWindow::saveTestConfigToSettings()
+{
+ // 保存串口选择
+ QString portText = ui->portNameBox->currentText();
+ configManager.setTestConfig("portName", portText);
+
+ // 保存音频测试参数
+ configManager.setTestConfig("audioVolume", ui->audioVolumeLineEdit->text());
+ if (ui->recordVolumelineEdit) {
+ configManager.setTestConfig("audioLevelStandard", ui->recordVolumelineEdit->text().trimmed());
+ }
+
+ // 保存期望版本信息
+ configManager.setTestConfig("expectedModemVer", ui->expectedModemVerLineEdit->text());
+ configManager.setTestConfig("expectedPYVer", ui->expectedPYVerLineEdit->text());
+ configManager.setTestConfig("expectedVer", ui->expectedVerLineEdit->text());
+
+ // 保存蓝牙测试参数
+ configManager.setTestConfig("bluetoothAddress", ui->bluetoothAddressLineEdit->text());
+ configManager.setTestConfig("bluetoothRSSI", ui->bluetoothRSSILineEdit->text());
+
+ // 保存到文件
+ configManager.saveConfig();
+
+ qDebug() << "测试参数已保存到settings.json";
+}
+
+// 从settings.json加载测试参数
+void MainWindow::loadTestConfigFromSettings()
+{
+ // 恢复串口选择(在updateSerialPorts之后调用,确保串口列表已更新)
+ QString savedPortName = configManager.getTestConfig("portName", "");
+ if (!savedPortName.isEmpty()) {
+ // 查找匹配的串口项
+ int index = ui->portNameBox->findText(savedPortName);
+ if (index >= 0) {
+ ui->portNameBox->setCurrentIndex(index);
+ qDebug() << "恢复串口选择:" << savedPortName;
+ } else {
+ qDebug() << "保存的串口不存在,使用默认选择";
+ }
+ }
+
+ // 恢复音频测试参数
+ QString audioVolume = configManager.getTestConfig("audioVolume", "2.0");
+ ui->audioVolumeLineEdit->setText(audioVolume);
+
+ QString audioLevelStandard = configManager.getTestConfig("audioLevelStandard", "中");
+ if (ui->recordVolumelineEdit) {
+ ui->recordVolumelineEdit->setText(audioLevelStandard);
+ }
+
+ // 恢复期望版本信息
+ ui->expectedModemVerLineEdit->setText(configManager.getTestConfig("expectedModemVer", ""));
+ ui->expectedPYVerLineEdit->setText(configManager.getTestConfig("expectedPYVer", ""));
+ ui->expectedVerLineEdit->setText(configManager.getTestConfig("expectedVer", ""));
+
+ // 恢复蓝牙测试参数
+ ui->bluetoothAddressLineEdit->setText(configManager.getTestConfig("bluetoothAddress", ""));
+ ui->bluetoothRSSILineEdit->setText(configManager.getTestConfig("bluetoothRSSI", ""));
+
+ qDebug() << "测试参数已从settings.json加载";
+}
+
+// 保存recvTextEdit内容到日志文件
+void MainWindow::saveRecvTextEditToLog()
+{
+ QString logContent = ui->recvTextEdit->toPlainText();
+
+ // 检查是否有内容
+ if (logContent.trimmed().isEmpty()) {
+ qDebug() << "recvTextEdit内容为空,跳过保存";
+ return;
+ }
+
+ // 检查IMEI和ICCID
+ QString imei = ui->IMEIlineEdit->text().trimmed();
+ QString iccid = ui->ICCIDlineEdit->text().trimmed();
+
+ if (imei.isEmpty() || imei == "未获取" || iccid.isEmpty() || iccid == "未获取") {
+ qDebug() << "IMEI或ICCID未获取,跳过保存日志。IMEI:" << imei << "ICCID:" << iccid;
+ return;
+ }
+
+ // 创建日志目录
+ QString appPath = QCoreApplication::applicationDirPath();
+ QString logsDir = appPath + "/产测记录/logs";
+ QDir dir;
+ if (!dir.exists(logsDir)) {
+ dir.mkpath(logsDir);
+ }
+
+ // 生成日志文件名
+ QDateTime now = QDateTime::currentDateTime();
+ QString fileName = QString("%1_%2_%3_%4_UI日志.log")
+ .arg(now.toString("yyyyMMdd"))
+ .arg(now.toString("hhmmss"))
+ .arg(imei)
+ .arg(iccid);
+
+ QString filePath = logsDir + "/" + fileName;
+
+ // 保存到文件
+ QFile logFile(filePath);
+ if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream stream(&logFile);
+ stream.setCodec("UTF-8");
+ stream << QString("=== UI日志保存时间: %1 ===\n").arg(now.toString("yyyy-MM-dd hh:mm:ss"));
+ stream << QString("IMEI: %1\n").arg(imei);
+ stream << QString("ICCID: %1\n").arg(iccid);
+ stream << "========================================\n";
+ stream << logContent;
+ logFile.close();
+
+ qDebug() << "UI日志已保存到:" << filePath;
+ ui->statusbar->showMessage(QString("UI日志已保存: %1").arg(fileName), 3000);
+ } else {
+ qDebug() << "无法保存UI日志文件:" << filePath << "错误:" << logFile.errorString();
+ }
+}
+
// 创建测试日志文件
void MainWindow::createTestLogFile()
{
#include <QSet>
#include <QFile>
#include <QTextStream>
+#include "config_manager.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
void on_agingTestButton_2_clicked();
void on_openButton_3_clicked();
+
+ // 版本信息获取按钮
+ void on_getVersionInfoButton_clicked();
private:
Ui::MainWindow *ui;
QPushButton *audioPassButton; // 录音通过按钮
QPushButton *audioFailButton; // 录音失败按钮
QPushButton *audioRetestButton; // 重新测试按钮
- int audioMicMiddleConsecutiveCount; // 连续检测到"fac:mic level:中"的次数
+ int audioMicMiddleConsecutiveCount; // 连续检测到设置的标准Level的次数
+ QString audioLevelStandard; // 音频测试通过标准("中"或"低"等)
bool audioTestFinished; // 录音测试是否已完成(成功或失败)
QSet<QString> bluetoothAddresses; // 蓝牙测试检测到的不同蓝牙地址集合
bool bluetoothTestFinished; // 蓝牙测试是否已完成(成功或失败)
QTextStream *testLogStream; // 测试日志文件流
QString testLogFilePath; // 测试日志文件路径
+ // 配置管理
+ ConfigManager configManager; // 配置管理器(不使用指针,直接作为成员)
+
+ // 开机检测相关变量
+ bool bootDetected; // 是否已检测到开机
+ bool factoryModeChecked; // 是否已检测产测模式
+ bool versionInfoFetched; // 是否已获取版本信息
+
+ // 版本信息获取相关变量
+ QStringList versionCommandQueue; // 版本信息AT指令队列
+ int currentVersionCommandIndex; // 当前执行的版本信息指令索引
+ QTimer *versionCommandTimer; // 版本信息指令发送定时器
+
enum AudioTestStep {
AUDIO_STARTING_RECORD, // 开始录音
AUDIO_PLAYING_1KHZ, // 正在播放1kHz音频
void ShowPppInfoPYVer(const QString& data);
// CAT1信号测试相关函数
void parseNetworkStatChanged(const QString& data);
+
+ // 开机检测和版本信息获取相关函数
+ void checkBootDetection(const QString& data); // 检测设备开机
+ void checkFactoryMode(const QString& data); // 检测产测模式
+ void startVersionInfoFetch(); // 开始获取版本信息
+ void sendNextVersionCommand(); // 发送下一个版本信息指令
+ void onVersionCommandTimeout(); // 版本信息指令超时处理
+ void saveRecvTextEditToLog(); // 保存recvTextEdit内容到日志文件
+
+ // 测试参数配置保存和恢复(使用settings.json)
+ void saveTestConfigToSettings(); // 保存测试参数到settings.json
+ void loadTestConfigFromSettings(); // 从settings.json加载测试参数
};
#endif // MAINWINDOW_H
<x>0</x>
<y>0</y>
<width>1309</width>
- <height>641</height>
+ <height>823</height>
</rect>
</property>
<property name="font">
<number>6</number>
</property>
<item>
- <widget class="QWidget" name="leftPanel">
- <property name="maximumSize">
- <size>
- <width>280</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <layout class="QVBoxLayout" name="leftLayout">
+ <property name="spacing">
+ <number>6</number>
</property>
- <layout class="QVBoxLayout" name="leftLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <item>
- <widget class="QComboBox" name="portNameBox">
- <property name="font">
- <font>
- <family>Arial</family>
- <pointsize>14</pointsize>
- </font>
- </property>
- <property name="sizeAdjustPolicy">
- <enum>QComboBox::AdjustToContentsOnFirstShow</enum>
- </property>
- </widget>
- </item>
<item>
<layout class="QGridLayout" name="buttonGridLayout">
<property name="spacing">
<number>6</number>
</property>
- <item row="2" column="0">
- <widget class="QPushButton" name="openButton_2">
+ <item row="7" column="0">
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_aging">
+ <property name="font">
+ <font>
+ <family>Arial Black</family>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>老化测试:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openButton_agingresult">
+ <property name="font">
+ <font>
+ <family>Agra</family>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>老化结果</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="agingTestButton">
+ <property name="font">
+ <font>
+ <family>Agra</family>
+ <pointsize>14</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string>QPushButton {
+background-color: #9C27B0;
+color: white;
+border-radius: 4px;
+font-weight: bold;
+}
+QPushButton:hover {
+background-color: #7B1FA2;
+}</string>
+ </property>
+ <property name="text">
+ <string>老化测试</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="0">
+ <widget class="QPushButton" name="clearRecvButton">
<property name="font">
<font>
<family>Agra</family>
</font>
</property>
<property name="text">
- <string>开始产测</string>
+ <string>清空数据</string>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QPushButton" name="openButton">
+ <item row="6" column="0">
+ <widget class="QPushButton" name="getVersionInfoButton">
<property name="font">
<font>
<family>Agra</family>
</font>
</property>
<property name="text">
- <string>打开串口</string>
+ <string>获取设备信息</string>
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QPushButton" name="agingTestButton_2">
+ <item row="3" column="0">
+ <widget class="QPushButton" name="openButton_2">
<property name="font">
<font>
<family>Agra</family>
<pointsize>14</pointsize>
- <weight>75</weight>
- <bold>true</bold>
</font>
</property>
- <property name="styleSheet">
- <string>QPushButton {
-background-color: #9C27B0;
-color: white;
-border-radius: 4px;
-font-weight: bold;
-}
-QPushButton:hover {
-background-color: #7B1FA2;
-}</string>
- </property>
<property name="text">
- <string>恢复出厂</string>
+ <string>开始产测</string>
</property>
</widget>
</item>
<item row="5" column="0">
- <widget class="QPushButton" name="agingTestButton">
+ <widget class="QPushButton" name="agingTestButton_2">
<property name="font">
<font>
<family>Agra</family>
}</string>
</property>
<property name="text">
- <string>老化测试</string>
+ <string>恢复出厂</string>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QPushButton" name="clearRecvButton">
+ <item row="1" column="0">
+ <widget class="QPushButton" name="openButton">
<property name="font">
<font>
<family>Agra</family>
</font>
</property>
<property name="text">
- <string>æ¸\85空æ\95°æ\8d®</string>
+ <string>æ\89\93å¼\80串å\8f£</string>
</property>
</widget>
</item>
- <item row="6" column="0">
- <widget class="QPushButton" name="openButton_3">
+ <item row="0" column="0">
+ <widget class="QComboBox" name="portNameBox">
<property name="font">
<font>
- <family>Agra</family>
+ <family>Arial</family>
<pointsize>14</pointsize>
</font>
</property>
- <property name="text">
- <string>老化结果</string>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="9" column="0">
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="12" column="0">
<widget class="QPushButton" name="openRecordsFolderButton">
<property name="font">
<font>
</layout>
</item>
<item>
- <layout class="QHBoxLayout" name="audioVolumeLayout">
- <property name="spacing">
- <number>6</number>
- </property>
+ <layout class="QVBoxLayout" name="verticalLayout_">
<item>
- <widget class="QLabel" name="AudioVolumeLabel">
+ <widget class="Line" name="line_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
<property name="font">
<font>
- <family>Agra</family>
- <pointsize>14</pointsize>
+ <family>Arial Black</family>
+ <weight>75</weight>
+ <bold>true</bold>
</font>
</property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <property name="text">
+ <string>测试参数及通过标准:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="audioVolumeLayout">
+ <property name="spacing">
+ <number>6</number>
</property>
+ <item>
+ <widget class="QLabel" name="AudioVolumeLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <family>Agra</family>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>测试音频播放音量</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="audioVolumeLineEdit">
+ <property name="font">
+ <font>
+ <family>Arial</family>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="statusTip">
+ <string>0.0~2.0, 取值标准,麦克风能收音的最低喇叭音量。</string>
+ </property>
+ <property name="text">
+ <string>2.0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string>例如: 2</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>录音音量标准:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="recordVolumelineEdit">
+ <property name="statusTip">
+ <string>可选:高,中,低,极低,静音。连续出现三个指定的音量标准,视为测试通过。</string>
+ </property>
+ <property name="text">
+ <string>中</string>
+ </property>
+ <property name="placeholderText">
+ <string>可选:高,中,低,极低,静音</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="ExpectedModemLabel">
<property name="text">
- <string>音频测试音量</string>
+ <string>目标MODEM版本:</string>
</property>
</widget>
</item>
<item>
- <widget class="QLineEdit" name="audioVolumeLineEdit">
- <property name="font">
- <font>
- <family>Agra</family>
- <pointsize>14</pointsize>
- </font>
+ <widget class="QLineEdit" name="expectedModemVerLineEdit">
+ <property name="statusTip">
+ <string>为空不校验Modem版本是否正确</string>
</property>
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ExpectedModemLabel_2">
<property name="text">
- <string>2</string>
+ <string>目标PY版本:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="expectedPYVerLineEdit">
+ <property name="statusTip">
+ <string>为空不校验Py版本是否正确</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="ExpectedVerLabel">
+ <property name="text">
+ <string>目标固件版本:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="expectedVerLineEdit">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="statusTip">
+ <string>为空不校验固件版本是否正确。</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="BluetoothAddressLabel">
+ <property name="text">
+ <string>广播设备-蓝牙地址:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="bluetoothAddressLineEdit">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="statusTip">
+ <string>供测试用常广播的经典蓝牙设备地址。可为空,为空时,扫描到3个以上设备为通过。</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string>例如: 1C:1D:2B:68:82:68</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="BluetoothRSSILabel">
+ <property name="text">
+ <string>广播设备- Min_RSSI:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="bluetoothRSSILineEdit">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="statusTip">
+ <string>如Min_RSSI = -80,则扫到广播设备且RSSI > -80为成功。</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
- <string>例如: 2</string>
+ <string>例如: -80</string>
</property>
</widget>
</item>
</spacer>
</item>
</layout>
- </widget>
</item>
<item>
- <widget class="QWidget" name="centerPanel">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>5</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QVBoxLayout" name="centerLayout">
+ <layout class="QVBoxLayout" name="centerLayout">
<property name="spacing">
<number>6</number>
</property>
</item>
</layout>
</item>
- </layout>
- </widget>
- </item>
+ </layout>
+ </item>
<item>
- <widget class="QWidget" name="rightPanel">
- <property name="minimumSize">
- <size>
- <width>380</width>
- <height>0</height>
- </size>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>2</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QVBoxLayout" name="rightLayout">
+ <layout class="QVBoxLayout" name="rightLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>4</number>
</property>
- <item row="0" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="Verlabel">
<property name="text">
<string>Ver:</string>
</property>
</widget>
</item>
- <item row="0" column="1">
+ <item row="2" column="1">
<widget class="QLineEdit" name="VerlineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="Verlabel_2">
<property name="text">
<string>IMEI:</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="3" column="1">
<widget class="QLineEdit" name="IMEIlineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="Verlabel_3">
<property name="text">
<string>ICCID</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="4" column="1">
<widget class="QLineEdit" name="ICCIDlineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="5" column="0">
<widget class="QLabel" name="Verlabel_4">
<property name="text">
<string>Modem:</string>
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="5" column="1">
<widget class="QLineEdit" name="ModemVerlineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="4" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="Verlabel_5">
<property name="text">
<string>PYVER</string>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="6" column="1">
<widget class="QLineEdit" name="PYVerlineEdit">
- <property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
<property name="text">
<string/>
</property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="ExpectedVerLabel">
- <property name="text">
- <string>最新VER:</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QLineEdit" name="expectedVerLineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="ExpectedModemLabel">
- <property name="text">
- <string>最新MODEM:</string>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
- <item row="6" column="1">
- <widget class="QLineEdit" name="expectedModemVerLineEdit">
- <property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <family>Arial Black</family>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
</property>
- </widget>
- </item>
- <item row="7" column="0">
- <widget class="QLabel" name="ExpectedModemLabel_2">
<property name="text">
- <string>最新PY:</string>
+ <string>设备状态:</string>
</property>
</widget>
</item>
<item row="7" column="1">
- <widget class="QLineEdit" name="expectedPYVerLineEdit">
- <property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <widget class="QLineEdit" name="factoryModeLineEdit">
+ <property name="font">
+ <font>
+ <family>Arial</family>
+ <pointsize>14</pointsize>
+ </font>
</property>
- </widget>
- </item>
- <item row="8" column="0">
- <widget class="QLabel" name="BluetoothAddressLabel">
<property name="text">
- <string>蓝牙地址:</string>
+ <string/>
</property>
- </widget>
- </item>
- <item row="8" column="1">
- <widget class="QLineEdit" name="bluetoothAddressLineEdit">
<property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
</property>
<property name="placeholderText">
- <string>例如: 1C:1D:2B:68:82:68</string>
+ <string>例如: 是/否</string>
</property>
</widget>
</item>
- <item row="9" column="0">
- <widget class="QLabel" name="BluetoothRSSILabel">
- <property name="text">
- <string>RSSI阈值:</string>
+ <item row="7" column="0">
+ <widget class="QLabel" name="factoryModeLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- </widget>
- </item>
- <item row="9" column="1">
- <widget class="QLineEdit" name="bluetoothRSSILineEdit">
- <property name="alignment">
- <set>Qt::AlignLeft|Qt::AlignVCenter</set>
+ <property name="font">
+ <font>
+ <family>Agra</family>
+ <pointsize>14</pointsize>
+ </font>
</property>
- <property name="placeholderText">
- <string>例如: -80</string>
+ <property name="text">
+ <string>设备在产测模式</string>
</property>
</widget>
</item>
</layout>
</item>
+ <item>
+ <widget class="Line" name="line_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QScrollArea" name="testStatusScrollArea">
<property name="sizePolicy">
<x>0</x>
<y>0</y>
<width>424</width>
- <height>318</height>
+ <height>523</height>
</rect>
</property>
<property name="title">
</widget>
</item>
</layout>
- </widget>
</item>
</layout>
</widget>
--- /dev/null
+{\r
+ "bootDetectionKeywords": [\r
+ "BuildVer",\r
+ "NAND flash ID",\r
+ "NAND ID:"\r
+ ],\r
+ "versionInfoCommands": [\r
+ "AT^CAT1GETVER",\r
+ "AT^CAT1GETSIGNAL",\r
+ "AT^FACTORY"\r
+ ],\r
+ "factoryModeCheckCommand": "AT^FACTORY",\r
+ "factoryModeKeywords": [\r
+ "FACTORY TEST MODE:"\r
+ ],\r
+ "testConfig": {\r
+ "portName": "",\r
+ "audioVolume": "2.0",\r
+ "audioLevelStandard": "中",\r
+ "expectedModemVer": "",\r
+ "expectedPYVer": "",\r
+ "expectedVer": "",\r
+ "bluetoothAddress": "",\r
+ "bluetoothRSSI": ""\r
+ }\r
+}\r
+\r