#include "ILedDisplayDevice.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { struct GuideStateItem { int code; const char* name; const char* description; bool danger = false; }; const std::vector kGuideStates = { {1, "START", "开始引导"}, {2, "CAPTURE", "目标捕获"}, {5, "CENTER", "对中引导"}, {6, "SLOW", "减速提示"}, {7, "AZIMUTH", "方位引导"}, {8, "STOP", "到位停止", true}, {10, "TOO FAR", "停止过远"}, {15, "ID FAIL", "识别失败", true}, {16, "GATE BLOCK", "入口遮挡"}, {17, "VIEW BLOCK", "视野遮挡"}, {20, "STOP", "停止状态", true}, {21, "CHOCK ON", "轮挡到位"}, {22, "ERROR", "系统错误", true}, }; QString StatusName(ELedDisplayStatus status) { switch (status) { case ELedDisplayStatus::Disconnected: return QStringLiteral("未连接"); case ELedDisplayStatus::Connected: return QStringLiteral("已连接"); case ELedDisplayStatus::Error: return QStringLiteral("异常"); } return QStringLiteral("未知"); } class LedDisplayTestWindow final : public QMainWindow { public: LedDisplayTestWindow() { setWindowTitle(QStringLiteral("LED 显示屏协议调试")); setMinimumSize(1000, 700); resize(1220, 820); ILedDisplayDevice* rawDevice = nullptr; if (ILedDisplayDevice::CreateObject(&rawDevice) == 0 && rawDevice) { m_device.reset(rawDevice); m_device->SetStatusCallback( [](ELedDisplayStatus status, const std::string& message, void* user) { auto* self = static_cast(user); if (self) { self->handleDeviceStatus( status, QString::fromUtf8(message.c_str())); } }, this); } buildUi(); applyStyle(); setConnected(false); appendLog(QStringLiteral("LED 协议调试工具已启动")); } ~LedDisplayTestWindow() override { m_demoTimer.stop(); if (m_device) { m_device->SetStatusCallback({}, nullptr); m_device->Close(); } } private: void buildUi() { auto* central = new QWidget(this); auto* rootLayout = new QVBoxLayout(central); rootLayout->setContentsMargins(20, 16, 20, 20); rootLayout->setSpacing(14); auto* headerLayout = new QHBoxLayout(); auto* titleLayout = new QVBoxLayout(); auto* title = new QLabel(QStringLiteral("LED 显示屏协议调试"), central); title->setObjectName(QStringLiteral("pageTitle")); auto* subtitle = new QLabel( QStringLiteral("独立连接控制器并发送停机引导显示状态"), central); subtitle->setObjectName(QStringLiteral("pageSubtitle")); titleLayout->addWidget(title); titleLayout->addWidget(subtitle); headerLayout->addLayout(titleLayout); headerLayout->addStretch(); m_statusDot = new QLabel(central); m_statusDot->setFixedSize(12, 12); m_statusText = new QLabel(QStringLiteral("未连接"), central); m_statusText->setObjectName(QStringLiteral("connectionStatus")); headerLayout->addWidget(m_statusDot); headerLayout->addWidget(m_statusText); rootLayout->addLayout(headerLayout); auto* contentLayout = new QHBoxLayout(); contentLayout->setSpacing(14); contentLayout->addWidget(buildSettingsPanel(), 0); contentLayout->addWidget(buildCommandPanel(), 1); rootLayout->addLayout(contentLayout, 1); setCentralWidget(central); } QWidget* buildSettingsPanel() { auto* scrollArea = new QScrollArea(this); scrollArea->setObjectName(QStringLiteral("settingsScroll")); scrollArea->setWidgetResizable(true); scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea->setFixedWidth(340); auto* panel = new QWidget(scrollArea); auto* layout = new QVBoxLayout(panel); layout->setContentsMargins(0, 0, 8, 0); layout->setSpacing(12); auto* connectionGroup = new QGroupBox(QStringLiteral("连接配置"), panel); auto* connectionForm = new QFormLayout(connectionGroup); connectionForm->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); connectionForm->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); m_ipEdit = new QLineEdit(QStringLiteral("192.168.1.199"), connectionGroup); m_portSpin = makeSpinBox(1, 65535, 5005, connectionGroup); m_timeoutSpin = makeSpinBox(100, 60000, 1000, connectionGroup); m_timeoutSpin->setSuffix(QStringLiteral(" ms")); m_slaveIdEdit = new QLineEdit(QStringLiteral("0xFFFE"), connectionGroup); m_controllerTypeEdit = new QLineEdit(QStringLiteral("0xFE"), connectionGroup); connectionForm->addRow(QStringLiteral("控制器 IP"), m_ipEdit); connectionForm->addRow(QStringLiteral("TCP 端口"), m_portSpin); connectionForm->addRow(QStringLiteral("响应超时"), m_timeoutSpin); connectionForm->addRow(QStringLiteral("从机地址"), m_slaveIdEdit); connectionForm->addRow(QStringLiteral("控制器类型"), m_controllerTypeEdit); auto* connectionButtons = new QHBoxLayout(); m_connectButton = new QPushButton(QStringLiteral("连接"), connectionGroup); m_connectButton->setObjectName(QStringLiteral("primaryButton")); m_disconnectButton = new QPushButton(QStringLiteral("断开"), connectionGroup); connectionButtons->addWidget(m_connectButton); connectionButtons->addWidget(m_disconnectButton); connectionForm->addRow(connectionButtons); layout->addWidget(connectionGroup); auto* areaGroup = new QGroupBox(QStringLiteral("显示区域与动画"), panel); auto* areaForm = new QFormLayout(areaGroup); areaForm->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); m_areaXSpin = makeSpinBox(0, 32767, 0, areaGroup); m_areaYSpin = makeSpinBox(0, 32767, 0, areaGroup); m_areaWidthSpin = makeSpinBox(1, 32767, 64, areaGroup); m_areaHeightSpin = makeSpinBox(1, 32767, 32, areaGroup); m_startAddressSpin = makeSpinBox(0, 7, 0, areaGroup); m_dynamicTimeoutSpin = makeSpinBox(0, 65535, 10, areaGroup); m_dynamicTimeoutSpin->setSuffix(QStringLiteral(" s")); m_modeSpin = makeSpinBox(1, 7, 1, areaGroup); m_speedSpin = makeSpinBox(0, 24, 2, areaGroup); m_staySpin = makeSpinBox(0, 255, 10, areaGroup); areaForm->addRow(QStringLiteral("区域 X"), m_areaXSpin); areaForm->addRow(QStringLiteral("区域 Y"), m_areaYSpin); areaForm->addRow(QStringLiteral("区域宽度"), m_areaWidthSpin); areaForm->addRow(QStringLiteral("区域高度"), m_areaHeightSpin); areaForm->addRow(QStringLiteral("动态区编号"), m_startAddressSpin); areaForm->addRow(QStringLiteral("动态超时"), m_dynamicTimeoutSpin); areaForm->addRow(QStringLiteral("显示模式"), m_modeSpin); areaForm->addRow(QStringLiteral("动画速度"), m_speedSpin); areaForm->addRow(QStringLiteral("停留时间"), m_staySpin); layout->addWidget(areaGroup); layout->addStretch(); scrollArea->setWidget(panel); connect(m_connectButton, &QPushButton::clicked, this, [this]() { connectDevice(); }); connect(m_disconnectButton, &QPushButton::clicked, this, [this]() { disconnectDevice(); }); return scrollArea; } QWidget* buildCommandPanel() { auto* panel = new QWidget(this); auto* layout = new QVBoxLayout(panel); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(12); auto* dataGroup = new QGroupBox(QStringLiteral("测试数据"), panel); auto* previewGroup = new QGroupBox(QStringLiteral("Screen Preview (one full-screen area)"), panel); auto* previewLayout = new QVBoxLayout(previewGroup); m_screenPreview = new QLabel(QStringLiteral("NO DATA"), previewGroup); m_screenPreview->setObjectName(QStringLiteral("screenPreview")); m_screenPreview->setAlignment(Qt::AlignCenter); m_screenPreview->setWordWrap(true); m_screenPreview->setMinimumHeight(190); previewLayout->addWidget(m_screenPreview); layout->addWidget(previewGroup); auto* dataGrid = new QGridLayout(dataGroup); m_modelEdit = new QLineEdit(QStringLiteral("A320"), dataGroup); m_distanceSpin = makeDoubleSpinBox(-1000000.0, 1000000.0, 12500.0, QStringLiteral(" mm"), dataGroup); m_offsetSpin = makeDoubleSpinBox(-100000.0, 100000.0, 0.0, QStringLiteral(" mm"), dataGroup); m_angleSpin = makeDoubleSpinBox(-360.0, 360.0, 0.0, QStringLiteral("°"), dataGroup); m_errorCodeSpin = makeSpinBox(-999999, 999999, 22, dataGroup); dataGrid->addWidget(new QLabel(QStringLiteral("机型"), dataGroup), 0, 0); dataGrid->addWidget(m_modelEdit, 0, 1); dataGrid->addWidget(new QLabel(QStringLiteral("距离"), dataGroup), 0, 2); dataGrid->addWidget(m_distanceSpin, 0, 3); dataGrid->addWidget(new QLabel(QStringLiteral("横向偏移"), dataGroup), 1, 0); dataGrid->addWidget(m_offsetSpin, 1, 1); dataGrid->addWidget(new QLabel(QStringLiteral("角度"), dataGroup), 1, 2); dataGrid->addWidget(m_angleSpin, 1, 3); dataGrid->addWidget(new QLabel(QStringLiteral("错误码"), dataGroup), 2, 0); dataGrid->addWidget(m_errorCodeSpin, 2, 1); dataGrid->setColumnStretch(1, 1); dataGrid->setColumnStretch(3, 1); layout->addWidget(dataGroup); auto* stateGroup = new QGroupBox(QStringLiteral("标准引导状态"), panel); auto* stateGrid = new QGridLayout(stateGroup); stateGrid->setSpacing(8); for (int index = 0; index < static_cast(kGuideStates.size()); ++index) { const GuideStateItem& item = kGuideStates[static_cast(index)]; auto* button = new QPushButton( QStringLiteral("%1\n%2") .arg(QString::fromLatin1(item.name), QString::fromUtf8(item.description)), stateGroup); button->setProperty("stateButton", true); button->setProperty("danger", item.danger); button->setMinimumHeight(54); m_sendControls.push_back(button); connect(button, &QPushButton::clicked, this, [this, code = item.code]() { sendState(code); }); stateGrid->addWidget(button, index / 4, index % 4); } layout->addWidget(stateGroup); auto* customGroup = new QGroupBox(QStringLiteral("自定义与批量测试"), panel); auto* customLayout = new QGridLayout(customGroup); m_customTextEdit = new QLineEdit(customGroup); m_customTextEdit->setPlaceholderText(QStringLiteral("输入任意显示文本")); m_sendTextButton = new QPushButton(QStringLiteral("发送文本"), customGroup); m_blankButton = new QPushButton(QStringLiteral("清屏"), customGroup); m_invalidButton = new QPushButton(QStringLiteral("发送 NO DATA"), customGroup); m_demoButton = new QPushButton(QStringLiteral("启动演示"), customGroup); m_screenOnButton = new QPushButton(QStringLiteral("开屏"), customGroup); m_screenOffButton = new QPushButton(QStringLiteral("关屏"), customGroup); m_demoButton->setObjectName(QStringLiteral("accentButton")); m_demoIntervalSpin = makeSpinBox(100, 60000, 1000, customGroup); m_demoIntervalSpin->setSuffix(QStringLiteral(" ms")); customLayout->addWidget(m_customTextEdit, 0, 0, 1, 3); customLayout->addWidget(m_sendTextButton, 0, 3); customLayout->addWidget(m_blankButton, 1, 0); customLayout->addWidget(m_invalidButton, 1, 1); customLayout->addWidget(m_demoIntervalSpin, 1, 2); customLayout->addWidget(m_demoButton, 1, 3); customLayout->addWidget(m_screenOnButton, 2, 0); customLayout->addWidget(m_screenOffButton, 2, 1); layout->addWidget(customGroup); m_sendControls.push_back(m_sendTextButton); m_sendControls.push_back(m_blankButton); m_sendControls.push_back(m_invalidButton); m_sendControls.push_back(m_screenOnButton); m_sendControls.push_back(m_screenOffButton); m_sendControls.push_back(m_demoButton); connect(m_sendTextButton, &QPushButton::clicked, this, [this]() { sendCustomText(); }); connect(m_blankButton, &QPushButton::clicked, this, [this]() { sendBlank(); }); connect(m_invalidButton, &QPushButton::clicked, this, [this]() { sendInvalid(); }); connect(m_screenOnButton, &QPushButton::clicked, this, [this]() { setScreenPower(true); }); connect(m_screenOffButton, &QPushButton::clicked, this, [this]() { setScreenPower(false); }); connect(m_demoButton, &QPushButton::clicked, this, [this]() { toggleDemo(); }); connect(&m_demoTimer, &QTimer::timeout, this, [this]() { sendNextDemoState(); }); auto* logGroup = new QGroupBox(QStringLiteral("协议响应日志"), panel); auto* logLayout = new QVBoxLayout(logGroup); m_logEdit = new QPlainTextEdit(logGroup); m_logEdit->setReadOnly(true); m_logEdit->setMaximumBlockCount(1000); auto* clearLogButton = new QPushButton(QStringLiteral("清空日志"), logGroup); clearLogButton->setFixedWidth(96); auto* logToolbar = new QHBoxLayout(); logToolbar->addStretch(); logToolbar->addWidget(clearLogButton); logLayout->addLayout(logToolbar); logLayout->addWidget(m_logEdit, 1); connect(clearLogButton, &QPushButton::clicked, m_logEdit, &QPlainTextEdit::clear); layout->addWidget(logGroup, 1); return panel; } static QSpinBox* makeSpinBox(int minimum, int maximum, int value, QWidget* parent) { auto* spin = new QSpinBox(parent); spin->setRange(minimum, maximum); spin->setValue(value); spin->setAccelerated(true); return spin; } static QDoubleSpinBox* makeDoubleSpinBox(double minimum, double maximum, double value, const QString& suffix, QWidget* parent) { auto* spin = new QDoubleSpinBox(parent); spin->setRange(minimum, maximum); spin->setDecimals(1); spin->setValue(value); spin->setSuffix(suffix); spin->setAccelerated(true); return spin; } void applyStyle() { setStyleSheet(QStringLiteral(R"( QMainWindow, QWidget { background: #f4f6f8; color: #20252b; font-family: "Microsoft YaHei UI"; font-size: 13px; } QLabel#pageTitle { font-size: 24px; font-weight: 700; color: #182028; } QLabel#pageSubtitle { color: #68737d; font-size: 13px; } QLabel#connectionStatus { font-size: 14px; font-weight: 600; } QGroupBox { background: #ffffff; border: 1px solid #d7dde3; border-radius: 6px; margin-top: 14px; padding: 14px 12px 12px 12px; font-weight: 600; } QGroupBox::title { subcontrol-origin: margin; left: 12px; padding: 0 5px; color: #35404a; } QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox { min-height: 32px; background: #ffffff; border: 1px solid #bfc8d0; border-radius: 4px; padding: 0 8px; selection-background-color: #2474a8; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus { border: 1px solid #2474a8; } QPushButton { min-height: 34px; background: #eef1f3; border: 1px solid #bfc8d0; border-radius: 4px; padding: 0 12px; font-weight: 600; } QPushButton:hover { background: #e2e7eb; } QPushButton:pressed { background: #d5dce2; } QPushButton:disabled { color: #9aa3aa; background: #f1f3f4; border-color: #dce1e5; } QPushButton#primaryButton { color: white; background: #2474a8; border-color: #2474a8; } QPushButton#primaryButton:hover { background: #1d628f; } QPushButton#accentButton { color: white; background: #2d7d56; border-color: #2d7d56; } QPushButton#accentButton:hover { background: #246746; } QPushButton[stateButton="true"] { text-align: left; padding: 5px 10px; background: #f8fafb; } QPushButton[stateButton="true"]:hover { background: #e8f1f6; border-color: #6d9dbb; } QPushButton[stateButton="true"][danger="true"] { background: #fff6f4; border-color: #dfafa6; color: #8c3024; } QPushButton[stateButton="true"][danger="true"]:hover { background: #fde8e4; } QPlainTextEdit { background: #171b1f; color: #d9e2e8; border: 1px solid #2c3339; border-radius: 4px; font-family: Consolas; font-size: 12px; padding: 8px; } QLabel#screenPreview { background: #101820; color: #67f3a1; border: 2px solid #344452; border-radius: 8px; font-family: Consolas; font-size: 28px; font-weight: 700; padding: 18px; } QScrollArea#settingsScroll { border: none; background: transparent; } QScrollArea#settingsScroll > QWidget > QWidget { background: transparent; } )")); } bool parseHexField(QLineEdit* edit, const QString& fieldName, int maximum, int& value) { bool ok = false; value = edit->text().trimmed().toInt(&ok, 0); if (!ok || value < 0 || value > maximum) { QMessageBox::warning( this, QStringLiteral("参数错误"), QStringLiteral("%1 必须是 0 到 0x%2 之间的十进制或十六进制数。") .arg(fieldName) .arg(maximum, 0, 16)); edit->setFocus(); return false; } return true; } bool readConfig(LedDisplayConfig& config) { int slaveId = 0; int controllerType = 0; if (m_ipEdit->text().trimmed().isEmpty()) { QMessageBox::warning(this, QStringLiteral("参数错误"), QStringLiteral("请输入控制器 IP。")); m_ipEdit->setFocus(); return false; } if (!parseHexField(m_slaveIdEdit, QStringLiteral("从机地址"), 0xFFFF, slaveId) || !parseHexField(m_controllerTypeEdit, QStringLiteral("控制器类型"), 0xFF, controllerType)) { return false; } config.enabled = true; config.ip = m_ipEdit->text().trimmed().toStdString(); config.port = m_portSpin->value(); config.timeoutMs = m_timeoutSpin->value(); config.slaveId = slaveId; config.controllerType = controllerType; config.startAddress = m_startAddressSpin->value(); config.areaX = m_areaXSpin->value(); config.areaY = m_areaYSpin->value(); config.areaWidth = m_areaWidthSpin->value(); config.areaHeight = m_areaHeightSpin->value(); config.dynamicTimeoutSec = m_dynamicTimeoutSpin->value(); config.displayMode = m_modeSpin->value(); config.speed = m_speedSpin->value(); config.stayTime = m_staySpin->value(); return true; } void connectDevice() { if (!m_device) { QMessageBox::critical(this, QStringLiteral("初始化失败"), QStringLiteral("无法创建设备对象。")); return; } LedDisplayConfig config; if (!readConfig(config)) { return; } appendLog(QStringLiteral("连接 %1:%2,超时 %3 ms") .arg(QString::fromStdString(config.ip)) .arg(config.port) .arg(config.timeoutMs)); QApplication::setOverrideCursor(Qt::WaitCursor); const int result = m_device->Open(config); QApplication::restoreOverrideCursor(); const bool connected = result == 0 && m_device->IsConnected(); setConnected(connected); if (connected) { m_screenPoweredOn = true; if (m_screenPreview) { m_screenPreview->setText(m_lastPreviewText); } } appendLog(QStringLiteral("OPEN return=%1,connected=%2") .arg(result) .arg(connected ? QStringLiteral("yes") : QStringLiteral("no"))); } void disconnectDevice() { stopDemo(); if (m_device) { m_device->Close(); } setConnected(false); appendLog(QStringLiteral("连接已断开")); } LedDisplayResult makeResult(int stateCode) const { LedDisplayResult result; result.valid = true; result.guideCode = stateCode == 22 ? 2 : 1; result.guideStateCode = stateCode; result.errorCode = m_errorCodeSpin->value(); result.modelType = m_modelEdit->text().trimmed().toStdString(); result.distance = static_cast(m_distanceSpin->value()); result.lateralOffset = static_cast(m_offsetSpin->value()); result.angle = static_cast(m_angleSpin->value()); return result; } void sendState(int stateCode) { sendResult(makeResult(stateCode), QStringLiteral("state=%1").arg(stateCode)); } QString previewText(const LedDisplayResult& result) const { if (result.blank) { return QString(); } if (!result.valid) { return QStringLiteral("NO DATA"); } if (!result.stateText.empty() && result.guideStateCode == 0) { return QString::fromLocal8Bit(result.stateText.data(), static_cast(result.stateText.size())); } switch (result.guideStateCode) { case 1: return QStringLiteral("START\n%1").arg(QString::fromStdString(result.modelType)); case 2: return QStringLiteral("CAPTURE\n%1").arg(QString::fromStdString(result.modelType)); case 5: return QStringLiteral("CENTER\n%1m\n%2") .arg(result.distance / 1000.0, 0, 'f', 1) .arg(QString::fromStdString(result.modelType)); case 6: return QStringLiteral("SLOW\n%1m") .arg(result.distance / 1000.0, 0, 'f', 1); case 7: return QStringLiteral("AZIMUTH\n%1m\nL:%2") .arg(result.distance / 1000.0, 0, 'f', 1) .arg(result.lateralOffset, 0, 'f', 0); case 8: case 20: return QStringLiteral("STOP"); case 10: return QStringLiteral("TOO FAR"); case 15: return QStringLiteral("STOP\nID FAIL"); case 16: return QStringLiteral("WAIT\nGATE BLOCK"); case 17: return QStringLiteral("WAIT\nVIEW BLOCK"); case 21: return QStringLiteral("CHOCK ON"); case 22: return QStringLiteral("ERROR\nE:%1").arg(result.errorCode); default: return result.stateText.empty() ? QStringLiteral("OK") : QString::fromLocal8Bit(result.stateText.data(), static_cast(result.stateText.size())); } } void sendCustomText() { const QString text = m_customTextEdit->text(); if (text.isEmpty()) { QMessageBox::information(this, QStringLiteral("自定义文本"), QStringLiteral("请先输入要显示的文本。")); return; } LedDisplayResult result = makeResult(0); QTextCodec* gbk = QTextCodec::codecForName("GBK"); const QByteArray encoded = gbk ? gbk->fromUnicode(text) : text.toLocal8Bit(); result.stateText.assign(encoded.constData(), static_cast(encoded.size())); sendResult(result, QStringLiteral("text=\"%1\"").arg(text)); } void sendBlank() { LedDisplayResult result; result.valid = true; result.blank = true; sendResult(result, QStringLiteral("blank")); } void sendInvalid() { sendResult(LedDisplayResult(), QStringLiteral("invalid / NO DATA")); } void setScreenPower(bool on) { if (!m_device || !m_device->IsConnected()) { setConnected(false); appendLog(QStringLiteral("Screen power command cancelled: device is not connected")); return; } QApplication::setOverrideCursor(Qt::WaitCursor); const int returnCode = on ? m_device->OpenScreen() : m_device->CloseScreen(); QApplication::restoreOverrideCursor(); if (returnCode == 0) { m_screenPoweredOn = on; if (m_screenPreview) { m_screenPreview->setText(on ? m_lastPreviewText : QStringLiteral("SCREEN OFF")); } appendLog(on ? QStringLiteral("Screen ON accepted") : QStringLiteral("Screen OFF accepted")); } else { appendLog(QStringLiteral("Screen power command failed, return=%1") .arg(returnCode)); if (!m_device->IsConnected()) { setConnected(false); } } } bool sendResult(const LedDisplayResult& result, const QString& description) { // The simulator models the physical screen as one full-screen // dynamic area. Keep it useful even before a controller is connected. m_lastPreviewText = previewText(result); if (m_screenPreview && m_screenPoweredOn) { m_screenPreview->setText(m_lastPreviewText); } if (!m_device || !m_device->IsConnected()) { setConnected(false); appendLog(QStringLiteral("发送已取消:设备未连接")); return false; } appendLog(QStringLiteral("SEND %1").arg(description)); QApplication::setOverrideCursor(Qt::WaitCursor); const int returnCode = m_device->SendResult(result); QApplication::restoreOverrideCursor(); const bool success = returnCode == 0 && m_device->IsConnected(); appendLog(QStringLiteral("%1 return=%2,connected=%3") .arg(success ? QStringLiteral("控制器已接收(实际显示需现场确认)") : QStringLiteral("FAILED")) .arg(returnCode) .arg(success ? QStringLiteral("yes") : QStringLiteral("no"))); if (!success) { stopDemo(); setConnected(false); } return success; } void toggleDemo() { if (m_demoTimer.isActive()) { stopDemo(); appendLog(QStringLiteral("自动演示已停止")); return; } if (!m_device || !m_device->IsConnected()) { setConnected(false); return; } m_demoIndex = 0; m_demoTimer.setInterval(m_demoIntervalSpin->value()); m_demoTimer.start(); m_demoButton->setText(QStringLiteral("停止演示")); appendLog(QStringLiteral("自动演示已启动,间隔 %1 ms") .arg(m_demoTimer.interval())); sendNextDemoState(); } void sendNextDemoState() { if (kGuideStates.empty()) { return; } const GuideStateItem& item = kGuideStates[static_cast(m_demoIndex)]; if (!sendResult(makeResult(item.code), QStringLiteral("demo state=%1").arg(item.code))) { return; } m_demoIndex = (m_demoIndex + 1) % static_cast(kGuideStates.size()); } void stopDemo() { m_demoTimer.stop(); if (m_demoButton) { m_demoButton->setText(QStringLiteral("启动演示")); } } void handleDeviceStatus(ELedDisplayStatus status, const QString& message) { appendLog(QStringLiteral("STATUS %1%2") .arg(StatusName(status), message.isEmpty() ? QString() : QStringLiteral(":%1").arg(message))); } void setConnected(bool connected) { m_connected = connected; m_statusText->setText(connected ? QStringLiteral("已连接") : QStringLiteral("未连接")); m_statusDot->setStyleSheet( connected ? QStringLiteral("background: #2d8a5f; border-radius: 6px;") : QStringLiteral("background: #a6afb7; border-radius: 6px;")); m_connectButton->setEnabled(!connected); m_disconnectButton->setEnabled(connected); for (QPushButton* button : m_sendControls) { button->setEnabled(connected); } if (!connected) { stopDemo(); } } void appendLog(const QString& message) { if (!m_logEdit) { return; } m_logEdit->appendPlainText( QStringLiteral("[%1] %2") .arg(QDateTime::currentDateTime().toString( QStringLiteral("HH:mm:ss.zzz")), message)); } private: std::unique_ptr m_device; bool m_connected = false; QLabel* m_statusDot = nullptr; QLabel* m_statusText = nullptr; QLineEdit* m_ipEdit = nullptr; QSpinBox* m_portSpin = nullptr; QSpinBox* m_timeoutSpin = nullptr; QLineEdit* m_slaveIdEdit = nullptr; QLineEdit* m_controllerTypeEdit = nullptr; QSpinBox* m_areaXSpin = nullptr; QSpinBox* m_areaYSpin = nullptr; QSpinBox* m_areaWidthSpin = nullptr; QSpinBox* m_areaHeightSpin = nullptr; QSpinBox* m_startAddressSpin = nullptr; QSpinBox* m_dynamicTimeoutSpin = nullptr; QSpinBox* m_modeSpin = nullptr; QSpinBox* m_speedSpin = nullptr; QSpinBox* m_staySpin = nullptr; QLineEdit* m_modelEdit = nullptr; QDoubleSpinBox* m_distanceSpin = nullptr; QDoubleSpinBox* m_offsetSpin = nullptr; QDoubleSpinBox* m_angleSpin = nullptr; QSpinBox* m_errorCodeSpin = nullptr; QLineEdit* m_customTextEdit = nullptr; QSpinBox* m_demoIntervalSpin = nullptr; QPushButton* m_connectButton = nullptr; QPushButton* m_disconnectButton = nullptr; QPushButton* m_sendTextButton = nullptr; QPushButton* m_blankButton = nullptr; QPushButton* m_invalidButton = nullptr; QPushButton* m_screenOnButton = nullptr; QPushButton* m_screenOffButton = nullptr; QPushButton* m_demoButton = nullptr; QPlainTextEdit* m_logEdit = nullptr; QLabel* m_screenPreview = nullptr; QString m_lastPreviewText = QStringLiteral("NO DATA"); bool m_screenPoweredOn = true; std::vector m_sendControls; QTimer m_demoTimer; int m_demoIndex = 0; }; } // namespace int main(int argc, char* argv[]) { QApplication app(argc, argv); QApplication::setApplicationName(QStringLiteral("LedDisplayDeviceTest")); QApplication::setApplicationDisplayName(QStringLiteral("LED 显示屏协议调试")); LedDisplayTestWindow window; window.show(); return app.exec(); }