Files
giesCANne/signalviewerwindow.cpp
T
Andy Huska ab476c746e Added fully qualified dbc, node, and msg searching
...to graphing window and signal viewer so complex systems with message
name duplication (eg "Status") works well.  DBCHandler class has a new
function to find a msg by fully qualified node name...Utility class defines
the qualified name seperator, right now it is :: and is used thusly
filenameNoExtension::nodeName for display in the node dropdown (because
nodes can be common between dbc files).  To get the message from the
system you use the findMessage function in dbchandler and pass the
msgName and the fully qualified node name.  This is about as unique as we
can get, second only to message ID.

Added node comboBox to graph signal editor for easier data filtering
(took the same implementation that was in signal viewer, and tuned up
both of them)
2023-05-17 17:23:27 -05:00

399 lines
12 KiB
C++

#include "signalviewerwindow.h"
#include "ui_signalviewerwindow.h"
#include "helpwindow.h"
#include "mainwindow.h"
#include "utility.h"
#include <QDebug>
#define MSG_COL 1
#define VALUE_COL 2
SignalViewerWindow::SignalViewerWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::SignalViewerWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Window);
modelFrames = frames;
QStringList headers;
headers << "Node" << "Signal" << "Value";
ui->tableViewer->setHorizontalHeaderLabels(headers);
ui->tableViewer->setColumnWidth(0, 100);
ui->tableViewer->setColumnWidth(1, 150);
QSettings settings;
QFont sysFont;
int fontSize = settings.value("Main/FontSize", 9).toUInt();
if(settings.value("Main/FontFixedWidth", false).toBool())
sysFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); //get default fixed width font
else
sysFont = QFont(); //get default font
sysFont.setPointSize(fontSize);
ui->tableViewer->setFont(sysFont);
QHeaderView *HorzHdr = ui->tableViewer->horizontalHeader();
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
HorzHdr->setFont(QFont());
QHeaderView *verticalHeader = ui->tableViewer->verticalHeader();
verticalHeader->setFont(QFont());
dbcHandler = DBCHandler::getReference();
currentlySelectedMsg = nullptr;
connect(ui->cbNodes, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMessages(int)));
connect(ui->cbMessages, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSignals(int)));
connect(ui->btnAdd, SIGNAL(clicked(bool)), this, SLOT(addSignal()));
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
connect(ui->btnRemove, SIGNAL(clicked(bool)), this, SLOT(removeSelectedSignal()));
connect(ui->btnSave, SIGNAL(clicked(bool)), this, SLOT(saveSignalsFile()));
connect(ui->btnLoad, SIGNAL(clicked(bool)), this, SLOT(loadSignalsFile()));
connect(ui->btnAppend, SIGNAL(clicked(bool)), this, SLOT(appendSignalsFile()));
connect(ui->btnClear, SIGNAL(clicked(bool)), this, SLOT(clearSignalsTable()));
loadNodes();
}
SignalViewerWindow::~SignalViewerWindow()
{
delete ui;
}
void SignalViewerWindow::updatedFrames(int numFrames)
{
CANFrame thisFrame;
if (numFrames == -1) //all frames deleted. Don't care
{
}
else if (numFrames == -2) //all new set of frames. Reset
{
for (int i = 0; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
processFrame(thisFrame);
}
}
else //just got some new frames. See if they are relevant.
{
if (numFrames > modelFrames->count()) return;
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
processFrame(thisFrame);
}
}
}
void SignalViewerWindow::processFrame(CANFrame &frame)
{
QString sigString;
DBC_SIGNAL *sig;
for (int i = 0; i < signalList.count(); i++)
{
sig = signalList.at(i);
if (!sig) return;
if (sig->parentMessage->ID == frame.frameId())
{
if (sig->processAsText(frame, sigString, false)) //if true we could interpret the signal so update it in the list
{
QTableWidgetItem *item = ui->tableViewer->item(i, VALUE_COL);
if (!item)
{
item = new QTableWidgetItem(sigString);
ui->tableViewer->setItem(i, VALUE_COL, item);
}
else item->setText(sigString);
}
}
}
}
void SignalViewerWindow::removeSelectedSignal()
{
int selRow = ui->tableViewer->currentRow();
if (selRow < 0) return; //no selected row
signalList.removeAt(selRow);
ui->tableViewer->removeRow(selRow);
}
void SignalViewerWindow::loadNodes()
{
int numFiles;
ui->cbNodes->clear();
if (dbcHandler == nullptr) return;
if ((numFiles = dbcHandler->getFileCount()) == 0) return;
qDebug() << numFiles;
for (int f = 0; f < numFiles; f++)
{
DBCFile* thisFile = dbcHandler->getFileByIdx(f);
qDebug() << thisFile->messageHandler->getCount();
QList<QString> names;
for (int x = 0; x < thisFile->dbc_nodes.count(); x++)
{
bool messagesInNode = false;
for (int m = 0; m < thisFile->messageHandler->getCount(); m++)
{
if(thisFile->messageHandler->findMsgByIdx(m)->sender->name == thisFile->dbc_nodes[x].name)
{
messagesInNode = true;
break;
}
}
if(messagesInNode)
{
QString fullyQualifiedNodeName = thisFile->getFilenameNoExt() + Utility::fullyQualifiedNameSeperator + thisFile->dbc_nodes[x].name;
names.append(fullyQualifiedNodeName);
}
}
if(names.count() > 0)
{
names.sort();
ui->cbNodes->addItem("----" + thisFile->getFilename());
Utility::SetComboBoxItemEnabled(ui->cbNodes, ui->cbNodes->count() -1, false);
for(int i=0; i<names.count(); i++)
ui->cbNodes->addItem(names[i]);
}
}
}
void SignalViewerWindow::loadMessages(int idx)
{
int numFiles = 0;
ui->cbMessages->clear();
if (dbcHandler == nullptr) return;
if ((numFiles = dbcHandler->getFileCount()) == 0) return;
qDebug() << numFiles;
QString displayedNodeName = ui->cbNodes->itemText(idx);
for (int f = 0; f < numFiles; f++)
{
qDebug() << dbcHandler->getFileByIdx(f)->messageHandler->getCount();
for (int x = 0; x < dbcHandler->getFileByIdx(f)->messageHandler->getCount(); x++)
{
QString fullyQualifiedNodeName = dbcHandler->getFileByIdx(f)->getFilenameNoExt() + Utility::fullyQualifiedNameSeperator + dbcHandler->getFileByIdx(f)->messageHandler->findMsgByIdx(x)->sender->name;
if(fullyQualifiedNodeName == displayedNodeName)
ui->cbMessages->addItem(dbcHandler->getFileByIdx(f)->messageHandler->findMsgByIdx(x)->name);
}
}
}
void SignalViewerWindow::loadSignals(int idx)
{
Q_UNUSED(idx);
ui->cbSignals->clear();
QString fullyQualifiedNodeName = ui->cbNodes->itemText(ui->cbNodes->currentIndex());
QString msgName = ui->cbMessages->itemText(ui->cbMessages->currentIndex());
DBC_MESSAGE *msg = dbcHandler->findMessage(msgName, fullyQualifiedNodeName);
if (msg == nullptr) return;
for (int x = 0; x < msg->sigHandler->getCount(); x++)
{
ui->cbSignals->addItem(msg->sigHandler->findSignalByIdx(x)->name);
}
}
void SignalViewerWindow::addSignal()
{
DBC_MESSAGE *msg = nullptr;
QString fullyQualifiedNodeName = ui->cbNodes->itemText(ui->cbNodes->currentIndex());
QString msgName = ui->cbMessages->itemText(ui->cbMessages->currentIndex());
msg = dbcHandler->findMessage(msgName, fullyQualifiedNodeName);
if (!msg) return;
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
if (!sig) return;
addSignal(sig);
}
void SignalViewerWindow::addSignal(DBC_SIGNAL *sig)
{
signalList.append(sig);
int rowIdx = ui->tableViewer->rowCount();
ui->tableViewer->insertRow(rowIdx);
QTableWidgetItem *nodeitem = new QTableWidgetItem(sig->parentMessage->sender->name);
ui->tableViewer->setItem(rowIdx, 0, nodeitem);
QTableWidgetItem *msgitem = new QTableWidgetItem(sig->name);
ui->tableViewer->setItem(rowIdx, 1, msgitem);
}
void SignalViewerWindow::saveSignalsFile()
{
saveDefinitions();
}
void SignalViewerWindow::loadSignalsFile()
{
loadDefinitions(false);
}
void SignalViewerWindow::appendSignalsFile()
{
loadDefinitions(true);
}
void SignalViewerWindow::clearSignalsTable()
{
clearSignalsTable(true);
}
void SignalViewerWindow::clearSignalsTable(bool askForConfirmation)
{
if(askForConfirmation)
{
QMessageBox::StandardButton confirmDialog;
confirmDialog = QMessageBox::question(this, "Danger Will Robinson", "Are you sure you want to clear all of your signals?",
QMessageBox::Yes|QMessageBox::No);
if (confirmDialog == QMessageBox::No)
{
return;
}
}
signalList.clear();
ui->tableViewer->setRowCount(0);
}
void SignalViewerWindow::saveDefinitions()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("SignalViewer definition (*.sdf)")));
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("SignalViewer/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("SignalViewer/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".sdf";
QFile *outFile = new QFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
return;
DBC_SIGNAL *sig;
for (int i = 0; i < signalList.count(); i++)
{
sig = signalList.at(i);
outFile->write("SV1");
outFile->putChar(',');
outFile->write(QString::number(sig->parentMessage->ID, 16).toUtf8());
outFile->putChar(',');
outFile->write(sig->parentMessage->name.toUtf8());
outFile->putChar(',');
outFile->write(sig->name.toUtf8());
outFile->write("\n");
}
outFile->close();
}
}
void SignalViewerWindow::loadDefinitions(bool append)
{
QString filename;
QFileDialog dialog;
QSettings settings;
QStringList filters;
filters.append(QString(tr("SignalViewer definition (*.sdf)")));
QList<DBC_SIGNAL *> loadedSignals;
if (dbcHandler == nullptr) return;
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setDirectory(settings.value("SignalViewer/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("SignalViewer/LoadSaveDirectory", dialog.directory().path());
QFile *inFile = new QFile(filename);
QByteArray line;
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
return;
while (!inFile->atEnd()) {
line = inFile->readLine().simplified();
if (line.length() > 2)
{
QList<QByteArray> tokens = line.split(',');
DBC_SIGNAL *sig;
if (tokens[0] == "SV1") //signal viewer save format v1
{
// = tokens[1].toUInt(nullptr, 16);
int msgId = tokens[1].toUInt(nullptr, 16);
QString msgName = QString(tokens[2]);
QString sigName = QString(tokens[3]);
DBC_MESSAGE *msg;;
if( (msg = dbcHandler->findMessage(msgId)) )
{
sig = msg->sigHandler->findSignalByName(sigName);
if(sig)
loadedSignals.append(sig);
}
else if ( (msg = dbcHandler->findMessage(msgName)) )
{
//this is not a very safe way to match since messages names can be duplicated
sig = msg->sigHandler->findSignalByName(sigName);
if(sig)
loadedSignals.append(sig);
}
else
{
qDebug() << "Couldn't find the message by ID or name! " << msgName << " " << sigName;
}
}
}
}
inFile->close();
if(loadedSignals.count() > 0)
{
if(append == false)
{
clearSignalsTable(false);
}
for (int i=0; i<loadedSignals.count(); i++)
{
addSignal(loadedSignals[i]);
}
}
}
}