From 4e7614f93dc335d074001173e01bd6b705424c6b Mon Sep 17 00:00:00 2001 From: "Mr.V" Date: Thu, 14 Mar 2024 21:14:36 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E6=9B=B4=E6=96=B0socket=E8=BE=85?= =?UTF-8?q?=E5=8A=A9=E6=8E=A7=E5=88=B6=E6=98=AF=E5=90=A6=E6=9D=A5=E8=BD=A6?= =?UTF-8?q?=202=E3=80=81=E6=96=B0=E5=A2=9E=E6=B5=8B=E8=AF=95=E7=89=88?= =?UTF-8?q?=EF=BC=8C=E7=9B=B4=E6=8E=A5=E8=AF=BB=E5=8F=96=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E5=8E=9F=E5=A7=8B=E6=95=B0=E6=8D=AE=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Train_RFID/config/config.ini | 20 +++ app/config/config.ini | 7 +- src/ConfigUtil/ConfigUtil.cpp | 22 ++++ src/ConfigUtil/ConfigUtil.h | 10 ++ src/common/common.h | 3 +- src/interface/TcpClient.cpp | 178 +++++++++++++++----------- src/interface/TcpClient.h | 32 +++-- src/main.cpp | 4 +- src/qt_source/mainwindow.cpp | 227 +++++++++++++++++++++++++++------- src/qt_source/mainwindow.h | 58 ++++++--- src/qt_source/mainwindow.ui | 101 +++++++++++---- src/qt_source/ui_MainWindow.h | 44 +++++-- src/serial/ComDetect.cpp | 1 + 13 files changed, 524 insertions(+), 183 deletions(-) create mode 100644 Train_RFID/config/config.ini diff --git a/Train_RFID/config/config.ini b/Train_RFID/config/config.ini new file mode 100644 index 0000000..0965dfc --- /dev/null +++ b/Train_RFID/config/config.ini @@ -0,0 +1,20 @@ +[base] +com_name=COM2 +baud=19200 +track_name=2 +have_magnet_steel=true +magnet_steel_order=8421 +up_result=false +use_socket_server=true + +[interface] +http_ip=192.168.137.104 +http_port=20004 +token_path=/api/token_path +up_result_path=/api/train-carriage/identification/rfid-save +username=guest_01 +password=d55b0f642e817eea24725d2f2a31dd08 + +[socket_server] +server_ip=172.24.192.1 +server_port=60001 diff --git a/app/config/config.ini b/app/config/config.ini index 308e49d..0965dfc 100644 --- a/app/config/config.ini +++ b/app/config/config.ini @@ -4,7 +4,8 @@ baud=19200 track_name=2 have_magnet_steel=true magnet_steel_order=8421 -up_result=true +up_result=false +use_socket_server=true [interface] http_ip=192.168.137.104 @@ -13,3 +14,7 @@ token_path=/api/token_path up_result_path=/api/train-carriage/identification/rfid-save username=guest_01 password=d55b0f642e817eea24725d2f2a31dd08 + +[socket_server] +server_ip=172.24.192.1 +server_port=60001 diff --git a/src/ConfigUtil/ConfigUtil.cpp b/src/ConfigUtil/ConfigUtil.cpp index b4c0f31..5fc8615 100644 --- a/src/ConfigUtil/ConfigUtil.cpp +++ b/src/ConfigUtil/ConfigUtil.cpp @@ -26,6 +26,7 @@ bool ConfigUtil::readBaseConfig(const QString &configFile, QString &errorMessage config.havaMagnetSteel = mset->value("have_magnet_steel", false).toBool(); config.magnetSteelOrder = mset->value("magnet_steel_order", "").toString(); config.upResult = mset->value("up_result", false).toBool(); + config.useSocketServer = mset->value("use_socket_server", false).toBool(); mset->endGroup(); } catch (const std::exception &e) { @@ -58,4 +59,25 @@ bool ConfigUtil::readInterfaceConfig(const QString &configFile, QString &errorMe return false; } return true; +} + +bool ConfigUtil::readSocketServerConfig(const QString &configFile, QString &errorMessage, + ai_matrix::SServerConfig &config) { + try { + if (configFile.isEmpty() || configFile.isNull()) { + errorMessage = "配置文件地址为空,读取配置文件失败!"; + return false; + } + QSettings* mset = new QSettings(configFile, QSettings::IniFormat); + mset->setIniCodec(QTextCodec::codecForName("UTF-8")); + mset->beginGroup("socket_server"); + config.server_ip = mset->value("server_ip", "").toString(); + config.server_port = mset->value("server_port", "").toInt(); + + mset->endGroup(); + } catch (const std::exception &e) { + errorMessage = e.what(); + return false; + } + return true; } \ No newline at end of file diff --git a/src/ConfigUtil/ConfigUtil.h b/src/ConfigUtil/ConfigUtil.h index d0db783..23da3e9 100644 --- a/src/ConfigUtil/ConfigUtil.h +++ b/src/ConfigUtil/ConfigUtil.h @@ -21,6 +21,8 @@ namespace ai_matrix { QString magnetSteelOrder; // 上传识别结果标志 bool upResult; + // 使用socket来车通讯 + bool useSocketServer; }; struct InterfaceConfig { @@ -38,6 +40,13 @@ namespace ai_matrix { // 密码 QString password; }; + + struct SServerConfig { + // socket server IP + QString server_ip; + // server_port + int server_port; + }; }; class ConfigUtil { @@ -47,6 +56,7 @@ public: static bool readBaseConfig(const QString& configFile, QString &errorMessage, ai_matrix::BaseConfig &config); static bool readInterfaceConfig(const QString& configFile, QString &errorMessage, ai_matrix::InterfaceConfig &config); + static bool readSocketServerConfig(const QString& configFile, QString &errorMessage, ai_matrix::SServerConfig &config); }; diff --git a/src/common/common.h b/src/common/common.h index 00558b3..fb50356 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -16,7 +16,6 @@ #include #include "Log.h" #include "StringUtil.h" -extern QString io_car; -extern QString direction; + #endif //TRAIN_RFID_COMMON_H diff --git a/src/interface/TcpClient.cpp b/src/interface/TcpClient.cpp index e686e2c..c66cb70 100644 --- a/src/interface/TcpClient.cpp +++ b/src/interface/TcpClient.cpp @@ -1,93 +1,123 @@ #include "TcpClient.h" + //#include "mainWindow.h" TcpClient::TcpClient(QObject *parent) - : QObject(parent) + : QObject(parent) { - m_heartbeatTimer = new QTimer(this); //心跳包定时器 - connect(&m_tcpSocket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead); - connect(m_heartbeatTimer, &QTimer::timeout, this, &TcpClient::sendHeartbeat);//心跳包 - connect(&m_tcpSocket, &QTcpSocket::connected, this, &TcpClient::handleConnected); - connect(&m_tcpSocket, &QTcpSocket::disconnected, this, &TcpClient::handleDisconnected); + connect(this, &TcpClient::restartSocket, this, &TcpClient::connectToServer); } -void TcpClient::connectToServer(const QString &host, int port) -{ - m_host = host; - m_port = port; - m_tcpSocket.connectToHost(host,port); // Replace with actual server IP and port +void TcpClient::connectToServer(QString ip, int port) { + try { -} + this->ip_ = ip; + this->port_ = port; + this->tcp_ = new QTcpSocket; + this->heartbeatTimer_ = new QTimer(this); //心跳包定时器 + QAbstractSocket::SocketState state = this->tcp_->state(); -void TcpClient::onReadyRead() -{ + if(QAbstractSocket::UnconnectedState == state) { + emit sendTcpInfoSignals("未连接Socket服务器"); + } - QByteArray jsonData = m_tcpSocket.readAll(); -// qDebug()<< jsonData <tcp_->connectToHost(ip, port); // Replace with actual server IP and port - m_tcpSocket.write(jsonData); - } - else - { - QJsonObject jsonObject; - jsonObject["success"] = "true"; - jsonObject["err_msg"] = ""; - QJsonDocument jsonDocument(jsonObject); - QByteArray jsonData = jsonDocument.toJson(); - m_tcpSocket.write(jsonData); - } + if(QAbstractSocket::ConnectingState == this->tcp_->state()) { + emit sendTcpInfoSignals("正在连接Socket服务器..."); + } + if (!this->tcp_->waitForConnected(2000)) + { + emit sendTcpInfoSignals("链接服务端超时"); + // 5秒后尝试重新连接 + QTimer::singleShot(5000, this, [=](){ +// this->tcp_ = new QTcpSocket; + emit sendTcpInfoSignals("重新连接Socket"); + emit restartSocket(this->ip_, this->port_); + }); + return; + } + else + { + if (!this->heartbeatTimer_->isActive()) { + // 心跳包定时器启动 + this->heartbeatTimer_->start(3000); + } + emit sendTcpInfoSignals("链接服务端成功"); + // 连接失败 + connect(this->tcp_, &QTcpSocket::errorOccurred, this, [=](QAbstractSocket::SocketError err){ + emit sendTcpInfoSignals("链接服务端失败"); // 连接失败或其他错误,若服务器没有打开或连接失败,可以从这里会发出提示 + }); + // 断开连接 + connect(this->tcp_, &QTcpSocket::disconnected, this, [=](){ + emit sendTcpInfoSignals("服务端断开连接"); + this->tcp_->close(); + this->tcp_->deleteLater(); + this->tcp_ = nullptr; + if (this->heartbeatTimer_->isActive()) + { + // 停止发送心跳包 + this->heartbeatTimer_->stop(); + } -// // Process received JSON data -// // ... - qDebug()<< jsonData <<" "<< io_car<<" "<< direction<<" "<< t << "\n"<ip_, this->port_); + }); - //QByteArray heartbeatData = "matrixai"; - // std::string head = "matrixai"; - m_tcpSocket.write("matrixai"); + }); + // 心跳信号 + connect(this->heartbeatTimer_, &QTimer::timeout, this, [=](){ + if (this->tcp_->state() == QAbstractSocket::ConnectedState) { + // 发送心跳包 + this->tcp_->write("matrixai"); + } + }); + // 接收到数据 + connect(this->tcp_, &QTcpSocket::readyRead, this, [=](){ + QByteArray jsonData = this->tcp_->readAll(); +// emit sendTcpInfoSignals("--" + QString(jsonData)); + jsonData.replace("}{", "}-{"); + QList jsonDataList = jsonData.split('-'); + for (int i = 0; i < jsonDataList.size(); i++) { + QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonDataList[i]); + if (jsonDocument.isObject()) { + QJsonObject jsonObject = jsonDocument.object(); + if (jsonObject["type"].toString() != carType && carType == "0") + { + // 来车 + emit this->comeTrainSignals(true); + come_time = jsonObject["cometime"].toString(); + carType = jsonObject["type"].toString(); + } + else if (jsonObject["type"].toString() != carType && carType == "1") + { + // 火车无 + emit this->comeTrainSignals(false); + come_time = jsonObject["cometime"].toString(); + carType = jsonObject["type"].toString(); + } + } + } + }); + } + + this->exit_flag = false; + emit socketComplete(this->tcp_, ip, port); } -} -void TcpClient::reconnect() -{ - if (m_tcpSocket.state() != QAbstractSocket::ConnectedState) { - // 断线重连 - m_tcpSocket.connectToHost("127.0.0.1",7000); - } -} -void TcpClient::handleConnected() -{ - if (!m_heartbeatTimer->isActive()) { - // 心跳包定时器启动 - m_heartbeatTimer->start(3000); + catch (const std::exception &e) { + emit sendTcpInfoSignals("链接服务端失败"); + this->exit_flag = true; } } -void TcpClient::handleDisconnected() +void TcpClient::SetExitFlag(bool flag) { - if (m_heartbeatTimer->isActive()) { - // 停止发送心跳包 - m_heartbeatTimer->stop(); - } - - // 5秒后尝试重新连接 - QTimer::singleShot(5000, this, &TcpClient::reconnect); + this->exit_flag = flag; +} + +void TcpClient::closeConnect() +{ + this->tcp_->close(); } diff --git a/src/interface/TcpClient.h b/src/interface/TcpClient.h index 32477fd..cf113a3 100644 --- a/src/interface/TcpClient.h +++ b/src/interface/TcpClient.h @@ -12,20 +12,30 @@ class TcpClient : public QObject public: explicit TcpClient(QObject *parent = nullptr); + void SetExitFlag(bool flag); + void closeConnect(); // 关闭连接 -public slots: - void connectToServer(const QString &host, int port); - void onReadyRead(); - void sendHeartbeat(); - void reconnect(); - void handleConnected(); - void handleDisconnected(); private: - QTcpSocket m_tcpSocket; - QTimer *m_heartbeatTimer; - QString m_host; - int m_port; + QTcpSocket* tcp_ = nullptr; + QTimer *heartbeatTimer_; + QString ip_; + int port_; + + QString carType = "0"; + QString direction = "0"; + QString come_time = ""; + + bool exit_flag = false; // 退出标记 + +public slots: + void connectToServer(QString ip, int port); + +signals: + void comeTrainSignals(bool type); + void sendTcpInfoSignals(QString info); + void socketComplete(QTcpSocket* tcp, QString ip, quint16 port); // tcp句柄发送给主线程监管 + void restartSocket(QString ip, int port); //重启Socket连接 }; #endif // TCPCLIENT_H diff --git a/src/main.cpp b/src/main.cpp index 2be3dd9..aad26e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,9 +42,7 @@ int main(int argc, char *argv[]) { QApplication::setWindowIcon(QIcon("./logo.ico")); MainWindow w; w.show(); - -// TcpClient tcpClient; -// tcpClient.connectToServer("127.0.0.1",7000); //与视频车号通信ip端口 + qInfo() << "111"; return QApplication::exec(); } return QApplication::exec(); diff --git a/src/qt_source/mainwindow.cpp b/src/qt_source/mainwindow.cpp index 65e341b..c07f3cb 100644 --- a/src/qt_source/mainwindow.cpp +++ b/src/qt_source/mainwindow.cpp @@ -1,7 +1,8 @@ -#include +#include #include "MainWindow.h" #include "ui_MainWindow.h" +#include "TcpClient.h" #define DEBUG_HTTP 1 @@ -11,6 +12,14 @@ MainWindow::MainWindow(QWidget *parent) { ui->setupUi(this); + this->statusBar = new QStatusBar(); + this->statusInfo = new QLabel("初始化完成",this); + this->statusBar->addPermanentWidget(this->statusInfo);//显示正常信息 + QLabel* statusVersion = new QLabel("编译版本:" + QDateTime::currentDateTime().toString("yy.MM.dd.hh.mm"),this); + this->statusBar->addWidget(statusVersion); + + layout()->addWidget(this->statusBar); + this->setWindowTitle("Matrix_RFID"); this->configPath_ = "./config/config.ini"; @@ -29,6 +38,14 @@ MainWindow::MainWindow(QWidget *parent) { this->logError(errorMessage); } + if (!ConfigUtil::readSocketServerConfig(this->configPath_, errorMessage, this->socketServerConfig_)) + { + this->logError(errorMessage); + } + // 创建菜单栏 +// this->initMenu(); + +// this->ui->testButton->setHidden(true); // 获取本机串口列表 this->getComList(); @@ -47,6 +64,9 @@ MainWindow::MainWindow(QWidget *parent) connect(this, &MainWindow::upRfid_signals, this, &MainWindow::upRfid); + connect(this->ui->testButton, &QPushButton::clicked, this, &MainWindow::readTestInfo); + // 识别状态改变 + connect(this, &MainWindow::IdentifyType, this, &MainWindow::IdentifyTypeUpdate); //最小化信号槽 connect(m_pSystemTray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason))); @@ -64,8 +84,6 @@ MainWindow::MainWindow(QWidget *parent) this->ui->resultTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); this->ui->resultTable->verticalHeader()->setMinimumWidth(50); - - if (!this->baseConfig_.upResult) { QIcon icon("./Fail.ico"); @@ -77,6 +95,52 @@ MainWindow::MainWindow(QWidget *parent) this->ui->upflagLabel->setPixmap(m_pic); } + if (this->baseConfig_.useSocketServer) + { + // 创建线程 + QThread *threadWork = new QThread; // 任务线程 + + this->tcpClient = new TcpClient(this); + this->tcpClient->moveToThread(threadWork); + + connect(this, &MainWindow::connect_socket, this->tcpClient, &TcpClient::connectToServer); + + // 子线程反馈 socket 到主线程 + connect(this->tcpClient, &TcpClient::socketComplete, this, [=](QTcpSocket* tcp, QString ip, quint16 port){ + this->tcp_ = tcp; + }); + + // 接收子线程的消息提示 + connect(this->tcpClient, &TcpClient::sendTcpInfoSignals, this, [=](QString info){ + this->logInfo(info); + this->statusInfo->setText(info); + if (info == "链接服务端超时" + || info == "未连接Socket服务器" + || info == "链接服务端失败" + || info == "服务端断开连接" + || info == "链接服务端失败") + { + this->videoHasTrain = false; + } + }); + + emit connect_socket(this->socketServerConfig_.server_ip, this->socketServerConfig_.server_port); + + connect(this->tcpClient, &TcpClient::comeTrainSignals, this, [=](bool type){ + if (type) + { + this->logInfo("视频车号识别-来车了"); + this->videoHasTrain = true; + emit IdentifyType(); + } + else + { + this->logInfo("视频车号识别-火车离开了"); + this->videoHasTrain = false; + emit IdentifyType(); + } + }); + } } MainWindow::~MainWindow() @@ -175,6 +239,7 @@ bool MainWindow::rnameRfidLog() void MainWindow::saveRfidLog(const QString &value) { try { +// QString logValue = "[" + QDateTime::currentDateTime().toString("hh:mm::ss") + "] " + value + "\n"; QString logValue = value + "\n"; if (!this->recvLog.isOpen()) { @@ -226,6 +291,9 @@ void MainWindow::initComboBox() { ui->BTBox->setCurrentText(QString::number(this->baseConfig_.baud)); ui->truckEdit->setText(QString::number(this->baseConfig_.trackName)); + + this->rfidHasTrain = false; + this->videoHasTrain = false; } /** @@ -292,14 +360,14 @@ bool MainWindow::upWeb(std::string &carriageType, std::string &carriageNumber, s Json::StreamWriterBuilder writer; std::string str = Json::writeString(writer, arrayObj); - this->logInfo("发送web: " + QString::fromStdString(str)); + this->logInfo("第" + QString::fromStdString(carriageOrder) + "节,发送web: " + QString::fromStdString(str)); auto res = cli.Post(this->interfaceConfig_.upResultPath.toStdString(), header, str, "application/json"); if (res) { if (res->status == 200) { - this->logInfo("web返回: " + QString::fromStdString(res->body)); + this->logInfo("第" + QString::fromStdString(carriageOrder) + "节,web返回: " + QString::fromStdString(res->body)); Json::CharReaderBuilder readerBuilder; std::istringstream iss(res->body); Json::Value root; @@ -315,21 +383,21 @@ bool MainWindow::upWeb(std::string &carriageType, std::string &carriageNumber, s { if (root["msg"].asString() == "请求未授权") { - this->logWarn("因请求未授权,而上传识别结果失败!重新请求token。"); + this->logWarn("第" + QString::fromStdString(carriageOrder) + "节,因请求未授权,而上传识别结果失败!重新请求token。"); if (!this->getToken()) return false; return this->upWeb(carriageType, carriageNumber, carriageOrder, time); } - this->logError("识别结果上传失败,原因:" + QString::fromStdString(root.asString())); + this->logError("第" + QString::fromStdString(carriageOrder) + "节,识别结果上传失败,原因:" + QString::fromStdString(root.asString())); } } else { - this->logError("识别结果上传失败,返回数据解析异常,返回数据非json:" + QString::fromStdString(res->body)); + this->logError("第" + QString::fromStdString(carriageOrder) + "节,识别结果上传失败,返回数据解析异常,返回数据非json:" + QString::fromStdString(res->body)); } } else { - this->logError("识别结果上传失败,原因:" + QString::number(res->status) + " - " + QString::fromStdString(res->body)); + this->logError("第" + QString::fromStdString(carriageOrder) + "节,识别结果上传失败,原因:" + QString::number(res->status) + " - " + QString::fromStdString(res->body)); if (res->status == 401) { this->logWarn("因请求未授权,而上传识别结果失败!重新请求token。"); this->getToken(); @@ -339,12 +407,12 @@ bool MainWindow::upWeb(std::string &carriageType, std::string &carriageNumber, s } else { - this->logError("上传数据失败,请检查网络,或者上传地址!"); + this->logError("第" + QString::fromStdString(carriageOrder) + "节,上传数据失败,请检查网络,或者上传地址!"); } } catch (std::exception &e) { - this->logError("上传识别结果失败,原因:"); + this->logError("第" + QString::fromStdString(carriageOrder) + "节,上传识别结果失败,原因:"); this->logError(e.what()); } return false; @@ -429,7 +497,7 @@ void MainWindow::changeEvent(QEvent *event) { if((event->type()==QEvent::WindowStateChange)&&isMinimized()) { -// hide(); + this->hide(); m_pSystemTray->setIcon(QIcon("./logo.ico")); // 托盘时显示的图片 m_pSystemTray->setToolTip("Rfid车号识别-股道号:" + QString::number(this->baseConfig_.trackName)); // 鼠标在托盘图片时的提示 m_pSystemTray->showMessage("Rfid车号识别","已隐藏至托盘",QSystemTrayIcon::Information,10000); @@ -449,6 +517,7 @@ void MainWindow::closeEvent(QCloseEvent *event) // 验证账号和密码是否正确 if (password == "matrix") { this->initParam(); + this->tcp_->close(); event->accept(); // 关闭窗口 exit(0); } else { @@ -486,6 +555,8 @@ void MainWindow::creat_menu() void MainWindow::on_ShowMainAction() { this->show(); + this->showNormal(); + this->activateWindow(); } /** @@ -495,13 +566,16 @@ void MainWindow::on_ShowMainAction() */ void MainWindow::on_ExitAppAction() { - QString password = QInputDialog::getText(this, "关闭账号密码验证", "请输入密码:", QLineEdit::Password); + // 弹出对话框要求用户输入账号和密码 + QString password = QInputDialog::getText(this, "密码验证", "请输入密码:", QLineEdit::Password); // 验证账号和密码是否正确 - if (password == "123") { + if (password == "matrix") { + this->initParam(); + this->tcp_->close(); exit(0); } else { - QMessageBox::warning(this, "验证失败", "账号或密码不正确!"); + QMessageBox::warning(this, "验证失败", "密码不正确!"); } } @@ -516,6 +590,7 @@ void MainWindow::on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason reaso //双击托盘图标 //双击后显示主程序窗口 this->showNormal(); + this->activateWindow(); break; default: break; @@ -549,6 +624,7 @@ void MainWindow::openComClicked() // connect(timer, &QTimer::timeout, this, &MainWindow::readCom); // timer->start(10); connect(this->serial_, &QSerialPort::errorOccurred, this, &MainWindow::serialPort_error); + } else { @@ -629,21 +705,47 @@ void MainWindow::getQueueDataThread() QStringList rfidSubList = this->tmpRfid.split("&"); this->tmpRfid = ""; + auto split_lambda = [=](QString strFirst, QString strOther){ + if (strFirst == "0") + { + this->rfidHasTrain = false; + this->logInfo("RFID-火车离开了"); + // 关功放信号 + // 需要结合 “来车状态”广播消息,确认是否真的车离开了; TODO:没有真离开,则向串口发送 @on& 避免关功放 + emit IdentifyType(); + } + else + { + // TODO: 此处按照4个磁钢来配置,可能存在一定限制; 另外逻辑需要优化 + if (strOther == "000000" // 第一次检测来车时(前提是上一次功放已关闭) + && (strFirst == this->baseConfig_.magnetSteelOrder.left(1) + || strFirst == this->baseConfig_.magnetSteelOrder.mid(1, 1))) + { + this->rfidHasTrain = true; + this->logInfo("RFID-来车了"); + emit IdentifyType(); + } + } + }; + for (const auto & i : rfidSubList) { if (i.size() == 26) { // 车厢信息 QString strTrainInfo = i.left(14); + if (vecTrain.empty() || !vecTrain.contains(strTrainInfo)) { - bool isCarriage = false; - strTrainInfo.mid(3, 2).toInt(&isCarriage); - if (isCarriage) continue; + bool isNoCarriage = false; + int carT = strTrainInfo.mid(3, 2).simplified().toInt(&isNoCarriage); + isNoCarriage = carT >= 10; + if (isNoCarriage) continue; vecTrain.append(strTrainInfo); - this->resultTableModel_->setItem(vecTrain.size()-1, 0, new QStandardItem(strTrainInfo)); + int train_order = vecTrain.size(); + this->resultTableModel_->setItem(train_order - 1, 0, new QStandardItem(strTrainInfo)); + this->logInfo(QString("第%1节 %2").arg(train_order).arg(strTrainInfo)); emit upRfid_signals(); - this->logInfo(QString("第%1节 %2").arg(vecTrain.size()).arg(strTrainInfo)); } } else if (i.size() == 7) @@ -651,29 +753,13 @@ void MainWindow::getQueueDataThread() // 磁钢信号 QString strFirst = i.left(1); QString strOther = i.mid(1, i.size() - 1); - - if (strFirst == "0") - { - // 关功放信号 - // TODO: 需要结合 “来车状态”广播消息,确认是否真的车离开了 没有真离开,则向串口发送 @on& 避免关功放 - this->initParam(); - this->logInfo("功放关闭"); - } - else - { - // TODO: 此处按照4个磁钢来配置,可能存在一定限制; 另外逻辑需要优化 - if (strOther == "000000" // 第一次检测来车时(前提是上一次功放已关闭) - && (strFirst == this->baseConfig_.magnetSteelOrder.left(1) - || strFirst == this->baseConfig_.magnetSteelOrder.mid(1, 1))) - { - this->logInfo("来车了"); - this->mkRfidLog(); - this->needIdentify = true; - this->trainTime = this->getSystemTime(); - this->resultTableModel_->clear(); - this->resultTableModel_ = this->getStandardItemModel(); - } - } + split_lambda(strFirst, strOther); + } + else if (i.size() == 14) // 特殊情况,来车信号少了&符 + { + QString strFirst = i.left(1); + QString strOther = i.mid(1, 6); + split_lambda(strFirst, strOther); } } } @@ -704,7 +790,60 @@ void MainWindow::upRfid() std::string strOrder = QString::number(order).toStdString(); if (!this->upWeb(carriageType, carriageNum, strOrder, nowTime)) { - this->logError("识别结果上传失败!"); + this->logError("第" + QString::fromStdString(strOrder) + "节,识别结果上传失败!"); } } +void MainWindow::IdentifyTypeUpdate() { + if (this->rfidHasTrain || this->videoHasTrain) + { + if (!this->needIdentify) + { + this->logInfo("来车了"); + this->mkRfidLog(); + this->needIdentify = true; + this->trainTime = this->getSystemTime(); + this->resultTableModel_->clear(); + this->resultTableModel_ = this->getStandardItemModel(); + } + } + else if (!this->rfidHasTrain && !this->videoHasTrain) + { + this->initParam(); + this->logInfo("火车离开了"); + } +} + +// ============================= 测试 ==================================== + +void MainWindow::readTestInfo() +{ + + if (this->isOpenCom) + { + logWarn("请先关闭串口后进行测试操作!"); + return; + } + QString filePath = QFileDialog::getOpenFileName(this, "选择一个文件", QDir::currentPath(), "(*.*)"); + if(filePath.isEmpty()){ + QMessageBox::warning(this, "打开文件", "选择文件不能为空"); + return; + } + // 创建一个QFile对象并打开要读取的文本文件 + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + logError("无法打开测试文件:" + filePath); + return; + } + logInfo("开始读取测试数据..."); + // 将文件内容读入到QStringList中 + QTextStream in(&file); + while(!in.atEnd()) { + QString line = in.readLine(); + this->queue_.push(line); + emit getRfid_signals(); + } + // 关闭文件 + file.close(); + logInfo("---读取测试数据完毕---"); +} \ No newline at end of file diff --git a/src/qt_source/mainwindow.h b/src/qt_source/mainwindow.h index eb928f5..0ba48d9 100644 --- a/src/qt_source/mainwindow.h +++ b/src/qt_source/mainwindow.h @@ -40,6 +40,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -47,6 +50,7 @@ #include "common.h" #include "ConfigUtil.h" #include "ComDetect.h" +#include "TcpClient.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -59,6 +63,14 @@ class MainWindow : public QWidget public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); + void logDebug(const QString& message); + void logInfo(const QString& message); + void logWarn(const QString& message); + void logError(const QString& message); + + bool mkRfidLog(); + bool rnameRfidLog(); + void saveRfidLog(const QString &value); void initParam(); @@ -67,21 +79,30 @@ public: QString getSystemTime(); + // 获const 取串口列表& + QList getComList(); + // 将所有串口const 展示在下&拉列表 + void initComboBox(); + // 设置菜单项 + void initMenu(); + // 创建日志目录 + static bool mkLogDir(); + // 获取QStandardItem + QStandardItemModel* getStandardItemModel(); + QStandardItem* getStandardItem(const QString &value); + private: QString trainTime; QString logRfidRecvName; QFile recvLog; - bool mkRfidLog(); - bool rnameRfidLog(); - void saveRfidLog(const QString &value); QString configPath_; // ai_matrix::BaseConfig baseConfig_; ai_matrix::InterfaceConfig interfaceConfig_; + ai_matrix::SServerConfig socketServerConfig_; std::string webToken; //授权信息 - QSerialPort *serial_; //串口 // 表格model @@ -99,23 +120,19 @@ private: // 识别方向正确标志 bool needIdentify = false; + // 视频识别有火车标志(使用socket服务时才有用) + bool videoHasTrain = false; + // RFID识别有火车标志 + bool rfidHasTrain = false; // 获取当前时间 QDateTime currentTime_ = QDateTime::currentDateTime(); - void logDebug(const QString& message); - void logInfo(const QString& message); - void logWarn(const QString& message); - void logError(const QString& message); - // 获const 取串口列表& - QList getComList(); - // 将所有串口const 展示在下&拉列表 - void initComboBox(); - // 创建日志目录 - static bool mkLogDir(); - // 获取QStandardItem - QStandardItemModel* getStandardItemModel(); - QStandardItem* getStandardItem(const QString &value); + TcpClient* tcpClient; + private: + QTcpSocket* tcp_ = nullptr; + QStatusBar* statusBar; + QLabel *statusInfo; QMenu* m_pTrayMennu; //系统托盘右键菜单项 QSystemTrayIcon* m_pSystemTray; //系统托盘图标 @@ -123,16 +140,18 @@ private: //右键菜单栏选项 QAction* m_pActionShow; QAction* m_pActionQuit; - void creat_menu(); void creat_action(); void changeEvent(QEvent *event); void on_ShowMainAction(); void on_ExitAppAction(); void closeEvent(QCloseEvent *event); + void creat_menu(); signals: void getRfid_signals(); void upRfid_signals(); + void connect_socket(QString ip, int port); + void IdentifyType(); private slots: void openComClicked(); void readCom(); @@ -140,7 +159,8 @@ private slots: void upRfid(); void serialPort_error(QSerialPort::SerialPortError error); void on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason reason); - + void readTestInfo(); + void IdentifyTypeUpdate(); private: Ui::MainWindow *ui; diff --git a/src/qt_source/mainwindow.ui b/src/qt_source/mainwindow.ui index 6aff531..83f96f6 100644 --- a/src/qt_source/mainwindow.ui +++ b/src/qt_source/mainwindow.ui @@ -35,7 +35,7 @@ - 100 + 80 16777215 @@ -70,7 +70,7 @@ - 100 + 80 16777215 @@ -120,7 +120,7 @@ - 100 + 80 16777215 @@ -139,7 +139,7 @@ - 120 + 100 40 @@ -205,6 +205,45 @@ border: 2px solid rgb(134, 134, 134); + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 20 + 20 + + + + + + + + + 50 + 50 + + + + + 50 + 50 + + + + background-color: rgb(255, 255, 255); +border: 2px solid rgb(134, 134, 134); + + + 测试 + + + @@ -309,23 +348,43 @@ border: 2px solid rgb(134, 134, 134); - - - - 700 - 20 - - - - - 700 - 20 - - - - 日志: - - + + + + + + 50 + 20 + + + + + 100 + 20 + + + + Qt::NoContextMenu + + + 日志: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/src/qt_source/ui_MainWindow.h b/src/qt_source/ui_MainWindow.h index 7906839..b26f54c 100644 --- a/src/qt_source/ui_MainWindow.h +++ b/src/qt_source/ui_MainWindow.h @@ -39,6 +39,8 @@ public: QSpacerItem *horizontalSpacer; QLabel *LEDlabel; QPushButton *openComButton; + QSpacerItem *horizontalSpacer_5; + QPushButton *testButton; QSpacerItem *horizontalSpacer_2; QHBoxLayout *horizontalLayout_2; QVBoxLayout *verticalLayout; @@ -48,7 +50,9 @@ public: QSpacerItem *horizontalSpacer_3; QTableView *resultTable; QVBoxLayout *verticalLayout_2; + QHBoxLayout *horizontalLayout_4; QLabel *label_5; + QSpacerItem *horizontalSpacer_4; QTextBrowser *textBrowser; void setupUi(QWidget *MainWindow) @@ -65,7 +69,7 @@ public: horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); label = new QLabel(MainWindow); label->setObjectName(QString::fromUtf8("label")); - label->setMaximumSize(QSize(100, 16777215)); + label->setMaximumSize(QSize(80, 16777215)); label->setStyleSheet(QString::fromUtf8("font: 75 9pt \"Arial\";")); horizontalLayout->addWidget(label); @@ -80,7 +84,7 @@ public: label_2 = new QLabel(MainWindow); label_2->setObjectName(QString::fromUtf8("label_2")); - label_2->setMaximumSize(QSize(100, 16777215)); + label_2->setMaximumSize(QSize(80, 16777215)); label_2->setStyleSheet(QString::fromUtf8("font: 75 9pt \"Arial\";")); horizontalLayout->addWidget(label_2); @@ -98,14 +102,14 @@ public: label_3 = new QLabel(MainWindow); label_3->setObjectName(QString::fromUtf8("label_3")); - label_3->setMaximumSize(QSize(100, 16777215)); + label_3->setMaximumSize(QSize(80, 16777215)); horizontalLayout->addWidget(label_3); truckEdit = new QLineEdit(MainWindow); truckEdit->setObjectName(QString::fromUtf8("truckEdit")); truckEdit->setMinimumSize(QSize(120, 40)); - truckEdit->setMaximumSize(QSize(120, 40)); + truckEdit->setMaximumSize(QSize(100, 40)); truckEdit->setStyleSheet(QString::fromUtf8("background-color: rgb(255, 255, 255);")); horizontalLayout->addWidget(truckEdit); @@ -132,6 +136,19 @@ public: horizontalLayout->addWidget(openComButton); + horizontalSpacer_5 = new QSpacerItem(20, 20, QSizePolicy::Maximum, QSizePolicy::Minimum); + + horizontalLayout->addItem(horizontalSpacer_5); + + testButton = new QPushButton(MainWindow); + testButton->setObjectName(QString::fromUtf8("testButton")); + testButton->setMinimumSize(QSize(50, 50)); + testButton->setMaximumSize(QSize(50, 50)); + testButton->setStyleSheet(QString::fromUtf8("background-color: rgb(255, 255, 255);\n" +"border: 2px solid rgb(134, 134, 134);")); + + horizontalLayout->addWidget(testButton); + horizontalSpacer_2 = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Minimum); horizontalLayout->addItem(horizontalSpacer_2); @@ -155,7 +172,7 @@ public: upflagLabel = new QLabel(MainWindow); upflagLabel->setObjectName(QString::fromUtf8("upflagLabel")); - upflagLabel->setMinimumSize(QSize(60, 20)); + upflagLabel->setMinimumSize(QSize(70, 20)); upflagLabel->setMaximumSize(QSize(80, 20)); horizontalLayout_3->addWidget(upflagLabel); @@ -180,12 +197,22 @@ public: verticalLayout_2 = new QVBoxLayout(); verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2")); + horizontalLayout_4 = new QHBoxLayout(); + horizontalLayout_4->setObjectName(QString::fromUtf8("horizontalLayout_4")); label_5 = new QLabel(MainWindow); label_5->setObjectName(QString::fromUtf8("label_5")); - label_5->setMinimumSize(QSize(700, 20)); - label_5->setMaximumSize(QSize(700, 20)); + label_5->setMinimumSize(QSize(50, 20)); + label_5->setMaximumSize(QSize(100, 20)); + label_5->setContextMenuPolicy(Qt::NoContextMenu); - verticalLayout_2->addWidget(label_5); + horizontalLayout_4->addWidget(label_5); + + horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + horizontalLayout_4->addItem(horizontalSpacer_4); + + + verticalLayout_2->addLayout(horizontalLayout_4); textBrowser = new QTextBrowser(MainWindow); textBrowser->setObjectName(QString::fromUtf8("textBrowser")); @@ -224,6 +251,7 @@ public: label_3->setText(QCoreApplication::translate("MainWindow", "\350\202\241\351\201\223\345\220\215:", nullptr)); LEDlabel->setText(QString()); openComButton->setText(QCoreApplication::translate("MainWindow", "\346\211\223\345\274\200\344\270\262\345\217\243", nullptr)); + testButton->setText(QCoreApplication::translate("MainWindow", "\346\265\213\350\257\225", nullptr)); label_4->setText(QCoreApplication::translate("MainWindow", "\350\257\206\345\210\253\347\273\223\346\236\234:", nullptr)); upflagLabel->setText(QCoreApplication::translate("MainWindow", "\344\270\215\344\270\212\344\274\240", nullptr)); label_5->setText(QCoreApplication::translate("MainWindow", "\346\227\245\345\277\227:", nullptr)); diff --git a/src/serial/ComDetect.cpp b/src/serial/ComDetect.cpp index 08d4b74..5a9b6fe 100644 --- a/src/serial/ComDetect.cpp +++ b/src/serial/ComDetect.cpp @@ -60,6 +60,7 @@ QSerialPort* ComDetect::openCom(const QString &com, int baud) bool ComDetect::closeCom() { + this->serial_->clear(); this->serial_->close(); return true; }