SL100_FactoryTestTool/FactoryTestTool/SourceCode/Widget/MainWidget.cpp

1818 lines
79 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// MainWidget.cpp
#include "MainWidget.h"
#include <qrencode.h>
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;
}
// 初始化 UI 组件和服务器
MainWidget::MainWidget(QWidget* parent) :
QWidget(parent),
nextClientId(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;
}
setupHttpServer();
// 打印线程池状态信息
setupTimerForThreadPoolInfo();
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->setParent(nullptr);
// 将 socket 移动到新的线程中
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::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();
#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();
QVBoxLayout* leftLayout = new QVBoxLayout;
leftLayout->addLayout(buttonLayout);
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, 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);
}
void MainWidget::onStartImageSharing(int width, int height, QString img_type, std::function<void(QString)> 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<QHostAddress> 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::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();
//}
//
////注意事项
////端口冲突:确保 8080 端口未被其他程序占用,可以更换为其他端口。
////防火墙规则:确保防火墙允许外部设备访问该端口。
////图片格式:上述代码默认处理 PNG/JPG/JPEG 格式,如果需要支持其他格式,可根据 MIME 类型调整 Content - Type
//void MainWidget::onStartImageSharing(int width, int height, std::function<void(QString)> 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() << "Image dimensions:" << imageSize.width() << "x" << imageSize.height();
//
// QString localIP;
// QList<QHostAddress> 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;
// }
//
// QString downloadUrl = QString("http://%1:%2/").arg(localIP).arg(serverPort);
// qDebug() << "Download URL:" << downloadUrl;
//
// callback(downloadUrl);
//}
// 服务器响应
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<QString, QString>& params, const QString& httpMethod, const QString& secret, const QString& request_id, const QString& timestamp) {
// 1. 按字典序排序参数
QList<QPair<QString, QString>> 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<QString, QString>& 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<QString, QString>& 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<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> 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();
testJsonConfig = readJson_testConfig();
funcJsonConfig = readJson_funcConfig();
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::onStartTimeout(int clientId, int timeout)
{
//qDebug() << "---------------> onStartTimeout :" << clientId << "timeout :" << timeout;
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) {
QPushButton* button = qobject_cast<QPushButton*>(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) {
isRequestSuccessful = 0;
//licenseHwInfoEdit->setPlainText("您使用了License去获取License这是不允许的!!!");
LicenseConfirmWindow dialog("您使用了License去获取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<char*>(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<char*>(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<char*>(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);
}
}
}
}
}
else {
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
listItem->setBackground(Qt::red);
}
}
void MainWidget::onUuidButtonClicked()
{
if (connectedClientsCount) {
QPushButton* button = qobject_cast<QPushButton*>(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();
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;
}
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() {
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, 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()) {
startMdnsService();
#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<QPushButton*>(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<QPushButton*>(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;
}
}
}
}
}
}
else {
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
listItem->setBackground(Qt::red);
}
}
// 处理发送拉视频流按键点击事件
void MainWidget::onSendGetVideoClicked()
{
if (connectedClientsCount) {
QPushButton* button = qobject_cast<QPushButton*>(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;
}
}
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<QPushButton*>(sender());
if (button) {
int itemIndex = button->property("getVideoIndex").toInt();
qDebug() << "New Button clicked with itemIndex:" << itemIndex;
if (itemIndex == FOCUS_WINDOWS_BUTTON) {
for (ClientHandler* handler : clients) {
if (handler->getClientId() == handler->preVideoClientId) {
DataHandler* dataHandler = dataHandlers[handler->getClientId()];
if (dataHandler) {
dataHandler->handleOpenFocusWindow(itemIndex);
break;
}
}
}
}
}
}
// 处理一键发送按键点击事件
void MainWidget::onSendAllClicked()
{
if (connectedClientsCount) {
QMutexLocker locker(&mutex);
isSendingAll = !isSendingAll;
if (isSendingAll) {
sendAllButton->setText("一键功能测试中...\n再次点击取消");
sendAllButton->setStyleSheet("background-color: green;");
manualSend = true;
for (ClientHandler* handler : clients) {
// 重置索引
handler->resetCurrentItemIndex();
if (handler->getClientId() == handler->controlClientId) {
handler->sendNextItem(frontBoardOneClickTest);
break;
}
else if (isBackBoardOrAllBoard) {
handler->sendNextItem(backBoardOneClickTest);
break;
}
}
}
else {
sendAllButton->setText("一键功能测试");
sendAllButton->setStyleSheet("background-color: white;");
manualSend = false;
for (ClientHandler* handler : clients) {
handler->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<QPushButton*>(sender());
int itemIndex = button->property("frontBoardFuncConfig").toInt();
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 {
QListWidgetItem* listItem = new QListWidgetItem(QString("No device is connected !!!"), statusListWidget);
listItem->setBackground(Qt::red);
}
}
void MainWidget::onSendBackFuncItemClicked()
{
if (connectedClientsCount) {
QPushButton* button = qobject_cast<QPushButton*>(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" ;
if (connectedClientsCount) {
QPushButton* button = qobject_cast<QPushButton*>(sender());
int itemIndex = button->property("frontBoardTest").toInt();
for (ClientHandler* handler : clients) {
if (isReplyOrTimeout && ((isBackBoardOrAllBoard) || (handler->getClientId() == handler->controlClientId))) {
handler->sendFrontItem(itemIndex);
isReplyOrTimeout = false;
break;
}
}
}
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<QPushButton*>(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(const QString& client, bool success, const QJsonArray& jsonArray, int itemJsonIndex)
{
isReplyOrTimeout = true;
int clientId = -1;
QString label;
for (ClientHandler* handler : clients) {
if (handler->getClientAddress() == client) {
clientId = handler->getClientId();
QString lable = handler->getCurrentItemLable();
lable = handler->getCurrentFuncItemLable();
break;
}
}
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(const QString& client, int itemsProcessedCount)
{
isSendingAll = false;
sendAllButton->setText(TOOL_UI.ONE_CLICKED_TEST);
sendAllButton->setStyleSheet("background-color: white;");
int clientId = -1;
for (ClientHandler* handler : clients) {
if (handler->getClientAddress() == client) {
clientId = handler->getClientId();
qDebug() << "Current clientId:" << clientId;
break;
}
else
{
//qDebug() << "" << __FUNCTION__ << "handler->getClientAddress() != client";
}
}
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();
}