增加蓝牙扫描测试,优化录音测试
authorpenglei <1624952103@qq.com>
Thu, 4 Dec 2025 03:20:52 +0000 (11:20 +0800)
committerpenglei <1624952103@qq.com>
Thu, 4 Dec 2025 03:20:52 +0000 (11:20 +0800)
mainwindow.cpp
mainwindow.h
mainwindow.ui

index 15c091b..6143792 100644 (file)
@@ -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() << "ç\94µæ± æµ\8bè¯\95å®\8cæ\88\90ï¼\88ç\94µå\8e\8bã\80\81温度å\9d\87正常ï¼\89ï¼\8cå¼\80å§\8bG-sensoræµ\8bè¯\95";
             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");
+}
index 2c87f27..44e904d 100644 (file)
@@ -16,6 +16,7 @@
 #include <QHBoxLayout>
 #include <QVBoxLayout>
 #include <QLabel>
+#include <QSet>
 
 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<QString> 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,
index 52a6a1a..6b2243e 100644 (file)
@@ -290,9 +290,9 @@ background-color: #7B1FA2;
    <widget class="QGroupBox" name="testStatusGroupBox">
     <property name="geometry">
      <rect>
-      <x>1020</x>
-      <y>280</y>
-      <width>281</width>
+      <x>1010</x>
+      <y>330</y>
+      <width>261</width>
       <height>271</height>
      </rect>
     </property>
@@ -587,7 +587,7 @@ background-color: #7B1FA2;
       <string>未测试</string>
      </property>
     </widget>
-    <widget class="QLabel" name="pppTestLabel">
+    <widget class="QLabel" name="bluetoothTestLabel">
      <property name="geometry">
       <rect>
        <x>10</x>
@@ -596,6 +596,54 @@ background-color: #7B1FA2;
        <height>20</height>
       </rect>
      </property>
+     <property name="text">
+      <string>蓝牙测试:</string>
+     </property>
+    </widget>
+    <widget class="QLabel" name="bluetoothStatusIcon">
+     <property name="geometry">
+      <rect>
+       <x>80</x>
+       <y>205</y>
+       <width>20</width>
+       <height>20</height>
+      </rect>
+     </property>
+     <property name="styleSheet">
+      <string>color: #888888; font-size: 18px; font-weight: bold;</string>
+     </property>
+     <property name="text">
+      <string>○</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+    <widget class="QLabel" name="bluetoothStatusText">
+     <property name="geometry">
+      <rect>
+       <x>110</x>
+       <y>205</y>
+       <width>60</width>
+       <height>20</height>
+      </rect>
+     </property>
+     <property name="styleSheet">
+      <string>color: #888888;</string>
+     </property>
+     <property name="text">
+      <string>未测试</string>
+     </property>
+    </widget>
+    <widget class="QLabel" name="pppTestLabel">
+     <property name="geometry">
+      <rect>
+       <x>10</x>
+       <y>235</y>
+       <width>60</width>
+       <height>20</height>
+      </rect>
+     </property>
      <property name="text">
       <string>4G测试:</string>
      </property>
@@ -604,7 +652,7 @@ background-color: #7B1FA2;
      <property name="geometry">
       <rect>
        <x>80</x>
-       <y>205</y>
+       <y>235</y>
        <width>20</width>
        <height>20</height>
       </rect>
@@ -623,7 +671,7 @@ background-color: #7B1FA2;
      <property name="geometry">
       <rect>
        <x>110</x>
-       <y>205</y>
+       <y>235</y>
        <width>60</width>
        <height>20</height>
       </rect>
@@ -639,7 +687,7 @@ background-color: #7B1FA2;
      <property name="geometry">
       <rect>
        <x>10</x>
-       <y>235</y>
+       <y>265</y>
        <width>60</width>
        <height>20</height>
       </rect>
@@ -652,7 +700,7 @@ background-color: #7B1FA2;
      <property name="geometry">
       <rect>
        <x>80</x>
-       <y>235</y>
+       <y>265</y>
        <width>20</width>
        <height>20</height>
       </rect>
@@ -671,7 +719,7 @@ background-color: #7B1FA2;
      <property name="geometry">
       <rect>
        <x>110</x>
-       <y>235</y>
+       <y>265</y>
        <width>80</width>
        <height>20</height>
       </rect>
@@ -770,6 +818,87 @@ background-color: #7B1FA2;
      </rect>
     </property>
    </widget>
+   <widget class="QLabel" name="BluetoothAddressLabel">
+    <property name="geometry">
+     <rect>
+      <x>1010</x>
+      <y>270</y>
+      <width>71</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>蓝牙地址:</string>
+    </property>
+   </widget>
+   <widget class="QLineEdit" name="bluetoothAddressLineEdit">
+    <property name="geometry">
+     <rect>
+      <x>1090</x>
+      <y>270</y>
+      <width>231</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="placeholderText">
+     <string>例如: 1C:1D:2B:68:82:68</string>
+    </property>
+   </widget>
+   <widget class="QLabel" name="BluetoothRSSILabel">
+    <property name="geometry">
+     <rect>
+      <x>1010</x>
+      <y>300</y>
+      <width>71</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>RSSI阈值:</string>
+    </property>
+   </widget>
+   <widget class="QLineEdit" name="bluetoothRSSILineEdit">
+    <property name="geometry">
+     <rect>
+      <x>1090</x>
+      <y>300</y>
+      <width>231</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="placeholderText">
+     <string>例如: -80</string>
+    </property>
+   </widget>
+   <widget class="QLineEdit" name="audioVolumeLineEdit">
+    <property name="geometry">
+     <rect>
+      <x>110</x>
+      <y>360</y>
+      <width>101</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>2</string>
+    </property>
+    <property name="placeholderText">
+     <string>例如: 2</string>
+    </property>
+   </widget>
+   <widget class="QLabel" name="AudioVolumeLabel">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>360</y>
+      <width>121</width>
+      <height>20</height>
+     </rect>
+    </property>
+    <property name="text">
+     <string>音频测试音量:</string>
+    </property>
+   </widget>
   </widget>
   <widget class="QMenuBar" name="menubar">
    <property name="geometry">