效果:
1.实时抓取串口数据,并对串口数据做解密,解密后显示在QTextEdit上。
2.对显示的内容做特殊关键字标记处理,比如对出现的Error关键字标红
高亮另一个版本
3.对显示的明文进行查询,类似编辑文件中的Ctrl+F
4.对串口抓取到的数据存储到本地
实现:
1.在mainwindow中使用串口类子线程对象,其中mHexEdit是显示hex进制数据的自定义控件
MainWindow::~MainWindow()
{mSerialWork->quitWork();delete mSerialWork;
}void MainWindow::initConnect()
{mLastCursor = new QTextCursor(mSerialEdit->document());mSerialWork = new SerialWorker;connect(mSerialWork, &SerialWorker::readData, this, [&](const QByteArray &data){mHexEdit->appenData(data);
});connect(mSerialWork,&SerialWorker::sendparserslt, this, [&](const QString& data){mSerialEdit->append(data); //mSerialEdit是普通的QTextEdit控件
});
}//dict是解密用的字典文件, serial是串口的属性,比如波特率、停止位等
void MainWindow::startWork(bool start, const QString &dict, const QVariantMap &serial)
{if(!start){mPortList->setEnabled(true);mSerialWork->startWork(0, "", false);return;}auto port = mPortList->currentItem();if(nullptr== port){QMessageBox::warning(this, tr("Warning"),tr("Please select a serial port"));return;}if(dict.isEmpty())return;QVariantMap data = serial;data["port"] = port->text();dicUartParseFilePath = dict;mSerialWork->setProperty(data);mHexEdit->setData(QByteArray());mSerialEdit->clear();mSerialWork->startWork(mProductType, dicUartParseFilePath);
}void MainWindow::saveHexDataToLocal(const QString& path)
{const auto& data = mHexEdit->data();if(data.isEmpty())return;bool ret = false;QString result = tr("Save serial port data failed!");auto lastPath = ParseWork::Instance().getLogFilePath();if(path.isEmpty())return;QFile file(path);if(file.open(QIODevice::WriteOnly|QIODevice::Truncate)){ret = true;file.write(data);file.close();result = tr("Save serial port data successful!");}statusMessage(ret, result);ParseWork::Instance().setLogFilePath(path);
}void MainWindow::ShowStr(const QString& str)
{mSerialEdit->append(str);auto doc = mSerialEdit->document();QTextCursor highlightCursor(doc);auto keywords = ParseWork::Instance().getKeywords();foreach (auto key, keywords.keys()){auto names = key.split("-");QTextCursor cursor(doc);cursor.beginEditBlock();QTextCharFormat plainFormat(mLastCursor->charFormat());QTextCharFormat colorFormat = plainFormat;colorFormat.setForeground(QColor("#ff8911"));while (!highlightCursor.isNull() && !highlightCursor.atEnd()){highlightCursor = doc->find(names[1], *mLastCursor,QTextDocument::FindWholeWords);if (!highlightCursor.isNull()){highlightCursor.select(QTextCursor::LineUnderCursor);highlightCursor.mergeCharFormat(colorFormat);break;}}cursor.endEditBlock();}*mLastCursor = highlightCursor;
}
2.关于SerialWorker的具体实现,部分无用代码需自己删减
#ifndef SERIALWORKER_H
#define SERIALWORKER_H#include "parse/parsework.h"
#include "utils/utility.h"
#include <QObject>class QThread;
class QSerialPort;
class SerialWorker : public QObject
{Q_OBJECT
public:explicit SerialWorker(QObject *parent = nullptr);~SerialWorker();void setProperty(const QVariantMap& data);void setPortName(const QString& name);void setBaudrate(qint32 rate);void setDataBit(ushort);void setStopBit(ushort bit);void setParity(ushort parity);void startWork(uint product, const QString& dictPath, bool start=true);void quitWork();signals:void openStatus(bool open);void readData(const QByteArray& data);void sendparserslt(QString parseStr);private slots:void readSerialData();private:QThread* mThread;QSerialPort* mSerialPort;QString mPortName;qint32 mBaudrate;ushort mDataBit;ushort mStopBit;ushort mParity;uint mProductType;QString mDictPath;private:unsigned long long dataHasParsedSize = 0;deque<unsigned char> parsedatalist;unsigned int curFileLen = 0; //base on the current file len to split filestd::ofstream *outputBinFile = NULL;FILE *outputTxtFile = NULL;unsigned long saveFileNum = 1;string subFolderName;unsigned int singleFileSize = 20;public:string CreateSaveFolder();bool CreateTextFile(string subFolderName);bool CreateBinaryFile(string subFolderName);string GetProjectName(ProjectItem project);
};#endif // SERIALWORKER_H
#include "serialworker.h"#include <QDebug>
#include <QThread>
#include <QSerialPort>
#include <QVariantMap>
#define GET_ENUM_NAME(value) case value:return (#value);
unsigned int parsedcnt = 0;
SerialWorker::SerialWorker(QObject *parent): QObject(parent)
{mSerialPort = new QSerialPort(this);mThread = new QThread;moveToThread(mThread);connect(mSerialPort, &QSerialPort::readyRead, this, &SerialWorker::readSerialData);mThread->start();
}SerialWorker::~SerialWorker()
{quitWork();delete mThread;delete mSerialPort;
}void SerialWorker::setProperty(const QVariantMap &data)
{if(data.isEmpty())return;mPortName = data["port"].toString();mBaudrate = data["buadrate"].toLongLong();mParity = data["pority"].toUInt();mDataBit = data["dataBit"].toUInt();mStopBit = data["stopBit"].toUInt();
}void SerialWorker::setPortName(const QString &name)
{mPortName = name;
}void SerialWorker::setBaudrate(qint32 rate)
{mBaudrate = rate;
}void SerialWorker::setDataBit(ushort bit)
{mDataBit = bit;
}void SerialWorker::setStopBit(ushort bit)
{mStopBit = bit;
}void SerialWorker::setParity(ushort parity)
{mParity = parity;
}void SerialWorker::startWork(uint product, const QString& dictPath, bool start)
{if(!start){mSerialPort->flush();mSerialPort->close();return;}curFileLen = 0;parsedatalist.clear();subFolderName.clear();dataHasParsedSize = 0;mDictPath = dictPath;mProductType = product;QSerialPort::BaudRate baudrate = (QSerialPort::BaudRate)mBaudrate;mSerialPort->setBaudRate(baudrate,QSerialPort::AllDirections);QSerialPort::DataBits dataBits = (QSerialPort::DataBits)mDataBit;mSerialPort->setDataBits(dataBits);mSerialPort->setFlowControl(QSerialPort::NoFlowControl);QSerialPort::Parity parity = (QSerialPort::Parity)mParity;QSerialPort::StopBits stopBits = (QSerialPort::StopBits)mStopBit;mSerialPort->setPortName(mPortName);mSerialPort->setBaudRate(baudrate,QSerialPort::AllDirections);mSerialPort->setDataBits(dataBits);mSerialPort->setParity(parity);mSerialPort->setStopBits(stopBits);mSerialPort->setFlowControl(QSerialPort::NoFlowControl);if(start && !mSerialPort->isOpen()){mSerialPort->open(QIODevice::ReadWrite);}string folderPath = CreateSaveFolder();CreateTextFile(folderPath);CreateBinaryFile(folderPath);openStatus(mSerialPort->isOpen());
}void SerialWorker::quitWork()
{saveFileNum = 1; //reset file numberdataHasParsedSize += parsedatalist.size();for(uint i=0;i<parsedatalist.size();i++){outputBinFile->write((char *)&parsedatalist.at(i),1);}if(outputBinFile){outputBinFile->close();outputBinFile = NULL;}if(outputTxtFile){fclose(outputTxtFile);outputTxtFile = NULL;}parsedatalist.clear();parsedcnt = 0;mSerialPort->close();mThread->quit();mThread->wait();
}void SerialWorker::readSerialData()
{const auto& data = mSerialPort->readAll();for(int i=0;i<data.size();i++){parsedatalist.push_back(data.at(i));}QString parseStr;int value1 = parsedatalist.size();switch (mProductType){case TypeO:ParseWork::Instance().ParseTypeOSerialData(parsedatalist,mDictPath,parseStr, outputTxtFile,outputBinFile);case TypeT:ParseWork::Instance().ParseTypeTSerialData(parsedatalist,mDictPath,parseStr, outputTxtFile,outputBinFile);default:break;}if(parseStr.size()){emit sendparserslt(parseStr);}int value2 = parsedatalist.size();parsedcnt += (value1 - value2);if(parsedcnt >= (saveFileNum * singleFileSize * 1024 * 1024)){saveFileNum++;CreateTextFile(subFolderName);CreateBinaryFile(subFolderName);}emit readData(data);
}string SerialWorker::CreateSaveFolder()
{string stCurrentTime = GetCurrentTimeStamp();std::string comName = mPortName.toStdString();string folderName = "SaveInfo_" + comName + "_" +stCurrentTime;string rootdir = get_current_directory();string path = rootdir + "/" + folderName;bool result = CreateFolder(path);if (result)return path;elsereturn "";
}bool SerialWorker::CreateTextFile(string subFolderName)
{if(outputTxtFile){fclose(outputTxtFile);outputTxtFile = NULL;}string project = GetProjectName((ProjectItem)mProductType);char buf[128] = {0};sprintf(buf, "/%s_RS232Log_%ld.txt", project.c_str(), saveFileNum);string saveFileName;saveFileName = subFolderName + buf;outputTxtFile = fopen(saveFileName.data(), "w+");if(outputTxtFile){qDebug()<<"txt file create successfully";}else{qDebug()<<"txt file create fail";}return true;
}bool SerialWorker::CreateBinaryFile(string subFolderName)
{if(outputBinFile){delete outputBinFile;outputBinFile = NULL;}string project = GetProjectName((ProjectItem)mProductType);char buf[100] = {0};sprintf(buf, "/%s_RS232Log_%ld.bin", project.c_str(), saveFileNum);string saveFileName;saveFileName = subFolderName + buf;outputBinFile = new std::ofstream(saveFileName, std::ios::out | std::ios::binary | std::ios::app);if(outputBinFile){qDebug()<<"raw data file create successfully";}else{qDebug()<<"raw data file create fail";}return true;
}string SerialWorker::GetProjectName(ProjectItem project)
{switch (project){GET_ENUM_NAME(PE500 );GET_ENUM_NAME(SQ_UFS_2_2);default:return "";break;}
}