Ai
1 Star 5 Fork 5

TMRNic/LabTool-V2

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
mainwindow.cpp 64.74 KB
一键复制 编辑 原始数据 按行查看 历史
TMRNic 提交于 2024-12-13 23:44 +08:00 . GNSS轨迹
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPoint>
#include <QDebug>
#include <QToolBox>
#include <QMessageBox>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QMetaType> //用来注册数据类型
#include<QElapsedTimer> //测量函数运行时间
QElapsedTimer debugTime;
#define PI (3.141592653)
#define DEG (PI/180.0)
/**************************************************** 主界面 *********************************************************/
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) //构造主界面
{
frameLen = 0; // 帧信息
frameHeaderLen = 0;
frameDataTypeLen = 0;
checkSumPosOnframeDataType = -1;
TimeStampPosOnframeDataType = -1;
recv_frameCounter = 0;
XAxis = frameCount; // X轴绘图类型:帧计数/时间戳
curveRefreshCycle = 1; // 曲线刷新周期 10ms(默认)
clearCurveTiming_3min = 0;
timingPeriod10ms = 10;
timing10msCounter= 0;
isOpenSerialPort = false; // 串口打开
isSaveTxtFile = false; // 文件保存
isOpenCurvePlot = false; // 绘图
isStartCurvePlot = false; // 开始绘图
isOpenDashBoard = false; // 仪表盘
isOpenHelpUi = false; // 帮助面板
isIMUSerOpen = false; // 串口状态
isGNSSActive = false; // GNSS激活状态
// pos_ew = QVector<double>(3600);
// pos_ew = QVector<double>(3600);
qRegisterMetaType<QVector<quint8>>("QVector<quint8>"); //注册信号与槽的传递参数类型
ui->setupUi(this);
this->setFixedSize(this->width(),this->height());
// qDebug() << "UI线程id" <<QThread::currentThreadId();
/**************************************** 选择面板 ******************************************/
//数据协议面板(默认显示)
ui->toolBox->setCurrentIndex(0);
ui->confirmDataFrame_btn->setChecked(false);
//串口设置面板
ui->setBaud_combox->setCurrentIndex(1);
ui->setDataBits_combox->setCurrentIndex(0);
ui->setParity_combox->setCurrentIndex(0);
ui->setStopBits_combox->setCurrentIndex(0);
ui->switchSerialPort_btn->setChecked(false);
setSerialLedState(false);
// GNSS串口设置
ui->setBaud_combox_g->setCurrentIndex(3);
ui->setDataBits_combox_g->setCurrentIndex(0);
ui->setParity_combox_g->setCurrentIndex(0);
ui->setStopBits_combox_g->setCurrentIndex(0);
setGNSSLedState(false);
ui->tabWidget_List->setCurrentIndex(0);
ui->lcdNumber_gnss_time->setDigitCount(6);
ui->lcdNumber_gnss_hdop->setDigitCount(5);
ui->lcdNumber_gnss_ve->setDigitCount(6);
ui->lcdNumber_gnss_vn->setDigitCount(6);
ui->lcdNumber_gnss_vu->setDigitCount(6);
ui->lcdNumber_gnss_lat->setDigitCount(10);
ui->lcdNumber_gnss_lng->setDigitCount(10);
ui->lcdNumber_gnss_alt->setDigitCount(6);
init_mapplot();
//串口线程
serialPortModule = new mySerialPort();
serialPortModule->device_type = IMU; // 设置为IMU
serialPortSubThread = new QThread();
serialPortModule->moveToThread(serialPortSubThread);
serialPortSubThread->start();
connect(serialPortSubThread,&QThread::started,serialPortModule,&mySerialPort::serialPortInfoInit); //线程初始化后 新建串口对象并初始化信息
connect(ui->setPort_combox,&mySerialCombox::detectSerialPorts,serialPortModule,&mySerialPort::updateAvailableSerialPorts); //点击串口号下拉框自动检测
connect(serialPortModule,&mySerialPort::sendAvailableSerialPortName,ui->setPort_combox,&mySerialCombox::updateSerialComboxItem); //检测后更新串口号
connect(ui->switchSerialPort_btn,&QPushButton::clicked,this,&MainWindow::slot_switchSerialPort); //打开串口
connect(this,&MainWindow::signal_openSerialPortx,serialPortModule,&mySerialPort::openSerialPortx); //绑定串口打开信号
connect(this,&MainWindow::signal_closeSerialPortx,serialPortModule,&mySerialPort::closeSerialPortx); //绑定关闭串口信号
connect(serialPortModule,&mySerialPort::isSerialPortxOpenSuccessfully,this,&MainWindow::slot_showSerialPortxOpenStatus); //显示串口打开状态
connect(serialPortModule,&mySerialPort::isSerialPortxCloseSuccessfully,this,&MainWindow::slot_showSerialPortxCloseStauts); //显示串口关闭状态
connect(this,&MainWindow::signal_sendFrameInfoToSerialSubThread,serialPortModule,&mySerialPort::slot_recvFrameInfoFromUiThread); //同步帧信息
// connect(serialPortModule,&mySerialPort::signal_sendFrameInfoToUiThread,ui->label_showRecvFrameNum,&QLabel::setText); //显示总帧数
//串口线程
serialPortModule_GNSS = new mySerialPort();
serialPortModule_GNSS->device_type = GNSS; // 设置为GNSS
serialPortSubThread_GNSS = new QThread();
serialPortModule_GNSS->moveToThread(serialPortSubThread_GNSS);
serialPortSubThread_GNSS->start();
connect(serialPortSubThread_GNSS,&QThread::started,serialPortModule_GNSS,&mySerialPort::serialPortInfoInit); //线程初始化后 新建串口对象并初始化信息
connect(ui->setPort_combox_g,&mySerialCombox::detectSerialPorts,serialPortModule_GNSS,&mySerialPort::updateAvailableSerialPorts); //点击串口号下拉框自动检测
connect(serialPortModule_GNSS,&mySerialPort::sendAvailableSerialPortName,ui->setPort_combox_g,&mySerialCombox::updateSerialComboxItem); //检测后更新串口号
//connect(ui->switchSerialPort_btn,&QPushButton::clicked,this,&MainWindow::slot_switchSerialPort); //打开串口
connect(this,&MainWindow::signal_openSerialPortx_g,serialPortModule_GNSS,&mySerialPort::openSerialPortx); //绑定串口打开信号
connect(this,&MainWindow::signal_closeSerialPortx_g,serialPortModule_GNSS,&mySerialPort::closeSerialPortx); //绑定关闭串口信号
connect(serialPortModule_GNSS,&mySerialPort::isSerialPortxOpenSuccessfully,this,&MainWindow::slot_showSerialPortxOpenStatus_GNSS); //显示串口打开状态
connect(serialPortModule_GNSS,&mySerialPort::isSerialPortxCloseSuccessfully,this,&MainWindow::slot_showSerialPortxCloseStauts_GNSS); //显示串口关闭状态
//connect(this,&MainWindow::signal_sendFrameInfoToSerialSubThread_g,serialPortModule_GNSS,&mySerialPort::slot_recvFrameInfoFromUiThread); //同步帧信息
// connect(serialPortModule,&mySerialPort::signal_sendFrameInfoToUiThread,ui->label_showRecvFrameNum,&QLabel::setText); //显示总帧数
connect(ui->checkBox_active_gnss, &QCheckBox::clicked, this, &MainWindow::on_changeGNSSActiveState);
connect(ui->meas_combox_g, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::on_changeGNSSMeasType);
connect(this, &MainWindow::signal_updateMeasType, serialPortModule_GNSS, &mySerialPort::slot_changeMeasType);
//绘图功能9
curvePlot = new myCurvePlot();
ui->curveShow_btn->setCheckable(true);
connect(curvePlot,&myCurvePlot::signal_clearCurvePlotUi,this,[=](){clearCurveTiming_3min = 0;});
connect(curvePlot,&myCurvePlot::signal_StartCurvePlot,this,[=](bool on){isStartCurvePlot = on;});
connect(curvePlot,&myCurvePlot::signal_hideCurvePlotUi,this,[=](){ui->curveShow_btn->setChecked(false);});
connect(curvePlot,&myCurvePlot::signal_sendCurveRefreshFreq,this,[=](int freq){curveRefreshCycle = 1000 / freq / timingPeriod10ms;});
//仪表盘
//============= 删除仪表盘 =============//
// 删除仪表盘,完成与quc的解耦
// by TMRNic, 2024-11-20
// attDashBoard = new myDashBoard();
// ui->dashboardShow_btn->setCheckable(true);
// connect(attDashBoard,&myDashBoard::signal_hideDashBoardUi,this,[=](){ui->dashboardShow_btn->setChecked(false);});
//帮助面板
helpInfo = new help();
connect(helpInfo,&help::signal_hideHelpUi,this,[=](){isOpenHelpUi = false;});
//主线程定时器 10ms 任务调度
runTimer = new QTimer(this);
runTimer->setInterval(timingPeriod10ms); //10ms
connect(runTimer,&QTimer::timeout,this,&MainWindow::slot_taskScheduler);
/****************************************** 表格 *******************************************/
QStringList headerText;
headerText << "名称" << "数据类型" << "数值 * k" <<"标度因数(k)"<< "图1" << "图2" << "图3";
ui->tableWidget->setColumnCount(headerText.count()); //列数
ui->tableWidget->setHorizontalHeaderLabels(headerText); //行表头名
ui->tableWidget->verticalHeader()->setVisible(true); //表头
ui->tableWidget->horizontalHeader()->setVisible(true);
ui->tableWidget->setColumnWidth(colName,125); //列宽(总和为540)
ui->tableWidget->setColumnWidth(colType,111);
ui->tableWidget->setColumnWidth(colData,115);
ui->tableWidget->setColumnWidth(colScal,90);
ui->tableWidget->setColumnWidth(colIsCurve,33);
ui->tableWidget->setColumnWidth(colIsCurve1,33);
ui->tableWidget->setColumnWidth(colIsCurve2,33);
ui->tableWidget->setAlternatingRowColors(true); //隔行换色
ui->tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); //滚动条
ui->tableWidget->setItemDelegateForColumn(colType,&comBoxDelegate); //委托
// ui->tableWidget->setStyleSheet("QTableWidget::item:selected{background:lightblue}");
connect(ui->tableWidget,&QTableWidget::itemClicked,this,&MainWindow::slot_clickedItemAction);
ui->tableWidget->insertRow(0);
creatItemsARow(0,"Frame_Header","uint8_t(hex)","0xAA");
// 加载.lastConfig.txt
/* 建立一个子文件夹 用于存放文件 */
QString curPath = QDir::currentPath();
QDir dir(curPath);
QString savePath = curPath+ "/Config";
if(dir.exists(savePath)) {
QString loadFilename = savePath + "/.lastConfig.txt";
QFile configFile(loadFilename);
if(configFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
//遍历表格
QString strLine;
QTextStream in(&configFile);
/* 先清空表格 */
this->on_clearDataFrame_btn_clicked();
for(uint8_t i=0; in.atEnd() == false; i++)
{
strLine = in.readLine();
QStringList strList = strLine.split(",");
int curRow = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(curRow);
this->creatItemsARow(i,strList.at(0),strList.at(1),strList.at(2), strList.at(3));
}
configFile.close();
}
}
}
MainWindow::~MainWindow() //主界面析构
{
/* 结束子线程 并删除 不可使用deletelater(该函数是基于主线程事件循环的,在析构函数调用时,主线程的线程循环已经被终止了!) */
serialPortSubThread->quit();
if(serialPortSubThread->wait(5) == false){
serialPortSubThread->terminate();
}
delete serialPortSubThread;
delete serialPortModule;
delete helpInfo;
delete curvePlot;
//delete attDashBoard;
// qDebug() << "主界面被销毁" <<endl;
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *event) //重写主界面关闭事件
{
//if(ui->switchSerialPort_btn->getChecked())
if(isIMUSerOpen)
{
QMessageBox::critical(this,"@!!!!","请先关闭串口!");
event->ignore();
}
else if(isSaveTxtFile)
{
QMessageBox::critical(this,"@!!!!","请先关闭数据捕获功能!");
event->ignore();
}
else
{
event->accept();
}
}
/*************************************************** 其它设置 *********************************************************/
void MainWindow::on_comboBox_setEndianMode_currentIndexChanged(int index) //设置大小端模式
{
CV.updateEndianMode(index);
}
void MainWindow::on_comboBox_setXAxis_currentIndexChanged(int index) //设置曲线X轴
{
if(index == 0){
XAxis = frameCount;
}else if(index == 1){
XAxis = TimeStamp;
if(TimeStampPosOnframeDataType < 0){
QMessageBox::critical(this,"@!!!!","未定义数据戳或未确认数据帧");
ui->comboBox_setXAxis->setCurrentIndex(0);
XAxis = frameCount;
}
}else{
XAxis = frameCount;
}
}
void MainWindow::slot_clickedItemAction() //曲线绘制复选框点击事件
{
// currentItemIndex = ui->tableWidget->currentIndex(); //获取当前坐标
//绘图复选框
// QVector<quint8> isPlotXyz,isPlotxYz,isPlotxyZ;
isPlotXyz.clear();isPlotxYz.clear();isPlotxyZ.clear();
for(quint16 i=0; i<ui->tableWidget->rowCount(); i++){
if(ui->tableWidget->item(i,colIsCurve )->checkState() == Qt::Checked){ isPlotXyz.append(i); }
if(ui->tableWidget->item(i,colIsCurve1)->checkState() == Qt::Checked){ isPlotxYz.append(i); }
if(ui->tableWidget->item(i,colIsCurve2)->checkState() == Qt::Checked){ isPlotxyZ.append(i); }
}
if(isPlotXyz.size() >= 3){ isEnableCurvePlotCheckBox(isPlotXyz,colIsCurve,false); }//失能除选中之外的所有复选框
else{ isEnableCurvePlotCheckBox(isPlotXyz,colIsCurve,true); } //使能所有复选框
if(isPlotxYz.size() >= 3){ isEnableCurvePlotCheckBox(isPlotxYz,colIsCurve1,false); }//失能除选中之外的所有复选框
else{ isEnableCurvePlotCheckBox(isPlotxYz,colIsCurve1,true); } //使能所有复选框
if(isPlotxyZ.size() >= 3){ isEnableCurvePlotCheckBox(isPlotxyZ,colIsCurve2,false); }//失能除选中之外的所有复选框
else{ isEnableCurvePlotCheckBox(isPlotxyZ,colIsCurve2,true); } //使能所有复选框
}
void MainWindow::detectAllCurvePlotCheckBox() //检测曲线绘制复选框
{
// 清除
for(uint8_t i=0; i<3; i++){
xIsPlot1.clear(); xIsPlot2.clear(); xIsPlot3.clear();
xIsPlot1Name.clear(); xIsPlot2Name.clear(); xIsPlot3Name.clear();
xPlotKeys.clear();
xPlot1Value[i].clear(); xPlot2Value[i].clear(); xPlot3Value[i].clear();
}
// 遍历状态:是否需要曲线绘制
for(quint16 i=0; i<ui->tableWidget->rowCount(); i++)
{
//绘图1 一共3条
if(ui->tableWidget->item(i,colIsCurve)->checkState() == Qt::Checked){
xIsPlot1.append(i - frameHeaderLen); //对应了数据类型的位置
xIsPlot1Name.append( ui->tableWidget->item(i,colName)->text() ); //画图时的图例
}
//绘图2 一共3条
if(ui->tableWidget->item(i,colIsCurve1)->checkState() == Qt::Checked){
xIsPlot2.append(i - frameHeaderLen); //对应了数据类型的位置
xIsPlot2Name.append( ui->tableWidget->item(i,colName)->text() ); //画图时的图例
}
//绘图2 一共3条
if(ui->tableWidget->item(i,colIsCurve2)->checkState() == Qt::Checked){
xIsPlot3.append(i - frameHeaderLen); //对应了数据类型的位置
xIsPlot3Name.append( ui->tableWidget->item(i,colName)->text() ); //画图时的图例
}
}
}
void MainWindow::isEnableCurvePlotCheckBox(QVector<quint8> &plotXxx, MainWindow::FieldColNum colIsCurvex, bool checked) //使/失能曲线绘制复选框
{
quint8 len = 0;
if(plotXxx.empty())//全部修改为使能或失能
{
for(quint8 i=0; i<ui->tableWidget->rowCount(); i++)
{
Qt::ItemFlags f = ui->tableWidget->item(i,colIsCurvex)->flags();
if(checked){ ui->tableWidget->item(i,colIsCurvex)->setFlags(f | Qt::ItemIsEnabled); }//使能复选框
else{ ui->tableWidget->item(i,colIsCurvex)->setFlags(f &~ Qt::ItemIsEnabled); } //失能复选框
}
}
else
{
for(quint8 i=0; i<ui->tableWidget->rowCount(); i++)
{
if( i == plotXxx.at(len)){
len++;
if(len >= plotXxx.size()) len = plotXxx.size()-1; //防止索引越界
}else{
Qt::ItemFlags f = ui->tableWidget->item(i,colIsCurvex)->flags();
if(checked){ ui->tableWidget->item(i,colIsCurvex)->setFlags(f | Qt::ItemIsEnabled); }//使能复选框
else{ ui->tableWidget->item(i,colIsCurvex)->setFlags(f &~ Qt::ItemIsEnabled); } //失能复选框
}
}
}
}
//void MainWindow::detectEulerAnglesToDashBoard() //检测是否有欧拉角,有则显示到仪表盘
//{
// pitchPosOnframeDataType = -1;
// rollPosOnframeDataType = -1;
// yawPosOnframeDataType = -1;
// QString strEuler;
// // 遍历名称:是否含欧拉角的字符串
// for(quint16 i=0; i<ui->tableWidget->rowCount(); i++)
// {
// //绘图1 一共3条
// strEuler = ui->tableWidget->item(i,colName)->text().toLower();
// if( strEuler == "pitch" ) pitchPosOnframeDataType = i - frameHeaderLen;
// else if( strEuler == "roll") rollPosOnframeDataType = i - frameHeaderLen;
// else if( strEuler == "yaw" ) yawPosOnframeDataType = i - frameHeaderLen;
// }
//// qDebug() << pitchPosOnframeDataType << rollPosOnframeDataType << yawPosOnframeDataType;
//}
/*************************************************** 任务调度 *********************************************************/
void MainWindow::slot_taskScheduler() //任务调度器
{
// debugTime.start();
timing10msCounter++;
parseOrSaveDataTask_GNSS();
quint8 yPacket = parseOrSaveDataTask(); //10ms 解数据-存文件
if(timing10msCounter % 100 == 0) //1s 计时 (不费时 放最开头)
{
QTime t = QTime::fromMSecsSinceStartOfDay(timing10msCounter*10);
QString str = t.toString("hh:mm:ss");
ui->label_showTiming->setText(str);
}
if(timing10msCounter % 50 == 0) //500ms 更新表格
{
ui->label_showRecvFrameNum->setText(QString::number(recv_frameCounter));
refreshTableTask(yPacket);
}
if(timing10msCounter % 25 == 0) //250ms 更新仪表盘
{
// if(isOpenDashBoard && !outStr.empty() )
// {
// bool ok = false;
// float eulerTmp[3] = {0.0f};
// if(pitchPosOnframeDataType != -1) eulerTmp[0] = outStr.at(pitchPosOnframeDataType).toFloat(&ok);
// if(rollPosOnframeDataType != -1) eulerTmp[1] = outStr.at(rollPosOnframeDataType).toFloat(&ok);
// if(yawPosOnframeDataType != -1) eulerTmp[2] = outStr.at(yawPosOnframeDataType).toFloat(&ok);
// attDashBoard->setValue(eulerTmp[0],eulerTmp[1],eulerTmp[2]);
// }
}
if(isOpenCurvePlot) //10ms 刷新波形
{
if(yPacket == 0) return;
xIsPlotPacketCount = recv_frameCounter - yPacket + 1;
//根据选中的个数存数据(最多九条曲线) 根据选中状态抽数据 与解包周期一致
for(quint8 i=0; i<yPacket; ++i)
{
for(quint8 m=0; m<xIsPlot1.size(); m++){
xPlot1Value[m].append(outStr.at( xIsPlot1.at(m) + i*frameDataTypeLen ).toDouble());
}
for(quint8 m=0; m<xIsPlot2.size(); m++){
xPlot2Value[m].append(outStr.at( xIsPlot2.at(m) + i*frameDataTypeLen ).toDouble());
}
for(quint8 m=0; m<xIsPlot3.size(); m++){
xPlot3Value[m].append(outStr.at( xIsPlot3.at(m) + i*frameDataTypeLen ).toDouble());
}
if(XAxis == TimeStamp){ // 横轴为时间戳
xPlotKeys.append(outStr.at( TimeStampPosOnframeDataType + i*frameDataTypeLen ).toDouble());
}else{ // 横轴为帧计数
xPlotKeys.append(xIsPlotPacketCount); xIsPlotPacketCount++;
}
}
if( (timing10msCounter % curveRefreshCycle == 0) && isStartCurvePlot )
{
curvePlot->plot1_AddData(xPlotKeys,xPlot1Value[0],xPlot1Value[1],xPlot1Value[2],xIsPlot1Name);
curvePlot->plot2_AddData(xPlotKeys,xPlot2Value[0],xPlot2Value[1],xPlot2Value[2],xIsPlot2Name);
curvePlot->plot3_AddData(xPlotKeys,xPlot3Value[0],xPlot3Value[1],xPlot3Value[2],xIsPlot3Name);
xPlotKeys.clear();
for(uint8_t i=0; i<3; ++i){
xPlot1Value[i].clear();xPlot2Value[i].clear();xPlot3Value[i].clear();
}
}
else if(!isStartCurvePlot) //暂停显示
{
if(xPlotKeys.size() > 30000) //若下位机10ms发送一帧数据,则30000对应5min的数据 暂停了5分钟则自动清空
{
xPlotKeys.clear();
for(uint8_t i=0; i<3; ++i){
xPlot1Value[i].clear();xPlot2Value[i].clear();xPlot3Value[i].clear();
}
}
}
}
/* 5分钟清空一次绘图 */
if( clearCurveTiming_3min == 30000 )
{
// clearCurveTiming_3min = 0;
curvePlot->clearAllCurve_clicked();
}
clearCurveTiming_3min++;
outStr.clear();
// int debugTimeMs = debugTime.elapsed();
// qDebug() << debugTimeMs;
}
void MainWindow::GNSSDataDisplayUpdate(double* gnssdata)
{
ui->lcdNumber_gnss_time->display(QString::number(gnssdata[6],'g',6));
ui->lcdNumber_gnss_hdop->display(QString::number(gnssdata[7],'g',6));
ui->lcdNumber_gnss_ve->display(QString::number(gnssdata[0],'g',6));
ui->lcdNumber_gnss_vn->display(QString::number(gnssdata[1],'g',6));
ui->lcdNumber_gnss_vu->display(QString::number(gnssdata[2],'g',6));
ui->lcdNumber_gnss_lat->display(QString::number(gnssdata[3],'g',12));
ui->lcdNumber_gnss_lng->display(QString::number(gnssdata[4],'g',12));
ui->lcdNumber_gnss_alt->display(QString::number(gnssdata[5],'g',7));
}
quint8 MainWindow::parseOrSaveDataTask_GNSS() //解析GNSS数据
{
if (!threadBuffer_g.isEmpty()) { // threadBuffer_g是全部数据,所以不能能用while判断
rwLock_g.lockForRead();
recvThreadDataBuffer_GNSS = threadBuffer_g; //读写锁同时到达 写锁优先级最高 所以一定为帧长的整数倍(包括帧头)
threadBuffer_g.clear(); // 清空缓冲区
rwLock_g.unlock();
} else {
return 0;
}
quint32 packetLen = recvThreadDataBuffer_GNSS.size();
if( packetLen == 0) return 0; //有数据才解包
qDebug() << "GNSSpkg" << packetLen;
for (size_t k=0; k<packetLen; k++) { // 按照报文逐条处理
QString element = recvThreadDataBuffer_GNSS.at(k);
QString head_str = element.left(6);
if (head_str == QString(HEAD_NMEA_GGA0) || head_str == QString(HEAD_NMEA_GGA1)) { // GGA
parseGPGGA(element, ggadata);
gnss_vp[3] = ggadata.latitude;
gnss_vp[4] = ggadata.longitude;
gnss_vp[5] = ggadata.altitude;
gnss_vp[6] = ggadata.utcTime.toDouble();
gnss_vp[7] = ggadata.hdop;
} else if (head_str == QString(HEAD_NMEA_VTG0) || head_str == QString(HEAD_NMEA_VTG1)) { // 根据报头选择合适的解析程序
parseGPVTG(element, vtgdata);
gnss_vp[0] = vtgdata.speedKmh/3.6*sin(vtgdata.trueHeading*DEG); // 东向速度
gnss_vp[1] = vtgdata.speedKmh/3.6*cos(vtgdata.trueHeading*DEG); // 北向速度
gnss_vp[2] = 0.0; // 天向速度
} else if (head_str == QString(HEAD_NOVT_POS)) { // 根据报头选择合适的解析程序
parseNovAP(element, napdata);
gnss_vp[3] = napdata.latitude; // 纬度
gnss_vp[4] = napdata.longitude; // 经度
gnss_vp[5] = napdata.height; // 高度
gnss_vp[6] = napdata.timestamp.toDouble(); // 时间
gnss_vp[7] = napdata.hdop; // 精度因子
} else if (head_str == QString(HEAD_NOVT_VEL)) { // 根据报头选择合适的解析程序
parseNovAV(element, navdata);
gnss_vp[0] = navdata.velocityH*sin(navdata.heading*DEG); // 东向速度
gnss_vp[1] = navdata.velocityH*cos(navdata.heading*DEG); // 北向速度
gnss_vp[2] = navdata.velocityU; // 天向速度
}
}
GNSSDataDisplayUpdate(gnss_vp);
mapplot_update_scal(gnss_vp[3], gnss_vp[4]);
toggleGNSSLedState();
str_gnss_save = QString(" %1 %2 %3 %4 %5 %6 %7 %8").arg(gnss_vp[0],0,'g',6).arg(gnss_vp[1],0,'g',6).arg(gnss_vp[2],0,'g',6)
.arg(gnss_vp[3],0,'g',12).arg(gnss_vp[4],0,'g',12).arg(gnss_vp[5],0,'g',7)
.arg(gnss_vp[6],0,'g',6).arg(gnss_vp[7],0,'g',4);
isGNSSUpdata = true;
for (size_t k=0; k<8; k++) {
gnss_vp[k] = 0.0;
}
// qDebug() << str_gnss_save;
return 1;
}
quint8 MainWindow::parseOrSaveDataTask() //解析并保存数据
{
// 线程资源同步
rwLock.lockForRead();
while (!threadBuffer.isEmpty())
recvThreadDataBuffer.append( threadBuffer.dequeue() ); //读写锁同时到达 写锁优先级最高 所以一定为帧长的整数倍(包括帧头)
rwLock.unlock();
quint32 packetLen = recvThreadDataBuffer.size();
if( packetLen == 0) return 0; //有数据才解包
QString str;
quint16 xPacket = packetLen/frameLen;
quint8* pBuf = recvThreadDataBuffer.data(); // 容器首地址 也就是帧头地址
for(quint16 m=0; m<xPacket; ++m) // 解m包
{
pBuf += frameHeaderLen; // 跳过帧头(没必要再判一次帧头了吧......)
for(quint16 i=0; i<frameDataTypeLen; ++i) // 解一包中的数据(类型)
{
quint8 tmp = frameDataType.at(i);
double scal = dataTypeDivisorFactor.at(i); // 加载标度因数
switch(tmp)
{
case 0:{ //myChar 需与mydatatype的值对应!!!
qint8 tmp0 = qint8(*pBuf); pBuf += 1;
if (scal > 9999) {
str = QString::number((int)tmp0);
} else {
str = QString::number((int)tmp0*scal,'g',7);
}
} break;
case 1:{ //myUint8_t
quint8 tmp1 = quint8(*pBuf); pBuf += 1;
if (scal > 9999) {
str = QString::number((uint)tmp1);
} else {
str = QString::number((uint)tmp1,'g',7);
}
} break;
case 2:{ //myShort
qint16 tmp2 = CV.func_2bytesToShort(pBuf); pBuf += 2;
if (scal > 9999) {
str = QString::number((int)tmp2);
} else {
str = QString::number((int)tmp2*scal,'g',7);
}
} break;
case 3:{ //myUint16_t
quint16 tmp3 = CV.func_2bytesToUint16(pBuf); pBuf += 2;
if (scal > 9999) {
str = QString::number((uint)tmp3);
} else {
str = QString::number((uint)tmp3*scal,'g',7);
}
} break;
case 4:{ //myInt
qint32 tmp4 = CV.func_4bytesToInt(pBuf); pBuf += 4;
if (scal > 9999) {
str = QString::number((int)tmp4);
} else {
str = QString::number((int)tmp4*scal,'g',7);
}
} break;
case 5:{ //myUint32_t
quint32 tmp5 = CV.func_4bytesToUint32(pBuf); pBuf += 4;
if (scal > 9999) {
str = QString::number((uint)tmp5);
} else {
str = QString::number((uint)tmp5*scal,'g',7);
}
} break;
case 6:{ //myFloat
float tmp6 = CV.func_4bytesToFloat(pBuf); pBuf += 4;
if (scal > 9999) {
str = QString::number((double)tmp6,'g',7); //float最大有效位数7位
} else {
str = QString::number((double)tmp6*scal,'g',7);
}
} break;
case 7:{ //myDouble
double tmp7 = CV.func_8bytesToDouble(pBuf); pBuf += 8;
if (scal > 9999) {
str = QString::number((double)tmp7,'g',15); //double最大有效位数15位
} else {
str = QString::number((double)tmp7*scal,'g',15);
}
} break;
case 8:{ //_3bytesToInt
qint32 tmp8 = CV.func_3bytesToInt(pBuf); pBuf += 3;
if (scal > 9999) {
str = QString::number((int)tmp8);
} else {
str = QString::number((int)tmp8*scal,'g',7);
}
} break;
case 9:{ //_2bytesToShort ? _2bytesToFloat
qint32 tmp9 = CV.func_2bytesToInt(pBuf); pBuf += 2;
if (scal > 9999) {
str = QString::number((int)tmp9);
} else {
str = QString::number((int)tmp9*scal,'g',7);
}
} break;
}
outStr.append(str); //存起来(没存帧头) ①保存到文件 ②更新到表格
}
recv_frameCounter++; //接收帧总计数
}
if(isSaveTxtFile) // 使能了文件保存
{
//解析数据保存为文本
QTextStream txtOut(&txtFile);
for(quint16 n=0; n<outStr.size(); ++n)
{
if( (n+1)%frameDataTypeLen == 0 )
{
if (isGNSSSerOpen) {
if (isGNSSUpdata) {
txtOut << outStr.at(n) + str_gnss_save + "\n"; // GNSS更新
isGNSSUpdata = false;
} else {
txtOut << outStr.at(n) + " 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0" + "\n"; //GNSS为0
}
} else {
txtOut << outStr.at(n) + "\n"; //正常保存
}
}
else
{
txtOut << outStr.at(n) + " "; //全保存
}
}
//原始数据保存为文本
quint8 num = 0;
QString strHex;
QDataStream txtHexOut(&txtFileHex);
for(quint16 m=0; m<packetLen; ++m)
{
num = recvThreadDataBuffer.at(m);
txtHexOut << num;
// if( num > 15){
// strHex = QString::number(num,16).toUpper();
// }else{
// strHex = "0" + QString::number(num,16).toUpper();
// }
// if( (m+1)%frameLen == 0 ) {
// txtHexOut << strHex + "\n"; //一帧的最后一个字节 补换行
// }else{
// txtHexOut << strHex + " ";
// }
}
}
recvThreadDataBuffer.clear(); //保存完原始数据清空
return xPacket;
}
void MainWindow::refreshTableTask(quint8 xPacket) //刷新表格数据显示
{
if(xPacket == 0) return;
quint16 tmp = (xPacket - 1) * frameDataTypeLen; // 只取最后一包数据显示在表格内
for(quint16 i=frameHeaderLen,cnt = tmp; i<ui->tableWidget->rowCount(); i++,cnt++)
{
ui->tableWidget->item(i,colData)->setData(Qt::DisplayRole,outStr.at(cnt));
}
}
/**************************************************** 协议帧 *********************************************************/
void MainWindow::creatItemsARow(int curRow, QString name, QString type, QString data, QString scal, QString Curve)
{
QFont font;
font.setFamily("Times New Roman");
font.setPointSize(13);
QTableWidgetItem *item;
//名称
item = new QTableWidgetItem(name,ctName);
ui->tableWidget->setItem(curRow,colName,item);
item->setFont(font); item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
if( (name == "Frame_Header") || (name == "Frame_Tail") || (name == "Check_Sum") || (name == "Time_Stamp")) // 固定名称不可编辑
{
item->setFlags( item->flags() & (~Qt::ItemIsEditable));
}
// if( (name != "Frame_Header") && (name != "Frame_Tail") && (name != "Check_Sum")) //名称前加复选框 用于保存
// {
// item->setCheckState(Qt::Checked);
// }
//数据类型
item = new QTableWidgetItem(type,ctType);
ui->tableWidget->setItem(curRow,colType,item);
item->setFont(font); item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
if( (name == "Frame_Header") || (name == "Frame_Tail")) // 固定名称不可编辑
{
item->setFlags( item->flags() & (~Qt::ItemIsEditable));
}
//数据
item = new QTableWidgetItem(data,ctData);
ui->tableWidget->setItem(curRow,colData,item);
item->setFont(font); item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
//标度因数
item = new QTableWidgetItem(scal,ctScal); // 默认插入“/”表示没有必要使用标度因数
ui->tableWidget->setItem(curRow,colScal,item);
item->setFont(font); item->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
//绘图1
item = new QTableWidgetItem(Curve,ctIsCurve);
ui->tableWidget->setItem(curRow,colIsCurve,item);
if( (name == "Frame_Header") || (name == "Frame_Tail") || (name == "Check_Sum")){ // 固定名称不可绘图
item->setText("--");
item->setFlags(Qt::NoItemFlags);
}else{
item->setCheckState(Qt::Unchecked);
item->setFlags(item->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
}
item->setFont(font);
//绘图2
item = new QTableWidgetItem(Curve,ctIsCurve1);
ui->tableWidget->setItem(curRow,colIsCurve1,item);
if( (name == "Frame_Header") || (name == "Frame_Tail") || (name == "Check_Sum")){ // 固定名称不可绘图
item->setText("--");
item->setFlags(Qt::NoItemFlags);
}else{
item->setCheckState(Qt::Unchecked);
item->setFlags(item->flags()&~Qt::ItemIsEditable & ~Qt::ItemIsSelectable); //不可选中 不可编辑
}
item->setFont(font);
//绘图3
item = new QTableWidgetItem(Curve,ctIsCurve2);
ui->tableWidget->setItem(curRow,colIsCurve2,item);
if( (name == "Frame_Header") || (name == "Frame_Tail") || (name == "Check_Sum")){ // 固定名称不可绘图
item->setText("--");
item->setFlags(Qt::NoItemFlags);
}else{
item->setCheckState(Qt::Unchecked);
item->setFlags(item->flags()&~Qt::ItemIsEditable & ~Qt::ItemIsSelectable); //不可选中 不可编辑
}
item->setFont(font);
}
void MainWindow::on_confirmDataFrame_btn_clicked(bool checked) //确认数据帧
{
if(checked)
{
ui->confirmDataFrame_btn->setText("编辑数据帧");
/* 失能所有按键 失能表格编辑功能并遍历元素 */
isEnabledAllFrameBtn(false);
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
bool ok;
int tmp = 0;
QString str;
frameLen = 0;
frameHeaderLen = 0;
frameDataTypeLen = 0;
checkSumPosOnframeDataType = -1; //默认没有校验和
TimeStampPosOnframeDataType = -1; //默认没有时间戳
frameTailNum.clear();
frameDataType.clear();
frameDataName.clear();
frameHeaderNum.clear();
dataTypeDivisorFactor.clear();
// 遍历表格所有行
for(uint8_t i=0; i<ui->tableWidget->rowCount(); i++)
{
str = ui->tableWidget->item(i,colName)->text();
// 帧头
if( str == "Frame_Header")
{
tmp = ui->tableWidget->item(i,colData)->text().toInt(&ok,16);
if((tmp > 255) || (ok == false)){
QMessageBox::critical(this,"@!!!!","帧头值设置错误..........");return;
}
frameHeaderNum.append( (uint8_t)tmp );
frameLen += 1;
}
// 帧尾 (用处不大)
else if( str == "Frame_Tail")
{
tmp = ui->tableWidget->item(i,colData)->text().toInt(&ok,16);
if((tmp > 255) || (ok == false)){
QMessageBox::critical(this,"@!!!!","帧尾值设置错误..........");return;
}
frameTailNum.append( (uint8_t)tmp );
frameLen += 1;
/* 检验帧尾是否处于最末端 */
if( i != (ui->tableWidget->rowCount()-1) ){
QMessageBox::critical(this,"@!!!!","帧尾不在末端?..........");return;
}
}
// 数据区(时间戳 + 数据 + 校验)
else
{
//将数据区的所有名字保存,用于作存储数据时的表头
frameDataName.append(str);
// 时间戳
if( str == "Time_Stamp" )
{
str = ui->tableWidget->item(i,colType)->text();
if (str == myDataTypeList.at(1)) { frameLen += 1; frameDataType.append(myUint8_t );}
else if(str == myDataTypeList.at(3)) { frameLen += 2; frameDataType.append(myUint16_t);}
else if(str == myDataTypeList.at(5)) { frameLen += 4; frameDataType.append(myUint32_t);}
else if(str == myDataTypeList.at(6)) { frameLen += 4; frameDataType.append(myFloat); }
else {
QMessageBox::critical(this,"@!!!!","时间戳数据类型不支持......");return;
}
TimeStampPosOnframeDataType = frameDataType.count() - 1; //时间戳在数据区中的位置
// qDebug() << "时间戳在数据区中的位置" << TimeStampPosOnframeDataType;
}
// 和校验
else if( str == "Check_Sum")
{
str = ui->tableWidget->item(i,colType)->text();
if (str == myDataTypeList.at(1)) { frameLen += 1; frameDataType.append(myUint8_t );}
// else if(str == myDataTypeList.at(3)) { frameLen += 2; frameDataType.append(myUint16_t);}
else if(str == myDataTypeList.at(5)) { frameLen += 4; frameDataType.append(myUint32_t);}
else {
QMessageBox::critical(this,"@!!!!","和校验数据类型不支持......");return;
}
checkSumPosOnframeDataType = frameDataType.count() - 1; //校验和在数据区中的位置
// qDebug() << "校验和在数据区中的位置" << checkSumPosOnframeDataType;
}
// 数据
else
{
str = ui->tableWidget->item(i,colType)->text();
if(str == myDataTypeList.at(0)) { frameDataType.append(myChar); frameLen += 1;}
else if(str == myDataTypeList.at(1)) { frameDataType.append(myUint8_t); frameLen += 1;}
else if(str == myDataTypeList.at(2)) { frameDataType.append(myShort); frameLen += 2;}
else if(str == myDataTypeList.at(3)) { frameDataType.append(myUint16_t);frameLen += 2;}
else if(str == myDataTypeList.at(4)) { frameDataType.append(myInt); frameLen += 4;}
else if(str == myDataTypeList.at(5)) { frameDataType.append(myUint32_t);frameLen += 4;}
else if(str == myDataTypeList.at(6)) { frameDataType.append(myFloat); frameLen += 4;}
else if(str == myDataTypeList.at(7)) { frameDataType.append(myDouble); frameLen += 8;}
else if(str == myDataTypeList.at(8)) //一般的数据手册 都会除以一个比例尺 这里对应dataTypeDivisorFactor
{
frameDataType.append(_3bytesToInt);
// tmp = ui->tableWidget->item(i,colData)->text().toInt(&ok,10);
// if((tmp > 32) || (tmp < -32) || (ok == false)){
// QMessageBox::critical(this,"@!!!!","_3bytesToInt类型的除数设置错误");return;
// }
// dataTypeDivisorFactor.append(tmp);
frameLen += 3;
}
else if(str == myDataTypeList.at(9))
{
frameDataType.append(_2bytesToInt);
// tmp = ui->tableWidget->item(i,colData)->text().toInt(&ok,10);
// if((tmp > 32) || (tmp < -32) || (ok == false)){
// QMessageBox::critical(this,"@!!!!","_2bytesToInt类型的除数设置错误");return;
// }
// dataTypeDivisorFactor.append(tmp);
frameLen += 2;
}
}
// 加载标度因子
str = ui->tableWidget->item(i,colScal)->text();
if (str == "/") {
dataTypeDivisorFactor.append(9999.99); // 特殊的数表示不需要使用标度因数
} else {
dataTypeDivisorFactor.append(str.toDouble());
}
}
}
frameHeaderLen = frameHeaderNum.size();
frameDataTypeLen = frameDataType.size();
ui->label_showFrameLen->setText(QString::number(frameLen));
/******************* 保存配置到.lastConfig.txt ****************************/
/* 建立一个子文件夹 用于存放文件 */
QString curPath = QDir::currentPath();
QDir dir(curPath);
QString savePath = curPath+ "/Config";
if(!dir.exists(savePath)) {
dir.mkdir("Config");
}
QString saveFilename = savePath + "/.lastConfig.txt";
/* 写文件 */
QFile configFile(saveFilename);
if(configFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) //如果文件存在则打开,不存在创建并打开,打开后清空原有数据
{
//遍历表格
QString str;
QTextStream out(&configFile);
for(uint8_t i=0; i<ui->tableWidget->rowCount(); i++)
{
str = ui->tableWidget->item(i,colName)->text(); out << str << ",";
str = ui->tableWidget->item(i,colType)->text(); out << str << ",";
str = ui->tableWidget->item(i,colData)->text(); out << str << ",";
str = ui->tableWidget->item(i,colScal)->text(); out << str << "\n"; // 加入标度因数
}
configFile.close();
}
emit signal_sendFrameInfoToSerialSubThread(frameLen,frameHeaderNum);
/***************************************************帧信息*******************************************************/
// qDebug() << "帧长" << frameLen << "帧头长度" << frameHeaderLen << "数据区长度" << frameDataTypeLen;
// qDebug() << "帧头值";
// for(uint8_t i=0; i<frameHeaderNum.size(); ++i)
// {
// qDebug() << frameHeaderNum.at(i);
// }
// qDebug() << "数据名" << "数据类型";
// for(uint8_t i=0; i<frameDataName.size(); ++i)
// {
// qDebug() << frameDataName.at(i) << frameDataType.at(i);
// }
// qDebug() << "校验位在数据区的位置" << checkSumPosOnframeDataType << "校验类型" << frameDataType.at(checkSumPosOnframeDataType);
}
else
{
ui->confirmDataFrame_btn->setText("确认数据帧");
/* 使能所有按键 使能表格编辑功能 */
isEnabledAllFrameBtn(true);
ui->tableWidget->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);
}
}
void MainWindow::isEnabledAllFrameBtn(bool checked) //使/失能协议帧相关按键
{
ui->addRow_btn->setEnabled(checked);
ui->deleteRow_btn->setEnabled(checked);
ui->insertRow_btn->setEnabled(checked);
ui->loadDataFrame_btn->setEnabled(checked);
ui->clearDataFrame_btn->setEnabled(checked);
ui->insertCheckSum_btn->setEnabled(checked);
ui->insertTimeStamp_btn->setEnabled(checked);
ui->insertFrameHeader_btn->setEnabled(checked);
// ui->insertFrameTail_btn->setEnabled(checked); //不失能插入帧尾
// ui->saveDataFrame_btn->setEnabled(checked);
}
void MainWindow::on_insertRow_btn_clicked()
{
int curRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow);
}
void MainWindow::on_addRow_btn_clicked()
{
int curRow = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow);
}
void MainWindow::on_insertFrameHeader_btn_clicked()
{
int curRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow,"Frame_Header","uint8_t(hex)","<keyboard Input>");
}
void MainWindow::on_insertFrameTail_btn_clicked()
{
int curRow = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow,"Frame_Tail","uint8_t(hex)","<keyboard Input>");
}
void MainWindow::on_insertTimeStamp_btn_clicked()
{
int curRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow,"Time_Stamp");
}
void MainWindow::on_insertCheckSum_btn_clicked()
{
int curRow = ui->tableWidget->currentRow();
ui->tableWidget->insertRow(curRow);
creatItemsARow(curRow,"Check_Sum");
}
void MainWindow::on_deleteRow_btn_clicked()
{
int curRow = ui->tableWidget->currentRow();
ui->tableWidget->removeRow(curRow);
}
void MainWindow::on_clearDataFrame_btn_clicked() //清除所有数据帧
{
for(int i = (ui->tableWidget->rowCount()-1); i>=0; i--)
{
ui->tableWidget->removeRow(i);
}
}
void MainWindow::on_changeGNSSActiveState()
{
isGNSSActive = ui->checkBox_active_gnss->isChecked(); // 更新GNSS激活状态
}
void MainWindow::on_changeGNSSMeasType(int index)
{
switch (index) {
case 0:
gnssMeasType = onlypos; // 量测类型
break;
case 1:
gnssMeasType = velpos; // 量测类型
break;
default:
gnssMeasType = velpos; // 量测类型
break;
}
signal_updateMeasType(gnssMeasType); // 修改serialPort中的参数
}
/***************************************************** 串口 *********************************************************/
void MainWindow::slot_switchSerialPort() //打开/关闭串口
{
//无论什么操作均将队列清空
threadBuffer.clear();
pos_ns.clear();
pos_ew.clear();
isGNSSWorking = false; // 重新等待GNSS更新
xPlotKeys.clear();
for(uint8_t i=0; i<3; ++i){
xPlot1Value[i].clear();xPlot2Value[i].clear();xPlot3Value[i].clear();
}
if(isIMUSerOpen == false) //打开IMU串口
{
QString portxName = ui->setPort_combox->currentText();
qint32 portxBaudrate = ui->setBaud_combox->currentText().toInt();
qint8 portxDataBits = ui->setDataBits_combox->currentText().toUShort();
qint8 portxStopBits = ui->setStopBits_combox->currentIndex();
qint8 portxParity = ui->setParity_combox->currentIndex();
switch(portxStopBits)
{
case 0: portxStopBits = 1; break; // 1停止位
case 1: portxStopBits = 3; break; // 1.5
case 2: portxStopBits = 2; break; // 2
default:portxStopBits = 1;
}
switch(portxParity)
{
case 0: portxParity = 0; break; //无校验
case 1: portxParity = 2; break; //偶校验
case 2: portxParity = 3; break; //奇
default:portxParity = 0;
}
emit signal_openSerialPortx(portxName,portxBaudrate,portxDataBits,portxParity,portxStopBits);
if (isGNSSSerOpen == false) { // 打开GNSS串口
if (isGNSSActive) {
// serialPortModule_GNSS->gnss_vel_format = ui->vel_combox_g->currentIndex()==0?NMEA:NovAtel;
// serialPortModule_GNSS->gnss_pos_format = ui->pos_combox_g->currentIndex()==0?NMEA:NovAtel;
portxName = ui->setPort_combox_g->currentText();
portxBaudrate = ui->setBaud_combox_g->currentText().toInt();
portxDataBits = ui->setDataBits_combox_g->currentText().toUShort();
portxStopBits = ui->setStopBits_combox_g->currentIndex();
portxParity = ui->setParity_combox_g->currentIndex();
switch(portxStopBits)
{
case 0: portxStopBits = 1; break; // 1停止位
case 1: portxStopBits = 3; break; // 1.5
case 2: portxStopBits = 2; break; // 2
default:portxStopBits = 1;
}
switch(portxParity)
{
case 0: portxParity = 0; break; //无校验
case 1: portxParity = 2; break; //偶校验
case 2: portxParity = 3; break; //奇
default:portxParity = 0;
}
emit signal_openSerialPortx_g(portxName,portxBaudrate,portxDataBits,portxParity,portxStopBits);
printf("GNSSSerial: %d\r\n", portxBaudrate);
}
}
}
else //关闭串口
{
runTimer->stop(); //关闭串口停止计时
emit signal_closeSerialPortx(); //关闭IMU串口
if (isGNSSSerOpen) {
emit signal_closeSerialPortx_g(); //关闭GNSS串口
}
ui->curveShow_btn->setChecked(false); //关闭串口-->关闭曲线Ui
isIMUSerOpen = false;
ui->switchSerialPort_btn->setText("打开串口");
}
}
void MainWindow::slot_showSerialPortxOpenStatus(bool checked) //显示串口打开状态
{
if(checked) {
isIMUSerOpen = true;
ui->switchSerialPort_btn->setText("关闭串口");
isEnabledSerialPortPanelBtn(false);
setSerialLedState(true);
outStr.clear();
timing10msCounter = 0;
recv_frameCounter = 0;
runTimer->start(); //打开成功开始计时
}else{ // Tips: Why the parameter isIMUSerOpen doesn't need be set false???
isEnabledSerialPortPanelBtn(true);
setSerialLedState(false);
ui->switchSerialPort_btn->setChecked(false);
QMessageBox::critical(this,"@!!!!","串口打开失败或已被占用......");
}
}
void MainWindow::slot_showSerialPortxCloseStauts(bool checked) //显示串口关闭状态
{
if(checked) {
isEnabledSerialPortPanelBtn(true);
setSerialLedState(false);
}else{
isEnabledSerialPortPanelBtn(false);
setSerialLedState(true);
QMessageBox::critical(this,"@!!!!","串口关闭失败......");
}
}
void MainWindow::slot_showSerialPortxOpenStatus_GNSS(bool checked) //显示串口打开状态
{
if(checked) {
isGNSSSerOpen = true;
// ui->switchSerialPort_btn->setText("关闭串口");
// isEnabledSerialPortPanelBtn(false);
// setSerialLedState(true);
}else{
QMessageBox::critical(this,"@!!!!","GNSS串口打开失败或已被占用......");
}
}
void MainWindow::slot_showSerialPortxCloseStauts_GNSS(bool checked) //显示串口关闭状态
{
if(checked) {
isGNSSSerOpen = false;
// isEnabledSerialPortPanelBtn(true);
// setSerialLedState(false);
}else{
// isEnabledSerialPortPanelBtn(false);
// setSerialLedState(true);
QMessageBox::critical(this,"@!!!!","GNSS串口关闭失败......");
}
}
void MainWindow::isEnabledSerialPortPanelBtn(bool checked) //使/失能串口相关按钮
{
ui->setPort_combox->setEnabled(checked);
ui->setBaud_combox->setEnabled(checked);
ui->setParity_combox->setEnabled(checked);
ui->setDataBits_combox->setEnabled(checked);
ui->setStopBits_combox->setEnabled(checked);
ui->confirmDataFrame_btn->setEnabled(checked); //打开串口后 数据帧面板使/失能
ui->comboBox_setEndianMode->setEnabled(checked); //打开串口后 大小端模式使/失能
}
void MainWindow::setGNSSLedState(bool led_active)
{
if (led_active) {
ui->GNSSStatus_LED0->setPixmap(QPixmap("://Icon/led-green.png"));
ui->GNSSStatus_LED1->setPixmap(QPixmap("://Icon/led-green.png"));
ui->GNSSStatus_LED2->setPixmap(QPixmap("://Icon/led-green.png"));
} else {
ui->GNSSStatus_LED0->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED1->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED2->setPixmap(QPixmap("://Icon/led-red.png"));
}
}
void MainWindow::toggleGNSSLedState()
{
static qint16 state = 0;
if (state == 0) {
ui->GNSSStatus_LED0->setPixmap(QPixmap("://Icon/led-green.png"));
ui->GNSSStatus_LED1->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED2->setPixmap(QPixmap("://Icon/led-red.png"));
} else if (state == 1) {
ui->GNSSStatus_LED0->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED1->setPixmap(QPixmap("://Icon/led-green.png"));
ui->GNSSStatus_LED2->setPixmap(QPixmap("://Icon/led-red.png"));
} else {
ui->GNSSStatus_LED0->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED1->setPixmap(QPixmap("://Icon/led-red.png"));
ui->GNSSStatus_LED2->setPixmap(QPixmap("://Icon/led-green.png"));
}
if (state++ == 2) {
state = 0;
}
}
/***************************************************** 地图 *********************************************************/
void MainWindow::init_mapplot(){
posxy0[0] = 34.00;
posxy0[1] = 108.00;
ui->plot_trace->addGraph();
ui->plot_trace->graph(0)->setLineStyle(QCPGraph::lsNone);
ui->plot_trace->graph(0)->setScatterStyle(QCPScatterStyle(
QCPScatterStyle::ssCircle, // 圆形点
Qt::blue, // 边框颜色
Qt::black, // 填充颜色
5 // 点大小(单位:像素)
));
ui->plot_trace->graph(0)->setData(pos_ew,pos_ns);
double xMin = *std::min_element(pos_ew.begin(), pos_ew.end());
double xMax = *std::max_element(pos_ew.begin(), pos_ew.end());
double yMax = *std::max_element(pos_ns.begin(), pos_ns.end());
double yMin = *std::min_element(pos_ns.begin(), pos_ns.end());
ui->plot_trace->xAxis->setRange(xMin-1, xMax+1); // x轴显示最近10个数据点
ui->plot_trace->yAxis->setRange(yMin-1, yMax+1); // y轴范围根据数据的最大最小值调整
// 设置点的颜色为红色,并且设置为点标记
//ui->plot_trace->graph(0)->setBrush(QBrush(Qt::red)); // 设置点的颜色为红色
ui->plot_trace->xAxis->setLabel("EAST/WEST");
ui->plot_trace->yAxis->setLabel("North/South");
ui->plot_trace->replot();
}
void MainWindow::mapplot_update_scal(double lat, double lng){
if (isGNSSWorking == false) {
posxy0[0] = lat;
posxy0[1] = lng;
posxy_1[0] = (posxy0[1]-lng)*DEG*clRNh;;
posxy_1[1] = (posxy0[0]-lat)*DEG*RMh;;
clRNh = cos(lat*DEG)*RMh;
isGNSSWorking = true;
}
dx = (posxy0[1]-lng)*DEG*clRNh;
dy = (posxy0[0]-lat)*DEG*RMh;
if (pos_ew.size() >= 3600) {
pos_ew.removeFirst(); // 移除最旧的数据
pos_ns.removeFirst(); // 移除最旧的数据
}
pos_ew.append(dx); // 添加新数据
pos_ns.append(dy);
/*ui->plot_trace->graph(0)->setScatterStyle(QCPScatterStyle(
QCPScatterStyle::ssCircle, // 圆形点
Qt::blue, // 边框颜色
Qt::black, // 填充颜色
5 // 点大小(单位:像素)
));
ui->plot_trace->graph(0)->addData(posxy_1[0],posxy_1[1]); */ // 覆盖前一个数据点
ui->plot_trace->graph(0)->setScatterStyle(QCPScatterStyle(
QCPScatterStyle::ssCircle, // 圆形点
Qt::blue, // 边框颜色
Qt::red, // 填充颜色
5 // 点大小(单位:像素)
));
ui->plot_trace->graph(0)->addData(dx,dy);
// posxy_1[0] = dx; // 更新前一时刻数据
// posxy_1[1] = dy;
double xMin = *std::min_element(pos_ew.begin(), pos_ew.end());
double xMax = *std::max_element(pos_ew.begin(), pos_ew.end());
double yMax = *std::max_element(pos_ns.begin(), pos_ns.end());
double yMin = *std::min_element(pos_ns.begin(), pos_ns.end());
ui->plot_trace->xAxis->setRange(xMin-1, xMax+1); // x轴显示最近10个数据点
ui->plot_trace->yAxis->setRange(yMin-1, yMax+1); // y轴范围根据数据的最大最小值调整
ui->plot_trace->replot();
}
void MainWindow::setSerialLedState(bool led_active)
{
if (led_active) {
ui->serialPortStauts_led->setPixmap(QPixmap("://Icon/led-green.png"));
} else {
ui->serialPortStauts_led->setPixmap(QPixmap("://Icon/led-red.png"));
}
}
/***************************************************** 文件 *********************************************************/
void MainWindow::on_saveData_btn_clicked() //捕获数据
{
if(!isSaveTxtFile)
{
/* 建立一个子文件夹 用于存放txt文件 */
QString curPath = QDir::currentPath();
QDir dir(curPath);
QString savePath = curPath+ "/txtFile";
if(!dir.exists(savePath)) {
dir.mkdir("txtFile");
}
QString dlgTitle = tr("另存为");
// QString filter = "文本文件(*.txt);;所有文件(*.)";
QString filter = "文本文件(*.txt)";
QString saveFilename = QFileDialog::getSaveFileName(this,dlgTitle,savePath,filter);
if (saveFilename.isEmpty())
{
ui->saveData_btn->setChecked(false);
return ;
}
// saveXDataTypeToTxt.clear();
// // 遍历状态:该数据类型是否需要保存到txt
// for(quint16 i=0; i<ui->tableWidget->rowCount(); i++)
// {
// if(ui->tableWidget->item(i,colName)->checkState() == Qt::Checked){
// saveXDataTypeToTxt.append(ui->tableWidget->row(ui->tableWidget->item(i,colName)) - frameHeaderLen); //对应了数据类型的位置
// }
// }
txtFile.setFileName(saveFilename); //解析数据
txtFileHex.setFileName(saveFilename.remove(".txt") + "Hex.bin"); //原始数据
QTextStream txtOut(&txtFile);
// QTextStream txtHexOut(&txtFileHex); //这里只打开,不存数据
if(txtFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate )) //如果文件存在则打开,不存在创建并打开 打开后在原有内容后开始写入
{
ui->saveData_btn->setText("停止捕获");
ui->saveData_btn->setStyleSheet("QPushButton{color:rgb(170,0,0,255);}");
for(uint8_t i=0; i<frameDataName.size(); ++i)
{
txtOut << "%"+frameDataName.at(i)+" ";
}
txtOut << "\n";
// //按选中保存数据
// for(uint8_t i=0; i<saveXDataTypeToTxt.size(); ++i)
// {
// txtOut << "%"+frameDataName.at( saveXDataTypeToTxt.at(i) )+" ";
// }
// txtOut << "\n";
isSaveTxtFile = true;
ui->label_showFileInfo->setText("数据正在保存.........");
}
if(txtFileHex.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate )) //如果文件存在则打开,不存在创建并打开 打开后在原有内容后开始写入
{
ui->label_showFileInfo->setText("数据正在保存......!!!");
}
}
else{
int ret = QMessageBox::question(this, "question","确定要停止捕获数据???",QMessageBox::Yes|QMessageBox::No,QMessageBox::No);
if(ret == QMessageBox::Yes)
{
txtFile.close();
txtFileHex.close();
isSaveTxtFile = false;
ui->saveData_btn->setText("捕获数据");
ui->saveData_btn->setStyleSheet("QPushButton{color:rgb(0,0,0,255);}");
ui->label_showFileInfo->setText("数据保存成功.........");
}
}
}
void MainWindow::on_saveDataFrame_btn_clicked() //保存数据帧配置
{
/* 建立一个子文件夹 用于存放文件 */
QString curPath = QDir::currentPath();
QDir dir(curPath);
QString savePath = curPath+ "/Config";
if(!dir.exists(savePath)) {
dir.mkdir("Config");
}
QString dlgTitle = tr("另存为");
QString filter = "文本文件(*.txt);;所有文件(*.)";
QString saveFilename = QFileDialog::getSaveFileName(this,dlgTitle,savePath,filter);
if (saveFilename.isEmpty())
return ;
/* 写文件 */
QFile configFile(saveFilename);
if(configFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) //如果文件存在则打开,不存在创建并打开,打开后清空原有数据
{
//遍历表格
QString str;
QTextStream out(&configFile);
for(uint8_t i=0; i<ui->tableWidget->rowCount(); i++)
{
str = ui->tableWidget->item(i,colName)->text(); out << str << ",";
str = ui->tableWidget->item(i,colType)->text(); out << str << ",";
str = ui->tableWidget->item(i,colData)->text(); out << str << ",";
str = ui->tableWidget->item(i,colScal)->text(); out << str << "\n"; // 加入标度因数
}
configFile.close();
ui->label_showFileInfo->setText("数据协议帧已保存.........");
}
}
void MainWindow::on_loadDataFrame_btn_clicked() //加载数据帧配置
{
/* 建立一个子文件夹 用于存放文件 */
QString curPath = QDir::currentPath();
QDir dir(curPath);
QString savePath = curPath+ "/Config";
if(!dir.exists(savePath)) {
dir.mkdir("Config");
}
QString dlgTitle = tr("加载配置文件");
QString filter = "文本文件(*.txt);;所有文件(*.)";
QString loadFilename = QFileDialog::getOpenFileName(this,dlgTitle,savePath,filter);
if (loadFilename.isEmpty())
return ;
/* 写文件 */
QFile configFile(loadFilename);
if(configFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
//遍历表格
QString strLine;
QTextStream in(&configFile);
/* 先清空表格 */
this->on_clearDataFrame_btn_clicked();
for(uint8_t i=0; in.atEnd() == false; i++)
{
strLine = in.readLine();
QStringList strList = strLine.split(",");
/* 添加表格 */
int curRow = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(curRow);
this->creatItemsARow(i,strList.at(0),strList.at(1),strList.at(2), strList.at(3));
}
configFile.close();
ui->label_showFileInfo->setText("数据协议帧加载成功.........");
}
}
/****************************************************** UI *********************************************************/
void MainWindow::on_curveShow_btn_toggled(bool checked) //曲线UI
{
QVector<quint8> VecEmpty;
//打开曲线显示 清除原有图像
if(checked){
if(!isOpenCurvePlot)
{
detectAllCurvePlotCheckBox();
curvePlot->clearAllCurve_clicked();
curvePlot->move(this->pos().x()+200,this->pos().y()+66);
curvePlot->resize(800,510);
curvePlot->show();
isStartCurvePlot = true;
isOpenCurvePlot = true;
curvePlot->resetAllBtn();
ui->comboBox_setXAxis->setEnabled(false); //X轴属性不可调节
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve ,false); //失能所有复选框
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve1,false); //失能所有复选框
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve2,false); //失能所有复选框
}
}else{
if(isOpenCurvePlot)
{
// qDebug() << "关闭绘图显示";
isOpenCurvePlot = false;
isStartCurvePlot = false;
curvePlot->clearAllCurve_clicked();
curvePlot->close();
ui->comboBox_setXAxis->setEnabled(true); //X轴属性可调节
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve ,true); //使能所有复选框
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve1,true); //使能所有复选框
isEnableCurvePlotCheckBox( VecEmpty,colIsCurve2,true); //使能所有复选框
if(isPlotXyz.size() >= 3) isEnableCurvePlotCheckBox(isPlotXyz,colIsCurve,false); //失能除选中之外的所有复选框
if(isPlotxYz.size() >= 3) isEnableCurvePlotCheckBox(isPlotxYz,colIsCurve1,false); //失能除选中之外的所有复选框
if(isPlotxyZ.size() >= 3) isEnableCurvePlotCheckBox(isPlotxyZ,colIsCurve2,false); //失能除选中之外的所有复选框
}
}
}
//void MainWindow::on_dashboardShow_btn_toggled(bool checked) //仪表盘UI
//{
// if(checked)
// {
// if(!isOpenDashBoard)
// {
// detectEulerAnglesToDashBoard();
// attDashBoard->move(this->pos().x()+200,this->pos().y()+150);
// attDashBoard->show();
// attDashBoard->setValue(10.5,0.5,0.5);
// isOpenDashBoard = true;
// }
// }
// else
// {
// if(isOpenDashBoard)
// {
//// qDebug() << "关闭仪表盘显示";
// attDashBoard->close();
// isOpenDashBoard = false;
// }
// }
//}
void MainWindow::on_showHelp_btn_clicked() //帮助UI
{
if(!isOpenHelpUi){
helpInfo->show();
isOpenHelpUi = true;
}else{
helpInfo->close();
isOpenHelpUi = false;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/tmrnic/lab-tool-v2.git
git@gitee.com:tmrnic/lab-tool-v2.git
tmrnic
lab-tool-v2
LabTool-V2
main

搜索帮助