From: penglei <1624952103@qq.com> Date: Thu, 4 Dec 2025 03:20:52 +0000 (+0800) Subject: 增加蓝牙扫描测试,优化录音测试 X-Git-Url: http://git.snicker.com.cn/sitemap.xml?a=commitdiff_plain;h=8bcfdbf2dcff8d272218fca3fb05092a198751dc;p=mirrors%2Ffactory_tool.git 增加蓝牙扫描测试,优化录音测试 --- diff --git a/mainwindow.cpp b/mainwindow.cpp index 15c091b..6143792 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -84,6 +84,13 @@ MainWindow::MainWindow(QWidget *parent) audioPassButton = nullptr; audioFailButton = nullptr; audioRetestButton = nullptr; + audioMicMiddleConsecutiveCount = 0; + audioTestFinished = false; + bluetoothTestTimer = new QTimer(this); + bluetoothAddresses.clear(); + bluetoothTestFinished = false; + detectedBluetoothAddress = ""; + detectedBluetoothRSSI = 0; currentAudioStep = AUDIO_PLAYING_1KHZ; currentModemVersion = ""; currentSimStatus = -1; @@ -102,6 +109,7 @@ MainWindow::MainWindow(QWidget *parent) connect(cat1SignalTimer, &QTimer::timeout, this, &MainWindow::onCat1SignalTimer); connect(testTimeoutTimer, &QTimer::timeout, this, &MainWindow::onTestTimeout); connect(audioRecordTimer, &QTimer::timeout, this, &MainWindow::onAudioRecordTimer); + connect(bluetoothTestTimer, &QTimer::timeout, this, &MainWindow::onBluetoothTestTimer); } MainWindow::~MainWindow() @@ -1075,8 +1083,9 @@ void MainWindow::readSerialData() } // 检测录音测试结果(用于产测) - if (line.contains("MEDIAAUDIORECORD") || line.contains("MEDIAMUSICPLAY") || - line.contains("Start Audio Capturer SUCCESS")) { + if (line.contains("MEDIAAUDIORECORD") || line.contains("MEDIAMUSICPLAY") || + line.contains("Start Audio Capturer SUCCESS") || + line.contains("fac:mic level:")) { qDebug() << "录音测试相关数据匹配:" << line.trimmed(); checkAudioTestResult(line); } @@ -1092,6 +1101,12 @@ void MainWindow::readSerialData() checkGsensorTestResult(line); } + // 检测蓝牙测试结果(用于产测) + if (line.contains("fac:Device:") || line.contains("[BtScan]") || line.contains("BTSCANTEST")) { + qDebug() << "检测到蓝牙测试相关数据,调用checkBluetoothTestResult:" << line.trimmed(); + checkBluetoothTestResult(line); + } + // 检测CAT1信号测试结果 - 只在CAT1测试期间且包含特定格式时处理 if (hasReceivedFirstSignal && isProductionTestRunning && line.contains("signal:")) { // 根据MODEM类型过滤特定格式的数据 @@ -2412,6 +2427,11 @@ void MainWindow::updateTestStatus(const QString& testName, TestStatus status) ui->gsensorStatusIcon->setStyleSheet(iconStyle); ui->gsensorStatusText->setText(statusText); ui->gsensorStatusText->setStyleSheet(textStyle); + } else if (testName == "bluetooth") { + ui->bluetoothStatusIcon->setText(iconText); + ui->bluetoothStatusIcon->setStyleSheet(iconStyle); + ui->bluetoothStatusText->setText(statusText); + ui->bluetoothStatusText->setStyleSheet(textStyle); } else if (testName == "ppp") { ui->pppStatusIcon->setText(iconText); ui->pppStatusIcon->setStyleSheet(iconStyle); @@ -2433,11 +2453,12 @@ void MainWindow::updateOverallStatus() bool audioSuccess = ui->audioStatusText->text() == "通过"; bool batterySuccess = ui->batteryStatusText->text() == "通过"; bool gsensorSuccess = ui->gsensorStatusText->text() == "通过"; + bool bluetoothSuccess = ui->bluetoothStatusText->text() == "通过"; bool pppSuccess = ui->pppStatusText->text() == "通过"; QString overallIcon, overallText, overallColor; - if (lcdSuccess && motorSuccess && keySuccess && audioSuccess && batterySuccess && gsensorSuccess && pppSuccess) { + if (lcdSuccess && motorSuccess && keySuccess && audioSuccess && batterySuccess && gsensorSuccess && bluetoothSuccess && pppSuccess) { // 所有测试都通过 overallIcon = "✓"; overallText = "通过"; @@ -2516,6 +2537,7 @@ QString MainWindow::saveTestRecord() QString audioResult = ui->audioStatusText->text(); QString batteryResult = ui->batteryStatusText->text(); QString gsensorResult = ui->gsensorStatusText->text(); + QString bluetoothResult = ui->bluetoothStatusText->text(); QString pppResult = ui->pppStatusText->text(); QString overallResult = ui->overallStatusText->text(); @@ -2535,7 +2557,7 @@ QString MainWindow::saveTestRecord() bool isNewFile = !QFile::exists(csvFilePath); // 构建新的测试数据行 - QString newDataLine = QString("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15\n") + QString newDataLine = QString("%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16\n") .arg(startTimeStr) .arg(endTimeStr) .arg(durationStr) @@ -2550,6 +2572,7 @@ QString MainWindow::saveTestRecord() .arg(audioResult) .arg(batteryResult) .arg(gsensorResult) + .arg(bluetoothResult) .arg(pppResult) .arg(overallResult); @@ -2557,7 +2580,7 @@ QString MainWindow::saveTestRecord() if (isNewFile) { // 新文件,写入表头和数据 - finalContent += "开始时间,结束时间,测试耗时,软件版本,IMEI,ICCID,Modem版本,PYVER版本,LCD测试,马达测试,按键测试,录音测试,电池测试,G-sensor测试,4G测试,整体结果\n"; + finalContent += "开始时间,结束时间,测试耗时,软件版本,IMEI,ICCID,Modem版本,PYVER版本,LCD测试,马达测试,按键测试,录音测试,电池测试,G-sensor测试,蓝牙测试,4G测试,整体结果\n"; finalContent += newDataLine; qDebug() << "创建新的CSV文件:" << csvFilePath; } else { @@ -2615,7 +2638,7 @@ QString MainWindow::saveTestRecord() } } else { // 文件为空,重建 - finalContent = "开始时间,结束时间,测试耗时,软件版本,IMEI,ICCID,Modem版本,LCD测试,马达测试,按键测试,录音测试,电池测试,G-sensor测试,4G测试,整体结果\n"; + finalContent = "开始时间,结束时间,测试耗时,软件版本,IMEI,ICCID,Modem版本,PYVER版本,LCD测试,马达测试,按键测试,录音测试,电池测试,G-sensor测试,蓝牙测试,4G测试,整体结果\n"; finalContent += newDataLine; } } @@ -2973,6 +2996,7 @@ void MainWindow::on_openButton_2_clicked() updateTestStatus("audio", STATUS_UNTESTED); updateTestStatus("battery", STATUS_UNTESTED); updateTestStatus("gsensor", STATUS_UNTESTED); + updateTestStatus("bluetooth", STATUS_UNTESTED); updateTestStatus("ppp", STATUS_UNTESTED); qDebug() << "已清空所有UI内容,准备开始新的产测"; @@ -3013,17 +3037,55 @@ void MainWindow::performAudioTest() return; } - qDebug() << "开始录音测试"; + qDebug() << "开始录音测试(自动模式:AT^AUDIOTEST)"; updateTestStatus("audio", STATUS_TESTING); - ui->statusbar->showMessage("录音测试准备就绪", 3000); - - // 重置录音测试相关标志 - audioTestPopupShown = false; - audioPlaybackPopupShown = false; - currentAudioStep = AUDIO_STARTING_RECORD; - - // 显示录音测试弹窗,等待用户点击开始录音 - showAudioTestDialog(); + ui->statusbar->showMessage("录音测试中:正在发送AUDIOTEST指令...", 3000); + + // 重置录音测试相关状态 + audioMicMiddleConsecutiveCount = 0; + audioTestFinished = false; + + // 发送录音测试指令:先 AT^AUDIOTEST=5 再 AT^AUDIOTEST=7 <音量> + QString audioCmd1 = "AT^AUDIOTEST=5\r\n"; + serial->write(audioCmd1.toUtf8()); + qDebug() << "发送录音测试指令1:" << audioCmd1.trimmed(); + + // 稍微延迟后发送第二条指令(带音量参数) + QTimer::singleShot(200, this, [this]() { + if (!isProductionTestRunning || currentTestStep != TEST_AUDIO) { + qDebug() << "录音测试已结束或步骤变化,取消发送第二条AUDIOTEST指令"; + return; + } + + // 从界面读取音量文本框的值 + QString volumeStr; + if (ui->audioVolumeLineEdit) { + volumeStr = ui->audioVolumeLineEdit->text().trimmed(); + } + + float volume = 2; // 默认音量为2 + bool ok = false; + if (!volumeStr.isEmpty()) { + float v = volumeStr.toFloat(&ok); + if (ok && v >= 0) { + volume = v; + } else { + qDebug() << "音量文本框内容非法,使用默认音量 2,原始值:" << volumeStr; + } + } else { + qDebug() << "音量文本框为空,使用默认音量 2"; + } + + QString audioCmd2 = QString("AT^AUDIOTEST=7 %1\r\n").arg(volume); + serial->write(audioCmd2.toUtf8()); + qDebug() << "发送录音测试指令2:" << audioCmd2.trimmed(); + }); + + // 启动 8 秒定时器,在此期间统计“fac:mic level:中” + if (audioRecordTimer->isActive()) { + audioRecordTimer->stop(); + } + audioRecordTimer->start(8000); } // 显示录音测试弹窗 @@ -3254,7 +3316,7 @@ void MainWindow::showAudioTestDialog() qDebug() << "录音测试弹窗已显示"; } -// 录音测试定时器 - 处理多个步骤的定时 +// 录音测试定时器 - 8秒超时检查“fac:mic level:中” void MainWindow::onAudioRecordTimer() { audioRecordTimer->stop(); @@ -3262,90 +3324,27 @@ void MainWindow::onAudioRecordTimer() if (!isProductionTestRunning || currentTestStep != TEST_AUDIO) { return; } - - switch (currentAudioStep) { - case AUDIO_PLAYING_1KHZ: - { - // 2秒播放1kHz音频完成,停止播放 - qDebug() << "1kHz音频播放2秒完成,发送停止播放指令"; - ui->statusbar->showMessage("停止1kHz音频播放...", 2000); - - // 更新弹窗信息 - if (audioDialogInfo) { - audioDialogInfo->setText("⏹️ 停止播放1kHz音频,随后停止录音...\n请稍等片刻..."); - } - - // 先发送停止播放指令 - serial->write("AT^MEDIAMUSICSTOP\r\n"); - qDebug() << "发送停止播放指令: AT^MEDIAMUSICSTOP"; - - // 随后立即发送停止录音指令 - serial->write("AT^MEDIAAUDIORECORDSTOP\r\n"); - qDebug() << "发送停止录音指令: AT^MEDIAAUDIORECORDSTOP"; - - // 设置下一步骤,1秒后播放录制的音频 - currentAudioStep = AUDIO_STOPPING_RECORD; - audioRecordTimer->start(1000); - break; - } - - case AUDIO_STOPPING_RECORD: - { - // 1秒延迟完成,播放录制的音频 - qDebug() << "开始播放录制的音频"; - ui->statusbar->showMessage("正在播放录制的音频...", 3000); - - // 更新弹窗信息 - if (audioDialogInfo) { - audioDialogInfo->setText("🔊 正在播放刚才录制的音频(3秒)\n请仔细聆听音质是否清晰"); - } - - // 发送播放录制音频指令 - QString playRecordedCommand = "AT^MEDIAMUSICPLAY=xx,/user/res/music/1.mp3,1,0\r\n"; - serial->write(playRecordedCommand.toUtf8()); - qDebug() << "发送播放录制音频指令:" << playRecordedCommand.trimmed(); - - // 设置下一步骤,3秒后停止播放录制的音频 - currentAudioStep = AUDIO_PLAYING_RECORDED; - audioRecordTimer->start(3000); - break; - } - - case AUDIO_PLAYING_RECORDED: - { - // 3秒播放录制音频完成,自动停止播放 - qDebug() << "录制音频播放3秒完成,发送停止播放指令"; - ui->statusbar->showMessage("录音测试流程完成", 2000); - - // 更新弹窗信息并启用测试按钮 - if (audioDialogInfo) { - audioDialogInfo->setText("✅ 录音测试流程完成!\n请根据刚才听到的音质选择测试结果"); - } - if (audioPassButton) { - audioPassButton->setEnabled(true); - } - if (audioFailButton) { - audioFailButton->setEnabled(true); - } - if (audioRetestButton) { - audioRetestButton->setEnabled(true); - } - - // 自动发送停止播放指令 - serial->write("AT^MEDIAMUSICSTOP\r\n"); - qDebug() << "发送停止播放指令: AT^MEDIAMUSICSTOP"; - - // 录音测试流程完成 - currentAudioStep = AUDIO_STOPPING_PLAYBACK; - break; - } - - default: - { - qDebug() << "未知的录音测试步骤:" << currentAudioStep; - break; - } + + if (audioTestFinished) { + qDebug() << "录音测试已在8秒内完成,不再处理超时"; + return; } + + // 8秒内未检测到连续5个"fac:mic level:中",判定录音测试失败 + qDebug() << "录音测试8秒超时,未检测到连续5个\"fac:mic level:中\",测试失败"; + ui->statusbar->showMessage("录音测试失败:8秒内未检测到连续5个\"fac:mic level:中\"", 3000); + updateTestStatus("audio", STATUS_FAILED); + + audioTestFinished = true; + + // 发送结束音频测试指令 + QString audioEndCmd = "AT^AUDIOTEST=6\r\n"; + serial->write(audioEndCmd.toUtf8()); + qDebug() << "发送结束音频测试指令:" << audioEndCmd.trimmed(); + + // 继续后续电池测试 + currentTestStep = TEST_BATTERY; + performBatteryTest(); } // 检查录音测试结果 @@ -3357,8 +3356,43 @@ void MainWindow::checkAudioTestResult(const QString& data) qDebug() << "录音测试收到数据:" << data.trimmed(); - // 录音测试现在由用户手动控制,不需要自动检测 - qDebug() << "录音测试收到数据(用户手动控制模式):" << data.trimmed(); + qDebug() << "录音测试收到数据:" << data.trimmed(); + + // 只在录音测试过程中统计“fac:mic level:中” + if (data.contains("fac:mic level:")) { + if (data.contains("fac:mic level:中")) { + audioMicMiddleConsecutiveCount++; + qDebug() << "检测到 \"fac:mic level:中\" ,当前连续计数:" + << audioMicMiddleConsecutiveCount; + } else { + // 遇到其他 mic level 打印,连续计数清零 + qDebug() << "检测到其他 mic level 打印,重置连续计数"; + audioMicMiddleConsecutiveCount = 0; + } + + // 达到连续5次"fac:mic level:中"视为录音测试通过 + if (!audioTestFinished && audioMicMiddleConsecutiveCount >= 3) { + qDebug() << "录音测试通过:已检测到连续5个 \"fac:mic level:中\""; + ui->statusbar->showMessage("录音测试通过:检测到连续3个\"fac:mic level:中\"", 3000); + updateTestStatus("audio", STATUS_SUCCESS); + + audioTestFinished = true; + + // 停止8秒定时器,避免再触发超时失败 + if (audioRecordTimer->isActive()) { + audioRecordTimer->stop(); + } + + // 发送结束音频测试指令 + QString audioEndCmd = "AT^AUDIOTEST=6\r\n"; + serial->write(audioEndCmd.toUtf8()); + qDebug() << "发送结束音频测试指令:" << audioEndCmd.trimmed(); + + // 继续后续电池测试 + currentTestStep = TEST_BATTERY; + performBatteryTest(); + } + } } // 执行电池测试 @@ -3372,107 +3406,168 @@ void MainWindow::performBatteryTest() updateTestStatus("battery", STATUS_TESTING); ui->statusbar->showMessage("电池测试中,正在获取电池电压...", 3000); - // 发送电池电量查询指令 - serial->write("AT^GETPOWER\r\n"); - qDebug() << "发送电池测试指令: AT^GETPOWER"; - - // 启动10秒超时检测 - testTimeoutTimer->start(10000); + // 延迟100ms后发送电池电量查询指令,确保串口已准备好 + QTimer::singleShot(100, this, [this]() { + if (isProductionTestRunning && currentTestStep == TEST_BATTERY && serial && serial->isOpen()) { + // 发送电池电量查询指令 + serial->write("AT^GETPOWER\r\n"); + qDebug() << "发送电池测试指令: AT^GETPOWER"; + + // 启动10秒超时检测 + testTimeoutTimer->start(10000); + } else { + qDebug() << "电池测试:串口未打开或产测已停止,无法发送指令"; + } + }); } -// 检查电池测试结果 void MainWindow::checkBatteryTestResult(const QString& data) { if (!isProductionTestRunning || currentTestStep != TEST_BATTERY) { return; } - + qDebug() << "电池测试收到数据:" << data.trimmed(); - - // 解析电池电压数据,支持多种格式: - // 1. fac:voltage : 3.8 , percent 85 , charge : 1 - // 2. Battery: 3.8V - // 3. 3.8V - QRegExp facVoltagePattern("fac:voltage\\s*:\\s*(\\d+\\.\\d+)\\s*,\\s*percent\\s*(\\d+)\\s*,\\s*charge\\s*:\\s*(\\d+)"); + + // 解析电池数据,支持多种格式: + // 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 batteryPattern("Battery.*?(\\d+\\.\\d+)V?"); QRegExp voltagePattern("(\\d+\\.\\d+)V"); - + double voltage = 0.0; int percent = 0; - int charge = -1; // -1表示未检测到充电状态 + double temp = -1.0; // -1.0表示未检测到温度 + int charge = -1; // -1表示未检测到充电状态 bool voltageFound = 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 : 3.8 , percent 85 , charge : 1 + // 解析支持「带温度」和「不带温度」的两种fac格式 voltage = facVoltagePattern.cap(1).toDouble(); percent = facVoltagePattern.cap(2).toInt(); - charge = facVoltagePattern.cap(3).toInt(); + if (!facVoltagePattern.cap(4).isEmpty()) { + temp = facVoltagePattern.cap(4).toDouble(); + } + charge = facVoltagePattern.cap(5).toInt(); voltageFound = true; - - qDebug() << "使用fac:voltage格式解析到电压:" << voltage << "V, 电量:" << percent << "%, 充电状态:" << charge; + + // 日志区分是否有温度 + if (temp != -1.0) { + qDebug() << "使用fac:voltage(带温度)格式解析到:" + << "电压:" << voltage << "V, 电量:" << percent << "%, " + << "温度:" << temp << "℃, 充电状态:" << charge; + } else { + qDebug() << "使用fac:voltage(无温度)格式解析到:" + << "电压:" << voltage << "V, 电量:" << percent << "%, " + << "充电状态:" << charge; + } } else if (batteryPattern.indexIn(data) != -1) { voltage = batteryPattern.cap(1).toDouble(); voltageFound = true; - qDebug() << "使用Battery格式解析到电压:" << voltage; + qDebug() << "使用Battery格式解析到电压:" << voltage << "V(无电量、温度、充电状态)"; } else if (voltagePattern.indexIn(data) != -1) { voltage = voltagePattern.cap(1).toDouble(); voltageFound = true; - qDebug() << "使用通用电压格式解析到电压:" << voltage; + qDebug() << "使用通用电压格式解析到电压:" << voltage << "V(无电量、温度、充电状态)"; } - + if (voltageFound) { - // 停止超时检测,因为已经收到响应 + // 停止超时检测 if (testTimeoutTimer->isActive()) { testTimeoutTimer->stop(); qDebug() << "电池测试收到响应,停止超时检测"; } - - qDebug() << "检测到电池电压:" << voltage << "V"; - - // 首先检查充电状态(如果有充电状态信息) + + // 拼接检测结果日志(包含所有已获取的字段) + 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 ? "充电中" : "未充电"); + qDebug() << resultLog; + + // 充电状态检查(原有逻辑不变) if (charge == 0) { qDebug() << "电池未充电,测试失败"; ui->statusbar->showMessage("电池测试失败 - 设备未充电", 2000); showBatteryChargeFailDialog(); - return; // 不继续后续测试,等待用户操作 + return; } else if (charge == -1) { qDebug() << "未检测到充电状态信息"; ui->statusbar->showMessage("电池测试 - 未检测到充电状态", 2000); - // 显示提醒框告知用户未检测到充电状态 QMessageBox msgBox(this); msgBox.setWindowTitle("充电状态提醒"); - msgBox.setText("未检测到充电状态"); + msgBox.setText("未检测到设备的充电状态信息"); msgBox.setInformativeText("系统未能检测到设备的充电状态信息,\n但电压检测正常,是否继续测试?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); msgBox.setIcon(QMessageBox::Warning); - + int ret = msgBox.exec(); if (ret == QMessageBox::No) { updateTestStatus("battery", STATUS_FAILED); return; } } - - // 判断电压是否在正常范围内 (3.3V - 4.4V) - if (voltage >= 3.3 && voltage <= 4.4) { + + // 核心修改:同时判断电压和温度是否正常 + bool isVoltageNormal = (voltage >= 3.3 && voltage <= 4.4); + bool isTempNormal = true; // 默认温度正常(未检测到温度时不影响结果) + QString failReason; + + // 若检测到温度,才判断温度是否在正常范围 + if (temp != -1.0) { + isTempNormal = (temp >= MIN_NORMAL_TEMP && temp <= MAX_NORMAL_TEMP); + if (!isTempNormal) { + failReason += QString("温度异常(%1℃,正常范围%2℃-%3℃)").arg(temp).arg(MIN_NORMAL_TEMP).arg(MAX_NORMAL_TEMP); + } + } + + // 判断电压是否正常,拼接失败原因 + if (!isVoltageNormal) { + if (!failReason.isEmpty()) failReason += ","; + failReason += QString("电压异常(%1V,正常范围3.3V-4.4V)").arg(voltage); + } + + // 最终判断测试结果 + if (isVoltageNormal && isTempNormal) { + // 电压和温度均正常(或未检测到温度但电压正常) + QString successMsg; if (charge == 1) { - qDebug() << "电池电压正常且正在充电,测试通过"; - ui->statusbar->showMessage(QString("电池测试通过 - 电压: %1V, 充电中").arg(voltage), 2000); + successMsg = QString("电池测试通过 - 电压: %1V, 充电中").arg(voltage); } else { - qDebug() << "电池电压正常,测试通过"; - ui->statusbar->showMessage(QString("电池测试通过 - 电压: %1V").arg(voltage), 2000); + successMsg = QString("电池测试通过 - 电压: %1V").arg(voltage); } + if (temp != -1.0) successMsg += QString(", 温度: %1℃").arg(temp); + if (percent > 0) successMsg += QString(", 电量: %1%").arg(percent); + + qDebug() << successMsg; + ui->statusbar->showMessage(successMsg, 2000); updateTestStatus("battery", STATUS_SUCCESS); } else { - qDebug() << "电池电压异常,测试失败"; - ui->statusbar->showMessage(QString("电池测试失败 - 电压异常: %1V").arg(voltage), 2000); + // 电压或温度异常 + QString failMsg = QString("电池测试失败 - %1").arg(failReason); + if (temp == -1.0 && !isVoltageNormal) { + // 未检测到温度,仅电压异常 + failMsg = QString("电池测试失败 - 电压异常: %1V(正常范围3.3V-4.4V)").arg(voltage); + } else if (voltage >= 3.3 && voltage <= 4.4 && !isTempNormal) { + // 仅温度异常 + failMsg = QString("电池测试失败 - 温度异常: %1℃(正常范围%2℃-%3℃)").arg(temp).arg(MIN_NORMAL_TEMP).arg(MAX_NORMAL_TEMP); + } + + qDebug() << failMsg; + ui->statusbar->showMessage(failMsg, 2000); updateTestStatus("battery", STATUS_FAILED); } - - // 电池测试完成,开始G-sensor测试 - if (isProductionTestRunning && currentTestStep == TEST_BATTERY) { - qDebug() << "电池测试完成,开始G-sensor测试"; + + // 电池测试完成,进入G-sensor测试(仅测试通过时继续) + if (isProductionTestRunning && currentTestStep == TEST_BATTERY && isVoltageNormal && isTempNormal) { + qDebug() << "电池测试完成(电压、温度均正常),开始G-sensor测试"; currentTestStep = TEST_GSENSOR; performGsensorTest(); } @@ -3570,13 +3665,13 @@ void MainWindow::checkGsensorTestResult(const QString& data) updateTestStatus("gsensor", STATUS_FAILED); } - // G-sensor测试完成,开始4G测试 + // G-sensor测试完成,开始蓝牙测试 if (isProductionTestRunning && currentTestStep == TEST_GSENSOR) { - qDebug() << "G-sensor测试完成,开始4G测试"; + qDebug() << "G-sensor测试完成,开始蓝牙测试"; - // 开始4G测试 - currentTestStep = TEST_PPP_INIT; - perform4GTest(); + // 开始蓝牙测试 + currentTestStep = TEST_BLUETOOTH; + performBluetoothTest(); } } else { qDebug() << "G-sensor正则表达式匹配失败,数据:" << data.trimmed(); @@ -3587,13 +3682,13 @@ void MainWindow::checkGsensorTestResult(const QString& data) ui->statusbar->showMessage("G-sensor测试通过 - ID: 0x13 (手动检测)", 2000); updateTestStatus("gsensor", STATUS_SUCCESS); - // G-sensor测试完成,开始4G测试 + // G-sensor测试完成,开始蓝牙测试 if (isProductionTestRunning && currentTestStep == TEST_GSENSOR) { - qDebug() << "G-sensor测试完成(手动),开始4G测试"; + qDebug() << "G-sensor测试完成(手动),开始蓝牙测试"; - // 开始4G测试 - currentTestStep = TEST_PPP_INIT; - perform4GTest(); + // 开始蓝牙测试 + currentTestStep = TEST_BLUETOOTH; + performBluetoothTest(); } } } @@ -3607,15 +3702,243 @@ void MainWindow::checkGsensorTestResult(const QString& data) ui->statusbar->showMessage("G-sensor测试失败 - 设备无响应", 2000); updateTestStatus("gsensor", STATUS_FAILED); - // G-sensor测试失败,仍然继续4G测试 + // G-sensor测试失败,仍然继续蓝牙测试 if (isProductionTestRunning && currentTestStep == TEST_GSENSOR) { - qDebug() << "G-sensor测试失败,继续4G测试"; + qDebug() << "G-sensor测试失败,继续蓝牙测试"; - // 开始4G测试 + // 开始蓝牙测试 + currentTestStep = TEST_BLUETOOTH; + performBluetoothTest(); + } + } +} + +// 执行蓝牙测试 +void MainWindow::performBluetoothTest() +{ + if (!isProductionTestRunning || currentTestStep != TEST_BLUETOOTH) { + return; + } + + qDebug() << "开始蓝牙测试"; + updateTestStatus("bluetooth", STATUS_TESTING); + + // 重置蓝牙测试相关状态 + bluetoothAddresses.clear(); + bluetoothTestFinished = false; + detectedBluetoothAddress = ""; + detectedBluetoothRSSI = 0; + + // 检查是否使用指定地址+RSSI模式 + QString targetAddress = ui->bluetoothAddressLineEdit->text().trimmed().toUpper(); + QString rssiThresholdStr = ui->bluetoothRSSILineEdit->text().trimmed(); + + if (!targetAddress.isEmpty() && !rssiThresholdStr.isEmpty()) { + // 使用指定地址+RSSI模式 + bool ok; + int rssiThreshold = rssiThresholdStr.toInt(&ok); + if (ok) { + ui->statusbar->showMessage(QString("蓝牙测试中:扫描指定地址 %1,RSSI阈值 %2").arg(targetAddress).arg(rssiThreshold), 3000); + qDebug() << "蓝牙测试模式:指定地址+RSSI,地址:" << targetAddress << ",RSSI阈值:" << rssiThreshold; + } else { + ui->statusbar->showMessage("蓝牙测试中:RSSI阈值格式错误,使用3设备模式", 3000); + qDebug() << "RSSI阈值格式错误,切换到3设备模式"; + targetAddress = ""; + } + } else { + // 使用3设备模式 + ui->statusbar->showMessage("蓝牙测试中:正在开启蓝牙扫描(3设备模式)...", 3000); + qDebug() << "蓝牙测试模式:3设备模式"; + } + + // 发送开启蓝牙扫描指令 + QString bluetoothCmd = "AT^BTSCANTEST=1\r\n"; + serial->write(bluetoothCmd.toUtf8()); + qDebug() << "发送蓝牙测试开启指令:" << bluetoothCmd.trimmed(); + + // 启动10秒超时检测 + bluetoothTestTimer->start(15000); +} + +// 检查蓝牙测试结果 +void MainWindow::checkBluetoothTestResult(const QString& data) +{ + if (!isProductionTestRunning || currentTestStep != TEST_BLUETOOTH) { + return; + } + + if (bluetoothTestFinished) { + qDebug() << "蓝牙测试已完成,不再处理数据"; + return; + } + + qDebug() << "蓝牙测试收到数据:" << data.trimmed(); + + // 解析蓝牙设备地址和RSSI:支持两种格式 + // 格式1: fac:Device: 1C:1D:2B:68:82:68, RSSI=-89 dBm + // 格式2: [BtScan] Device: 1C:1D:2B:68:82:68, RSSI=-89 dBm + QRegExp bluetoothPattern1("fac:Device:\\s*([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})\\s*,\\s*RSSI=(-?\\d+)\\s*dBm"); + QRegExp bluetoothPattern2("\\[BtScan\\]\\s*Device:\\s*([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})\\s*,\\s*RSSI=(-?\\d+)\\s*dBm"); + + QString address; + int rssi = 0; + bool rssiOk = false; + bool matched = false; + + if (bluetoothPattern1.indexIn(data) != -1) { + address = bluetoothPattern1.cap(1).toUpper(); + rssi = bluetoothPattern1.cap(2).toInt(&rssiOk); + matched = true; + qDebug() << "使用格式1 (fac:Device:) 解析"; + } else if (bluetoothPattern2.indexIn(data) != -1) { + address = bluetoothPattern2.cap(1).toUpper(); + rssi = bluetoothPattern2.cap(2).toInt(&rssiOk); + matched = true; + qDebug() << "使用格式2 ([BtScan] Device:) 解析"; + } + + if (matched && rssiOk) { + qDebug() << "解析到蓝牙地址:" << address << ",RSSI:" << rssi; + + // 检查是否使用指定地址+RSSI模式 + QString targetAddress = ui->bluetoothAddressLineEdit->text().trimmed().toUpper(); + QString rssiThresholdStr = ui->bluetoothRSSILineEdit->text().trimmed(); + + if (!targetAddress.isEmpty() && !rssiThresholdStr.isEmpty()) { + // 指定地址+RSSI模式 + bool ok; + int rssiThreshold = rssiThresholdStr.toInt(&ok); + if (ok && address == targetAddress) { + qDebug() << "检测到目标地址:" << address << ",RSSI:" << rssi << ",阈值:" << rssiThreshold; + detectedBluetoothAddress = address; + detectedBluetoothRSSI = rssi; + + if (rssi >= rssiThreshold) { + // RSSI满足要求,测试通过 + qDebug() << "蓝牙测试通过:检测到指定地址" << address << ",RSSI" << rssi << "大于等于阈值" << rssiThreshold; + ui->statusbar->showMessage(QString("蓝牙测试通过:地址 %1,RSSI %2").arg(address).arg(rssi), 3000); + updateTestStatus("bluetooth", STATUS_SUCCESS); + + bluetoothTestFinished = true; + + // 停止10秒定时器 + if (bluetoothTestTimer->isActive()) { + bluetoothTestTimer->stop(); + } + + // 发送结束蓝牙扫描指令 + QString bluetoothEndCmd = "AT^BTSCANTEST=2\r\n"; + serial->write(bluetoothEndCmd.toUtf8()); + qDebug() << "发送蓝牙测试结束指令:" << bluetoothEndCmd.trimmed(); + + // 继续后续4G测试 + QTimer::singleShot(500, this, [this]() { + if (isProductionTestRunning && currentTestStep == TEST_BLUETOOTH) { + currentTestStep = TEST_PPP_INIT; + perform4GTest(); + } + }); + } else { + qDebug() << "RSSI不满足要求:" << rssi << "<" << rssiThreshold; + ui->statusbar->showMessage(QString("蓝牙测试:检测到地址 %1,但RSSI %2 小于阈值 %3").arg(address).arg(rssi).arg(rssiThreshold), 2000); + } + } + } else { + // 3设备模式 + if (!bluetoothAddresses.contains(address)) { + bluetoothAddresses.insert(address); + qDebug() << "检测到新的蓝牙地址:" << address << ",当前已检测到" << bluetoothAddresses.size() << "个不同地址"; + ui->statusbar->showMessage(QString("蓝牙测试:已检测到 %1 个不同地址").arg(bluetoothAddresses.size()), 2000); + + // 检查是否达到3个及以上不同的蓝牙地址 + if (bluetoothAddresses.size() >= 3) { + qDebug() << "蓝牙测试通过:已检测到" << bluetoothAddresses.size() << "个不同的蓝牙地址"; + ui->statusbar->showMessage(QString("蓝牙测试通过:检测到 %1 个不同地址").arg(bluetoothAddresses.size()), 3000); + updateTestStatus("bluetooth", STATUS_SUCCESS); + + bluetoothTestFinished = true; + + // 停止10秒定时器 + if (bluetoothTestTimer->isActive()) { + bluetoothTestTimer->stop(); + } + + // 发送结束蓝牙扫描指令 + QString bluetoothEndCmd = "AT^BTSCANTEST=2\r\n"; + serial->write(bluetoothEndCmd.toUtf8()); + qDebug() << "发送蓝牙测试结束指令:" << bluetoothEndCmd.trimmed(); + + // 继续后续4G测试 + QTimer::singleShot(500, this, [this]() { + if (isProductionTestRunning && currentTestStep == TEST_BLUETOOTH) { + currentTestStep = TEST_PPP_INIT; + perform4GTest(); + } + }); + } + } else { + qDebug() << "检测到重复的蓝牙地址:" << address << ",已存在,跳过"; + } + } + } +} + +// 蓝牙测试超时处理 +void MainWindow::onBluetoothTestTimer() +{ + bluetoothTestTimer->stop(); + + if (!isProductionTestRunning || currentTestStep != TEST_BLUETOOTH) { + return; + } + + if (bluetoothTestFinished) { + qDebug() << "蓝牙测试已在10秒内完成,不再处理超时"; + return; + } + + // 检查是否使用指定地址+RSSI模式 + QString targetAddress = ui->bluetoothAddressLineEdit->text().trimmed().toUpper(); + QString rssiThresholdStr = ui->bluetoothRSSILineEdit->text().trimmed(); + + if (!targetAddress.isEmpty() && !rssiThresholdStr.isEmpty()) { + // 指定地址+RSSI模式超时 + bool ok; + int rssiThreshold = rssiThresholdStr.toInt(&ok); + if (ok) { + if (detectedBluetoothAddress.isEmpty()) { + qDebug() << "蓝牙测试10秒超时,未检测到指定地址" << targetAddress; + ui->statusbar->showMessage(QString("蓝牙测试失败:10秒内未检测到指定地址 %1").arg(targetAddress), 3000); + } else { + qDebug() << "蓝牙测试10秒超时,检测到指定地址" << detectedBluetoothAddress << "但RSSI" << detectedBluetoothRSSI << "小于阈值" << rssiThreshold; + ui->statusbar->showMessage(QString("蓝牙测试失败:检测到地址 %1,但RSSI %2 小于阈值 %3").arg(detectedBluetoothAddress).arg(detectedBluetoothRSSI).arg(rssiThreshold), 3000); + } + } else { + qDebug() << "蓝牙测试10秒超时,RSSI阈值格式错误"; + ui->statusbar->showMessage("蓝牙测试失败:RSSI阈值格式错误", 3000); + } + } else { + // 3设备模式超时 + qDebug() << "蓝牙测试10秒超时,仅检测到" << bluetoothAddresses.size() << "个不同地址(需要3个及以上),测试失败"; + ui->statusbar->showMessage(QString("蓝牙测试失败:10秒内仅检测到 %1 个不同地址(需要3个及以上)").arg(bluetoothAddresses.size()), 3000); + } + + updateTestStatus("bluetooth", STATUS_FAILED); + + bluetoothTestFinished = true; + + // 发送结束蓝牙扫描指令(无论成功失败都要发送) + QString bluetoothEndCmd = "AT^BTSCANTEST=2\r\n"; + serial->write(bluetoothEndCmd.toUtf8()); + qDebug() << "发送蓝牙测试结束指令:" << bluetoothEndCmd.trimmed(); + + // 继续后续4G测试 + QTimer::singleShot(500, this, [this]() { + if (isProductionTestRunning && currentTestStep == TEST_BLUETOOTH) { currentTestStep = TEST_PPP_INIT; perform4GTest(); } - } + }); } // 检查CAT1信号测试结果 @@ -4251,6 +4574,7 @@ void MainWindow::showFinalTestResult() QString audioResult = ui->audioStatusText->text(); QString batteryResult = ui->batteryStatusText->text(); QString gsensorResult = ui->gsensorStatusText->text(); + QString bluetoothResult = ui->bluetoothStatusText->text(); QString pppResult = ui->pppStatusText->text(); QString overallResult = ui->overallStatusText->text(); @@ -4267,10 +4591,11 @@ void MainWindow::showFinalTestResult() "🎤 录音测试:%4\n" "🔋 电池测试:%5\n" "📡 G-sensor测试:%6\n" - "🌐 4G测试:%7\n\n" - "📊 整体结果:%8" + "📶 蓝牙测试:%7\n" + "🌐 4G测试:%8\n\n" + "📊 整体结果:%9" ).arg(lcdResult, motorResult, keyResult, audioResult, - batteryResult, gsensorResult, pppResult, overallResult); + batteryResult, gsensorResult, bluetoothResult, pppResult, overallResult); resultDialog.setText(resultContent); @@ -4376,6 +4701,10 @@ void MainWindow::onTestTimeout() testName = "gsensor"; testDescription = "G-sensor测试"; break; + case TEST_BLUETOOTH: + testName = "bluetooth"; + testDescription = "蓝牙测试"; + break; default: qDebug() << "未知的测试步骤超时:" << currentTestStep; return; @@ -4452,6 +4781,9 @@ void MainWindow::onTestTimeout() case TEST_GSENSOR: performGsensorTest(); break; + case TEST_BLUETOOTH: + performBluetoothTest(); + break; default: break; } @@ -4475,9 +4807,18 @@ void MainWindow::onTestTimeout() break; case TEST_GSENSOR: { - // G-sensor测试超时,继续4G测试 - qDebug() << "G-sensor测试超时,继续4G测试"; + // G-sensor测试超时,继续蓝牙测试 + qDebug() << "G-sensor测试超时,继续蓝牙测试"; updateTestStatus("gsensor", STATUS_FAILED); + currentTestStep = TEST_BLUETOOTH; + performBluetoothTest(); + break; + } + case TEST_BLUETOOTH: + { + // 蓝牙测试超时,继续4G测试 + qDebug() << "蓝牙测试超时,继续4G测试"; + updateTestStatus("bluetooth", STATUS_FAILED); currentTestStep = TEST_PPP_INIT; perform4GTest(); break; @@ -4576,6 +4917,7 @@ void MainWindow::clearProductionTestState() updateTestStatus("audio", STATUS_UNTESTED); updateTestStatus("battery", STATUS_UNTESTED); updateTestStatus("gsensor", STATUS_UNTESTED); + updateTestStatus("bluetooth", STATUS_UNTESTED); updateTestStatus("ppp", STATUS_UNTESTED); // 清空串口接收文本框 @@ -4614,6 +4956,7 @@ void MainWindow::on_agingTestButton_clicked() updateTestStatus("audio", STATUS_UNTESTED); updateTestStatus("battery", STATUS_UNTESTED); updateTestStatus("gsensor", STATUS_UNTESTED); + updateTestStatus("bluetooth", STATUS_UNTESTED); updateTestStatus("ppp", STATUS_UNTESTED); serial->write("AT^FACTORY=2\r\n"); } @@ -4647,6 +4990,7 @@ void MainWindow::on_agingTestButton_2_clicked() updateTestStatus("audio", STATUS_UNTESTED); updateTestStatus("battery", STATUS_UNTESTED); updateTestStatus("gsensor", STATUS_UNTESTED); + updateTestStatus("bluetooth", STATUS_UNTESTED); updateTestStatus("ppp", STATUS_UNTESTED); serial->write("AT^RESTORE\r\n"); @@ -4681,7 +5025,14 @@ void MainWindow::on_openButton_3_clicked() updateTestStatus("audio", STATUS_UNTESTED); updateTestStatus("battery", STATUS_UNTESTED); updateTestStatus("gsensor", STATUS_UNTESTED); + updateTestStatus("bluetooth", STATUS_UNTESTED); updateTestStatus("ppp", STATUS_UNTESTED); serial->write("AT^FACTORY=3\r\n"); } + + +void MainWindow::on_openButton_4_clicked() +{ + serial->write("AT^FACTORY=3\r\n"); +} diff --git a/mainwindow.h b/mainwindow.h index 2c87f27..44e904d 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -16,6 +16,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -83,10 +84,15 @@ private slots: void checkBatteryTestResult(const QString& data); // 检查电池测试结果 void performGsensorTest(); // 执行G-sensor测试 void checkGsensorTestResult(const QString& data); // 检查G-sensor测试结果 + void performBluetoothTest(); // 执行蓝牙测试 + void checkBluetoothTestResult(const QString& data); // 检查蓝牙测试结果 + void onBluetoothTestTimer(); // 蓝牙测试超时处理 void updateTestStatus(const QString& testName, TestStatus status); void updateOverallStatus(); QString saveTestRecord(); // 保存测试记录到Excel(静默保存) void checkSignalAndSimValues(const QString& data); // 检查signal和sim值进行4G测试判断 + void on_openButton_4_clicked(); + void sendPppCommand(); // 发送PPP指令 void parseWstpPrintData(const QString& data); // 解析wstp_print格式的BTMAC和CyweeChipInfo数据 @@ -118,6 +124,7 @@ private: QTimer *testTimeoutTimer; // 通用测试超时定时器 QTimer *cat1SignalTimer; // CAT1信号测试定时器 + QTimer *bluetoothTestTimer; // 蓝牙测试定时器 int currentLcdColor; // 当前LCD测试颜色 (1=红, 2=绿, 3=蓝) int initRetry4GCount; // 4G初始化重试次数 bool hasReceivedFirstSignal; @@ -154,6 +161,12 @@ private: QPushButton *audioPassButton; // 录音通过按钮 QPushButton *audioFailButton; // 录音失败按钮 QPushButton *audioRetestButton; // 重新测试按钮 + int audioMicMiddleConsecutiveCount; // 连续检测到"fac:mic level:中"的次数 + bool audioTestFinished; // 录音测试是否已完成(成功或失败) + QSet bluetoothAddresses; // 蓝牙测试检测到的不同蓝牙地址集合 + bool bluetoothTestFinished; // 蓝牙测试是否已完成(成功或失败) + QString detectedBluetoothAddress; // 检测到的指定蓝牙地址 + int detectedBluetoothRSSI; // 检测到的指定蓝牙地址的RSSI值 enum AudioTestStep { AUDIO_STARTING_RECORD, // 开始录音 @@ -174,6 +187,7 @@ private: TEST_AUDIO, TEST_BATTERY, TEST_GSENSOR, + TEST_BLUETOOTH, TEST_PPP_INIT, TEST_PPP_UPDATE, TEST_PPP_SIGNAL, diff --git a/mainwindow.ui b/mainwindow.ui index 52a6a1a..6b2243e 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -290,9 +290,9 @@ background-color: #7B1FA2; - 1020 - 280 - 281 + 1010 + 330 + 261 271 @@ -587,7 +587,7 @@ background-color: #7B1FA2; 未测试 - + 10 @@ -596,6 +596,54 @@ background-color: #7B1FA2; 20 + + 蓝牙测试: + + + + + + 80 + 205 + 20 + 20 + + + + color: #888888; font-size: 18px; font-weight: bold; + + + ○ + + + Qt::AlignCenter + + + + + + 110 + 205 + 60 + 20 + + + + color: #888888; + + + 未测试 + + + + + + 10 + 235 + 60 + 20 + + 4G测试: @@ -604,7 +652,7 @@ background-color: #7B1FA2; 80 - 205 + 235 20 20 @@ -623,7 +671,7 @@ background-color: #7B1FA2; 110 - 205 + 235 60 20 @@ -639,7 +687,7 @@ background-color: #7B1FA2; 10 - 235 + 265 60 20 @@ -652,7 +700,7 @@ background-color: #7B1FA2; 80 - 235 + 265 20 20 @@ -671,7 +719,7 @@ background-color: #7B1FA2; 110 - 235 + 265 80 20 @@ -770,6 +818,87 @@ background-color: #7B1FA2; + + + + 1010 + 270 + 71 + 20 + + + + 蓝牙地址: + + + + + + 1090 + 270 + 231 + 20 + + + + 例如: 1C:1D:2B:68:82:68 + + + + + + 1010 + 300 + 71 + 20 + + + + RSSI阈值: + + + + + + 1090 + 300 + 231 + 20 + + + + 例如: -80 + + + + + + 110 + 360 + 101 + 20 + + + + 2 + + + 例如: 2 + + + + + + 10 + 360 + 121 + 20 + + + + 音频测试音量: + +