#include "MainWindow.h" #include "ui_MainWindow.h" #define DEBUG_HTTP 1 MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); this->setWindowTitle("Matrix"); btrainLeave = true; baccredit = false; m_sendHttpSign = false; m_icarriageOrder = 0; m_icot = 0; bdir = false; szHavdcarTime = ""; if (_access("Logs", 0) == -1) { //判断是否存在日志的文件夹,没有则创建 std::string folderPath = "Logs"; if (0 != _mkdir(folderPath.c_str())) { _mkdir(folderPath.c_str()); // 返回 0 表示创建成功,-1 表示失败 } } serial = new QSerialPort; m_pSystemTray=new QSystemTrayIcon(this); //读取配置文件 read_configure_file(); //设置并打开串口 // set_uart_parameter(); //串口接收数据信号槽 //connect(serial,&QSerialPort::readyRead,this,&MainWindow::rece_data_slots); QTimer* timer = new QTimer(this); // connect(timer, &QTimer::timeout, this, &MainWindow::rece_data_slots); // 设置定时器的时间间隔,例如50毫秒 // timer->start(10); //最小化信号槽 connect(m_pSystemTray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason))); //获取系统时间 get_system_time(); QString logName = "Logs/ceshi.txt"; logtest.setFileName(logName); logtest.open(QIODevice::ReadWrite | QIODevice::Append); QString logNamerecv = "Logs/recv.txt"; logrecv.setFileName(logNamerecv); logrecv.open(QIODevice::ReadWrite | QIODevice::Append); //初始最小化 //this->showMinimized();//最小化 // 设置最大展示数据行数 this->ui->textBrowser->document()->setMaximumBlockCount(1000); tid = std::thread(&MainWindow::get_queue_data,this); } MainWindow::~MainWindow() { serial->close(); logOut.close(); // if(tid.joinable()){ // tid.join(); // } delete ui; } /** * @brief:从queue中获取数据 * @param:空 * @return:空 */ void MainWindow::get_queue_data(){ std::string szData = ""; while(1) { bool bData = false; while(queData.size() > 0) { std::lock_guard lk(mtx_sync_); std::string str_temp = queData.front(); queData.pop(); szData.append(str_temp); if(szData.size() >= 8 && szData.front() == '@' && szData.back() == '&') { bData = true; break; } } if(bData){ deal_str_data(szData); szData.clear(); } std::this_thread::sleep_for(std::chrono::microseconds(20)); } } /** * @brief:解析数据 * @param:szStr:从queue中取到的字符串 * @return:空 */ void MainWindow::deal_str_data(const std::string &szStr) { std::string szcarModel = ""; std::string szcarNumber = ""; get_system_time(); std::string logstr = "长度:" + std::to_string(szStr.size()) + " 数据:" + szStr; print_log(logstr); int apos = 0,spos = 0; int cout = std::count(szStr.begin(),szStr.end(),'@'); if(cout > 0) { for (int i = 0;i < cout;i++) { apos = szStr.find('@',apos); spos = szStr.find('&',spos); if(apos == std::string::npos || spos == std::string::npos){ break; } std::string szdata = szStr.substr(apos,spos - apos + 1); ui->textBrowser->append(QString::fromStdString(szdata)); apos++; spos++; if (szdata.size() == 9) { if(szdata.at(1) == '0' && bdir==true && ((c_carnum == "" || zhcarNumber == c_carnum)|| io_car=="0")) {//火车离开了关功放 std::string logstr = "火车离开了 ... ...总共车节数 " + std::to_string(m_icarriageOrder) + " 方向:" + m_direction +" 进车完成" + io_car.toStdString(); btrainLeave = true; m_icot =0; m_icot2=0; m_flag=false; m_icarriageOrder = 0; m_direction.clear(); m_veclabel.clear(); m_sendHttpSign = false; judget = false; bdir = false ; io_car =""; //std::string logstr = "火车离开了 ... ...总共车节数 " + std::to_string(m_icarriageOrder) + " 方向:" + m_direction; print_log(logstr); ui->textBrowser->append(QString::fromStdString(logstr)); break; } if(szdata.at(1) == '0' && bdir==false && ((zhcarNumber == c_carnum && m_direction.compare("1") && m_direction.compare("14"))||io_car=="0")) { std::string logstr = "火车离开了 ... ...总共车节数 " + std::to_string(m_icarriageOrder) + " 方向:" + m_direction+" 装车完成" + io_car.toStdString(); btrainLeave = true; m_icot =0; m_icot2=0; m_flag=false; m_icarriageOrder = 0; io_car =""; m_direction.clear(); m_veclabel.clear(); m_sendHttpSign = false; judget = false; print_log(logstr); ui->textBrowser->append(QString::fromStdString(logstr)); break; } if(szdata.at(1) == '0' && (m_direction.size()==1) && m_icot == 1) { std::string logstr = " 触碰磁钢关闭 "; btrainLeave = true; //m_icot =0; m_icot2=0; m_flag=false; m_icarriageOrder = 0; m_direction.clear(); m_veclabel.clear(); m_sendHttpSign = false; judget = false; print_log(logstr); ui->textBrowser->append(QString::fromStdString(logstr)); break; } if(szdata.at(1) == '8'||szdata.at(1) == '2'||szdata.at(1) == '1'||szdata.at(1) == '4') {//磁钢数据处理 m_icot++; if(m_flag==true) { m_icot2++; } if(judget == false) { auto itmp = m_direction.find(szdata.at(1)); if(itmp == std::string::npos){ m_direction.append(szdata.substr(1,1)); } if(m_icot > 3){ bdir = Judge_direction(); if(m_direction == "8") //识别的单磁钢号为存储的最后一位时方向为false { bdir = false; } if(direction == "2") { bdir = true; } QString logs = "识别到的方向" + QString::number(bdir)+ " dir:" + QString::fromStdString(m_direction); ui->textBrowser->append(logs); print_log(logs.toStdString()); judget = true; } szHavdcarTime = szcurrentTime.substr(0, 19); } QString logs = QString::fromStdString("------------------------dir:" + m_direction + " 方向:" + std::to_string(bdir) + " 次数:" + std::to_string(m_icot) + " 车号:" + c_carnum+"io_car:"+io_car.toStdString()+"mv方向:"+direction.toStdString()); ui->textBrowser->append(logs); print_log(logs.toStdString()); if(m_icot > 25 && bdir==true) { m_flag=true; c_carnum = szcarNumber; //获取车号 m_icarriageOrder++; lc_carnum = m_icarriageOrder; m_sendHttpSign = true; m_icot = 0; //不在发送时清空 是防止装车方向最后一个为空 m_icot2= 0; } if(m_icot > 25 && bdir == false) { c_carnum = szcarNumber; m_icot = 0; } //连续两节车丢标签逻辑 if(m_icot2 > 15 && bdir==true) { m_icarriageOrder++; int k= m_icarriageOrder - 1 ; if(lc_carnum == k) //连续 { c_carnum = szcarNumber; lc_carnum = m_icarriageOrder; m_sendHttpSign = true; m_icot = 0 ; m_icot2 = 0; } else if(lc_carnum != k) //bu连续 { m_icarriageOrder--; m_sendHttpSign = false; m_icot2 = 0; m_flag = false; } } QString log = QString::fromStdString(szcurrentTime + szdata + " 次:" + std::to_string(m_icot) + " 方向:" + m_direction +"io_car:"+io_car.toStdString()+"mv方向:"+direction.toStdString()+"\r\n"); logtest.write(log.toUtf8()); logtest.flush(); } } else if (szdata.size() == 28) {//车厢信息处理 btrainLeave = false; //火车没有离开 std::string logstr = "车厢数据:" + szdata; print_log(logstr); szcarModel = szdata.substr(2, 5); //车型 szcarModel.erase(std::remove(szcarModel.begin(), szcarModel.end(), ' '), szcarModel.end()); //删除其中的空格 szcarNumber = szdata.substr(8, 7); //车厢号 c_carnum = szcarNumber; std::cout << "szcarModel" << szcarModel << " szcarNumber" << szcarNumber << std::endl; bool bret = label_compare(szcarNumber); //判断车厢号是否存在 if(bret == false){ m_icot = 0; continue; } m_veclabel.push_back(szcarNumber); m_icarriageOrder++; if(m_icarriageOrder==1 && bdir == true) { zhcarNumber = szcarNumber; c_carnum ="1"; } m_sendHttpSign = true; //有车厢信息一定上传 if(szcarModel.at(0) != 'C' && szcarModel != "") { m_sendHttpSign = false; m_icarriageOrder--; c_carnum = ""; szcarModel = ""; szcarNumber = ""; } QString log = QString::fromStdString(szcurrentTime + "------------------------------收到车厢数据\r\n"); m_icot = 0; m_icot2= 0; logtest.write(log.toUtf8()); logtest.flush(); } if(m_sendHttpSign == true && bdir == true) { QString log = QString::fromStdString(szcurrentTime + "发送车厢数据------------------------------方向:" + m_direction + " 车节号" + std::to_string(m_icarriageOrder) +"\r\n\r\n\r\n"); logtest.write(log.toUtf8()); logtest.flush(); m_sendHttpSign = false; itime = 0; deal_uart_data(szcarModel,szcarNumber); } } } } /* * 函数名:Logs() * 功能:打印日志 * 参数: * (空) * 返回值: * (预留) */ int MainWindow::debug_log_printf(std::string daystime) { logOut.close(); QString logName = "Logs/" + QString::fromStdString(daystime) + ".txt"; logOut.setFileName(logName); if(!logOut.open(QIODevice::ReadWrite | QIODevice::Append)) { return false; } return -1; } /** * @brief:打印加输出日志 * @param:time:时间 * @param:logstr:打印字符串 * @return:空 */ void MainWindow::print_log(std::string logstr) { //检查是否需要创建日志 if (szlastTime.compare(szcurrentTime.substr(0, 10))) // && btrainLeave == true { szlastTime = szcurrentTime.substr(0, 10); int ret = debug_log_printf(szlastTime); if (ret < 0) { std::cout << "Log file creat error" << std::endl; } } QString log = QString::fromStdString(szcurrentTime + logstr + "\r\n"); logOut.write(log.toUtf8()); logOut.flush(); qDebug() << log; } /** * @brief:获取系统时间 * @param: * @return:空 */ void MainWindow::get_system_time() { szcurrentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz").toStdString(); } /** * @brief:放倒车 * @param:label:车型 * @return:false 存在;true 不存在 */ bool MainWindow::label_compare(std::string &label) { if (m_veclabel.size() == 0) return true; std::vector ::const_iterator itr = std::find(m_veclabel.begin(), m_veclabel.end(),label); if (itr != m_veclabel.end()) { return false; } return true; } //false 和配置方向相反 //true 和配置方向相同 bool MainWindow::Judge_direction() { if(!m_direction.compare(configureInfo_T.configDirection) || m_direction.at(0) == configureInfo_T.configDirection.at(0)){ return true; } int pos = configureInfo_T.configDirection.find(m_direction.at(0)); for(int i = 0; i < pos;i++){ auto dirpos = m_direction.find(configureInfo_T.configDirection.at(pos - 1)); if(dirpos != std::string::npos){ return false; } } return true; } void MainWindow::rece_data_slots() { QByteArray data = serial->readAll(); // 读取数据 if(!data.isEmpty()) { std::lock_guard lk(mtx_sync_); queData.push(QString(data).toStdString()); QString log = QString::fromStdString(szcurrentTime) + QString(data); logrecv.write(log.toUtf8()); logrecv.flush(); } data.clear(); } /** * @brief:解析协议1的串口数据。 * @param:szcarModel: 车型 * @param:szcarNumber:车厢号 * @return: 成功:true * 失败:false */ bool MainWindow::deal_uart_data(std::string &szcarModel,std::string &szcarNumber) { print_log("进入数据发送流程"); std::string sztime = szHavdcarTime; #if DEBUG_HTTP int ix = 0; do{ ix++; std::string ord = std::to_string(m_icarriageOrder); int ret = http_send(szcarModel, szcarNumber,ord,sztime); if(ret == -2){ std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; }else{ break; } }while(ix < 3); #endif std::string str = "***************************车型:" + szcarModel + " 车号:" + szcarNumber + " 车节号:" + std::to_string(m_icarriageOrder); ui->textBrowser->append(QString::fromStdString(str)); print_log(str); return true; } /** * @brief:Http发送RFID数据 * @param:carModel:车型 * @param:carNum:车号 * @param:catFrequency:车节号 * @param:time:当前时间 * @return: 成功:true * 失败:false */ int MainWindow::http_send(std::string &carriageType, std::string &carriageNumber, std::string &carriageOrder, std::string &time) { httplib::Client cli(configureInfo_T.ip, std::atoi(configureInfo_T.port.c_str())); httplib::Headers header; httplib::Params params; Json::Value arrayObj; //构建对象 if (baccredit) { header.emplace("blade-auth", accreditInformation); //header.emplace("Content-Type", "application/json"); arrayObj["comeTime"] = time; arrayObj["carriageNumber"] = carriageNumber; arrayObj["carriageType"] = carriageType; arrayObj["carriageOrder"] = carriageOrder; Json::Value trainParams; trainParams["poundNo"] = configureInfo_T.stationTrack; arrayObj["trainParams"] = trainParams; Json::StreamWriterBuilder writer; std::cout << " http send:" << arrayObj << std::endl; std::string str = Json::writeString(writer, arrayObj); print_log(str); auto res = cli.Post(configureInfo_T.urlPath, header, str, "application/json"); if (res) { print_log(res->body.c_str()); 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["success"].asString().compare("true")) { print_log("已经成功发送数据到Web ..."); return 0; } else { if (!root["msg"].asString().compare("请求未授权")) { print_log("error : 发送数据到Web error 请求没有得到授权 需要请求授权."); obtain_accredit(); return -2; } } } } } } return true; } /** * @brief:Http获取授权 * @param: * @return: */ void MainWindow::obtain_accredit() { httplib::Client cli(configureInfo_T.ip, std::atoi(configureInfo_T.port.c_str())); httplib::Headers header; httplib::Params params; if (!baccredit) { header.emplace("Authorization", "Basic Y2xpZW50X2VudGVycHJpc2U6Y2xpZW50X2VudGVycHJpc2Vfc2VjcmV0"); params.emplace("username", "guest_01"); params.emplace("password", "d55b0f642e817eea24725d2f2a31dd08"); 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["success"].asString().compare("true")) { baccredit = true; accreditInformation = root["token_type"].asString(); accreditInformation.append(" "); accreditInformation.append(root["access_token"].asString()); std::string logs = "已经成功得到授权,授权信息为:" + accreditInformation + '\n'; std::cout << logs << std::endl; ui->textBrowser->setText(QString::fromStdString(logs)); print_log("已经成功得到授权."); } } } } else { auto err = res.error(); if (err == httplib::Error::Connection) { std::cout << " (连接出错)" << std::endl; } print_log("请求授权出错 error"); } } } /********************************串口初始化*************************************/ /** * @brief:设置串口 * @param: * @return:空 */ void MainWindow::set_uart_parameter() { serial->setPortName(QString::fromStdString(configureInfo_T.uartName)); if(!configureInfo_T.uartBaud.compare("9600")){ serial->setBaudRate(QSerialPort::Baud9600); }else if(!configureInfo_T.uartBaud.compare("19200")){ serial->setBaudRate(QSerialPort::Baud19200); }else if(!configureInfo_T.uartBaud.compare("115200")){ serial->setBaudRate(QSerialPort::Baud115200); } serial->setParity(QSerialPort::NoParity);// 校验 serial->setDataBits(QSerialPort::Data8); //数据位 serial->setStopBits(QSerialPort::OneStop);//停止位,停止位默认选择1位 serial->setFlowControl(QSerialPort::NoFlowControl);// 控制流,默认选择无 if(serial->open(QSerialPort::ReadWrite)){ #if DEBUG_HTTP obtain_accredit(); //获取http授权 #endif std::string logs; logs.append("串口打开成功\n"); logs.append(" 串口号:" + configureInfo_T.uartName + "\r\n"); logs.append(" 波特率:" + configureInfo_T.uartBaud + "\r\n"); logs.append(" IP :" + configureInfo_T.ip + "\r\n"); logs.append(" 端口号:" + configureInfo_T.port + "\r\n"); logs.append(" URL :" + configureInfo_T.urlPath + "\r\n"); logs.append(" 股道号:" + configureInfo_T.stationTrack + "\r\n"); logs.append(" 方向编号:" + configureInfo_T.configDirection + "\r\n"); ui->textBrowser->append(QString::fromStdString(logs)); print_log(logs); }else{ std::string logs; logs.append("打开串口失败,请确认!!!"); ui->textBrowser->append(QString::fromStdString(logs)); } } /******************************读写配置文件****************************************/ /** * @brief:读取配置文件,并显示在相应的位置 * @param: * @return:空 */ void MainWindow::read_configure_file(){ std::string str; int pos; std::ifstream file("laneConfig.txt"); if (file.good()) { while (std::getline(file, str)) { pos = str.find("uartName:"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.uartName = str.substr(pos + 1); if(std::atoi(configureInfo_T.uartName.substr(3).c_str())>=10){ configureInfo_T.uartName.insert(3,"\\\\.\\"); } std::cout<< "configureInfo_T.uartName:" << configureInfo_T.uartName << std::endl; } pos = str.find("uartBaud:"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.uartBaud = str.substr(pos + 1); std::cout<< "m_uartBaud:" << configureInfo_T.uartBaud << std::endl; } pos = str.find("IP:"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.ip = str.substr(pos + 1); std::cout<< "m_szip:" << configureInfo_T.ip << std::endl; } pos = str.find("Port:"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.port = str.substr(pos + 1); std::cout<< "m_iport:" << configureInfo_T.port << std::endl; } pos = str.find("Path:"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.urlPath = str.substr(pos + 1); std::cout<< "m_szurlPath:" << configureInfo_T.urlPath << std::endl; } pos = str.find("Station"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.stationTrack = str.substr(pos + 1); std::cout<< "m_szstationTrack:" << configureInfo_T.stationTrack << std::endl; } pos = str.find("Direction"); if (pos != std::string::npos) { pos = str.find(":"); configureInfo_T.configDirection = str.substr(pos + 1); std::cout<< "m_configDirection:" << configureInfo_T.configDirection << std::endl; } } file.close(); } } /** * @brief:将新的内容写入到配置文件中 * @param: * @return:空 */ void MainWindow::write_configure_file(){ ofswrite.open("laneConfig.txt", std::ios::out|std::ios::binary); // append,追加 ofswrite << "uartName:" << configureInfo_T.uartName << std::endl; ofswrite << "uartBaud:" << configureInfo_T.uartBaud << std::endl; ofswrite << "IP:" << configureInfo_T.ip << std::endl; ofswrite << "Port:" << configureInfo_T.port << std::endl; ofswrite << "Path:" << configureInfo_T.urlPath << std::endl; ofswrite << "Station:" << configureInfo_T.stationTrack << std::endl; ofswrite.close(); } /***************************最小化相关****************************************/ /** * @brief:接收最小化信号 * @param: * @return:空 */ void MainWindow::changeEvent(QEvent *event) { if((event->type()==QEvent::WindowStateChange)&&isMinimized()) { hide(); m_pSystemTray->setIcon(QIcon("./logo.ico")); // 托盘时显示的图片 m_pSystemTray->setToolTip("rfid车号识别"); // 鼠标在托盘图片时的提示 m_pSystemTray->showMessage("SystemTrayIcon","",QSystemTrayIcon::Information,10000); event->ignore(); //建立托盘操作的菜单 creat_action(); creat_menu(); m_pSystemTray->show(); // 显示图片图标 } } void MainWindow::closeEvent(QCloseEvent *event) { // QMessageBox::StandardButton button = QMessageBox::information(NULL, "提示", "确定关闭软件?",QMessageBox::Yes, QMessageBox::No);; // if(QMessageBox::Yes == button) // { // close(); // }else{ // event->ignore(); // } // 弹出对话框要求用户输入账号和密码 QString username = QInputDialog::getText(this, "关闭账号密码验证", "请输入账号:"); QString password = QInputDialog::getText(this, "关闭账号密码验证", "请输入密码:", QLineEdit::Password); // 验证账号和密码是否正确 if (username == "admin" && password == "brt123") { event->accept(); // 关闭窗口 } else { QMessageBox::warning(this, "验证失败", "账号或密码不正确!"); event->ignore(); // 阻止关闭窗口 } } void MainWindow::creat_action() { m_pActionShow = new QAction("show", this); connect(m_pActionShow, &QAction::triggered, this,&MainWindow::on_ShowMainAction); m_pActionQuit = new QAction("exit", this); connect(m_pActionQuit, &QAction::triggered, this, &MainWindow::on_ExitAppAction); } void MainWindow::creat_menu() { m_pTrayMennu = new QMenu(this); //新增菜单项---显示主界面 m_pTrayMennu->addAction(m_pActionShow); //增加分隔符 m_pTrayMennu->addSeparator(); //新增菜单项---退出程序 m_pTrayMennu->addAction(m_pActionQuit); //把QMenu赋给QSystemTrayIcon对象 m_pSystemTray->setContextMenu(m_pTrayMennu); } /** * @brief:显示 * @param: * @return:空 */ void MainWindow::on_ShowMainAction() { this->show(); } /** * @brief:最小化 * @param: * @return:空 */ void MainWindow::on_ExitAppAction() { exit(0); } void MainWindow::on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason reason) { switch(reason){ case QSystemTrayIcon::Trigger: //单击托盘图标 this->showNormal(); break; case QSystemTrayIcon::DoubleClick: //双击托盘图标 //双击后显示主程序窗口 this->showNormal(); break; default: break; } }