diff --git a/app/Train_RFID.exe b/app/Train_RFID.exe index 978f62c..6d9036b 100644 Binary files a/app/Train_RFID.exe and b/app/Train_RFID.exe differ diff --git a/app/config/config.ini b/app/config/config.ini index bebc858..35943f0 100644 --- a/app/config/config.ini +++ b/app/config/config.ini @@ -5,17 +5,22 @@ track_name=2 have_magnet_steel=true magnet_steel_order=8421 up_result=true -use_socket_server=false +use_socket_server=true +use_device_warn=true [interface] http_ip=192.168.2.212 http_port=20004 token_path=/api/token_path up_result_path=/api/train-carriage/identification/rfid-save +up_warning_path=/api/blade-train/deviceInfo/save username=guest_01 password=d55b0f642e817eea24725d2f2a31dd08 [socket_server] -server_ip=192.168.2.1 +server_ip=127.0.0.1 server_port=7000 delayed_upload=4 + +[device_warn] +min_train_size=10 diff --git a/src/ConfigUtil/ConfigUtil.cpp b/src/ConfigUtil/ConfigUtil.cpp index 5fc8615..e4636e3 100644 --- a/src/ConfigUtil/ConfigUtil.cpp +++ b/src/ConfigUtil/ConfigUtil.cpp @@ -27,6 +27,7 @@ bool ConfigUtil::readBaseConfig(const QString &configFile, QString &errorMessage 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(); + config.useDeviceWarn = mset->value("use_device_warn", false).toBool(); mset->endGroup(); } catch (const std::exception &e) { @@ -49,7 +50,8 @@ bool ConfigUtil::readInterfaceConfig(const QString &configFile, QString &errorMe config.httpIp = mset->value("http_ip", "").toString(); config.httpPort = mset->value("http_port", "").toInt(); config.tokenPath = mset->value("token_path", 19200).toString(); - config.upResultPath = mset->value("up_result_path", 1).toString(); + config.upResultPath = mset->value("up_result_path", "").toString(); + config.upWarningPath = mset->value("up_warning_path", "").toString(); config.username = mset->value("username", "").toString(); config.password = mset->value("password", false).toString(); @@ -80,4 +82,24 @@ bool ConfigUtil::readSocketServerConfig(const QString &configFile, QString &erro return false; } return true; +} + +bool ConfigUtil::readDeviceWarnConfig(const QString &configFile, QString &errorMessage, + ai_matrix::DeviceWarnConfig &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("device_warn"); + config.min_train_size = mset->value("min_train_size", 99).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 ac1993b..5f15356 100644 --- a/src/ConfigUtil/ConfigUtil.h +++ b/src/ConfigUtil/ConfigUtil.h @@ -20,6 +20,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); + static bool readDeviceWarnConfig(const QString& configFile, QString &errorMessage, ai_matrix::DeviceWarnConfig &config); }; diff --git a/src/common/common.h b/src/common/common.h index 49bbc85..41323bf 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -37,6 +37,8 @@ namespace ai_matrix { bool upResult; // 使用socket来车通讯 bool useSocketServer; + // 是否使用设备异常报警 + bool useDeviceWarn; }; struct InterfaceConfig { @@ -49,6 +51,8 @@ namespace ai_matrix { QString tokenPath; // 上传识别结果的方法 QString upResultPath; + // 上传报警的方法 + QString upWarningPath; // 用户名 QString username; // 密码 @@ -63,6 +67,12 @@ namespace ai_matrix { // 识别结果延后X节上传,以等待Socket反馈火车运行方向 int delayed_upload; }; + + struct DeviceWarnConfig { + // 识别车厢结束允许的最小值(小于这个值会报警) + int min_train_size; + }; + // --- 配置文件 --- struct TrainInfo { diff --git a/src/qt_source/mainwindow.cpp b/src/qt_source/mainwindow.cpp index c3df802..9bc85c3 100644 --- a/src/qt_source/mainwindow.cpp +++ b/src/qt_source/mainwindow.cpp @@ -15,7 +15,7 @@ MainWindow::MainWindow(QWidget *parent) 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); + QLabel* statusVersion = new QLabel("开启时间:" + QDateTime::currentDateTime().toString("yy-MM-dd hh:mm"),this); this->statusBar->addWidget(statusVersion); layout()->addWidget(this->statusBar); @@ -71,12 +71,15 @@ MainWindow::MainWindow(QWidget *parent) // 初始化LED指示灯 this->upResultType(this->baseConfig_.upResult); - this->readComThread = new ReadComThread(&this->queueTrainInfo_, this); + this->readComThread = new ReadComThread(&this->queueTrainInfo_, &this->queueWarn_, this); this->readComThread->start(); this->upResultThread = new UpResultThread(&this->queueTrainInfo_, this); this->upResultThread->start(); + this->upWarnThread = new UpWarnThread(&this->queueWarn_, this); + this->upWarnThread->start(); + connect(this, &MainWindow::openCom_signals, this->readComThread, &ReadComThread::openCom); connect(this, &MainWindow::readTestRfid_signals, this->readComThread, &ReadComThread::readTestInfo); @@ -97,6 +100,11 @@ MainWindow::MainWindow(QWidget *parent) connect(this->upResultThread, &UpResultThread::WarnSignals, this, &MainWindow::WarnSlots); connect(this->upResultThread, &UpResultThread::ErrorSignals, this, &MainWindow::ErrorSlots); + connect(this->upWarnThread, &UpWarnThread::DebugSignals, this, &MainWindow::DebugSlots); + connect(this->upWarnThread, &UpWarnThread::InfoSignals, this, &MainWindow::InfoSlots); + connect(this->upWarnThread, &UpWarnThread::WarnSignals, this, &MainWindow::WarnSlots); + connect(this->upWarnThread, &UpWarnThread::ErrorSignals, this, &MainWindow::ErrorSlots); + ui->openComButton->click(); } diff --git a/src/qt_source/mainwindow.h b/src/qt_source/mainwindow.h index 2a94a71..948b9d0 100644 --- a/src/qt_source/mainwindow.h +++ b/src/qt_source/mainwindow.h @@ -54,6 +54,7 @@ #include "UpResultThread.h" #include "ReadComThread.h" +#include "UpWarnThread.h" QT_BEGIN_NAMESPACE @@ -92,6 +93,7 @@ public: private: UpResultThread *upResultThread; + UpWarnThread *upWarnThread; ReadComThread *readComThread; QString logRfidRecvName; @@ -116,6 +118,7 @@ private: QStringList vecTrain; MQueue queue_{}; // RFID读取的数据队列 MQueue queueTrainInfo_{}; // RFID读取的磁钢信息队列 + MQueue queueWarn_{}; // 报警信息队列 QString rfidSourceInfo; QString tmpRfid; //临时存储的RFID原始数据,用于防止接收的数据不完整 diff --git a/src/threads/ReadComThread.cpp b/src/threads/ReadComThread.cpp index 956e4e4..719b998 100644 --- a/src/threads/ReadComThread.cpp +++ b/src/threads/ReadComThread.cpp @@ -5,6 +5,7 @@ #include "ReadComThread.h" ReadComThread::ReadComThread(MQueue *queueTrainInfo, + MQueue *queueWarnInfo, QObject *parent) : QThread(parent) { @@ -18,8 +19,13 @@ ReadComThread::ReadComThread(MQueue *queueTrainInfo, { emit this->ErrorSignals(errorMessage); } + if (!ConfigUtil::readDeviceWarnConfig(g_config_path, errorMessage, this->deviceWarnConfig_)) + { + emit this->ErrorSignals(errorMessage); + } this->queueTrainInfo_ = queueTrainInfo; + this->queueWarnInfo_ = queueWarnInfo; this->logRfidRecvName = "./Logs/rfid_data.txt"; this->recvLog.setFileName(logRfidRecvName); @@ -282,7 +288,6 @@ void ReadComThread::getQueueDataThread() QString rfidinfo = this->rfidSourceInfo; this->rfidSourceInfo = ""; emit this->upRfid_signals(rfidinfo); - } } else if (i.size() == 7) @@ -327,7 +332,10 @@ void ReadComThread::IdentifyTypeUpdate() { } else if (!this->rfidHasTrain && !this->videoHasTrain) { - this->rfidSourceInfo + if (this->vecTrain.size() < this->deviceWarnConfig_.min_train_size + && this->iDirection > 0 + && (this->rfidSourceInfo.size() > 128 || this->vecTrain.size() > 1)) + this->queueWarnInfo_->push("火车驶过,疑似RFID设备故障,读取到的车厢号有丢失"); this->initParam(); emit this->InfoSignals("火车离开了"); } diff --git a/src/threads/ReadComThread.h b/src/threads/ReadComThread.h index e5fbd7b..c6dcb18 100644 --- a/src/threads/ReadComThread.h +++ b/src/threads/ReadComThread.h @@ -19,12 +19,14 @@ class ReadComThread : public QThread{ Q_OBJECT public: ReadComThread(MQueue *queueTrainInfo, + MQueue *queueWarnInfo, QObject *parent = nullptr); ~ReadComThread() {}; void run() override; private: MQueue *queueTrainInfo_ = nullptr; + MQueue *queueWarnInfo_ = nullptr; MQueue queueTmpTrainInfo_{}; // RFID临时信息队列 QSerialPort *serial_; //串口 bool auto_reconnect_serial_ = false; @@ -32,6 +34,7 @@ private: ai_matrix::BaseConfig baseConfig_; ai_matrix::SServerConfig socketServerConfig_; + ai_matrix::DeviceWarnConfig deviceWarnConfig_; TcpClient* tcpClient; QTcpSocket* tcp_ = nullptr; @@ -101,6 +104,7 @@ public slots: void getQueueDataThread(); void IdentifyTypeUpdate(); void upRfid(const QString &rfidInfo); +// void upWarn(const QString &warnInfo); void tryToReconnect(); void readTestInfo(const QString &filePath); diff --git a/src/threads/UpResultThread.cpp b/src/threads/UpResultThread.cpp index 8d3407b..78abdfa 100644 --- a/src/threads/UpResultThread.cpp +++ b/src/threads/UpResultThread.cpp @@ -14,11 +14,11 @@ UpResultThread::UpResultThread(MQueue *queueTrainInfo, QObject *paren QString errorMessage = ""; if (!ConfigUtil::readBaseConfig(g_config_path, errorMessage, this->baseConfig_)) { - this->ErrorSignals(errorMessage); + emit this->ErrorSignals(errorMessage); } if (!ConfigUtil::readInterfaceConfig(g_config_path, errorMessage, this->interfaceConfig_)) { - this->ErrorSignals(errorMessage); + emit this->ErrorSignals(errorMessage); } } @@ -68,7 +68,7 @@ bool UpResultThread::upWeb(TrainInfo &trainInfo) Json::StreamWriterBuilder writer; std::string str = Json::writeString(writer, arrayObj); - this->InfoSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,发送web: " + QString::fromStdString(str)); + emit this->InfoSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,发送web: " + QString::fromStdString(str)); httplib::Client cli(this->interfaceConfig_.httpIp.toStdString(), this->interfaceConfig_.httpPort); cli.set_connection_timeout(3, 0); @@ -100,23 +100,23 @@ bool UpResultThread::upWeb(TrainInfo &trainInfo) { if (root["msg"].asString() == "请求未授权") { - this->WarnSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,因请求未授权,而上传识别结果失败!重新请求token。"); + emit this->WarnSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,因请求未授权,而上传识别结果失败!重新请求token。"); if (!this->getToken()) return false; return this->upWeb(trainInfo); } - this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,原因:" + QString::fromStdString(root["msg"].asString())); + emit this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,原因:" + QString::fromStdString(root["msg"].asString())); } } else { - this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,返回数据解析异常,返回数据非json:" + QString::fromStdString(res->body)); + emit this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,返回数据解析异常,返回数据非json:" + QString::fromStdString(res->body)); } } else { - this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,原因:" + QString::number(res->status) + " - " + QString::fromStdString(res->body)); + emit this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,识别结果上传失败,原因:" + QString::number(res->status) + " - " + QString::fromStdString(res->body)); if (res->status == 401) { - this->WarnSignals("因请求未授权,而上传识别结果失败!重新请求token。"); + emit this->WarnSignals("因请求未授权,而上传识别结果失败!重新请求token。"); this->getToken(); return this->upWeb(trainInfo); } @@ -124,12 +124,12 @@ bool UpResultThread::upWeb(TrainInfo &trainInfo) } else { - this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,上传数据失败,请检查网络,或者上传地址!"); + emit this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,上传数据失败,请检查网络,或者上传地址!"); } } catch (std::exception &e) { - this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,上传识别结果失败,原因:" + QString::fromStdString(e.what())); + emit this->ErrorSignals("第" + QString::fromStdString(trainInfo.strOrder) + "节,上传识别结果失败,原因:" + QString::fromStdString(e.what())); } return false; } @@ -173,17 +173,17 @@ bool UpResultThread::getToken() this->webToken = root["token_type"].asString(); this->webToken.append(" "); this->webToken.append(root["access_token"].asString()); - this->InfoSignals("已获取到web token"); + emit this->InfoSignals("已获取到web token"); return true; } else { - this->ErrorSignals("获取web token失败,原因:" + QString::fromStdString(res->body)); + emit this->ErrorSignals("获取web token失败,原因:" + QString::fromStdString(res->body)); } } else { - this->ErrorSignals("获取web token返回数据解析异常,返回数据非json。详细:" + QString::fromStdString(res->body)); + emit this->ErrorSignals("获取web token返回数据解析异常,返回数据非json。详细:" + QString::fromStdString(res->body)); } } } @@ -193,12 +193,12 @@ bool UpResultThread::getToken() // if (err == httplib::Error::Connection) { // std::cout << " (连接出错)" << std::endl; // } - this->ErrorSignals("获取web token失败!请检查网络或请求地址。详细:" + QString::fromStdString(to_string(err))); + emit this->ErrorSignals("获取web token失败!请检查网络或请求地址。详细:" + QString::fromStdString(to_string(err))); } } catch (std::exception &e) { - this->ErrorSignals("获取授权失败,原因:" + QString::fromStdString(e.what())); + emit this->ErrorSignals("获取授权失败,原因:" + QString::fromStdString(e.what())); } return false; } diff --git a/src/threads/UpWarnThread.cpp b/src/threads/UpWarnThread.cpp new file mode 100644 index 0000000..da1b221 --- /dev/null +++ b/src/threads/UpWarnThread.cpp @@ -0,0 +1,204 @@ +// +// Created by Mr.V on 2024/4/3. +// + +#include "UpWarnThread.h" + + +UpWarnThread::UpWarnThread(MQueue *queueWarnInfo, QObject *parent) : + QThread(parent) +{ + this->queueWarnInfo_ = queueWarnInfo; + + // 配置文件读取 + QString errorMessage = ""; + if (!ConfigUtil::readBaseConfig(g_config_path, errorMessage, this->baseConfig_)) + { + emit this->ErrorSignals(errorMessage); + } + if (!ConfigUtil::readInterfaceConfig(g_config_path, errorMessage, this->interfaceConfig_)) + { + emit this->ErrorSignals(errorMessage); + } +} + +void UpWarnThread::run() +{ + while (true) + { + while (!this->queueWarnInfo_->isEmpty()) + { + QString info = this->queueWarnInfo_->pop(); + if (!this->upWarn(info)) + { + + } + } + QThread::sleep(1); + } +} + +/** + * @brief:Http发送RFID设备异常 + * @param:info:RFID的原始数据(过滤掉了重复磁条信息) + * @return: 成功:true + * 失败:false + */ +bool UpWarnThread::upWarn(const QString &info) +{ + try { + Json::Value arrayObj; //构建对象 + + arrayObj["tainsModule"] = "2"; + arrayObj["networkStatus"] = "正常"; + arrayObj["devName"] = "RFID设备"; + arrayObj["devSn"] = this->baseConfig_.trackName + "股道"; + arrayObj["cpuData"] = ""; + arrayObj["memoryUsage"] = ""; + arrayObj["devRunningStatus"] = "异常"; + arrayObj["devCheckResult"] = info.toStdString(); + arrayObj["devIp"] = ""; + arrayObj["devAccount"] = ""; + + Json::Value trainParams; + trainParams["poundNo"] = std::to_string(this->baseConfig_.trackName); + arrayObj["trainParams"] = trainParams; + Json::StreamWriterBuilder writer; + std::string str = Json::writeString(writer, arrayObj); + + this->WarnSignals("根据RFID反馈的信号判断,疑似丢失车厢磁条标签。已发送web: " + QString::fromStdString(str)); + httplib::Client cli(this->interfaceConfig_.httpIp.toStdString(), this->interfaceConfig_.httpPort); + + cli.set_connection_timeout(3, 0); + cli.set_read_timeout(3, 0); + httplib::Headers header; + httplib::Params params; + header.emplace("blade-auth", this->webToken); + header.emplace("charset", "utf-8"); + //header.emplace("Content-Type", "application/json"); + + auto res = cli.Post(this->interfaceConfig_.upWarningPath.toStdString(), header, str, "application/json"); + + if (res) + { + if (res->status == 200) + { + emit this->InfoSignals("反馈报警信息,web返回: " + QString::fromStdString(res->body)); + Json::CharReaderBuilder readerBuilder; + std::istringstream iss(res->body); + Json::Value root; + std::string errs; + bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &root, &errs); + if (parsingSuccessful) + { + if (root["success"].asBool()) + { + return true; + } + else + { + + if (root["msg"].asString() == "请求未授权") { + emit this->WarnSignals("反馈报警信息,因请求未授权,而上传识别结果失败!重新请求token。"); + if (!this->getToken()) return false; + return this->upWarn(info); + } + emit this->ErrorSignals("报警信息上传失败,原因:" + QString::fromStdString(root["msg"].asString())); + } + } + else + { + emit this->ErrorSignals("报警信息上传失败,返回数据解析异常,返回数据非json:" + QString::fromStdString(res->body)); + } + } + else + { + emit this->ErrorSignals("报警信息上传失败,原因:" + QString::number(res->status) + " - " + QString::fromStdString(res->body)); + if (res->status == 401) { + emit this->WarnSignals("报警信息上传失败!重新请求token。"); + this->getToken(); + return this->upWarn(info); + } + } + } + else + { + emit this->ErrorSignals("报警信息,上传数据失败,请检查网络,或者上传地址!"); + } + } + catch (std::exception &e) + { + emit this->ErrorSignals("报警信息,上传识别结果失败,原因:" + QString::fromStdString(e.what())); + } + return false; +} + +/** + * @brief:Http获取授权 + * @param: + * @return: + */ +bool UpWarnThread::getToken() +{ + try + { + httplib::Client cli(this->interfaceConfig_.httpIp.toStdString(), this->interfaceConfig_.httpPort); + cli.set_connection_timeout(0, 300 * 1000); + cli.set_read_timeout(0,300*1000); + httplib::Headers header; + httplib::Params params; + + header.emplace("Authorization", "Basic Y2xpZW50X2VudGVycHJpc2U6Y2xpZW50X2VudGVycHJpc2Vfc2VjcmV0"); + + params.emplace("username", this->interfaceConfig_.username.toStdString()); + params.emplace("password", this->interfaceConfig_.password.toStdString()); + params.emplace("tenantId", "000000"); + params.emplace("grant_type", "password"); + auto res = cli.Post("/api/blade-auth/oauth/token", header, params); + if (res) + { + if (res->status == 200) + { + Json::CharReaderBuilder readerBuilder; + std::istringstream iss(res->body); + Json::Value root; + std::string errs; + bool parsingSuccessful = Json::parseFromStream(readerBuilder, iss, &root, &errs); + + if (parsingSuccessful) + { + if (!root.get("token_type", "").asString().empty()) + { + this->webToken = root["token_type"].asString(); + this->webToken.append(" "); + this->webToken.append(root["access_token"].asString()); + emit this->InfoSignals("已获取到web token"); + return true; + } + else + { + emit this->ErrorSignals("获取web token失败,原因:" + QString::fromStdString(res->body)); + } + } + else + { + emit this->ErrorSignals("获取web token返回数据解析异常,返回数据非json。详细:" + QString::fromStdString(res->body)); + } + } + } + else + { + auto err = res.error(); +// if (err == httplib::Error::Connection) { +// std::cout << " (连接出错)" << std::endl; +// } + emit this->ErrorSignals("获取web token失败!请检查网络或请求地址。详细:" + QString::fromStdString(to_string(err))); + } + } + catch (std::exception &e) + { + emit this->ErrorSignals("获取授权失败,原因:" + QString::fromStdString(e.what())); + } + return false; +} + diff --git a/src/threads/UpWarnThread.h b/src/threads/UpWarnThread.h new file mode 100644 index 0000000..9989736 --- /dev/null +++ b/src/threads/UpWarnThread.h @@ -0,0 +1,43 @@ +// +// Created by Mr.V on 2024/4/3. +// + +#ifndef TRAIN_RFID_UPWARNTHREAD_H +#define TRAIN_RFID_UPWARNTHREAD_H + +#include +#include "common.h" +#include "MQueue.h" +#include "httplib.h" +#include "json.h" +#include "ConfigUtil.h" + +using namespace ai_matrix; + +class UpWarnThread : public QThread{ + Q_OBJECT +public: + ~UpWarnThread() {}; + + UpWarnThread(MQueue *queueWarnInfo, QObject *parent = nullptr); + + void run() override; + +private: + MQueue *queueWarnInfo_ = nullptr; + ai_matrix::BaseConfig baseConfig_; + ai_matrix::InterfaceConfig interfaceConfig_; + std::string webToken; //授权信息 + + bool upWarn(const QString &info); + bool getToken(); + +signals: + void DebugSignals(const QString &info); + void InfoSignals(const QString &info); + void WarnSignals(const QString &info); + void ErrorSignals(const QString &info); +}; + + +#endif //TRAIN_RFID_UPWARNTHREAD_H