// MainWidget.cpp #include "MainWidget.h" #include //#include void onThreadFinished(QThread* thread, ClientHandler* handler, DataHandler* dataHandler) { qDebug() << "Thread finished. Deleting handler and thread."; handler->deleteLater(); dataHandler->deleteLater(); thread->deleteLater(); } bool initializeMdns() { #ifdef _WIN32 WORD versionWanted = MAKEWORD(1, 1); WSADATA wsaData; if (WSAStartup(versionWanted, &wsaData)) { qDebug() << "Failed to initialize WinSock"; return false; } #else // 设置中断信号处理器 signal(SIGINT, [](int signal) { qDebug() << "SIGINT received, cleaning up..."; // 处理退出信号的资源释放逻辑(如果需要) }); #endif qDebug() << "mDNS initialization completed."; return true; } QVector list_network_adapters() { QVector ipList; #ifdef _WIN32 ULONG family = AF_UNSPEC; // Both IPv4 and IPv6 ULONG flags = GAA_FLAG_INCLUDE_PREFIX; ULONG buffer_size = 15000; PIP_ADAPTER_ADDRESSES addresses = NULL; PIP_ADAPTER_ADDRESSES current_address = NULL; addresses = (IP_ADAPTER_ADDRESSES*)malloc(buffer_size); if (addresses == NULL) { qDebug() << "Failed to allocate memory."; return ipList; } if (GetAdaptersAddresses(family, flags, NULL, addresses, &buffer_size) == NO_ERROR) { current_address = addresses; while (current_address) { // Skip loopback interfaces if (current_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK || current_address->OperStatus != IfOperStatusUp) { current_address = current_address->Next; continue; } qDebug() << "Adapter:" << QString::fromWCharArray(current_address->FriendlyName); IP_ADAPTER_UNICAST_ADDRESS* unicast = current_address->FirstUnicastAddress; while (unicast) { SOCKADDR* addr = unicast->Address.lpSockaddr; char ip[INET6_ADDRSTRLEN] = { 0 }; if (addr->sa_family == AF_INET) { struct sockaddr_in* ipv4 = (struct sockaddr_in*)addr; inet_ntop(AF_INET, &ipv4->sin_addr, ip, sizeof(ip)); qDebug() << " IPv4:" << ip; ipList.append(QString::fromStdString(ip)); } else if (addr->sa_family == AF_INET6) { struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)addr; inet_ntop(AF_INET6, &ipv6->sin6_addr, ip, sizeof(ip)); qDebug() << " IPv6:" << ip; // IPv6 地址处理逻辑保留,但不添加到 ipList } unicast = unicast->Next; } current_address = current_address->Next; } } else { qDebug() << "Failed to get adapter addresses."; } free(addresses); #else struct ifaddrs* ifaddr = NULL; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); return ipList; } struct ifaddrs* current = ifaddr; while (current) { if (current->ifa_addr && (current->ifa_flags & IFF_UP)) { // Skip loopback interfaces if (strcmp(current->ifa_name, "lo") == 0) { current = current->ifa_next; continue; } char ip[INET6_ADDRSTRLEN] = { 0 }; if (current->ifa_addr->sa_family == AF_INET) { struct sockaddr_in* ipv4 = (struct sockaddr_in*)current->ifa_addr; inet_ntop(AF_INET, &ipv4->sin_addr, ip, sizeof(ip)); qDebug() << "Adapter:" << current->ifa_name; qDebug() << " IPv4:" << ip; ipList.append(QString::fromStdString(ip)); } else if (current->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)current->ifa_addr; inet_ntop(AF_INET6, &ipv6->sin6_addr, ip, sizeof(ip)); qDebug() << "Adapter:" << current->ifa_name; qDebug() << " IPv6:" << ip; // IPv6 地址处理逻辑保留,但不添加到 ipList } } current = current->ifa_next; } freeifaddrs(ifaddr); #endif return ipList; } // 注册QItemSelection类型 //qRegisterMetaType(); // 初始化 UI 组件和服务器 MainWidget::MainWidget(QWidget* parent) : QWidget(parent), nextClientId(1), nextSerialId(1), manualSend(false), isSendingAll(false), lastClickedGetPicCamIndex(-1), lastClickedGetPicDevIndex(-1), lastClickedGetVideoCamIndex(-1), lastClickedGetVideoDevIndex(-1), //mServiceProvider(new ServiceProvider(this)), mdnsTimer(new QTimer(this)), httpClient(new HttpClient(this)), httpServer(new QTcpServer(this)), mdnsThread(nullptr) #if TEST_UDP_BROADCAST ,multicastSocket(new QUdpSocket(this)), multicastTimer(new QTimer(this)) #endif { QString configFilePath = QDir::currentPath() + "/UI_config.ini"; TOOL_UI = loadConfig(configFilePath); leftLens_imageLabel = new QLabel(this); rightLens_imageLabel = new QLabel(this); leftLens_imageLabel_back = new QLabel(this); rightLens_imageLabel_back = new QLabel(this); leftLens_imageLabel_all = new QLabel(this); rightLens_imageLabel_all = new QLabel(this); videoLabel = new QLabel(this); video_Label_back = new QLabel(this); video_Label_all = new QLabel(this); frontFuncConfigLineEdit = new QLineEdit(this); backFuncConfigLineEdit = new QLineEdit(this); licenseHwInfoEdit = new QTextEdit(this); UuidHwInfoEdit = new QTextEdit(this); setupUI(); // 初始化 mDNS if (!initializeMdns()) { qDebug() << "Failed to initialize mDNS. Exiting..."; return; } //list_network_adapters(); setupHttpServer(); // 打印线程池状态信息 setupTimerForThreadPoolInfo(); QThread* DataSendThread = new QThread(this); // 必须在 DataSendThread 里创建 serialPortHandler connect(DataSendThread, &QThread::started, this, [this]() { serialPortHandler = new SerialPortHandler(serialComPortComboBox, serialConnectButton, frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig, frontBoardDevInfoJson, frontBoardLicenseJson, backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson, backBoardUuidJson, getPicJson, getVideoJson, nullptr); serialPortHandler->moveToThread(QThread::currentThread()); // 绑定到 DataSendThread qDebug() << "serialPortHandler created in thread:" << QThread::currentThread(); // 初始化 SerialPortHandler 和定时器(必须在 DataSendThread 内部) QMetaObject::invokeMethod(serialPortHandler, "initializeSerialPort", Qt::QueuedConnection); QMetaObject::invokeMethod(serialPortHandler, "initializeTimers", Qt::QueuedConnection); // 连接信号和槽确保在 DataSendThread connect(this, &MainWidget::requestDevInfo, serialPortHandler, &SerialPortHandler::sendDevInfoItem, Qt::QueuedConnection); connect(serialPortHandler, &SerialPortHandler::startTimeout, serialPortHandler, &SerialPortHandler::OnStartTimeout, Qt::QueuedConnection); connect(serialPortHandler, &SerialPortHandler::requestShowDialog, this, &MainWidget::onShowDialog, Qt::QueuedConnection); connect(serialPortHandler, &SerialPortHandler::allItemsProcessed, this, &MainWidget::onAllItemsProcessed); connect(serialPortHandler, &SerialPortHandler::serialDataReceived, this, &MainWidget::onSerialDataReceived); connect(serialPortHandler, &SerialPortHandler::HandleInvalidOperate, this, &MainWidget::onHandleInvalidOperate); connect(serialPortHandler, &SerialPortHandler::serialComPortDisconnected, this, [this]() { qDebug() << "-------- nextSerialId =" << nextSerialId; startServerButton->setStyleSheet(""); sendAllButton->setEnabled(false); isReplyOrTimeout = true; connectedClientsCount--; updateServerButtonText(); if (serialDataHandlers.contains(nextSerialId - 1)) { SerialDataHandler* serialDataHandler = serialDataHandlers[nextSerialId - 1]; serialDataHandlers.remove(nextSerialId - 1); // 从容器中移除 serialDataHandler->deleteLater(); // 延迟删除 serialDataHandler 对象 } }); qDebug() << "MainWidget ------- Current thread:" << QThread::currentThread(); connect(serialPortHandler, &SerialPortHandler::serialComPortConnected, this, [this]() { //qDebug() << "--------mm-----------"; int serialId = nextSerialId++; connectedClientsCount++; isFirstSendDevInfo = true; updateServerButtonText(); startServerButton->setStyleSheet("background-color: green;"); sendAllButton->setEnabled(true); QThread* DataHandlerThread = new QThread(this); SerialDataHandler* serialDataHandler = new SerialDataHandler(videoLabel, video_Label_back, VideoResolutionEdit, VideoResolutionEdit_back, leftLens_imageLabel->size(), &devInfoLineEdits, isBackBoardOrAllBoard, frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig, frontBoardDevInfoJson, frontBoardLicenseJson, backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson, backBoardUuidJson, getPicJson, getVideoJson, nullptr); // 将 serialDataHandler 移到线程池中的线程 serialDataHandler->moveToThread(DataHandlerThread); connect(DataHandlerThread, &QThread::finished, serialDataHandler, &QObject::deleteLater); connect(serialDataHandler, &SerialDataHandler::startTimeout, serialPortHandler, &SerialPortHandler::OnStartTimeout, Qt::QueuedConnection); DataHandlerThread->start(); qDebug() << "Thread running:" << DataHandlerThread->isRunning(); //qDebug() << "SerialPortHandler thread:" << serialPortHandler->thread(); //qDebug() << "SerialDataHandler thread:" << serialDataHandler->thread(); bool isConnected = connect(serialPortHandler, &SerialPortHandler::dataReceived, serialDataHandler, &SerialDataHandler::handleData, Qt::QueuedConnection); //qDebug() << "-- Connection successful:" << isConnected; // 线程结束时删除 DataHandlerThread 对象 connect(DataHandlerThread, &QThread::finished, this, [=]() { qDebug() << "Thread finished. Deleting serialDataHandler and thread."; serialDataHandler->deleteLater(); if (DataHandlerThread) { DataHandlerThread->deleteLater(); } }); connect(this, &MainWidget::openFocusWindow, serialDataHandler, &SerialDataHandler::handleOpenFocusWindow, Qt::UniqueConnection); connect(serialPortHandler, &SerialPortHandler::statusUpdated, this, &MainWidget::onStatusUpdated, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::statusUpdated, this, &MainWidget::onStatusUpdated, Qt::UniqueConnection); serialDataHandlers[serialId] = serialDataHandler; connect(serialDataHandler, &SerialDataHandler::sendHeartBeatData, serialPortHandler, &SerialPortHandler::onSendHeartBeatData); connect(serialDataHandler, &SerialDataHandler::recvNormalDataFlag, serialPortHandler, &SerialPortHandler::onRecvNormalDataFlag); connect(serialDataHandler, &SerialDataHandler::updateLicenseHwInfoEdit, this, [this](const QString& text) { licenseHwInfoEdit->setPlainText(text); }, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::updateUuidHwInfoEdit, this, [this](const QString& text) { UuidHwInfoEdit->setPlainText(text); }, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::updateLeftLensImage, leftLens_imageLabel, &QLabel::setPixmap, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::updateRightLensImage, rightLens_imageLabel, &QLabel::setPixmap, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::updateVideoLabel, videoLabel, &QLabel::setPixmap, Qt::UniqueConnection); connect(serialDataHandler, &SerialDataHandler::updateVideoResolution, VideoResolutionEdit, &QLineEdit::setText, Qt::UniqueConnection); connect(serialPortHandler, &SerialPortHandler::currentSendItem, serialDataHandler, &SerialDataHandler::getCurrentSendItem); connect(serialPortHandler, &SerialPortHandler::updateTimeout, serialDataHandler, &SerialDataHandler::onUpdateTimeout); connect(serialPortHandler, &SerialPortHandler::startImageSharing, this, &MainWidget::onStartImageSharing); connect(serialDataHandler, &SerialDataHandler::picRecvFinished, serialPortHandler, &SerialPortHandler::onPicRecvFinished); connect(serialDataHandler, &SerialDataHandler::commandError, serialPortHandler, &SerialPortHandler::onCommandError); // 前板有设备连接自动发送获取设备信息 //serialPortHandler->sendDevInfoItem(); }); }); connect(DataSendThread, &QThread::finished, this, [this]() { if (serialPortHandler) { serialPortHandler->deleteLater(); serialPortHandler = nullptr; } }); DataSendThread->start(); server = new QTcpServer(this); connect(server, &QTcpServer::newConnection, this, [this]() { while (server->hasPendingConnections()) { QTcpSocket* socket = server->nextPendingConnection(); int clientId = nextClientId ++; QHostAddress clientIp = socket->peerAddress(); quint16 clientPort = socket->peerPort(); QString ipString = clientIp.toString(); isReplyOrTimeout = true; if (ipString.startsWith("::ffff:")) { ipString = ipString.mid(7); } qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; qDebug() << "> A client is connected. ID:" << clientId; qDebug() << "> Client IP:" << ipString << " Port:" << clientPort; qDebug() << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; if (ipString.startsWith("10.10.10")) { //if (1) { qDebug() << "The client IP address is front board !!!"; isBackBoardOrAllBoard = 0; } else { onDisconnectClient(clientId - 1); qDebug() << "The client IP address is back board or all board"; isBackBoardOrAllBoard = clientId; } //stopMdnsService(); connectedClientsCount ++; updateServerButtonText(); QTimer* timer = new QTimer(this); timer->setSingleShot(true); clientTimers[clientId] = timer; // 连接定时器超时信号到槽函数 connect(timer, &QTimer::timeout, this, [this, clientId]() { //qDebug() << "Timeout occurred for client ID:" << clientId; for (ClientHandler* handler : clients) { if (handler->getClientId() == clientId) { bool invoked = QMetaObject::invokeMethod(handler, "onTimeout", Qt::DirectConnection); if (!invoked) { qWarning() << "Failed to invoke onTimeout for client ID:" << clientId; } } } }); QThread* thread = new QThread(this); ClientHandler* handler = new ClientHandler(frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig, frontBoardDevInfoJson, frontBoardLicenseJson, backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson, backBoardUuidJson, getPicJson, getVideoJson, clientId, isBackBoardOrAllBoard, nullptr); // 将 socket 移动到新的线程中,一定要先取消父对象 socket->setParent(nullptr); socket->moveToThread(thread); // 将 socket 传递到 handler handler->initialize(socket); DataHandler* dataHandler = new DataHandler(videoLabel, video_Label_back, VideoResolutionEdit, VideoResolutionEdit_back, leftLens_imageLabel->size(), &devInfoLineEdits, isBackBoardOrAllBoard, frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig, frontBoardDevInfoJson, frontBoardLicenseJson, backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson, backBoardUuidJson, getPicJson, getVideoJson, nullptr); // 将 ClientHandler 和 DataHandler 移到线程池中的线程 handler->moveToThread(thread); dataHandler->moveToThread(thread); connect(handler, &ClientHandler::sendData, handler, &ClientHandler::onSendData, Qt::QueuedConnection); connect(handler, &ClientHandler::startTimeout, this, [this, clientId](int timeout) { this->onStartTimeout(clientId, timeout); }); clients.append(handler); clients_1[clientId] = handler; clientThreads[clientId] = thread; connect(handler, &ClientHandler::statusUpdated, this, &MainWidget::onStatusUpdated); connect(handler, &ClientHandler::HandleInvalidOperate, this, &MainWidget::onHandleInvalidOperate); connect(handler, &ClientHandler::clientDisconnected, this, &MainWidget::onClientDisconnected); connect(handler, &ClientHandler::allItemsProcessed, this, &MainWidget::onAllItemsProcessed); //connect(handler, &ClientHandler::selectClientDisconnected, this, &MainWidget::onDisconnectClient); dataHandlers[clientId] = dataHandler; connect(handler, &ClientHandler::dataReceived, dataHandler, &DataHandler::handleData); connect(handler, &ClientHandler::currentSendItem, dataHandler, &DataHandler::getCurrentSendItem); connect(dataHandler, &DataHandler::picRecvFinished, handler, &ClientHandler::onPicRecvFinished); connect(dataHandler, &DataHandler::commandError, handler, &ClientHandler::onCommandError); connect(dataHandler, &DataHandler::statusUpdated, this, &MainWidget::onStatusUpdated); // 当线程结束时删除 handler connect(thread, &QThread::finished, this, [=]() { onThreadFinished(thread, handler, dataHandler); }); connect(dataHandler, &DataHandler::updateLicenseHwInfoEdit, this, [this](const QString& text) { licenseHwInfoEdit->setPlainText(text); }); connect(dataHandler, &DataHandler::updateUuidHwInfoEdit, this, [this](const QString& text) { UuidHwInfoEdit->setPlainText(text); }); connect(dataHandler, &DataHandler::updateLeftLensImage, leftLens_imageLabel, &QLabel::setPixmap); connect(dataHandler, &DataHandler::updateRightLensImage, rightLens_imageLabel, &QLabel::setPixmap); connect(dataHandler, &DataHandler::updateVideoLabel, videoLabel, &QLabel::setPixmap); connect(dataHandler, &DataHandler::updateVideoResolution, VideoResolutionEdit, &QLineEdit::setText); // 启动新的线程 thread->start(); connect(handler, &ClientHandler::startReadTimer, this, &MainWidget::startClientReadTimer); connect(handler, &ClientHandler::stopReadTimer, this, &MainWidget::stopClientReadTimer); connect(this, &MainWidget::openFocusWindowRequested, dataHandler, &DataHandler::handleOpenFocusWindow); // 创建和管理定时器 QTimer* readTimer = new QTimer(this); connect(readTimer, &QTimer::timeout, handler, &ClientHandler::onTimeoutRead); // readTimer->start(10); // 每 10ms 触发一次 // 将定时器存储到哈希表中,方便管理 clientReadTimers[clientId] = readTimer; connect(handler, &ClientHandler::sendDataToSomeClient, this, &MainWidget::sendDataToClient); connect(handler, &ClientHandler::startImageSharing, this, &MainWidget::onStartImageSharing); if (isBackBoardOrAllBoard != 0) { handler->sendDevInfoItem(); } } }); connect(httpClient, &HttpClient::requestFinished, this, &MainWidget::onHttpRequestFinished); connect(httpClient, &HttpClient::requestError, this, &MainWidget::onHttpRequestError); threadStatusTimer = new QTimer(this); connect(threadStatusTimer, &QTimer::timeout, this, &MainWidget::onCheckThreadStatus); //threadStatusTimer->start(100); // 每100ms检查一次线程状态 connectionStatusCheckTimer = new QTimer(this); connect(connectionStatusCheckTimer, &QTimer::timeout, this, &MainWidget::onCheckConnectionStatus); #if TEST_UDP_BROADCAST // 设置组播地址 QHostAddress groupAddress("224.0.0.251"); quint16 port = 5353; // 绑定UDP套接字 if (!multicastSocket->bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) { qWarning() << "Failed to bind multicast socket"; } // 加入组播组 bool joined = multicastSocket->joinMulticastGroup(groupAddress); if (!joined) { qWarning() << "Failed to join multicast group"; } // 定期发送组播消息 connect(multicastTimer, &QTimer::timeout, this, &MainWidget::sendMulticastMessage); multicastTimer->start(1000); // 每秒发送一次组播消息 #endif } MainWidget::~MainWidget() { stopMdnsService(); for (auto timer : clientReadTimers) { timer->stop(); delete timer; } clientReadTimers.clear(); for (auto dataHandler : dataHandlers) { dataHandler->deleteLater(); } dataHandlers.clear(); for (ClientHandler* handler : clients) { handler->deleteLater(); } server->close(); for (auto thread : clientThreads) { thread->quit(); thread->wait(); delete thread; } clientThreads.clear(); for (auto handler : clients_1) { handler->deleteLater(); } clients_1.clear(); for (auto timer : clientTimers) { timer->stop(); delete timer; } clientTimers.clear(); if (server->isListening()) { server->close(); } qDebug() << "MainWidget destroyed"; } void MainWidget::onShowDialog() { //qDebug() << "------------------------onShowDialog--------------------------"; DelUserWindow dialog(this); dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint); dialog.activateWindow(); dialog.raise(); QString userInput; if (dialog.exec() == QDialog::Accepted) { userInput = dialog.getUserInput(); } else { userInput = ""; } emit serialPortHandler->dialogResultReceived(userInput); } void MainWidget::sendLicenseData(int itemIndex, const QString text) { qDebug() << "------------ text:" << text; QJsonObject currentItem = frontBoardLicenseJson[itemIndex].toObject(); if (!text.isEmpty() && currentItem.contains("val")) { QJsonValue originalValue = currentItem["val"]; qDebug() << "text:" << text; if (originalValue.isDouble()) { bool ok; double doubleValue = text.toDouble(&ok); if (ok) { currentItem["val"] = doubleValue; } else { qWarning() << "Text conversion to double failed, original value is kept."; } } else if (originalValue.isString()) { currentItem["val"] = text; } } QString itemData = QJsonDocument(currentItem).toJson(); sendSerialData(itemData.toUtf8(), 0); } void MainWidget::sendSerialData(const QByteArray& data, bool heartBeat) { if (serialPortHandler) { serialPortHandler->sendData(data, heartBeat); } } QByteArray MainWidget::hexStringToByteArray(const QString& hexString) { QByteArray byteArray; for (int i = 0; i < hexString.length(); i += 2) { byteArray.append(static_cast(hexString.mid(i, 2).toUShort(nullptr, 16))); } return byteArray; } void MainWidget::onSerialDataReceived(const QByteArray& data) { //qDebug() << "Recv data (HEX):" << data.toHex(' ').toUpper(); qDebug() << "Recv data:<-----" << data.toHex(); QString receiveData = data.toHex(); QString heartData = "aa55aa5538010100000000"; QString licenseData = "aa55aa552004"; if (receiveData == heartData) { // 更新 UI 或处理数据 QByteArray payload; payload.append(static_cast(0x00)); // 构造需要发送的数据内容 bool heartBeat = true; sendSerialData(payload, heartBeat); } else { bool success = (static_cast(data.at(10)) != 0x00); if (data.mid(0, 6) == QByteArray::fromHex("aa55aa552004")) { int dataSize = (static_cast(data.at(9)) << 24) | (static_cast(data.at(8)) << 16) | (static_cast(data.at(7)) << 8) | (static_cast(data.at(6))); int totalSize = 10 + dataSize; QByteArray licenseData = data.mid(11, dataSize); QString hexString = QString::fromUtf8(licenseData.toHex().data()); QByteArray actual_data = hexStringToByteArray(hexString); qDebug() << "GET_FRONT_HW_INFO"; QStringList hexList; QString dataStr; if (actual_data.size() == PIX_HARDWARE_INFO_BYTES) { for (int i = 0; i < actual_data.size(); ++i) { hexList << QString("0x%1").arg(static_cast(actual_data[i]), 2, 16, QLatin1Char('0')).toUpper().replace("0X", "0x"); } dataStr = hexList.join(", "); } else dataStr = "前板发送的 HW INFO 数据大小不正确"; QString displayText = dataStr; //licenseHwInfoEdit->setPlainText(displayText); //emit updateLicenseHwInfoEdit(displayText); licenseHwInfoEdit->setPlainText(displayText); } else if (data.mid(0, 6) == QByteArray::fromHex("aa55aa552104")) { qDebug() << "currentIndex :" << currentIndex; QString label = ""; if (currentIndex >= 0 && currentIndex < frontBoardLicenseJson.size()) { QJsonObject jsonObject = frontBoardLicenseJson.at(currentIndex).toObject(); if (jsonObject.contains("lable")) { label = jsonObject["lable"].toString(); qDebug() << "label :" << label; } } QListWidgetItem* listItem = new QListWidgetItem(QString("device ID: %1 - Item %2: %3 ---> %4") .arg(nextSerialId - 1) .arg(currentIndex + 1) .arg(label) .arg(success ? "OK" : "NG"), statusListWidget); listItem->setBackground(success ? Qt::green : Qt::red); statusListWidget->addItem(listItem); statusListWidget->scrollToBottom(); } } } // 处理客户端断开连接信号 void MainWidget::onClientDisconnected(ClientHandler* handler) { int clientId = handler->getClientId(); int preVideoId = handler->preVideoClientId; int boardTpye = isBackBoardOrAllBoard; if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; timer->stop(); delete timer; clientTimers.remove(clientId); } clients.removeOne(handler); /* 将 ClientHandler 对象的删除操作放入事件队列中,等待事件循环处理。 在事件循环执行时,会安全地删除 ClientHandler 对象,这包括释放其占用的资源和内存 */ handler->deleteLater(); // 延迟删除 ClientHandler 对象 if (dataHandlers.contains(clientId)) { DataHandler* dataHandler = dataHandlers[clientId]; dataHandlers.remove(clientId); // 从容器中移除 dataHandler->deleteLater(); // 延迟删除 DataHandler 对象 } // 更新连接数并更新按键文本 connectedClientsCount--; //qDebug() << " connectedClientsCount :" << connectedClientsCount; if (nextClientId <= 2) nextClientId --; deviceConnected = true; updateServerButtonText(); int count = 200; while (count--); qDebug() << " preVideoClientId :" << preVideoId; qDebug() << " clientId :" << clientId; if ((boardTpye != 0) || (preVideoId == clientId)) { qDebug() << "Current path: " << QDir::currentPath(); QString filePath = QDir::currentPath() + "/add1.h264"; if (QFile::exists(filePath)) { QFile file(filePath); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qDebug() << "File add1.h264 cleared successfully."; } else { qDebug() << "Failed to clear file add1.h264:" << file.errorString(); } } else { qDebug() << "File add1.h264 does not exist."; } } } void MainWidget::onDisconnectClient(int clientId) { for (ClientHandler* handler : clients) { if (handler->getClientId() == clientId) { // 断开与该客户端的连接 if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; timer->stop(); delete timer; clientTimers.remove(clientId); } clients.removeOne(handler); handler->deleteLater(); if (dataHandlers.contains(clientId)) { DataHandler* dataHandler = dataHandlers[clientId]; dataHandlers.remove(clientId); // 从容器中移除 dataHandler->deleteLater(); // 延迟删除 DataHandler 对象 } int count = 200; int preVideoId = handler->preVideoClientId; int boardTpye = isBackBoardOrAllBoard; while (count--); qDebug() << " preVideoClientId :" << preVideoId; qDebug() << " clientId :" << clientId; if ((boardTpye != 0) || (preVideoId == clientId)) { qDebug() << "Current path: " << QDir::currentPath(); QString filePath = QDir::currentPath() + "/add1.h264"; if (QFile::exists(filePath)) { QFile file(filePath); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qDebug() << "File add1.h264 cleared successfully."; } else { qDebug() << "Failed to clear file add1.h264:" << file.errorString(); } } else { qDebug() << "File add1.h264 does not exist."; } } connectedClientsCount--; //qDebug() << " connectedClientsCount :" << connectedClientsCount; updateServerButtonText(); break; } } stopMdnsService(); //if (connectedClientsCount == 0) { // // 启动 mDNS 服务广播 // startMdnsService(); //} } // 更新按键文本的函数 void MainWidget::updateServerButtonText() { if (deviceConnected) { if (connectedClientsCount > 0) { startServerButton->setText(tr("正在监听(Listening)\n%1 台设备连接").arg(connectedClientsCount)); } else if (connectedClientsCount == 0) { #if START_MDNS // 这里会开启多个mdns广播,去掉 startMdnsService(getSelectedIp()); #endif deviceConnected = false; startServerButton->setText(tr("正在监听(Listening)")); } } else if (connectedClientsCount == 0) { startServerButton->setText(tr("开始监听\n(Start Listening...)")); } else { startServerButton->setText(tr("正在监听(Listening)\n%1 台设备连接").arg(connectedClientsCount)); } } void MainWidget::setupUI() { // 左侧部分 UI 元素 startServerButton = new QPushButton(TOOL_UI.START_LISTENING, this); startServerButton->setFixedSize(190, 70); sendAllButton = new QPushButton(TOOL_UI.ONE_CLICKED_TEST, this); sendAllButton->setFixedSize(190, 70); sendAllButton->setEnabled(false); statusListWidget = new QListWidget(this); statusListWidget->setMinimumSize(350, 840); statusListWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->addWidget(startServerButton); buttonLayout->addWidget(sendAllButton); buttonLayout->addStretch(); QLabel* serialComPortLabel = new QLabel("COM Port:", this); serialComPortComboBox = new QComboBox(this); serialComPortComboBox->setFixedSize(220, 28); // 创建一个连接按钮 serialConnectButton = new QPushButton("连接", this); serialConnectButton->setFixedSize(70, 28); // 创建一个新的水平布局,并将这三个元素添加到该布局 QHBoxLayout* comPortLayout = new QHBoxLayout; comPortLayout->addWidget(serialComPortLabel); comPortLayout->addWidget(serialComPortComboBox); comPortLayout->addWidget(serialConnectButton); QLabel* ipLabel = new QLabel("Select MDns IP:", this); ipComboBox = new QComboBox(this); ipComboBox->setFixedSize(260, 28); ipComboBox->clear(); // 获取网络适配器的 IPv4 地址列表 QVector ipAddresses = list_network_adapters(); for (const QString& ip : ipAddresses) { ipComboBox->addItem(ip); } QHBoxLayout* ipSelectionLayout = new QHBoxLayout; ipSelectionLayout->addWidget(ipLabel); ipSelectionLayout->addWidget(ipComboBox); ipSelectionLayout->addStretch(); QVBoxLayout* leftLayout = new QVBoxLayout; leftLayout->addLayout(buttonLayout); leftLayout->addLayout(comPortLayout); leftLayout->addLayout(ipSelectionLayout); leftLayout->setStretch(0, 1); leftLayout->addWidget(statusListWidget); leftLayout->setStretch(1, 200); saveCheckBox = new QCheckBox("", this); saveCheckBox->setChecked(true); selectFileButton = new QPushButton("Save", this); selectFileButton->setFixedSize(45, 28); clearLogButton = new QPushButton("Clear", this); clearLogButton->setFixedSize(55, 28); filePathLineEdit = new QLineEdit(this); filePathLineEdit->setFixedSize(250, 28); filePathLineEdit->setReadOnly(true); QHBoxLayout* fileLayout = new QHBoxLayout; fileLayout->addWidget(saveCheckBox); fileLayout->addWidget(selectFileButton); fileLayout->addWidget(filePathLineEdit); fileLayout->addWidget(clearLogButton); leftLayout->addLayout(fileLayout); leftLayout->setStretch(2, 1); // 读取 JSON 配置文件 readJsonConfig(); QWidget* leftContainer = new QWidget(this); leftContainer->setLayout(leftLayout); leftContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QTabWidget* mainTabWidget = new QTabWidget(this); VideoResolutionEdit = new QLineEdit(this); VideoResolutionEdit_back = new QLineEdit(this); VideoResolutionEdit_all = new QLineEdit(this); // 添加前板、后板、整机的布局 addDeviceAreaTab(mainTabWidget, TOOL_UI.FRONT_BOARD_NAME, createFrontDeviceInfoGroupBox(), createLicenseGroupBox(), frontBoardTest, frontBoardFuncConfig, "frontBoardTest", "frontBoardFuncConfig", TOOL_UI.FRONT_TEST_ITEM, TOOL_UI.FRONT_CONFID_ITEM, leftLens_imageLabel, rightLens_imageLabel, videoLabel, VideoResolutionEdit); addDeviceAreaTab(mainTabWidget, TOOL_UI.BACK_BOARD_NAME, createBackDeviceInfoGroupBox(), createBackConnectServerGroupBox(), backBoardTest, backBoardFuncConfig, "backBoardTest", "backBoardFuncConfig", TOOL_UI.BACK_TEST_ITEM, TOOL_UI.BACK_CONFID_ITEM, leftLens_imageLabel_back, rightLens_imageLabel_back, video_Label_back, VideoResolutionEdit_back); addAllDeviceAreaTab(mainTabWidget, TOOL_UI.ALL_BOARD_NAME, allBoardTest, allBoardFuncConfig, "allBoardTest", "allBoardFuncConfig", TOOL_UI.ALL_TEST_ITEM, TOOL_UI.ALL_CONFID_ITEM, leftLens_imageLabel_all, rightLens_imageLabel_all, video_Label_all, VideoResolutionEdit_all); // 右侧主布局 QVBoxLayout* rightVerticalLayout = new QVBoxLayout; rightVerticalLayout->addWidget(mainTabWidget, 5); // 主布局 QHBoxLayout* mainLayout = new QHBoxLayout; mainLayout->addWidget(leftContainer, 1, Qt::AlignTop | Qt::AlignLeft); mainLayout->addLayout(rightVerticalLayout, 3); setLayout(mainLayout); setWindowTitle(TOOL_UI.TOOL_VERSION); resize(TOOL_UI.SL100_FACTORY_TOOL_W, TOOL_UI.SL100_FACTORY_TOOL_H); // 信号槽连接 connect(startServerButton, &QPushButton::clicked, this, &MainWidget::onStartServerClicked); connect(sendAllButton, &QPushButton::clicked, this, &MainWidget::onSendAllClicked); connect(statusListWidget, &QListWidget::itemChanged, this, &MainWidget::scrollToBottom); connect(selectFileButton, &QPushButton::clicked, this, &MainWidget::onSelectFileButtonClicked); connect(clearLogButton, &QPushButton::clicked, this, &MainWidget::onclearLogButtonClicked); connect(saveCheckBox, &QCheckBox::stateChanged, this, &MainWidget::onSaveCheckBoxStateChanged); } char* MainWidget::getSelectedIp() const { QString selectedIp = ipComboBox->currentText(); qDebug() << "Selected MDns IP:" << selectedIp; // 打印当前选中的 IP // 将 QString 转换为 std::string std::string ipStdString = selectedIp.toStdString(); // 动态分配内存存储 char* char* ipChar = new char[ipStdString.size() + 1]; strcpy(ipChar, ipStdString.c_str()); return ipChar; } void MainWidget::onStartImageSharing(int width, int height, QString img_type, std::function callback) { imagePath = QFileDialog::getOpenFileName(this, "选择图片", QDir::homePath(), "Images (*.png *.jpg *.jpeg)"); if (imagePath.isEmpty()) { qDebug() << "No image selected."; return; } // 加载图片并获取尺寸 QImage image(imagePath); if (image.isNull()) { qDebug() << "Failed to load image."; return; } QSize imageSize = image.size(); qDebug() << "Original image dimensions:" << imageSize.width() << "x" << imageSize.height(); // 判断是否需要裁剪 if (imageSize.width() > width || imageSize.height() > height) { int x = (imageSize.width() - width) / 2; // 左右裁剪 int y = (imageSize.height() - height) / 2; // 上下裁剪 // 裁剪图片中间部分 image = image.copy(x, y, width, height); qDebug() << "Cropped image dimensions:" << image.width() << "x" << image.height(); } else if(imageSize.width() < width || imageSize.height() < height) { isReplyOrTimeout = true; QString info = QString("您选择的图片尺寸小于 %1 x %2,请重新操作并选择正确的尺寸的图片!!!").arg(width).arg(height); LicenseConfirmWindow dialog(info); dialog.exec(); callback(""); return; } // 保存裁剪后的图片到服务器目录 QString croppedImagePath = QCoreApplication::applicationDirPath() + QString("/%1_image.jpg").arg(img_type); if (!image.save(croppedImagePath, "JPEG")) { qDebug() << "Failed to save cropped image."; return; } qDebug() << "Cropped image saved to:" << croppedImagePath; // 更新服务使用裁剪后的图片路径 this->imagePath = croppedImagePath; // 获取本地 IP 地址 QString localIP; QList addresses = QNetworkInterface::allAddresses(); for (const QHostAddress& addr : addresses) { if (addr.protocol() == QAbstractSocket::IPv4Protocol && addr != QHostAddress::LocalHost) { localIP = addr.toString(); break; } } if (localIP.isEmpty()) { qDebug() << "Failed to determine local IP address."; return; } // 构建下载 URL QString downloadUrl = QString("http://%1:%2/%3_image.jpg").arg(localIP).arg(serverPort).arg(img_type); qDebug() << "Download URL:" << downloadUrl; // 回调返回下载地址 callback(downloadUrl); } void MainWidget::setupHttpServer() { connect(httpServer, &QTcpServer::newConnection, this, [this]() { QTcpSocket* clientSocket = httpServer->nextPendingConnection(); connect(clientSocket, &QTcpSocket::readyRead, this, [this, clientSocket]() { handleHttpRequest(clientSocket); }); }); if (!httpServer->listen(QHostAddress::Any, serverPort)) { qDebug() << "Failed to start HTTP server:" << httpServer->errorString(); } else { qDebug() << "HTTP server started on port" << serverPort; } } void MainWidget::handleHttpRequest(QTcpSocket* clientSocket) { QByteArray requestData = clientSocket->readAll(); qDebug() << "HTTP Request:" << requestData; if (imagePath.isEmpty()) { clientSocket->write("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"); clientSocket->disconnectFromHost(); return; } QFile file(imagePath); if (!file.open(QIODevice::ReadOnly)) { clientSocket->write("HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n"); clientSocket->disconnectFromHost(); return; } QByteArray imageData = file.readAll(); file.close(); QString response = QString("HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: %1\r\n\r\n") .arg(imageData.size()); clientSocket->write(response.toUtf8()); clientSocket->write(imageData); clientSocket->disconnectFromHost(); } // 服务器响应 void MainWidget::onHttpRequestFinished(const QJsonObject& response) { isRequestSuccessful = 0; if (response.contains("msg") && response["msg"].toString() == "ok") { if (response.contains("data") && response["data"].isObject()) { licenseDataArray = response["data"].toObject(); isRequestSuccessful = 1; } } else isRequestSuccessful = 2; } void MainWidget::onHttpRequestError(const QString& errorString) { qWarning() << "HTTP request failed:" << errorString; isRequestSuccessful = 2; } // 生成随机字符串 QString generateRandomRequestID(int minBitStr, int maxBitStr) { const QString possibleCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~"; int length = QRandomGenerator::global()->bounded(minBitStr, maxBitStr); // 生成长度在minBitStr到maxBitStr之间 QString randomString; for (int i = 0; i < length; ++i) { int index = QRandomGenerator::global()->bounded(possibleCharacters.size()); randomString.append(possibleCharacters.at(index)); } qDebug() << "randomString request_id:" << randomString; return randomString; } // 哈希256 转 base64 QString HmacSha256ToBase64(const QString& data, const QString& secret) { QByteArray keyBytes = secret.toUtf8(); QByteArray dataBytes = data.toUtf8(); // 使用 HMAC-SHA256 计算哈希值 QByteArray hash = QMessageAuthenticationCode::hash(dataBytes, keyBytes, QCryptographicHash::Sha256); qDebug() << "secret:" << secret; qDebug() << "hash (hex):" << hash.toHex(); qDebug() << "hash.toBase64():" << hash.toHex().toBase64(); // 将哈希值编码为 Base64 字符串 return hash.toHex().toBase64(); } // 计算签名 QString calculateSignature(const QMap& params, const QString& httpMethod, const QString& secret, const QString& request_id, const QString& timestamp) { // 1. 按字典序排序参数 QList> sortedParams; for (auto it = params.begin(); it != params.end(); ++it) { qDebug() << it.key() << ":" << it.value(); sortedParams.append(qMakePair(it.key(), it.value())); } std::sort(sortedParams.begin(), sortedParams.end()); qDebug() << "Sorted Params:"; for (const auto& param : sortedParams) { qDebug() << param.first << ":" << param.second; } // 2. URL 编码参数 QString canonicalizedQueryString; for (auto& param : sortedParams) { if (!canonicalizedQueryString.isEmpty()) { canonicalizedQueryString += "&"; } canonicalizedQueryString += QUrl::toPercentEncoding(param.first) + "=" + QUrl::toPercentEncoding(param.second); } qDebug() << "URL Canonicalized Query String:" << canonicalizedQueryString; // 3. 构造 BaseString //QString baseString = params["batch"] + params["label"] + params["model"] + params["request_id"] + params["timestamp"] + params["factory_id"]; //QString baseString = "1TEST_SL100_20240826SL100" + request_id + timestamp + FACTORY_ID; QString baseString = QString::number(BATCH) + QString(LABEL) + QString(MODEL) + request_id + timestamp + QString(FACTORY_ID); qDebug() << "baseString:" << baseString; // 4. 构造 stringToSign QString stringToSign = httpMethod + "&" + baseString + "&" + canonicalizedQueryString.replace("+", "%20"); qDebug() << "stringToSign:" << stringToSign; // 5. 计算签名 return HmacSha256ToBase64(stringToSign, secret); } // 请求头 void prepareRequestHeaders(QNetworkRequest& request, const QString& sign, const QString& request_id) { request.setRawHeader("factory_id", QByteArray(FACTORY_ID)); request.setRawHeader("label", QByteArray(LABEL)); request.setRawHeader("batch", QString::number(BATCH).toUtf8()); request.setRawHeader("model", QByteArray(MODEL)); request.setRawHeader("timestamp", QString::number(QDateTime::currentSecsSinceEpoch()).toUtf8()); request.setRawHeader("request_id", request_id.toUtf8()); request.setRawHeader("sign", sign.toUtf8()); request.setRawHeader("Content-Type", "application/json"); } // GET 请求 void sendGetRequest(HttpClient* httpClient, const QUrl& url, const QMap& params, const QString& secret) { QString request_id = generateRandomRequestID(1, 33); qDebug() << "request_id:" << request_id; QUrl modifiedUrl = url; QUrlQuery query; for (auto it = params.begin(); it != params.end(); ++it) { query.addQueryItem(it.key(), it.value()); } modifiedUrl.setQuery(query.query()); QString sign = calculateSignature(params, "GET", secret, request_id, QString::number(QDateTime::currentSecsSinceEpoch())); qDebug() << "sendGetRequest URL:" << modifiedUrl.toString(); QNetworkRequest request(modifiedUrl); prepareRequestHeaders(request, sign, request_id); //return; httpClient->sendGetRequest(request); } // POST 请求 void sendPostRequest(HttpClient* httpClient, const QUrl& url, const QMap& params, const QJsonObject& jsonData, const QString& secret) { QString request_id = generateRandomRequestID(1, 33); qDebug() << "request_id:" << request_id; QString sign = calculateSignature(params, "POST", secret, request_id, QString::number(QDateTime::currentSecsSinceEpoch())); qDebug() << "sendPostRequest URL:" << url.toString(); QNetworkRequest request(url); prepareRequestHeaders(request, sign, request_id); QByteArray jsonDataByteArray = QJsonDocument(jsonData).toJson(); //return; httpClient->sendPostRequest(request, jsonDataByteArray); } // GET 获取 UUID void MainWidget::FactoryToolSendGetUuidToHttpServer(const QString& mac_addr) { QUrl url("http://admin.hassecurity.cn/v1/getUuid"); QMap params = { {"label", "TEST_SL100_20240826"}, {"model", "SL100"}, {"batch", "1"}, {"mac", mac_addr} }; QString secret = "rCeOzwisLFLasvlt"; sendGetRequest(httpClient, url, params, secret); } // GET 查询 License void MainWidget::FactoryToolSendGetLicenseToHttpServer(const QString& hw_info) { QUrl url("http://admin.hassecurity.cn/v1/getAlgorithmKey"); QMap params = { {"id", hw_info} }; QString secret = "rCeOzwisLFLasvlt"; sendGetRequest(httpClient, url, params, secret); } // POST 确认烧录 void MainWidget::FactoryToolSendPostComfirmToHttpServer(const QString& mac_addr, const QString& uuid) { QUrl url("http://admin.hassecurity.cn/v1/confirm"); QMap params = { {"mac", mac_addr}, {"uuid", uuid} }; QJsonObject jsonData = { {"mac", mac_addr}, {"uuid", uuid} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } // POST 上报测试结果 void MainWidget::FactoryToolSendPostTestToHttpServer() { QUrl url("http://admin.hassecurity.cn/v1/testRecords"); QMap params = { {"id", "123456"}, {"location", "allMachine"} }; QString itemString = "[{\"function\":\"faceVerify\",\"msg\":\"timeout\",\"result\":false}]"; params["items"] = itemString; QJsonObject jsonItem = { {"function", "faceVerify"}, {"result", false}, {"msg", "timeout"} }; QJsonArray itemsArray; itemsArray.append(jsonItem); QJsonObject jsonData = { {"id", "123456"}, {"location", "allMachine"}, {"items", itemsArray} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } // POST 图语 License 上报 void MainWidget::FactoryToolSendPostLicenseToHttpServer(const QString& hardware_info, const QString& license_info) { QUrl url("http://admin.hassecurity.cn/v1/algorithmKey"); qint64 UTC_time = QDateTime::currentSecsSinceEpoch(); QMap params = { {"id", hardware_info}, {"key", license_info}, {"time", QString::number(UTC_time)} }; QJsonObject jsonData = { {"id", hardware_info}, {"key", license_info}, {"time", UTC_time} }; QString secret = "rCeOzwisLFLasvlt"; sendPostRequest(httpClient, url, params, jsonData, secret); } void MainWidget::startClientReadTimer(int clientId) { //qDebug() << "------ startClientReadTimer clientId:" << clientId; if (clientReadTimers.contains(clientId)) { clientReadTimers[clientId]->start(10); } } void MainWidget::stopClientReadTimer(int clientId) { qDebug() << "------ stopClientReadTimer clientId:" << clientId; if (clientReadTimers.contains(clientId)) { clientReadTimers[clientId]->stop(); } } void MainWidget::onCheckConnectionStatus() { int activeThreadCount = clients_1.size(); //qDebug() << "------Number of active threads:" << activeThreadCount; for (auto it = clients_1.begin(); it != clients_1.end(); ++it) { int clientId = it.key(); ClientHandler* handler = it.value(); QTcpSocket* socket = handler->getSocket(); if (socket->state() != QTcpSocket::ConnectedState) { qCritical() << "--------------Connection lost for clientId:" << clientId << ". Socket state:" << socket->state(); emit handler->clientDisconnected(handler); } else { qDebug() << "Connection for clientId:" << clientId << "is active."; } } } void MainWidget::onCheckThreadStatus() { //qDebug() << "Checking thread status..."; int activeThreadCount = clientThreads.size(); //qDebug() << "Number of active threads:" << activeThreadCount; for (auto it = clientThreads.begin(); it != clientThreads.end(); ++it) { int clientId = it.key(); QThread* thread = it.value(); ClientHandler* handler = nullptr; for (ClientHandler* h : clients) { if (h->getClientId() == clientId) { handler = h; break; } } if (handler && handler->isData_Stuck()) { qDebug() << "Thread for clientId:" << clientId << "is stuck."; // 处理线程卡住的情况,比如重启线程或记录更多日志 } else if (thread->isRunning()) { qDebug() << "isData_Stuck = :" << handler->isData_Stuck(); qDebug() << "Thread for clientId:" << clientId << "is running."; } else { qDebug() << "Thread for clientId:" << clientId << "is not running."; // 处理线程意外停止的情况 } } } // 打印线程池信息 void MainWidget::printThreadPoolInfo() { QThreadPool* threadPool = QThreadPool::globalInstance(); //qDebug() << "Active threads:" << threadPool->activeThreadCount(); //qDebug() << "Max threads:" << threadPool->maxThreadCount(); } void MainWidget::setupTimerForThreadPoolInfo() { QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWidget::printThreadPoolInfo); timer->start(5000); // 每5秒打印一次线程池信息 } void MainWidget::readJsonConfig() { frontBoardOneClickTest = readJson_frontBoardOneClickTest(); frontBoardTest = readJson_frontBoardTest(); frontBoardFuncConfig = readJson_frontBoardFuncConfig(); frontBoardDevInfoJson = readJson_frontDevInfo(); frontBoardLicenseJson = readJson_frontLicense(); //frontBoardCmdConfigJson = readJson_frontCmd_config(); backBoardOneClickTest = readJson_backBoardOneClickTest(); backBoardTest = readJson_backBoardTest(); backBoardFuncConfig = readJson_backBoardFuncConfig(); backBoardDevInfoJson = readJson_backDevInfo(); backBoardUuidJson = readJson_backUuid(); //backBoardCmdConfigJson = readJson_backCmd_config(); factoryProductInfo = readJson_factoryProductInfo(); allBoardTest = readJson_allBoardTest(); allBoardFuncConfig = readJson_allBoardFuncConfig(); getPicJson = readJson_getPic(); getVideoJson = readJson_getVideo(); } void MainWidget::onSelectFileButtonClicked() { QString filePath = QFileDialog::getSaveFileName(this, tr("选择文件路径"), "", tr("Text Files (*.txt);;All Files (*)")); if (!filePath.isEmpty()) { filePathLineEdit->setText(filePath); } } void MainWidget::onclearLogButtonClicked() { statusListWidget->clear(); } void MainWidget::onSaveCheckBoxStateChanged(int state) { if (state == Qt::Checked) checkBoxState = true; else checkBoxState = false; } void MainWidget::saveStatusListToFile(const QString& filePath) { QString actualFilePath = filePath; if (actualFilePath.isEmpty()) { QString defaultDirPath = QDir::currentPath() + "/TestLog"; QDir dir(defaultDirPath); if (!dir.exists()) { if (!dir.mkpath(defaultDirPath)) { qWarning() << "Failed to create directory:" << defaultDirPath; return; } } QString currentTime = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"); actualFilePath = defaultDirPath + "/" + currentTime + ".txt"; } QFile file(actualFilePath); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning() << "Failed to open file:" << actualFilePath; return; } QTextStream out(&file); for (int i = 0; i < statusListWidget->count(); ++i) { QListWidgetItem* item = statusListWidget->item(i); out << item->text() << "\n"; } file.close(); } void MainWidget::onCheckSerialRecvStatus() { } void MainWidget::onStartTimeout(int clientId, int timeout) { //qDebug() << "---------------> onStartTimeout :" << clientId << "timeout :" << timeout; if (clientId == -1) { qDebug() << "---------------> onStartTimeout :" << clientId << "timeout :" << timeout; /*if (timeout > 0) { serialTimer->start(timeout); } else { serialTimer->stop(); }*/ //serialPortHandler->OnStartTimeout(timeout); } else if (clientTimers.contains(clientId)) { QTimer* timer = clientTimers[clientId]; if (timeout > 0) { timer->start(timeout); } else { timer->stop(); } } } void MainWidget::scrollToBottom() { statusListWidget->scrollToBottom(); } QString formatLicenseKey(const QString& licenseKey) { QString formattedKey; qDebug() << "licenseKey.length():" << licenseKey.length(); for (int i = 0; i < licenseKey.length(); i += 2) { QString byteStr = licenseKey.mid(i, 2); // 每次取两个字符 formattedKey.append(QString("0x%1, ").arg(byteStr)); } if (!formattedKey.isEmpty()) { formattedKey.chop(2); } return formattedKey; } void MainWidget::onLicenseButtonClicked() { if (connectedClientsCount) //if (1) { QPushButton* button = qobject_cast(sender()); if (button) { int index = button->property("licenseIndex").toInt(); currentIndex = index; if (index >= 0 && index < frontBoardLicenseJson.size()) { QJsonObject jsonObject = frontBoardLicenseJson[index].toObject(); unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0 }; unsigned char license_info[PIX_LICENCE_BYTES] = { 0 }; QString dataStr = ""; if (jsonObject["lable"].toString() == "get_license") { QString hwInfoText = licenseHwInfoEdit->toPlainText(); if ((hwInfoText.count("0x") != PIX_HARDWARE_INFO_BYTES) && (hwInfoText.count("0x") != 0)) { isRequestSuccessful = 0; //licenseHwInfoEdit->setPlainText("您使用了License去获取License,这是不允许的!!!"); LicenseConfirmWindow dialog("您使用了License去获取License,这是不允许的!!!"); dialog.exec(); return; } else if (hwInfoText.count("0x") == 0) { isRequestSuccessful = 0; //licenseHwInfoEdit->setPlainText("您使用了License去获取License,这是不允许的!!!"); LicenseConfirmWindow dialog("没有检测到HWInfo,无法获取License!!!"); dialog.exec(); return; } dataStr = hwInfoText.remove(","); QString sendToHttpServerDataStr = dataStr.replace("0x", "").replace(" ", ""); // 去掉0x和空格 qDebug() << "sendToHttpServerDataStr:" << sendToHttpServerDataStr; FactoryToolSendGetLicenseToHttpServer(sendToHttpServerDataStr); while (isRequestSuccessful == 0) { QCoreApplication::processEvents(); // 防止阻塞线程 } qDebug() << "isRequestSuccessful:" << isRequestSuccessful; if (isRequestSuccessful == 2) { isRequestSuccessful = 0; return; } else if(isRequestSuccessful == 1) { if (licenseDataArray.contains("has") && licenseDataArray["has"].toBool()) { qDebug() << "Found item with 'has' = true"; if (licenseDataArray.contains("key")) { QString licenseKey = licenseDataArray["key"].toString(); licenseKey = formatLicenseKey(licenseKey); licenseHwInfoEdit->setPlainText(licenseKey); qDebug() << "HTTP Server License is:" << licenseKey; isRequestSuccessful = 0; return; } } else if (licenseDataArray.contains("has")) { qDebug() << "licenseDataArray[\"has\"].toBool():" << licenseDataArray["has"].toBool(); } } QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(hardware_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_HARDWARE_INFO_BYTES)); //unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0x46,0x0b,0x5d,0x11,0x58,0x17,0x4d,0x5e,0x55,0x5c,0x51,0x4a,0x5a,0x07,0x59,0x4c,0x5f,0x45,0x5b,0x5f,0x5a,0x45,0x1c,0x5a,0x45,0x43,0x44,0x47,0x51,0x5e,0x44,0x30 }; LicenseConfirmWindow dialog("您确定要获取此授权吗?\n请确认您的hw_info是否正确并且电脑插好U盘!"); if (dialog.exec() == QDialog::Accepted) { #if !MANUAL_UPLOAD_LICENSE if (!(licenseGenerate(hardware_info, license_info))) { qDebug() << "从U盘获取License失败"; isRequestSuccessful = 0; licenseHwInfoEdit->setPlainText("从U盘获取License失败,请检查U盘是否插入电脑!!!"); return; } QString licenseInfoHex = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex().toUpper(); #else //unsigned char license_info_1[PIX_LICENCE_BYTES] = { 0x07, 0xe8, 0xf3, 0x80, 0xa8, 0x07, 0x72, 0xa1, 0x17, 0xfe, 0xda, 0x67, 0xbd, 0x4a, 0x5a, 0xb5, 0xbb, 0x8b, 0x2d, 0xb2, 0xbf, 0x89, 0x74, 0xe5, 0xb0, 0x99, 0x70, 0x74, 0x3c, 0x6f, 0xf8, 0x82, 0x79, 0xab, 0x31, 0x9c, 0xdf, 0xe8, 0x9e, 0x75, 0x8f, 0x42, 0xb3, 0xcf, 0x00, 0x60, 0xa0, 0x38, 0xa4, 0xb8, 0xbe, 0xa6, 0x5d, 0x9f, 0x8b, 0x41, 0xf3, 0x0a, 0x69, 0xf6, 0x50, 0x94, 0x3f, 0xd0, 0xa5, 0xee, 0x88, 0x20, 0x93, 0x9a, 0x1c, 0xe9, 0x64, 0xd3, 0xaf, 0x9f, 0xc7, 0x66, 0x00, 0x7d, 0x7d, 0x68, 0xf1, 0xa4, 0xe1, 0x58, 0x00, 0x1d, 0x03, 0x0d, 0x40, 0x08, 0xa4, 0xcc, 0x0b, 0xd8, 0x19, 0x70, 0x9a, 0x83, 0x81, 0xbf, 0x27, 0x35, 0xb8, 0xec, 0x59, 0xa8, 0xd0, 0x03, 0xdb, 0xf6, 0xcf, 0x83, 0xaa, 0x0e, 0xfc, 0x95, 0x29, 0x77, 0xec, 0x89, 0xc5, 0x79, 0x10, 0x40, 0xd8, 0xbb }; unsigned char license_info_1[PIX_LICENCE_BYTES] = { 0x6a, 0x70, 0xc0, 0x40, 0xc9, 0x20, 0xf5, 0xd2, 0x78, 0xac, 0x05, 0x80, 0xa6, 0xcf, 0x3f, 0xd5, 0x72, 0xf6, 0xc3, 0x82, 0x11, 0x0d, 0x56, 0x37, 0xb3, 0x87, 0x19, 0x13, 0x79, 0xa5, 0x9b, 0x37, 0xf2, 0xab, 0xcb, 0xa3, 0xea, 0xc4, 0x45, 0xc6, 0xae, 0xc4, 0xa4, 0x72, 0xe9, 0x36, 0x1e, 0xbe, 0x78, 0xd6, 0xcd, 0x85, 0xd, 0x63, 0x93, 0x7a, 0x84, 0x9a, 0x31, 0x99, 0xe1, 0x09, 0xc1, 0xfa, 0xbe, 0x32, 0x42, 0xc5, 0xc9, 0x89, 0x03, 0x7e, 0x81, 0xe5, 0x25, 0xf, 0x4d, 0x68, 0x9d, 0x53, 0xd1, 0x04, 0x29, 0x34, 0x53, 0x09, 0x22, 0x5, 0x29, 0xce, 0xb1, 0xc9, 0x01, 0xed, 0x2a, 0xd2, 0x16, 0xfb, 0x3c, 0x27, 0xba, 0x4a, 0x69, 0x10, 0x3a, 0x54, 0x5a, 0x8f, 0xca, 0x47, 0x8d, 0x34, 0x2b, 0x57, 0xad, 0x27, 0x9a, 0x15, 0x37, 0x86, 0x60, 0xd6, 0x34, 0xd8, 0x32, 0xee, 0x9c, 0x46 }; QString licenseInfoHex = QByteArray(reinterpret_cast(license_info_1), PIX_LICENCE_BYTES).toHex().toUpper(); #endif qDebug() << "上报服务器 licenseInfoHex:" << licenseInfoHex; // License上报服务器 FactoryToolSendPostLicenseToHttpServer(sendToHttpServerDataStr, licenseInfoHex); QString licenseInfoStr; printf("U盘 Get License is\n"); for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { #if !MANUAL_UPLOAD_LICENSE printf("0x%02x, ", license_info[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); #else printf("0x%02x, ", license_info_1[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info_1[j])); #endif } printf("\n"); licenseHwInfoEdit->setPlainText(licenseInfoStr); isRequestSuccessful = 0; } } else { if (jsonObject["lable"].toString() == "write_license") { QString licenseInfoText = licenseHwInfoEdit->toPlainText(); qDebug() << "licenseInfoText:" << licenseInfoText; dataStr = licenseInfoText.remove(","); dataStr = dataStr.replace("0x", "").replace(" ", ""); QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(license_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_LICENCE_BYTES)); QString licenseInfoStr; for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); } dataStr = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex(); qDebug() << "license_info:" << dataStr; dataStr = dataByteArray.toBase64(); qDebug() << "Base64 Encoded:" << dataStr; } /*for (ClientHandler* handler : clients) { handler->sendLicenseItem(index, dataStr); }*/ //sendLicenseData(index, dataStr); serialPortHandler->sendLicenseItem(index, dataStr); } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); QPushButton* button = qobject_cast(sender()); if (button) { int index = button->property("licenseIndex").toInt(); if (index >= 0 && index < frontBoardLicenseJson.size()) { QJsonObject jsonObject = frontBoardLicenseJson[index].toObject(); unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0 }; unsigned char license_info[PIX_LICENCE_BYTES] = { 0 }; QString dataStr = ""; if (jsonObject["lable"].toString() == "get_license") { QString hwInfoText = licenseHwInfoEdit->toPlainText(); if ((hwInfoText.count("0x") != PIX_HARDWARE_INFO_BYTES) && (hwInfoText.count("0x") != 0)) { isRequestSuccessful = 0; //licenseHwInfoEdit->setPlainText("您使用了License去获取License,这是不允许的!!!"); LicenseConfirmWindow dialog("您使用了License去获取License,这是不允许的!!!"); dialog.exec(); return; } else if (hwInfoText.count("0x") == 0) { isRequestSuccessful = 0; //licenseHwInfoEdit->setPlainText("您使用了License去获取License,这是不允许的!!!"); LicenseConfirmWindow dialog("没有检测到HWInfo,无法获取License!!!"); dialog.exec(); return; } dataStr = hwInfoText.remove(","); QString sendToHttpServerDataStr = dataStr.replace("0x", "").replace(" ", ""); // 去掉0x和空格 qDebug() << "sendToHttpServerDataStr:" << sendToHttpServerDataStr; FactoryToolSendGetLicenseToHttpServer(sendToHttpServerDataStr); while (isRequestSuccessful == 0) { QCoreApplication::processEvents(); // 防止阻塞线程 } qDebug() << "isRequestSuccessful:" << isRequestSuccessful; if (isRequestSuccessful == 2) { isRequestSuccessful = 0; return; } else if (isRequestSuccessful == 1) { if (licenseDataArray.contains("has") && licenseDataArray["has"].toBool()) { qDebug() << "Found item with 'has' = true"; if (licenseDataArray.contains("key")) { QString licenseKey = licenseDataArray["key"].toString(); licenseKey = formatLicenseKey(licenseKey); licenseHwInfoEdit->setPlainText(licenseKey); qDebug() << "HTTP Server License is:" << licenseKey; isRequestSuccessful = 0; return; } } else if (licenseDataArray.contains("has")) { qDebug() << "licenseDataArray[\"has\"].toBool():" << licenseDataArray["has"].toBool(); } } QByteArray dataByteArray = QByteArray::fromHex(dataStr.toUtf8()); memcpy(hardware_info, dataByteArray.data(), qMin(dataByteArray.size(), PIX_HARDWARE_INFO_BYTES)); //unsigned char hardware_info[PIX_HARDWARE_INFO_BYTES] = { 0x46,0x0b,0x5d,0x11,0x58,0x17,0x4d,0x5e,0x55,0x5c,0x51,0x4a,0x5a,0x07,0x59,0x4c,0x5f,0x45,0x5b,0x5f,0x5a,0x45,0x1c,0x5a,0x45,0x43,0x44,0x47,0x51,0x5e,0x44,0x30 }; LicenseConfirmWindow dialog("你确定要获取此授权吗?\n请确认你的hw_info是否正确"); if (dialog.exec() == QDialog::Accepted) { #if !MANUAL_UPLOAD_LICENSE if (!(licenseGenerate(hardware_info, license_info))) { qDebug() << "从U盘获取License失败"; isRequestSuccessful = 0; licenseHwInfoEdit->setPlainText("从U盘获取License失败,请检查U盘是否插入电脑!!!"); return; } QString licenseInfoHex = QByteArray(reinterpret_cast(license_info), PIX_LICENCE_BYTES).toHex().toUpper(); #else //unsigned char license_info_1[PIX_LICENCE_BYTES] = { 0x07, 0xe8, 0xf3, 0x80, 0xa8, 0x07, 0x72, 0xa1, 0x17, 0xfe, 0xda, 0x67, 0xbd, 0x4a, 0x5a, 0xb5, 0xbb, 0x8b, 0x2d, 0xb2, 0xbf, 0x89, 0x74, 0xe5, 0xb0, 0x99, 0x70, 0x74, 0x3c, 0x6f, 0xf8, 0x82, 0x79, 0xab, 0x31, 0x9c, 0xdf, 0xe8, 0x9e, 0x75, 0x8f, 0x42, 0xb3, 0xcf, 0x00, 0x60, 0xa0, 0x38, 0xa4, 0xb8, 0xbe, 0xa6, 0x5d, 0x9f, 0x8b, 0x41, 0xf3, 0x0a, 0x69, 0xf6, 0x50, 0x94, 0x3f, 0xd0, 0xa5, 0xee, 0x88, 0x20, 0x93, 0x9a, 0x1c, 0xe9, 0x64, 0xd3, 0xaf, 0x9f, 0xc7, 0x66, 0x00, 0x7d, 0x7d, 0x68, 0xf1, 0xa4, 0xe1, 0x58, 0x00, 0x1d, 0x03, 0x0d, 0x40, 0x08, 0xa4, 0xcc, 0x0b, 0xd8, 0x19, 0x70, 0x9a, 0x83, 0x81, 0xbf, 0x27, 0x35, 0xb8, 0xec, 0x59, 0xa8, 0xd0, 0x03, 0xdb, 0xf6, 0xcf, 0x83, 0xaa, 0x0e, 0xfc, 0x95, 0x29, 0x77, 0xec, 0x89, 0xc5, 0x79, 0x10, 0x40, 0xd8, 0xbb }; unsigned char license_info_1[PIX_LICENCE_BYTES] = { 0x6a, 0x70, 0xc0, 0x40, 0xc9, 0x20, 0xf5, 0xd2, 0x78, 0xac, 0x05, 0x80, 0xa6, 0xcf, 0x3f, 0xd5, 0x72, 0xf6, 0xc3, 0x82, 0x11, 0x0d, 0x56, 0x37, 0xb3, 0x87, 0x19, 0x13, 0x79, 0xa5, 0x9b, 0x37, 0xf2, 0xab, 0xcb, 0xa3, 0xea, 0xc4, 0x45, 0xc6, 0xae, 0xc4, 0xa4, 0x72, 0xe9, 0x36, 0x1e, 0xbe, 0x78, 0xd6, 0xcd, 0x85, 0xd, 0x63, 0x93, 0x7a, 0x84, 0x9a, 0x31, 0x99, 0xe1, 0x09, 0xc1, 0xfa, 0xbe, 0x32, 0x42, 0xc5, 0xc9, 0x89, 0x03, 0x7e, 0x81, 0xe5, 0x25, 0xf, 0x4d, 0x68, 0x9d, 0x53, 0xd1, 0x04, 0x29, 0x34, 0x53, 0x09, 0x22, 0x5, 0x29, 0xce, 0xb1, 0xc9, 0x01, 0xed, 0x2a, 0xd2, 0x16, 0xfb, 0x3c, 0x27, 0xba, 0x4a, 0x69, 0x10, 0x3a, 0x54, 0x5a, 0x8f, 0xca, 0x47, 0x8d, 0x34, 0x2b, 0x57, 0xad, 0x27, 0x9a, 0x15, 0x37, 0x86, 0x60, 0xd6, 0x34, 0xd8, 0x32, 0xee, 0x9c, 0x46 }; QString licenseInfoHex = QByteArray(reinterpret_cast(license_info_1), PIX_LICENCE_BYTES).toHex().toUpper(); #endif qDebug() << "上报服务器 licenseInfoHex:" << licenseInfoHex; // License上报服务器 FactoryToolSendPostLicenseToHttpServer(sendToHttpServerDataStr, licenseInfoHex); QString licenseInfoStr; printf("U盘 Get License is\n"); for (int j = 0; j < PIX_LICENCE_BYTES; ++j) { #if !MANUAL_UPLOAD_LICENSE printf("0x%02x, ", license_info[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info[j])); #else printf("0x%02x, ", license_info_1[j]); licenseInfoStr.append(QString::asprintf("0x%02x, ", license_info_1[j])); #endif } printf("\n"); licenseHwInfoEdit->setPlainText(licenseInfoStr); isRequestSuccessful = 0; } } } } } } void MainWidget::onUuidButtonClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); if (button) { int index = button->property("UuidIndex").toInt(); if (index >= 0 && index < backBoardUuidJson.size()) { QJsonObject jsonObject = backBoardUuidJson[index].toObject(); QString dataStr = ""; if (jsonObject["lable"].toString() == "get_UUID_SN") { QString sendToHttpServerDataStr = UuidHwInfoEdit->toPlainText(); cur_mac_addr = sendToHttpServerDataStr; qDebug() << "sendToHttpServerDataStr:" << sendToHttpServerDataStr; // 测试随机生成8-12位字符串 // sendToHttpServerDataStr = generateRandomRequestID(8, 13); FactoryToolSendGetUuidToHttpServer(sendToHttpServerDataStr); while (isRequestSuccessful == 0) { QCoreApplication::processEvents(); // 防止阻塞UI线程 } qDebug() << "isRequestSuccessful:" << isRequestSuccessful; if (isRequestSuccessful == 2) { UuidHwInfoEdit->setPlainText("服务器没有回复UUID和SN !!!"); isRequestSuccessful = 0; return; } else if (isRequestSuccessful == 1) { if (licenseDataArray.contains("uuid") && licenseDataArray.contains("sn")) { QString backBoardUuid = licenseDataArray["uuid"].toString(); QString backBoardSn = licenseDataArray["sn"].toString(); QString displayText = QString("UUID:\n%1\nSN:\n%2").arg(backBoardUuid).arg(backBoardSn); UuidHwInfoEdit->setPlainText(displayText); qDebug() << "HTTP Server backBoardUuid is:" << backBoardUuid; qDebug() << "HTTP Server backBoardSn is:" << backBoardSn; isRequestSuccessful = 0; return; } else { qDebug() << "The UUID and SN are not found from the HTTP server!!!"; UuidHwInfoEdit->setPlainText("服务器没有回复UUID和SN !!!"); isRequestSuccessful = 0; return; } } } else { QString backBoardUuid = ""; QString backBoardSn = ""; if (jsonObject["lable"].toString() == "write_UUID_SN") { QString UUIDAndSNInfoText = UuidHwInfoEdit->toPlainText(); QStringList lines = UUIDAndSNInfoText.split("\n"); bool isUuidSection = false; bool isSnSection = false; for (const QString& line : lines) { QString trimmedLine = line.trimmed(); if (trimmedLine == "UUID:") { isUuidSection = true; isSnSection = false; continue; } if (trimmedLine == "SN:") { isUuidSection = false; isSnSection = true; continue; } if (isUuidSection) { if (!backBoardUuid.isEmpty()) { backBoardUuid += "\n"; } backBoardUuid += trimmedLine; } if (isSnSection) { if (!backBoardSn.isEmpty()) { backBoardSn += "\n"; } backBoardSn += trimmedLine; } } qDebug() << "UuidHwInfoEdit backBoardUuid is:" << backBoardUuid; qDebug() << "UuidHwInfoEdit backBoardSn is:" << backBoardSn; cur_UUID = backBoardUuid; } else if (jsonObject["lable"].toString() == "Confirm_burn") { if ((cur_mac_addr != "") && (cur_UUID != "")) { FactoryToolSendPostComfirmToHttpServer(cur_mac_addr, cur_UUID); while (isRequestSuccessful == 0) { QCoreApplication::processEvents(); // 防止阻塞UI线程 } qDebug() << "isRequestSuccessful:" << isRequestSuccessful; if (isRequestSuccessful == 2) { UuidHwInfoEdit->setPlainText("服务器回复false,请重试!!!"); } else if (isRequestSuccessful == 1) { UuidHwInfoEdit->setPlainText("服务器已确认!!!"); } isRequestSuccessful = 0; } else { qDebug() << "cur_mac_addr:" << cur_mac_addr; qDebug() << "cur_UUID:" << cur_UUID; qDebug() << "cur_UUID or cur_mac_addr are empty!"; UuidHwInfoEdit->setPlainText("MAC_addr 和 UUID 是空的,请先获取再进行确认!!!"); } return; } qDebug() << "onUuidButtonClicked index:" << index; for (ClientHandler* handler : clients) { handler->sendUuidItem(index, backBoardUuid, backBoardSn); } } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::startMdnsService(char* select_ip) { const char* hostname = "SL100-FactoryTool-Mdns"; const char* service_name = "_myservice._tcp.local."; int service_port = TCP_CONNECT_PORT; // 如果线程已经存在且正在运行,先停止 if (mdnsThread && mdnsThread->isRunning()) { qDebug() << "Stopping previous mDNS service thread..."; mdnsThread->stop(); mdnsThread->quit(); mdnsThread->wait(); delete mdnsThread; } // 创建新的线程并启动 mdnsThread = new MdnsServiceThread(hostname, service_name, service_port, select_ip, this); connect(mdnsThread, &QThread::finished, mdnsThread, &QObject::deleteLater); // 确保线程资源释放 mdnsThread->start(); } void MainWidget::stopMdnsService() { if (mdnsThread) { qDebug() << "Stopping mDNS service..."; mdnsThread->stop(); // 通知线程退出 if (mdnsThread->isRunning()) { mdnsThread->quit(); // 退出线程事件循环 mdnsThread->wait(); // 等待线程完全退出 } delete mdnsThread; // 释放线程资源 mdnsThread = nullptr; qDebug() << "mDNS service stopped."; } else { qDebug() << "mDNS service is not running."; } } // 处理开始服务器按键点击事件 void MainWidget::onStartServerClicked() { if (!server->isListening()) { //getSelectedIp(); startMdnsService(getSelectedIp()); #if TEST_UDP_BROADCAST sendMulticastMessage(); #endif // QHostAddress specifiedIpAddress("10.10.10.253"); quint16 specifiedPort = TCP_CONNECT_PORT; qDebug() << "" << specifiedPort; if (server->listen(QHostAddress::Any, specifiedPort)) { startServerButton->setText(tr("正在监听(Listening)")); startServerButton->setStyleSheet("background-color: green;"); sendAllButton->setEnabled(true); } else { qDebug() << "Failed to start server. Error:" << server->errorString(); } } else { server->close(); startServerButton->setText(tr("开始监听\n(Start Listening...)")); startServerButton->setStyleSheet(""); sendAllButton->setEnabled(false); stopMdnsService(); } } void MainWidget::sendDataToClient(int clientId, const QByteArray& data) { if ((clientId == 0) && (isBackBoardOrAllBoard)) { clientId = isBackBoardOrAllBoard; } if (clients_1.contains(clientId)) { ClientHandler* handler = clients_1[clientId]; handler->sendDataToClient(data); // 调用 ClientHandler 中的方法发送数据 } else { qWarning() << "没有找到 ID 为" << clientId << "的客户端!"; } } // 处理发送获取设备信息按键点击事件 void MainWidget::onSendGetDevInfoClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("deviceInfoIndex").toInt(); if (itemIndex + 1 > connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("No device %1 is connected !!!").arg(itemIndex + 1), statusListWidget); listItem->setBackground(Qt::red); } else { for (ClientHandler* handler : clients) { if (handler->getClientId() == handler->controlClientId) { handler->sendGetDevInfoItem(itemIndex); break; } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理发送取图按键点击事件 void MainWidget::onSendGetPicClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("getPicIndex").toInt(); if (itemIndex < 2) { button->setStyleSheet("background-color: green;"); if (lastClickedGetPicCamIndex != -1 && lastClickedGetPicCamIndex != itemIndex) { getPicButtons[lastClickedGetPicCamIndex]->setStyleSheet(""); if (lastClickedGetPicDevIndex != -1) { getPicButtons[lastClickedGetPicDevIndex]->setStyleSheet(""); } } lastClickedGetPicCamIndex = itemIndex; } else { if (lastClickedGetPicCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select \"左边镜头\" or \"右边镜头\" to get image!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 2 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("This device is not connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetPicDevIndex != -1 && lastClickedGetPicDevIndex != itemIndex) { getPicButtons[lastClickedGetPicDevIndex]->setStyleSheet(""); } lastClickedGetPicDevIndex = itemIndex; //QMutexLocker locker(&mutex); /*for (ClientHandler* handler : clients) { if (handler->getClientId() == handler->controlClientId) { handler->sendGetPicItem(itemIndex - 2, lastClickedGetPicCamIndex); break; } }*/ serialPortHandler->sendGetPicItem(itemIndex - 2, lastClickedGetPicCamIndex); } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理发送拉视频流按键点击事件 void MainWidget::onSendGetVideoClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = -1; if (button) { if (button->property(FRONT_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).isValid()) { itemIndex = button->property(FRONT_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).toInt(); if (itemIndex < 4) { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoCamIndex != -1 && lastClickedGetVideoCamIndex != itemIndex) { getVideoButtons[lastClickedGetVideoCamIndex]->setStyleSheet(""); if (lastClickedGetVideoDevIndex != -1) { getVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } } lastClickedGetVideoCamIndex = itemIndex; } else { if (lastClickedGetVideoCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select lens to get video!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 8 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("This device is not connected !!!").arg(itemIndex - 6), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoDevIndex != -1 && lastClickedGetVideoDevIndex != itemIndex) { //qDebug() << "itemIndex:" << itemIndex; getVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } lastClickedGetVideoDevIndex = itemIndex; //QMutexLocker locker(&mutex); /*for (ClientHandler* handler : clients) { if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) { qDebug() << "lens number:" << lastClickedGetVideoCamIndex; handler->sendGetVideoItem(itemIndex - 7, lastClickedGetVideoCamIndex); break; } }*/ serialPortHandler->sendGetVideoItem(itemIndex - 7, lastClickedGetVideoCamIndex); getVideoButtons[FOCUS_WINDOWS_BUTTON]->setEnabled(true); } } } } else if (button->property(BACK_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).isValid()) { itemIndex = button->property(BACK_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).toInt(); if (itemIndex < 4) { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoCamIndex != -1 && lastClickedGetVideoCamIndex != itemIndex) { getBackVideoButtons[lastClickedGetVideoCamIndex]->setStyleSheet(""); if (lastClickedGetVideoDevIndex != -1) { getBackVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } } lastClickedGetVideoCamIndex = itemIndex; } else { if (lastClickedGetVideoCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select lens to get video!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 8 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("This device is not connected !!!").arg(itemIndex - 6), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoDevIndex != -1 && lastClickedGetVideoDevIndex != itemIndex) { //qDebug() << "itemIndex:" << itemIndex; getBackVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } lastClickedGetVideoDevIndex = itemIndex; //QMutexLocker locker(&mutex); for (ClientHandler* handler : clients) { if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) { qDebug() << "lens number:" << lastClickedGetVideoCamIndex; handler->sendGetVideoItem(itemIndex - 7, lastClickedGetVideoCamIndex); break; } } getBackVideoButtons[FOCUS_WINDOWS_BUTTON]->setEnabled(true); } } } } else if (button->property(ALL_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).isValid()) { itemIndex = button->property(ALL_BOARD_VIDEO_BUTTON_INDEX_PROPERTY).toInt(); if (itemIndex < 4) { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoCamIndex != -1 && lastClickedGetVideoCamIndex != itemIndex) { getAllVideoButtons[lastClickedGetVideoCamIndex]->setStyleSheet(""); if (lastClickedGetVideoDevIndex != -1) { getAllVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } } lastClickedGetVideoCamIndex = itemIndex; } else { if (lastClickedGetVideoCamIndex == -1) { QListWidgetItem* listItem = new QListWidgetItem(QString("Please select lens to get video!!!"), statusListWidget); listItem->setBackground(Qt::red); } else { if (itemIndex - 8 >= connectedClientsCount) { QListWidgetItem* listItem = new QListWidgetItem(QString("This device is not connected !!!").arg(itemIndex - 6), statusListWidget); listItem->setBackground(Qt::red); } else { button->setStyleSheet("background-color: green;"); if (lastClickedGetVideoDevIndex != -1 && lastClickedGetVideoDevIndex != itemIndex) { //qDebug() << "itemIndex:" << itemIndex; getAllVideoButtons[lastClickedGetVideoDevIndex - 2]->setStyleSheet(""); } lastClickedGetVideoDevIndex = itemIndex; //QMutexLocker locker(&mutex); for (ClientHandler* handler : clients) { if ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId)) { qDebug() << "lens number:" << lastClickedGetVideoCamIndex; handler->sendGetVideoItem(itemIndex - 7, lastClickedGetVideoCamIndex); break; } } getAllVideoButtons[FOCUS_WINDOWS_BUTTON]->setEnabled(true); } } } } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onOpenFocusWindowClicked() { QPushButton* button = qobject_cast(sender()); if (button) { int itemIndex = button->property("getVideoIndex").toInt(); qDebug() << "New Button clicked with itemIndex:" << itemIndex; if (itemIndex == FOCUS_WINDOWS_BUTTON) { if (isBackBoardOrAllBoard) { for (ClientHandler* handler : clients) { if (handler->getClientId() == handler->preVideoClientId) { DataHandler* dataHandler = dataHandlers[handler->getClientId()]; if (dataHandler) { dataHandler->handleOpenFocusWindow(itemIndex); break; } } } } else { emit openFocusWindow(itemIndex); //SerialDataHandler->handleOpenFocusWindow(itemIndex); } } } } // 处理一键发送按键点击事件 void MainWidget::onSendAllClicked() { qDebug() << "Current connectedClientsCount:" << connectedClientsCount; if (connectedClientsCount) { QMutexLocker locker(&mutex); isSendingAll = !isSendingAll; if (isSendingAll) { sendAllButton->setText("一键功能测试中...\n再次点击取消"); sendAllButton->setStyleSheet("background-color: green;"); manualSend = true; if (isBackBoardOrAllBoard) { for (ClientHandler* handler : clients) { // 重置索引 handler->resetCurrentItemIndex(); handler->sendNextItem(backBoardOneClickTest); break; } } else { // 重置索引 serialPortHandler->resetCurrentItemIndex(); serialPortHandler->sendNextItem(frontBoardOneClickTest); } } else { sendAllButton->setText("一键功能测试"); sendAllButton->setStyleSheet("background-color: white;"); manualSend = false; if (isBackBoardOrAllBoard) { for (ClientHandler* handler : clients) { handler->resetCurrentItemIndex(); } } else { serialPortHandler->resetCurrentItemIndex(); } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理单独发送功能项按键点击事件 void MainWidget::onSendFrontFuncItemClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("frontBoardFuncConfig").toInt(); /*if (isBackBoardOrAllBoard) { for (ClientHandler* handler : clients) { if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) { QString text = frontFuncConfigLineEdit->text(); qDebug() << "Text in frontFuncConfigLineEdit:" << text; handler->sendFrontFuncItem(itemIndex, text); isReplyOrTimeout = false; break; } } } else { }*/ if (isReplyOrTimeout) { QString text = frontFuncConfigLineEdit->text(); qDebug() << "Text in frontFuncConfigLineEdit:" << text; serialPortHandler->sendFrontFuncItem(itemIndex, text); isReplyOrTimeout = false; } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onSendBackFuncItemClicked() { if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("backBoardFuncConfig").toInt(); for (ClientHandler* handler : clients) { if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) { QString text = backFuncConfigLineEdit->text(); qDebug() << "Text in backFuncConfigLineEdit:" << text; handler->sendBackFuncItem(itemIndex, text); isReplyOrTimeout = false; break; } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } // 处理单独发送项按键点击事件 void MainWidget::onSendFrontItemClicked() { qDebug() << "onSendFrontItemClicked isReplyOrTimeout = " << isReplyOrTimeout; if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("frontBoardTest").toInt(); /*for (ClientHandler* handler : clients) { if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) { handler->sendFrontItem(itemIndex); isReplyOrTimeout = false; break; } }*/ if (isReplyOrTimeout) { serialPortHandler->sendFrontItem(itemIndex); isReplyOrTimeout = false; } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onSendBackItemClicked() { qDebug() << "onSendBackItemClicked"; if (connectedClientsCount) { QPushButton* button = qobject_cast(sender()); int itemIndex = button->property("backBoardTest").toInt(); for (ClientHandler* handler : clients) { if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) { handler->sendBackItem(itemIndex); isReplyOrTimeout = false; break; } } } else { QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget); listItem->setBackground(Qt::red); } } void MainWidget::onStatusUpdated(int boardTpye, const QString& client, bool success, const QJsonArray& jsonArray, int itemJsonIndex) { qDebug() << "----> Current thread:" << QThread::currentThread(); if (boardTpye == -2) { qDebug() << "*********************************************"; qDebug() << "isFirstSendDevInfo = " << isFirstSendDevInfo; //serialPortHandler->sendDevInfoItem(); if (isFirstSendDevInfo) { emit requestDevInfo(); isFirstSendDevInfo = false; } return; } isReplyOrTimeout = true; int clientId = -1; QString label; if (boardTpye == 1) { for (ClientHandler* handler : clients) { if (handler->getClientAddress() == client) { clientId = handler->getClientId(); QString lable = handler->getCurrentItemLable(); lable = handler->getCurrentFuncItemLable(); break; } } } else { clientId = nextSerialId - 1; } qDebug() << "itemJsonIndex :" << itemJsonIndex; if (itemJsonIndex >= 0 && itemJsonIndex < jsonArray.size()) { QJsonObject jsonObject = jsonArray.at(itemJsonIndex).toObject(); if (jsonObject.contains("lable")) { label = jsonObject["lable"].toString(); qDebug() << "label :" << label; } } QListWidgetItem* listItem = new QListWidgetItem(QString("device ID: %1 - Item %2: %3 ---> %4") .arg(clientId) .arg(itemJsonIndex + 1) .arg(label) .arg(success ? "OK" : "NG"), statusListWidget); listItem->setBackground(success ? Qt::green : Qt::red); statusListWidget->addItem(listItem); statusListWidget->scrollToBottom(); } // json文件里面的配置项都测试结束 void MainWidget::onAllItemsProcessed(int boardTpye, const QString& client, int itemsProcessedCount) { qDebug() << "---------------------- onAllItemsProcessed"; qDebug() << "boardTpye:" << boardTpye << "itemsProcessedCount:" << itemsProcessedCount; isSendingAll = false; sendAllButton->setText(TOOL_UI.ONE_CLICKED_TEST); sendAllButton->setStyleSheet("background-color: white;"); sendAllButton->setEnabled(true); int clientId = -1; if (boardTpye == 1) { for (ClientHandler* handler : clients) { if (handler->getClientAddress() == client) { clientId = handler->getClientId(); qDebug() << "Current clientId:" << clientId; break; } else { //qDebug() << "" << __FUNCTION__ << "handler->getClientAddress() != client"; } } } else { clientId = nextSerialId - 1; } QListWidgetItem* listItem = new QListWidgetItem(QString("device ID:-%1 ---> All %2 items test completed !!!") .arg(clientId) .arg(itemsProcessedCount), statusListWidget); if(checkBoxState) saveStatusListToFile(filePathLineEdit->text()); statusListWidget->addItem(listItem); statusListWidget->scrollToBottom(); } void MainWidget::onHandleInvalidOperate(const QString& text) { QListWidgetItem* listItem = new QListWidgetItem(QString("%1").arg(text), statusListWidget); listItem->setBackground(Qt::red); statusListWidget->addItem(listItem); statusListWidget->scrollToBottom(); }