-#include "mainwindow.h"
+#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "config_manager.h"
#include <QMessageBox>
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
- setWindowTitle("FD272产测工具 V1.0");
+ setWindowTitle("FD272产测工具 V1.9");
// 确保控制台输出使用UTF-8编码
QTextCodec *utf8Codec = QTextCodec::codecForName("UTF-8");
lcdBacklightOn = false; // 初始化LCD背光状态为关闭
keyTestStarted = false;
keyTestDialog = nullptr;
- audioTestRoundIndex = 0;
- audioTestAnyPass = false;
audioTestAwaitingMicLevel = false;
bluetoothTestTimer = new QTimer(this);
gpsTestTimer = new QTimer(this);
leaklightGreenSeen = false;
leaklightRedSeen = false;
leaklightIrSeen = false;
+ leaklightAttemptIndex = 0;
// 初始化日志文件相关变量
testLogFile = nullptr;
testLogStream = nullptr;
connect(bluetoothTestTimer, &QTimer::timeout, this, &MainWindow::onBluetoothTestTimer);
connect(gpsTestTimer, &QTimer::timeout, this, &MainWindow::onGpsTestTimer);
connect(gpsPollTimer, &QTimer::timeout, this, &MainWindow::onGpsPollTimer);
-
// 初始化G-sensor采集状态
gSensorCollecting = false;
gSensorHasStart = false;
qDebug() << "产测模式: 已开启";
appendToLogFile(QString("=== 产测模式状态: 已开启 ===\n"));
- // 如果还未标记为已检测,标记并开始获取版本信息
- if (!factoryModeChecked) {
+ // 仅在非产测流程中自动拉版本;产测时串口可能出现该行,避免与当前测试 AT 并发(如 G-sensor)
+ if (!isProductionTestRunning && !factoryModeChecked) {
factoryModeChecked = true;
QTimer::singleShot(1000, this, [this]() {
- if (!versionInfoFetched) {
+ if (!isProductionTestRunning && !versionInfoFetched) {
startVersionInfoFetch();
}
});
qDebug() << "产测模式: 已关闭";
appendToLogFile(QString("=== 产测模式状态: 已关闭 ===\n"));
- // 如果还未标记为已检测,标记并开始获取版本信息
- if (!factoryModeChecked) {
+ if (!isProductionTestRunning && !factoryModeChecked) {
factoryModeChecked = true;
QTimer::singleShot(1000, this, [this]() {
- if (!versionInfoFetched) {
+ if (!isProductionTestRunning && !versionInfoFetched) {
startVersionInfoFetch();
}
});
}
}
-// 执行录音测试(配置了等级标准时共测 3 轮,任一轮「实际等级 >= 设置等级」则整体通过)
+// 执行录音测试(单轮;有等级标准则 mic level 与标准比较一次,无标准则只采样不判等级)
void MainWindow::performAudioTest()
{
if (!isTestItemEnabled("mic")) {
qDebug() << "开始录音测试";
appendToLogFile("\n========== 开始录音测试 ==========\n");
updateTestStatus("mic", STATUS_TESTING);
- audioTestRoundIndex = 0;
- audioTestAnyPass = false;
audioTestAwaitingMicLevel = false;
QString standard = ui->audioLevelStandardLineEdit->text().trimmed();
appendToLogFile(">>> 未配置等级标准:单轮采样,不做等级校验\n");
ui->statusbar->showMessage("录音测试中(未配标准,单轮),请对着麦克风说话...", 5000);
} else {
- appendToLogFile(QString(">>> å·²é\85\8dç½®ç\89级æ \87å\87\86ã\80\8c%1ã\80\8dï¼\9aå\85± 3 è½®ï¼\8cä»»ä¸\80轮达æ \87å\8d³é\80\9aè¿\87\n").arg(standard));
- ui->statusbar->showMessage("录音测试 1/3:请对着麦克风说话...", 5000);
+ appendToLogFile(QString(">>> å·²é\85\8dç½®ç\89级æ \87å\87\86ã\80\8c%1ã\80\8dï¼\9aå\8d\95è½®å\88¤å®\9a\n").arg(standard));
+ ui->statusbar->showMessage("录音测试中,请对着麦克风说话...", 5000);
}
// 录音前关闭LCD(与V1.7一致)
qDebug() << "录音测试前发送AT^LCDOFF";
}
- beginAudioTestAttempt(0);
+ beginAudioTestAttempt();
}
-void MainWindow::beginAudioTestAttempt(int roundIndex)
+void MainWindow::beginAudioTestAttempt()
{
if (!isProductionTestRunning || currentTestStep != TEST_AUDIO || !serial || !serial->isOpen()) {
qDebug() << "录音测试:产测已停止或串口未打开";
return;
}
- audioTestRoundIndex = roundIndex;
audioTestAwaitingMicLevel = true;
- QString standard = ui->audioLevelStandardLineEdit->text().trimmed();
- if (!standard.isEmpty()) {
- ui->statusbar->showMessage(QString("录音测试 %1/3:请对着麦克风说话...").arg(roundIndex + 1), 5000);
- }
-
QString volumeStr = ui->audioVolumeLineEdit->text().trimmed();
if (volumeStr.isEmpty()) volumeStr = "2.0";
testTimeoutTimer->stop();
qDebug() << "录音测试解析到mic level:" << micLevel;
- appendToLogFile(QString(">>> 录音测试 第%1轮: mic level=%2\n").arg(audioTestRoundIndex + 1).arg(micLevel));
- ui->recvTextEdit->append(QString(">>> 录音测试 第%1轮: mic level=%2").arg(audioTestRoundIndex + 1).arg(micLevel));
+ appendToLogFile(QString(">>> 录音测试 mic level=%1\n").arg(micLevel));
+ ui->recvTextEdit->append(QString(">>> 录音测试 mic level=%1").arg(micLevel));
// 结束本轮采集
if (serial && serial->isOpen()) {
appendToLogFile(">>> 发送指令: AT^AUDIOTEST=6 (结束本轮音频测试)\n");
qDebug() << "发送AT^AUDIOTEST=6";
}
-
- QString standard = ui->audioLevelStandardLineEdit->text().trimmed();
- if (standard.isEmpty()) {
- updateTestStatus("mic", STATUS_SUCCESS);
- ui->statusbar->showMessage(QString("录音测试通过(等级:%1,未配置标准不校验)").arg(micLevel), 3000);
- skipToNextEnabledTest();
- return;
- }
-
- // 等级排序:静音(0) < 极低(1) < 低(2) < 中(3) < 高(4);达标条件:micRank >= stdRank
- auto levelRank = [](const QString& s) -> int {
- if (s == QStringLiteral("静音")) return 0;
- if (s == QStringLiteral("极低")) return 1;
- if (s == QStringLiteral("低")) return 2;
- if (s == QStringLiteral("中")) return 3;
- if (s == QStringLiteral("高")) return 4;
- return -1;
- };
-
- int micRank = levelRank(micLevel);
- int stdRank = levelRank(standard);
-
- if (micRank < 0 || stdRank < 0) {
- updateTestStatus("mic", STATUS_FAILED);
- ui->statusbar->showMessage(QString("录音测试失败:无法解析等级(实际:%1, 标准:%2)").arg(micLevel).arg(standard), 3000);
- skipToNextEnabledTest();
- return;
- }
- const bool roundPass = (micRank >= stdRank);
- if (roundPass) {
- audioTestAnyPass = true;
- appendToLogFile(QString(">>> 第%1轮达标(%2 >= 标准%3)\n").arg(audioTestRoundIndex + 1).arg(micLevel).arg(standard));
- } else {
- appendToLogFile(QString(">>> 第%1轮未达标(%2 < 标准%3)\n").arg(audioTestRoundIndex + 1).arg(micLevel).arg(standard));
- }
+ // 固件在 =6 后异步停止 AI 语音/解码线程;稍候再判定/切下一项,减轻与后续 AT 的竞态。
+ static const int kMsAfterAudiotestStop = 2000;
+ ui->statusbar->showMessage(QStringLiteral("录音本轮已结束,等待设备完成音频收尾…"), 2000);
+ appendToLogFile(QString(">>> 等待 %1 ms 后再继续(避开 AUDIOTEST 异步停止)\n").arg(kMsAfterAudiotestStop));
+ qDebug() << "录音测试:已发 AUDIOTEST=6," << kMsAfterAudiotestStop << "ms 后再判定/切下一项";
- const int completedRound = audioTestRoundIndex;
- const int nextRound = completedRound + 1;
+ QTimer::singleShot(kMsAfterAudiotestStop, this, [this, micLevel]() {
+ if (!isProductionTestRunning || currentTestStep != TEST_AUDIO) {
+ return;
+ }
- if (nextRound < 3) {
- QTimer::singleShot(400, this, [this, nextRound]() {
- if (!isProductionTestRunning || currentTestStep != TEST_AUDIO) {
- return;
- }
- beginAudioTestAttempt(nextRound);
- });
- return;
- }
+ QString standard = ui->audioLevelStandardLineEdit->text().trimmed();
+ if (standard.isEmpty()) {
+ updateTestStatus("mic", STATUS_SUCCESS);
+ ui->statusbar->showMessage(QString("录音测试通过(等级:%1,未配置标准不校验)").arg(micLevel), 3000);
+ skipToNextEnabledTest();
+ return;
+ }
- if (audioTestAnyPass) {
- updateTestStatus("mic", STATUS_SUCCESS);
- ui->statusbar->showMessage(QString("录音测试通过(3轮中至少一轮达标,标准:%1)").arg(standard), 3000);
- } else {
- updateTestStatus("mic", STATUS_FAILED);
- ui->statusbar->showMessage(QString("录音测试失败:3轮均未达到标准%1").arg(standard), 3000);
- }
- skipToNextEnabledTest();
+ // 等级排序:静音(0) < 极低(1) < 低(2) < 中(3) < 高(4);达标条件:micRank >= stdRank
+ auto levelRank = [](const QString& s) -> int {
+ if (s == QStringLiteral("静音")) return 0;
+ if (s == QStringLiteral("极低")) return 1;
+ if (s == QStringLiteral("低")) return 2;
+ if (s == QStringLiteral("中")) return 3;
+ if (s == QStringLiteral("高")) return 4;
+ return -1;
+ };
+
+ int micRank = levelRank(micLevel);
+ int stdRank = levelRank(standard);
+
+ if (micRank < 0 || stdRank < 0) {
+ updateTestStatus("mic", STATUS_FAILED);
+ ui->statusbar->showMessage(QString("录音测试失败:无法解析等级(实际:%1, 标准:%2)").arg(micLevel).arg(standard), 3000);
+ skipToNextEnabledTest();
+ return;
+ }
+
+ const bool roundPass = (micRank >= stdRank);
+ if (roundPass) {
+ appendToLogFile(QString(">>> 单轮达标(%1 >= 标准%2)\n").arg(micLevel).arg(standard));
+ updateTestStatus("mic", STATUS_SUCCESS);
+ ui->statusbar->showMessage(QString("录音测试通过(%1 ≥ 标准%2)").arg(micLevel).arg(standard), 3000);
+ } else {
+ appendToLogFile(QString(">>> 单轮未达标(%1 < 标准%2)\n").arg(micLevel).arg(standard));
+ updateTestStatus("mic", STATUS_FAILED);
+ ui->statusbar->showMessage(QString("录音测试失败(%1 低于标准%2)").arg(micLevel).arg(standard), 3000);
+ }
+ skipToNextEnabledTest();
+ });
}
// 执行电池测试
updateTestStatus("battery", STATUS_TESTING);
ui->statusbar->showMessage("电池测试中,正在获取电池电压...", 3000);
- // 延迟100ms后发送电池电量查询指令,确保串口已准备好
- QTimer::singleShot(100, this, [this]() {
+ // 短暂延迟后再发 GETPOWER
+ QTimer::singleShot(200, this, [this]() {
if (isProductionTestRunning && currentTestStep == TEST_BATTERY && serial && serial->isOpen()) {
// 发送电池电量查询指令
serial->write("AT^GETPOWER\r\n");
ui->recvTextEdit->append(">>> 发送指令: AT^LEAKLIGHT");
ui->statusbar->showMessage("漏光测试中,等待green/red/ir数据...", 3000);
+ leaklightAttemptIndex = 0;
leaklightGreen = 0;
leaklightRed = 0;
leaklightIr = 0;
if (pass) {
updateTestStatus("leaklight", STATUS_SUCCESS);
ui->statusbar->showMessage("漏光测试通过(green/red/ir均非0)", 2500);
- } else {
- updateTestStatus("leaklight", STATUS_FAILED);
- ui->statusbar->showMessage("漏光测试失败(存在0值)", 2500);
+ skipToNextEnabledTest();
+ return;
}
+
+ // 首次不通过:自动再测一次;重测仍不通过则判失败
+ if (leaklightAttemptIndex == 0) {
+ leaklightAttemptIndex = 1;
+ leaklightGreen = 0;
+ leaklightRed = 0;
+ leaklightIr = 0;
+ leaklightGreenSeen = false;
+ leaklightRedSeen = false;
+ leaklightIrSeen = false;
+ ui->recvTextEdit->append(">>> 漏光首次未通过(存在0值),自动重测一次");
+ appendToLogFile(">>> 漏光首次未通过,自动重测一次\n");
+ ui->statusbar->showMessage("漏光首次未通过,正在自动重测…", 3000);
+ if (serial && serial->isOpen()) {
+ ui->recvTextEdit->append(">>> 发送指令: AT^LEAKLIGHT (重测)");
+ serial->write("AT^LEAKLIGHT\r\n");
+ }
+ testTimeoutTimer->start(10000);
+ return;
+ }
+
+ updateTestStatus("leaklight", STATUS_FAILED);
+ ui->statusbar->showMessage("漏光测试失败(重测后仍存在0值)", 2500);
skipToNextEnabledTest();
}
}
qDebug() << "显示最终测试结果弹窗";
resultDialog.exec();
- // 用户点击确定后的处理:关机,不执行重启/RESTORE
- qDebug() << "用户确认测试结果,发送关机指令";
-
- if (serial->isOpen()) {
- ui->recvTextEdit->append(">>> 发送指令: AT^POWEROFF (产测结束关机)");
- serial->write("AT^POWEROFF\r\n");
- qDebug() << "发送关机指令: AT^POWEROFF";
- ui->statusbar->showMessage("已发送关机指令", 3000);
- }
-
- // 恢复产测按钮状态 - 变回蓝色并启用
+ // 用户点击确定后:不自动发送关机(避免影响后续操作;需关机请用界面关机按钮)
+ qDebug() << "用户确认测试结果,产测收尾(不发送 AT^POWEROFF)";
+ ui->recvTextEdit->append(">>> 产测结束:未自动发送关机指令");
+ ui->statusbar->showMessage("产测已结束,未自动关机", 3000);
+ finalizeAfterProductionResultDialog();
+}
+
+void MainWindow::finalizeAfterProductionResultDialog()
+{
ui->openButton_2->setStyleSheet("QPushButton { background-color: #4A90E2; color: white; padding: 5px 10px; border: none; border-radius: 3px; }");
ui->openButton_2->setEnabled(true);
qDebug() << "产测完成 - 按钮已恢复蓝色并启用";
-
- // 清空整个产测状态
+
clearProductionTestState();
-
+
qDebug() << "产测流程完全结束,状态已清空";
}
void MainWindow::clearProductionTestState()
{
qDebug() << "开始清空产测状态";
-
+
// 停止所有定时器
if (lcdTestTimer->isActive()) {
lcdTestTimer->stop();