代码拉取完成,页面将自动刷新
#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;
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。