Merge pull request #200 from collin80/WIP

Merge WIP changes into Master
This commit is contained in:
Collin Kidder
2019-06-17 21:22:35 -04:00
committed by GitHub
43 changed files with 1127 additions and 181 deletions
+11
View File
@@ -71,6 +71,14 @@ Now run SavvyCAN
./SavvyCAN
```
### Compiling in debug mode for additional information
```sh
qmake CONFIG+=debug
make
```
## What to do if your compile failed?
The very first thing to do is try:
@@ -86,3 +94,6 @@ make
Did that fix it? Great! If not, ensure that you selected SerialBUS support
when you installed Qt.
### What to do if `qmake` fails with error `Project ERROR: Unknown module(s) in QT: qml serialbus help` on Ubuntu? :
`sudo apt install libqt5serialbus5-dev qtdeclarative5-dev qttools5-dev`
+6 -3
View File
@@ -67,7 +67,8 @@ SOURCES += main.cpp\
helpwindow.cpp \
blfhandler.cpp \
re/sniffer/SnifferDelegate.cpp \
connections/newconnectiondialog.cpp
connections/newconnectiondialog.cpp \
re/temporalgraphwindow.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -125,7 +126,8 @@ HEADERS += mainwindow.h \
helpwindow.h \
blfhandler.h \
re/sniffer/SnifferDelegate.h \
connections/newconnectiondialog.h
connections/newconnectiondialog.h \
re/temporalgraphwindow.h
FORMS += ui/candatagrid.ui \
ui/connectionwindow.ui \
@@ -153,7 +155,8 @@ FORMS += ui/candatagrid.ui \
ui/bisectwindow.ui \
ui/signalviewerwindow.ui \
helpwindow.ui \
ui/newconnectiondialog.ui
ui/newconnectiondialog.ui \
ui/temporalgraphwindow.ui
DISTFILES +=
+2
View File
@@ -16,6 +16,7 @@ public:
uint32_t len;
unsigned char data[8];
uint64_t timestamp;
uint64_t timedelta;
uint32_t frameCount; //used in overwrite mode
friend bool operator<(const CANFrame& l, const CANFrame& r)
@@ -32,6 +33,7 @@ public:
isReceived = true;
len = 0;
timestamp = 0;
timedelta = 0;
frameCount = 1;
}
};
+162 -23
View File
@@ -6,19 +6,6 @@
#include <QDateTime>
#include "utility.h"
enum class Column {
TimeStamp = 0, ///< The timestamp when the frame was transmitted or received
FrameId = 1, ///< The frames CAN identifier (Standard: 11 or Extended: 29 bit)
Extended = 2, ///< True if the frames CAN identifier is 29 bit
Remote = 3, ///< True if the frames is a remote frame
Direction = 4, ///< Whether the frame was transmitted or received
Bus = 5, ///< The bus where the frame was transmitted or received
Length = 6, ///< The frames payload data length
ASCII = 7, ///< The payload interpreted as ASCII characters
Data = 8, ///< The frames payload data
NUM_COLUMN
};
CANFrameModel::~CANFrameModel()
{
frames.clear();
@@ -26,7 +13,6 @@ CANFrameModel::~CANFrameModel()
filters.clear();
}
int CANFrameModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
@@ -82,6 +68,7 @@ CANFrameModel::CANFrameModel(QObject *parent)
needFilterRefresh = false;
lastUpdateNumFrames = 0;
timeFormat = "MMM-dd HH:mm:ss.zzz";
sortDirAsc = false;
}
void CANFrameModel::setHexMode(bool mode)
@@ -189,6 +176,119 @@ void CANFrameModel::setAllFilters(bool state)
sendRefresh();
}
/*
* There is probably a more correct way to have done this but below are several functions that collectively implement
* quicksort on the columns and interpret the columns numerically. But, correct or not, this implementation is quite fast
* and sorts the columns properly.
*/
uint64_t CANFrameModel::getCANFrameVal(int row, Column col)
{
uint64_t temp = 0;
if (row >= frames.count()) return 0;
CANFrame frame = frames[row];
switch (col)
{
case Column::TimeStamp:
if (overwriteDups) return frame.timedelta;
return frame.timestamp;
case Column::FrameId:
return frame.ID;
case Column::Extended:
if (frame.extended) return 1;
return 0;
case Column::Remote:
if (overwriteDups) return frame.frameCount;
if (frame.remote) return 1;
return 0;
case Column::Direction:
if (frame.isReceived) return 1;
return 0;
case Column::Bus:
return frame.bus;
case Column::Length:
return frame.len;
case Column::ASCII: //sort both the same for now
case Column::Data:
for (int i = 0; i < frame.len; i++) temp += ((uint64_t)frame.data[i] << (56 - (8 * i)));
//qDebug() << temp;
return temp;
}
}
void CANFrameModel::qSortCANFrameAsc(QVector<CANFrame> *frames, Column column, int lowerBound, int upperBound)
{
int p, i, j;
qDebug() << "Lower " << lowerBound << " Upper" << upperBound;
if (lowerBound < upperBound)
{
uint64_t piv = getCANFrameVal(lowerBound + (upperBound - lowerBound) / 2, column);
i = lowerBound - 1;
j = upperBound + 1;
for (;;){
do {
i++;
} while ((i < upperBound) && getCANFrameVal(i, column) < piv);
do
{
j--;
} while ((j > lowerBound) && getCANFrameVal(j, column) > piv);
if (i < j) {
CANFrame temp = frames->at(i);
frames->replace(i, frames->at(j));
frames->replace(j, temp);
}
else {p = j; break;}
}
qSortCANFrameAsc(frames, column, lowerBound, p);
qSortCANFrameAsc(frames, column, p+1, upperBound);
}
}
void CANFrameModel::qSortCANFrameDesc(QVector<CANFrame> *frames, Column column, int lowerBound, int upperBound)
{
int p, i, j;
qDebug() << "Lower " << lowerBound << " Upper" << upperBound;
if (lowerBound < upperBound)
{
uint64_t piv = getCANFrameVal(lowerBound + (upperBound - lowerBound) / 2, column);
i = lowerBound - 1;
j = upperBound + 1;
for (;;){
do {
i++;
} while ((i < upperBound) && getCANFrameVal(i, column) > piv);
do
{
j--;
} while ((j > lowerBound) && getCANFrameVal(j, column) < piv);
if (i < j) {
CANFrame temp = frames->at(i);
frames->replace(i, frames->at(j));
frames->replace(j, temp);
}
else {p = j; break;}
}
qSortCANFrameDesc(frames, column, lowerBound, p);
qSortCANFrameDesc(frames, column, p+1, upperBound);
}
}
void CANFrameModel::sortByColumn(int column)
{
sortDirAsc = !sortDirAsc;
//beginResetModel();
if (sortDirAsc) qSortCANFrameAsc(&frames, Column(column), 0, frames.count()-1);
else qSortCANFrameDesc(&frames, Column(column), 0, frames.count()-1);
//endResetModel();
sendRefresh();
}
//End of custom sorting code
void CANFrameModel::recalcOverwrite()
{
if (!overwriteDups) return; //no need to do a thing if mode is disabled
@@ -202,14 +302,24 @@ void CANFrameModel::recalcOverwrite()
beginResetModel();
//Look at the current list of frames and turn it into just a list of unique IDs
QHash<int, CANFrame> overWriteFrames;
QHash<uint64_t, CANFrame> overWriteFrames;
uint64_t idAugmented; //id in lower 29 bits, bus number shifted up 29 bits
foreach(CANFrame frame, frames)
{
if (!overWriteFrames.contains(frame.ID))
idAugmented = frame.ID;
idAugmented = idAugmented + (frame.bus << 29ull);
if (!overWriteFrames.contains(idAugmented))
{
overWriteFrames.insert(frame.ID, frame);
frame.timedelta = 0;
frame.frameCount = 1;
overWriteFrames.insert(idAugmented, frame);
}
else
{
frame.timedelta = frame.timestamp - overWriteFrames[idAugmented].timestamp;
frame.frameCount = overWriteFrames[idAugmented].frameCount + 1;
overWriteFrames[idAugmented] = frame;
}
else overWriteFrames[frame.ID] = frame;
}
//Then replace the old list of frames with just the unique list
frames.clear();
@@ -282,7 +392,17 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
switch (Column(index.column()))
{
case Column::TimeStamp:
case Column::TimeStamp:
//Reformatting the output a bit with custom code
if (overwriteDups)
{
if (timeSeconds) return QString::number(thisFrame.timedelta / 1000000.0, 'f', 5);
return QString::number(thisFrame.timedelta);
}
else ts = Utility::formatTimestamp(thisFrame.timestamp);
if (ts.type() == QVariant::Double) return QString::number(ts.toDouble(), 'f', 5); //never scientific notation, 5 decimal places
if (ts.type() == QVariant::LongLong) return QString::number(ts.toLongLong()); //never scientific notion, all digits shown
if (ts.type() == QVariant::DateTime) return ts.toDateTime().toString(timeFormat); //custom set format for dates and times
return Utility::formatTimestamp(thisFrame.timestamp);
case Column::FrameId:
return Utility::formatCANID(thisFrame.ID, thisFrame.extended);
@@ -378,13 +498,14 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
switch (Column(section))
{
case Column::TimeStamp:
if (overwriteDups) return QString(tr("Time Delta"));
return QString(tr("Timestamp"));
case Column::FrameId:
return QString(tr("ID"));
case Column::Extended:
return QString(tr("Ext"));
case Column::Remote:
if (!overwriteDups) return QString(tr("Rem"));
if (!overwriteDups) return QString(tr("RTR"));
return QString(tr("Cnt"));
case Column::Direction:
return QString(tr("Dir"));
@@ -407,6 +528,18 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
bool CANFrameModel::any_filters_are_configured(void)
{
for (auto const &val : filters)
{
if (val == true)
continue;
else
return true;
}
return false;
}
void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
{
@@ -421,7 +554,11 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
//if this ID isn't found in the filters list then add it and show it by default
if (!filters.contains(tempFrame.ID))
{
filters.insert(tempFrame.ID, true);
// if there are any filters already configured, leave the new filter disabled
if (any_filters_are_configured())
filters.insert(tempFrame.ID, false);
else
filters.insert(tempFrame.ID, true);
needFilterRefresh = true;
}
@@ -441,9 +578,10 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
bool found = false;
for (int i = 0; i < frames.count(); i++)
{
if (frames[i].ID == tempFrame.ID)
if ( (frames[i].ID == tempFrame.ID) && (frames[i].bus == tempFrame.bus) )
{
tempFrame.frameCount = frames[i].frameCount + 1;
tempFrame.timedelta = tempFrame.timestamp - frames[i].timestamp;
frames.replace(i, tempFrame);
found = true;
break;
@@ -456,6 +594,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
{
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count(), filteredFrames.count());
tempFrame.frameCount = 1;
tempFrame.timedelta = 0;
filteredFrames.append(tempFrame);
if (autoRefresh) endInsertRows();
}
@@ -464,7 +603,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false)
{
for (int j = 0; j < filteredFrames.count(); j++)
{
if (filteredFrames[j].ID == tempFrame.ID)
if ( (filteredFrames[j].ID == tempFrame.ID) && (filteredFrames[j].bus == tempFrame.bus) )
{
if (autoRefresh) beginResetModel();
filteredFrames.replace(j, tempFrame);
+20
View File
@@ -10,6 +10,19 @@
#include "dbc/dbchandler.h"
#include "connections/canconnection.h"
enum class Column {
TimeStamp = 0, ///< The timestamp when the frame was transmitted or received
FrameId = 1, ///< The frames CAN identifier (Standard: 11 or Extended: 29 bit)
Extended = 2, ///< True if the frames CAN identifier is 29 bit
Remote = 3, ///< True if the frames is a remote frame
Direction = 4, ///< Whether the frame was transmitted or received
Bus = 5, ///< The bus where the frame was transmitted or received
Length = 6, ///< The frames payload data length
ASCII = 7, ///< The payload interpreted as ASCII characters
Data = 8, ///< The frames payload data
NUM_COLUMN
};
class CANFrameModel: public QAbstractTableModel
{
Q_OBJECT
@@ -43,6 +56,7 @@ public:
void recalcOverwrite();
bool needsFilterRefresh();
void insertFrames(const QVector<CANFrame> &newFrames);
void sortByColumn(int column);
int getIndexFromTimeID(unsigned int ID, double timestamp);
const QVector<CANFrame> *getListReference() const; //thou shalt not modify these frames externally!
const QVector<CANFrame> *getFilteredListReference() const; //Thus saith the Lord, NO.
@@ -56,6 +70,11 @@ signals:
void updatedFiltersList();
private:
void qSortCANFrameAsc(QVector<CANFrame>* frames, Column column, int lowerBound, int upperBound);
void qSortCANFrameDesc(QVector<CANFrame>* frames, Column column, int lowerBound, int upperBound);
uint64_t getCANFrameVal(int row, Column col);
bool any_filters_are_configured(void);
QVector<CANFrame> frames;
QVector<CANFrame> filteredFrames;
QMap<int, bool> filters;
@@ -71,6 +90,7 @@ private:
uint64_t timeOffset;
int lastUpdateNumFrames;
uint32_t preallocSize;
bool sortDirAsc;
};
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONFIG
#define CONFIG
#define VERSION 197
#define VERSION 199
//try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision
+5
View File
@@ -66,6 +66,11 @@ void CANConManager::remove(CANConnection* pConn_p)
mConns.removeOne(pConn_p);
}
void CANConManager::replace(int idx, CANConnection* pConn_p)
{
mConns.replace(idx, pConn_p);
}
//Get total number of buses currently registered with the program
int CANConManager::getNumBuses()
{
+1
View File
@@ -17,6 +17,7 @@ public:
void add(CANConnection* pConn_p);
void remove(CANConnection* pConn_p);
void replace(int idx, CANConnection* pConn_p);
QList<CANConnection*>& getConnections();
void stopAllConnections();
+8
View File
@@ -126,6 +126,14 @@ void CANConnectionModel::remove(CANConnection* pConn_p)
endResetModel();
}
void CANConnectionModel::replace(int idx , CANConnection* pConn_p)
{
CANConManager* manager = CANConManager::getInstance();
beginResetModel();
manager->replace(idx, pConn_p);
endResetModel();
}
CANConnection* CANConnectionModel::getAtIdx(int pIdx) const
{
+1
View File
@@ -25,6 +25,7 @@ public:
void add(CANConnection* pConn_p);
void remove(CANConnection* pConn_p);
void replace(int idx , CANConnection* pConn_p);
CANConnection* getAtIdx(int) const;
void refresh(int pIndex=-1);
+53 -24
View File
@@ -55,6 +55,7 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
connect(ui->ckEnableConsole, &QCheckBox::toggled, this, &ConnectionWindow::consoleEnableChanged);
connect(ui->btnClearDebug, &QPushButton::clicked, this, &ConnectionWindow::handleClearDebugText);
connect(ui->btnNewConnection, &QPushButton::clicked, this, &ConnectionWindow::handleNewConn);
connect(ui->btnResetConn, &QPushButton::clicked, this, &ConnectionWindow::handleResetConn);
connect(ui->tableConnections->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ConnectionWindow::currentRowChanged);
connect(ui->tabBuses, &QTabBar::currentChanged, this, &ConnectionWindow::currentTabChanged);
connect(ui->btnSaveBus, &QPushButton::clicked, this, &ConnectionWindow::saveBusSettings);
@@ -207,6 +208,53 @@ void ConnectionWindow::handleNewConn()
delete thisDialog;
}
void ConnectionWindow::handleRemoveConn()
{
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
if (selIdx <0) return;
qDebug() << "remove connection at index: " << selIdx;
CANConnection* conn_p = connModel->getAtIdx(selIdx);
if(!conn_p) return;
/* remove connection from model & manager */
connModel->remove(conn_p);
/* stop and delete connection */
conn_p->stop();
delete conn_p;
/* select first connection in list */
ui->tableConnections->selectRow(0);
}
void ConnectionWindow::handleResetConn()
{
QString port, driver;
CANCon::type type;
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
if (selIdx <0) return;
qDebug() << "remove connection at index: " << selIdx;
CANConnection* conn_p = connModel->getAtIdx(selIdx);
if(!conn_p) return;
type = conn_p->getType();
port = conn_p->getPort();
driver = conn_p->getDriver();
/* stop and delete connection */
conn_p->stop();
conn_p = nullptr;
conn_p = create(type, port, driver);
if (conn_p) connModel->replace(selIdx, conn_p);
}
/* status */
void ConnectionWindow::connectionStatus(CANConStatus pStatus)
{
@@ -277,8 +325,8 @@ void ConnectionWindow::populateBusDetails(int offset)
return;
}
int busBase = CANConManager::getInstance()->getBusBase(conn_p);
ui->lblBusNum->setText(QString::number(busBase + offset));
//int busBase = CANConManager::getInstance()->getBusBase(conn_p);
//ui->lblBusNum->setText(QString::number(busBase + offset));
ui->ckListenOnly->setChecked(bus.isListenOnly());
ui->ckEnable->setChecked(bus.isActive());
@@ -328,7 +376,9 @@ void ConnectionWindow::currentRowChanged(const QModelIndex &current, const QMode
int numB = ui->tabBuses->count();
for (int i = 0; i < numB; i++) ui->tabBuses->removeTab(0);
if (numBuses > 1) for (int i = 0; i < numBuses; i++) ui->tabBuses->addTab(QString::number(i+1));
int busBase = CANConManager::getInstance()->getBusBase(conn_p);
/*if (numBuses > 1)*/ for (int i = 0; i < numBuses; i++) ui->tabBuses->addTab(QString::number(busBase + i));
populateBusDetails(0);
if (ui->ckEnableConsole->isChecked())
@@ -363,27 +413,6 @@ void ConnectionWindow::handleSendText() {
emit sendDebugData(bytes);
}
void ConnectionWindow::handleRemoveConn()
{
int selIdx = ui->tableConnections->selectionModel()->currentIndex().row();
if (selIdx <0) return;
qDebug() << "remove connection at index: " << selIdx;
CANConnection* conn_p = connModel->getAtIdx(selIdx);
if(!conn_p) return;
/* remove connection from model & manager */
connModel->remove(conn_p);
/* stop and delete connection */
conn_p->stop();
delete conn_p;
/* select first connection in list */
ui->tableConnections->selectRow(0);
}
CANConnection* ConnectionWindow::create(CANCon::type pTye, QString pPortName, QString pDriver)
{
CANConnection* conn_p;
+1
View File
@@ -46,6 +46,7 @@ private slots:
void consoleEnableChanged(bool checked);
void handleRemoveConn();
void handleNewConn();
void handleResetConn();
void handleClearDebugText();
void handleSendHex();
void handleSendText();
+12 -1
View File
@@ -9,7 +9,18 @@ NewConnectionDialog::NewConnectionDialog(QVector<QString>* ips, QWidget *parent)
{
ui->setupUi(this);
ui->rbSocketCAN->setEnabled(isSerialBusAvailable());
if (isSerialBusAvailable())
{
ui->rbSocketCAN->setEnabled(true);
}
else
{
ui->rbSocketCAN->setEnabled(false);
QString errorString;
const QList<QCanBusDeviceInfo> devices = QCanBus::instance()->availableDevices(QStringLiteral("socketcan"), &errorString);
if (!errorString.isEmpty()) ui->rbSocketCAN->setToolTip(errorString);
}
connect(ui->rbGVRET, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
connect(ui->rbSocketCAN, &QAbstractButton::clicked, this, &NewConnectionDialog::handleConnTypeChanged);
+4 -4
View File
@@ -36,7 +36,7 @@ s 5 47 46 45 44 43 42 41 40
So, the bits are 12, 11, 10, 9, 8, 23, 22, 21. Yes, that's confusing. They now go in reverse value order too.
Bit 12 is worth 128, 11 is worth 64, etc until bit 21 is worth 1.
*/
bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString)
bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString, bool outputName)
{
int64_t result = 0;
bool isSigned = false;
@@ -95,16 +95,16 @@ bool DBC_SIGNAL::processAsText(const CANFrame &frame, QString &outString)
endResult = (*((double *)(&result)) * factor) + bias;
}
outString = makePrettyOutput(endResult, result);
outString = makePrettyOutput(endResult, result, outputName);
cachedValue = endResult;
return true;
}
QString DBC_SIGNAL::makePrettyOutput(double floatVal, int64_t intVal)
QString DBC_SIGNAL::makePrettyOutput(double floatVal, int64_t intVal, bool outputName)
{
QString outputString;
outputString = name + ": ";
if (outputName) outputString = name + ": ";
if (valList.count() > 0) //if this is a value list type then look it up and display the proper string
{
+2 -2
View File
@@ -101,10 +101,10 @@ public: //TODO: this is sloppy. It shouldn't all be public!
QList<DBC_ATTRIBUTE_VALUE> attributes;
QList<DBC_VAL_ENUM_ENTRY> valList;
bool processAsText(const CANFrame &frame, QString &outString);
bool processAsText(const CANFrame &frame, QString &outString, bool outputName = true);
bool processAsInt(const CANFrame &frame, int32_t &outValue);
bool processAsDouble(const CANFrame &frame, double &outValue);
QString makePrettyOutput(double floatVal, int64_t intVal);
QString makePrettyOutput(double floatVal, int64_t intVal, bool outputName = true);
DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name);
DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx);
};
+15 -4
View File
@@ -7,6 +7,7 @@
#include <QFileDialog>
#include <QApplication>
#include <QPalette>
#include <QSettings>
#include "utility.h"
#include "connections/canconmanager.h"
@@ -460,9 +461,13 @@ DBC_SIGNAL* DBCFile::parseSignalLine(QString line, DBC_MESSAGE *msg)
if (!sig.receiver) sig.receiver = findNodeByIdx(0); //apply default if there was no match
sig.parentMessage = msg;
msg->sigHandler->addSignal(sig);
if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name);
return msg->sigHandler->findSignalByName(sig.name);
if (msg)
{
msg->sigHandler->addSignal(sig);
if (isMultiplexor) msg->multiplexorSignal = msg->sigHandler->findSignalByName(sig.name);
return msg->sigHandler->findSignalByName(sig.name);
}
else return nullptr;
}
return nullptr;
@@ -1335,6 +1340,8 @@ void DBCFile::saveFile(QString fileName)
void DBCHandler::saveDBCFile(int idx)
{
QSettings settings;
if (loadedFiles.count() == 0) return;
if (idx < 0) return;
if (idx >= loadedFiles.count()) return;
@@ -1345,6 +1352,7 @@ void DBCHandler::saveDBCFile(int idx)
QStringList filters;
filters.append(QString(tr("DBC File (*.dbc)")));
dialog.setDirectory(settings.value("DBC/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -1356,6 +1364,7 @@ void DBCHandler::saveDBCFile(int idx)
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".dbc";
loadedFiles[idx].saveFile(filename);
settings.setValue("DBC/LoadSaveDirectory", dialog.directory().path());
}
}
@@ -1407,10 +1416,12 @@ DBCFile* DBCHandler::loadDBCFile(int idx)
QString filename;
QFileDialog dialog;
QSettings settings;
QStringList filters;
filters.append(QString(tr("DBC File (*.dbc)")));
dialog.setDirectory(settings.value("DBC/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -1422,7 +1433,7 @@ DBCFile* DBCHandler::loadDBCFile(int idx)
DBCFile newFile;
newFile.loadFile(filename);
loadedFiles.append(newFile);
settings.setValue("DBC/LoadSaveDirectory", dialog.directory().path());
return &loadedFiles.last();
}
+6
View File
@@ -15,6 +15,8 @@ DBCLoadSaveWindow::DBCLoadSaveWindow(const QVector<CANFrame> *frames, QWidget *p
ui->setupUi(this);
inhibitCellProcessing = false;
QStringList header;
header << "Filename" << "Associated Bus" << "J1939";
ui->tableFiles->setColumnCount(3);
@@ -159,6 +161,7 @@ void DBCLoadSaveWindow::editFile()
void DBCLoadSaveWindow::cellChanged(int row, int col)
{
if (inhibitCellProcessing) return;
if (col == 1) //the bus column
{
DBCFile *file = dbcHandler->getFileByIdx(row);
@@ -214,6 +217,7 @@ void DBCLoadSaveWindow::swapTableRows(bool up)
const int destIdx = (up ? idx-1 : idx+1);
Q_ASSERT(destIdx >= 0 && destIdx < ui->tableFiles->rowCount());
inhibitCellProcessing = true;
// take whole rows
QList<QTableWidgetItem*> sourceItems = takeRow(idx);
QList<QTableWidgetItem*> destItems = takeRow(destIdx);
@@ -221,6 +225,8 @@ void DBCLoadSaveWindow::swapTableRows(bool up)
// set back in reverse order
setRow(idx, destItems);
setRow(destIdx, sourceItems);
inhibitCellProcessing = false;
}
QList<QTableWidgetItem*> DBCLoadSaveWindow::takeRow(int row)
+1
View File
@@ -35,6 +35,7 @@ private:
DBCFile *currentlyEditingFile;
const QVector<CANFrame> *referenceFrames;
DBCMainEditor *editorWindow;
bool inhibitCellProcessing;
void swapTableRows(bool up);
QList<QTableWidgetItem*> takeRow(int row);
Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

+22
View File
@@ -0,0 +1,22 @@
Temporal Window
=================
.
.. image:: ./images/TemporalWindow.png
Using the Temporal Window
=========================
This window gives a dual graphical representation of CAN IDs over time. For each frame in the capture a circle is placed
on the graph at a point given by the time when the frame came in on the X axis and the frame ID on the Y axis. That is, a frame with ID 0x300
that comes in at 23.543 seconds would be plotted at the point 23.543, 0x300. The graph background is color coded for "density." That brings up
the question "What do you mean by density?" The answer is somewhat nebulous but essentially the color coded density maps where there is a lot of
traffic within a small space on the graph. This could be because many frames with the same ID came in rapid fire or it could be because many
frames with similar IDs came in very close to each other - or both.
The general point of this window is to show how active the bus is at any given point in time and which IDs are most active (they'll create
bright streaks in the background color). There isn't a lot that can be done to modify the functionality of this window. All that can be done is
zooming and panning the view. If you get the view too messed up the R key will reset the view back to standard. As with the Graphing Window, it is
possible to select just the X or Y axis and zoom/pan that axis without affecting the other one. To do so, click on the axis marks of the axis you'd like
to independently control. To control both again click in the graph itself.
+10
View File
@@ -4,6 +4,7 @@
#include <QProgressDialog>
#include <QDateTime>
#include <QtEndian>
#include <QSettings>
#include <iostream>
#include "utility.h"
@@ -19,6 +20,7 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* fram
{
QString filename;
QFileDialog dialog(qApp->activeWindow());
QSettings settings;
bool result = false;
QStringList filters;
@@ -35,6 +37,7 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* fram
filters.append(QString(tr("Cabana Log(*.csv *.CSV)")));
filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -125,6 +128,7 @@ bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* fram
{
QStringList fileList = filename.split('/');
fileName = fileList[fileList.length() - 1];
settings.setValue("FileIO/LoadSaveDirectory", dialog.directory().path());
return true;
}
return false;
@@ -136,6 +140,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
{
QString filename;
QFileDialog dialog;
QSettings settings;
bool result = false;
QStringList filters;
@@ -159,6 +164,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
filters.append(QString(tr("Cabana Log (*.csv *.CSV)")));
filters.append(QString(tr("CANOpen Magic (*.csv *.CSV)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -203,6 +209,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
{
QStringList fileList = filename.split('/');
fileName = fileList[fileList.length() - 1];
settings.setValue("FileIO/LoadSaveDirectory", dialog.directory().path());
return true;
}
else
@@ -1575,10 +1582,12 @@ bool FrameFileIO::openContinuousNative()
{
QString filename;
QFileDialog dialog(qApp->activeWindow());
QSettings settings;
QStringList filters;
filters.append(QString(tr("GVRET Logs (*.csv *.CSV)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -1595,6 +1604,7 @@ bool FrameFileIO::openContinuousNative()
}
continuousFile.write("Time Stamp,ID,Extended,Dir,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8");
continuousFile.write("\n");
settings.setValue("FileIO/LoadSaveDirectory", dialog.directory().path());
return true;
}
return false;
+6
View File
@@ -173,10 +173,12 @@ void FramePlaybackWindow::saveFilters()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Filter list (*.ftl)")));
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -203,6 +205,7 @@ void FramePlaybackWindow::saveFilters()
}
outFile->close();
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
}
}
@@ -212,10 +215,12 @@ void FramePlaybackWindow::loadFilters()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Filter List (*.ftl)")));
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -264,6 +269,7 @@ void FramePlaybackWindow::loadFilters()
}
}
inFile->close();
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
}
}
+6 -1
View File
@@ -241,10 +241,12 @@ void FrameSenderWindow::saveGrid()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Frame Sender Definition (*.fsd)")));
dialog.setDirectory(settings.value("FrameSender/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -258,6 +260,7 @@ void FrameSenderWindow::saveGrid()
{
if (!filename.contains('.')) filename += ".fsd";
saveSenderFile(filename);
settings.setValue("FrameSender/LoadSaveDirectory", dialog.directory().path());
}
}
}
@@ -266,10 +269,12 @@ void FrameSenderWindow::loadGrid()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Frame Sender Definition (*.fsd)")));
dialog.setDirectory(settings.value("FrameSender/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -281,6 +286,7 @@ void FrameSenderWindow::loadGrid()
if (dialog.selectedNameFilter() == filters[0])
{
loadSenderFile(filename);
settings.setValue("FrameSender/LoadSaveDirectory", dialog.directory().path());
}
}
@@ -325,7 +331,6 @@ void FrameSenderWindow::saveSenderFile(QString filename)
outFile->close();
delete outFile;
}
void FrameSenderWindow::loadSenderFile(QString filename)
+6
View File
@@ -5,6 +5,12 @@ int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//These things are used by QSettings to set up setting storage
a.setOrganizationName("EVTV");
a.setApplicationName("SavvyCAN");
a.setOrganizationDomain("evtv.me");
QSettings::setDefaultFormat(QSettings::IniFormat);
MainWindow w;
QSettings settings;
+44 -45
View File
@@ -6,6 +6,7 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::MainSettingsDialog)
{
QSettings settings;
ui->setupUi(this);
ui->comboSendingBus->addItem(tr("None"));
@@ -14,29 +15,27 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
ui->comboSendingBus->addItem(tr("Both"));
ui->comboSendingBus->addItem(tr("From File"));
settings = new QSettings();
//update the GUI with all the settings we have stored giving things
//defaults if nothing was stored (if this is the first time)
ui->cbDisplayHex->setChecked(settings->value("Main/UseHex", true).toBool());
ui->cbFlowAutoRef->setChecked(settings->value("FlowView/AutoRef", false).toBool());
ui->cbFlowUseTimestamp->setChecked(settings->value("FlowView/UseTimestamp", true).toBool());
ui->cbInfoAutoExpand->setChecked(settings->value("InfoCompare/AutoExpand", false).toBool());
ui->cbMainAutoScroll->setChecked(settings->value("Main/AutoScroll", false).toBool());
ui->cbPlaybackLoop->setChecked(settings->value("Playback/AutoLoop", false).toBool());
ui->cbRestorePositions->setChecked(settings->value("Main/SaveRestorePositions", true).toBool());
ui->cbValidate->setChecked(settings->value("Main/ValidateComm", true).toBool());
ui->spinPlaybackSpeed->setValue(settings->value("Playback/DefSpeed", 5).toInt());
ui->lineClockFormat->setText(settings->value("Main/TimeFormat", "MMM-dd HH:mm:ss.zzz").toString());
ui->lineRemoteHost->setText(settings->value("Remote/Host", "api.savvycan.com").toString());
ui->lineRemotePort->setText(settings->value("Remote/Port", "21315").toString()); // = 0x5343 = SC. Yep, really creative port number
ui->cbAutoStartRemote->setChecked(settings->value("Remote/AutoStart", false).toBool());
ui->cbLoadConnections->setChecked(settings->value("Main/SaveRestoreConnections", false).toBool());
ui->cbDisplayHex->setChecked(settings.value("Main/UseHex", true).toBool());
ui->cbFlowAutoRef->setChecked(settings.value("FlowView/AutoRef", false).toBool());
ui->cbFlowUseTimestamp->setChecked(settings.value("FlowView/UseTimestamp", true).toBool());
ui->cbInfoAutoExpand->setChecked(settings.value("InfoCompare/AutoExpand", false).toBool());
ui->cbMainAutoScroll->setChecked(settings.value("Main/AutoScroll", false).toBool());
ui->cbPlaybackLoop->setChecked(settings.value("Playback/AutoLoop", false).toBool());
ui->cbRestorePositions->setChecked(settings.value("Main/SaveRestorePositions", true).toBool());
ui->cbValidate->setChecked(settings.value("Main/ValidateComm", true).toBool());
ui->spinPlaybackSpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt());
ui->lineClockFormat->setText(settings.value("Main/TimeFormat", "MMM-dd HH:mm:ss.zzz").toString());
ui->lineRemoteHost->setText(settings.value("Remote/Host", "api.savvycan.com").toString());
ui->lineRemotePort->setText(settings.value("Remote/Port", "21315").toString()); // = 0x5343 = SC. Yep, really creative port number
ui->cbAutoStartRemote->setChecked(settings.value("Remote/AutoStart", false).toBool());
ui->cbLoadConnections->setChecked(settings.value("Main/SaveRestoreConnections", false).toBool());
ui->spinFontSize->setValue(settings->value("Main/FontSize", ui->cbDisplayHex->font().pointSize()).toUInt());
ui->spinFontSize->setValue(settings.value("Main/FontSize", ui->cbDisplayHex->font().pointSize()).toUInt());
bool secondsMode = settings->value("Main/TimeSeconds", false).toBool();
bool clockMode = settings->value("Main/TimeClock", false).toBool();
bool secondsMode = settings.value("Main/TimeSeconds", false).toBool();
bool clockMode = settings.value("Main/TimeClock", false).toBool();
if (clockMode)
{
ui->rbSeconds->setChecked(false);
@@ -59,9 +58,9 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
}
}
ui->comboSendingBus->setCurrentIndex(settings->value("Playback/SendingBus", 4).toInt());
ui->cbUseFiltered->setChecked(settings->value("Main/UseFiltered", false).toBool());
ui->cbUseOpenGL->setChecked(settings->value("Main/UseOpenGL", false).toBool());
ui->comboSendingBus->setCurrentIndex(settings.value("Playback/SendingBus", 4).toInt());
ui->cbUseFiltered->setChecked(settings.value("Main/UseFiltered", false).toBool());
ui->cbUseOpenGL->setChecked(settings.value("Main/UseOpenGL", false).toBool());
//just for simplicity they all call the same function and that function updates all settings at once
connect(ui->cbDisplayHex, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
@@ -90,7 +89,6 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
MainSettingsDialog::~MainSettingsDialog()
{
delete ui;
delete settings;
}
void MainSettingsDialog::closeEvent(QCloseEvent *event)
@@ -98,7 +96,6 @@ void MainSettingsDialog::closeEvent(QCloseEvent *event)
Q_UNUSED(event);
removeEventFilter(this);
updateSettings();
settings->sync();
}
bool MainSettingsDialog::eventFilter(QObject *obj, QEvent *event)
@@ -122,27 +119,29 @@ bool MainSettingsDialog::eventFilter(QObject *obj, QEvent *event)
void MainSettingsDialog::updateSettings()
{
settings->setValue("Main/UseHex", ui->cbDisplayHex->isChecked());
settings->setValue("FlowView/AutoRef", ui->cbFlowAutoRef->isChecked());
settings->setValue("FlowView/UseTimestamp", ui->cbFlowUseTimestamp->isChecked());
settings->setValue("InfoCompare/AutoExpand", ui->cbInfoAutoExpand->isChecked());
settings->setValue("Main/AutoScroll", ui->cbMainAutoScroll->isChecked());
settings->setValue("Playback/AutoLoop", ui->cbPlaybackLoop->isChecked());
settings->setValue("Main/SaveRestorePositions", ui->cbRestorePositions->isChecked());
settings->setValue("Main/SaveRestoreConnections", ui->cbLoadConnections->isChecked());
settings->setValue("Main/ValidateComm", ui->cbValidate->isChecked());
settings->setValue("Playback/DefSpeed", ui->spinPlaybackSpeed->value());
settings->setValue("Main/TimeSeconds", ui->rbSeconds->isChecked());
settings->setValue("Main/TimeClock", ui->rbSysClock->isChecked());
settings->setValue("Playback/SendingBus", ui->comboSendingBus->currentIndex());
settings->setValue("Main/UseFiltered", ui->cbUseFiltered->isChecked());
settings->setValue("Main/UseOpenGL", ui->cbUseOpenGL->isChecked());
settings->setValue("Main/TimeFormat", ui->lineClockFormat->text());
settings->setValue("Main/FontSize", ui->spinFontSize->value());
settings->setValue("Remote/Host", ui->lineRemoteHost->text());
settings->setValue("Remote/Port", ui->lineRemotePort->text());
settings->setValue("Remote/AutoStart", ui->cbAutoStartRemote->isChecked());
QSettings settings;
settings->sync();
settings.setValue("Main/UseHex", ui->cbDisplayHex->isChecked());
settings.setValue("FlowView/AutoRef", ui->cbFlowAutoRef->isChecked());
settings.setValue("FlowView/UseTimestamp", ui->cbFlowUseTimestamp->isChecked());
settings.setValue("InfoCompare/AutoExpand", ui->cbInfoAutoExpand->isChecked());
settings.setValue("Main/AutoScroll", ui->cbMainAutoScroll->isChecked());
settings.setValue("Playback/AutoLoop", ui->cbPlaybackLoop->isChecked());
settings.setValue("Main/SaveRestorePositions", ui->cbRestorePositions->isChecked());
settings.setValue("Main/SaveRestoreConnections", ui->cbLoadConnections->isChecked());
settings.setValue("Main/ValidateComm", ui->cbValidate->isChecked());
settings.setValue("Playback/DefSpeed", ui->spinPlaybackSpeed->value());
settings.setValue("Main/TimeSeconds", ui->rbSeconds->isChecked());
settings.setValue("Main/TimeClock", ui->rbSysClock->isChecked());
settings.setValue("Playback/SendingBus", ui->comboSendingBus->currentIndex());
settings.setValue("Main/UseFiltered", ui->cbUseFiltered->isChecked());
settings.setValue("Main/UseOpenGL", ui->cbUseOpenGL->isChecked());
settings.setValue("Main/TimeFormat", ui->lineClockFormat->text());
settings.setValue("Main/FontSize", ui->spinFontSize->value());
settings.setValue("Remote/Host", ui->lineRemoteHost->text());
settings.setValue("Remote/Port", ui->lineRemotePort->text());
settings.setValue("Remote/AutoStart", ui->cbAutoStartRemote->isChecked());
settings.sync();
emit updatedSettings();
}
-1
View File
@@ -24,7 +24,6 @@ public slots:
private:
Ui::MainSettingsDialog *ui;
QSettings *settings;
void closeEvent(QCloseEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
+34 -13
View File
@@ -34,11 +34,6 @@ MainWindow::MainWindow(QWidget *parent) :
useHex = true;
//These things are used by QSettings to set up setting storage
QCoreApplication::setOrganizationName("EVTV");
QCoreApplication::setOrganizationDomain("evtv.me");
QCoreApplication::setApplicationName("SavvyCAN");
selfRef = this;
this->setWindowTitle("Savvy CAN V" + QString::number(VERSION));
@@ -55,9 +50,9 @@ MainWindow::MainWindow(QWidget *parent) :
readSettings();
QHeaderView *verticalHeader = ui->canFramesView->verticalHeader();
verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
verticalHeader->setDefaultSectionSize(10);
//QHeaderView *verticalHeader = ui->canFramesView->verticalHeader();
//verticalHeader->setSectionResizeMode(QHeaderView::Fixed);
//verticalHeader->setDefaultSectionSize(10);
QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader();
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
connect(HorzHdr, SIGNAL(sectionClicked(int)), this, SLOT(headerClicked(int)));
@@ -83,6 +78,7 @@ MainWindow::MainWindow(QWidget *parent) :
snifferWindow = nullptr;
bisectWindow = nullptr;
signalViewerWindow = nullptr;
temporalGraphWindow = nullptr;
dbcHandler = DBCHandler::getReference();
bDirty = false;
inhibitFilterUpdate = false;
@@ -131,6 +127,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->actionCapture_Bisector, &QAction::triggered, this, &MainWindow::showBisectWindow);
connect(ui->actionSignal_Viewer, &QAction::triggered, this, &MainWindow::showSignalViewer);
connect(ui->actionSave_Continuous_Logfile, &QAction::triggered, this, &MainWindow::handleContinousLogging);
connect(ui->actionTemporal_Graph, &QAction::triggered, this, &MainWindow::showTemporalGraphWindow);
connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames);
@@ -186,7 +183,6 @@ MainWindow::MainWindow(QWidget *parent) :
//so if you want to enable them and play with them then go for it.
ui->actionFirmware_Update->setVisible(false);
ui->actionMotorControlConfig->setVisible(false);
ui->actionSignal_Viewer->setVisible(false);
ui->actionSingle_Multi_State_2->setVisible(false);
installEventFilter(this);
@@ -227,6 +223,7 @@ void MainWindow::killEmAll()
killWindow(motorctrlConfigWindow);
killWindow(signalViewerWindow);
killWindow(connectionWindow);
killWindow(temporalGraphWindow);
}
//forcefully close the window, kill it, and salt the earth
@@ -368,7 +365,8 @@ void MainWindow::updateConnectionSettings(QString connectionType, QString port,
void MainWindow::headerClicked(int logicalIndex)
{
ui->canFramesView->sortByColumn(logicalIndex);
//ui->canFramesView->sortByColumn(logicalIndex);
model->sortByColumn(logicalIndex);
}
void MainWindow::gridClicked(QModelIndex idx)
@@ -647,10 +645,12 @@ void MainWindow::handleSaveFilters()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Filter list (*.ftl)")));
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -661,6 +661,7 @@ void MainWindow::handleSaveFilters()
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".ftl";
if (dialog.selectedNameFilter() == filters[0]) model->saveFilterFile(filename);
settings.setValue("Filters/LoadSaveDirectory", dialog.directory().path());
}
}
@@ -668,10 +669,12 @@ void MainWindow::handleLoadFilters()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Filter List (*.ftl)")));
dialog.setDirectory(settings.value("Filters/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -681,19 +684,20 @@ void MainWindow::handleLoadFilters()
filename = dialog.selectedFiles()[0];
//right now there is only one file type that can be loaded here so just do it.
model->loadFilterFile(filename);
settings.setValue("Filters/LoadSaveDirectory", dialog.directory().path());
}
}
//lbStatusDatabase.setText(fileList[fileList.length() - 1] + tr(" loaded."));
void MainWindow::handleSaveDecoded()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -704,6 +708,7 @@ void MainWindow::handleSaveDecoded()
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".txt";
saveDecodedTextFile(filename);
settings.setValue("FileIO/LoadSaveDirectory", dialog.directory().path());
}
}
@@ -837,6 +842,19 @@ void MainWindow::showGraphingWindow()
graphingWindow->show();
}
void MainWindow::showTemporalGraphWindow()
{
//only create an instance of the object if we dont have one. Otherwise just display the existing one.
if (!temporalGraphWindow)
{
if (!useFiltered)
temporalGraphWindow = new TemporalGraphWindow(model->getListReference());
else
temporalGraphWindow = new TemporalGraphWindow(model->getFilteredListReference());
}
temporalGraphWindow->show();
}
void MainWindow::showFrameDataAnalysis()
{
//only create an instance of the object if we dont have one. Otherwise just display the existing one.
@@ -1015,7 +1033,10 @@ void MainWindow::showSignalViewer()
{
if (!signalViewerWindow)
{
signalViewerWindow = new SignalViewerWindow();
if (!useFiltered)
signalViewerWindow = new SignalViewerWindow(model->getListReference());
else
signalViewerWindow = new SignalViewerWindow(model->getFilteredListReference());
}
signalViewerWindow->show();
}
+3
View File
@@ -31,6 +31,7 @@
#include "re/isotp_interpreterwindow.h"
#include "motorcontrollerconfigwindow.h"
#include "signalviewerwindow.h"
#include "re/temporalgraphwindow.h"
class CANConnection;
class ConnectionWindow;
@@ -81,6 +82,7 @@ private slots:
void showSnifferWindow();
void showBisectWindow();
void showSignalViewer();
void showTemporalGraphWindow();
void exitApp();
void handleSaveDecoded();
void connectionStatusUpdated(int conns);
@@ -159,6 +161,7 @@ private:
MotorControllerConfigWindow *motorctrlConfigWindow;
BisectWindow* bisectWindow;
SignalViewerWindow *signalViewerWindow;
TemporalGraphWindow *temporalGraphWindow;
//various private storage
QLabel lbStatusConnected;
+3
View File
@@ -367,6 +367,7 @@ void FileComparatorWindow::saveDetails()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
@@ -375,10 +376,12 @@ void FileComparatorWindow::saveDetails()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FileComparator/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("FileComparator/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".txt";
QFile *outFile = new QFile(filename);
+6
View File
@@ -297,6 +297,7 @@ void FlowViewWindow::saveFileGraph()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("PDF Files (*.pdf)")));
@@ -307,6 +308,7 @@ void FlowViewWindow::saveFileGraph()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FlowView/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
@@ -327,6 +329,7 @@ void FlowViewWindow::saveFileGraph()
if (!filename.contains('.')) filename += ".jpg";
ui->graphView->saveJpg(filename, 1024, 768);
}
settings.setValue("FlowView/LoadSaveDirectory", dialog.directory().path());
}
}
@@ -334,6 +337,7 @@ void FlowViewWindow::saveFileFlow()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("PNG Files (*.png)")));
@@ -343,6 +347,7 @@ void FlowViewWindow::saveFileFlow()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FlowView/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
@@ -358,6 +363,7 @@ void FlowViewWindow::saveFileFlow()
if (!filename.contains('.')) filename += ".jpg";
ui->flowView->saveImage(filename, 1024, 768);
}
settings.setValue("FlowView/LoadSaveDirectory", dialog.directory().path());
}
}
+3
View File
@@ -477,6 +477,7 @@ void FrameInfoWindow::saveDetails()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
@@ -485,9 +486,11 @@ void FrameInfoWindow::saveDetails()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FrameInfo/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
settings.setValue("FrameInfo/LoadSaveDirectory", dialog.directory().path());
filename = dialog.selectedFiles()[0];
if (!filename.contains('.')) filename += ".txt";
if (dialog.selectedNameFilter() == filters[0])
+21 -2
View File
@@ -81,7 +81,7 @@ GraphingWindow::GraphingWindow(const QVector<CANFrame> *frames, QWidget *parent)
selectedPen.setWidth(1);
selectedPen.setColor(Qt::blue);
ui->graphingView->setAttribute(Qt::WA_AcceptTouchEvents);
//ui->graphingView->setAttribute(Qt::WA_AcceptTouchEvents);
if (useOpenGL)
{
@@ -245,11 +245,15 @@ void GraphingWindow::plottableDoubleClick(QCPAbstractPlottable* plottable, int d
double x, y;
QCPGraph *graph = reinterpret_cast<QCPGraph *>(plottable);
graph->pixelsToCoords(event->localPos(), x, y);
locationText->setText("X: " + QString::number(x) + " Y: " + QString::number(y));
x = ui->graphingView->xAxis->pixelToCoord(event->localPos().x());
itemTracer->setGraph(graph);
itemTracer->setVisible(true);
itemTracer->setInterpolating(true);
itemTracer->setGraphKey(x);
itemTracer->updatePosition();
qDebug() << "val " << itemTracer->position->value();
locationText->setText("X: " + QString::number(x) + " Y: " + QString::number(itemTracer->position->value()));
}
void GraphingWindow::gotCenterTimeID(int32_t ID, double timestamp)
@@ -629,6 +633,7 @@ void GraphingWindow::saveGraphs()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("PDF Files (*.pdf)")));
@@ -639,10 +644,12 @@ void GraphingWindow::saveGraphs()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("Graphing/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (dialog.selectedNameFilter() == filters[0])
{
@@ -666,6 +673,7 @@ void GraphingWindow::saveSpreadsheet()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Spreadsheet (*.csv)")));
@@ -674,10 +682,13 @@ void GraphingWindow::saveSpreadsheet()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("Graphing/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".csv";
QFile *outFile = new QFile(filename);
@@ -785,6 +796,7 @@ void GraphingWindow::saveDefinitions()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Graph definition (*.gdf)")));
@@ -793,10 +805,13 @@ void GraphingWindow::saveDefinitions()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("Graphing/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".gdf";
QFile *outFile = new QFile(filename);
@@ -843,6 +858,7 @@ void GraphingWindow::loadDefinitions()
{
QString filename;
QFileDialog dialog;
QSettings settings;
QStringList filters;
filters.append(QString(tr("Graph definition (*.gdf)")));
@@ -853,10 +869,13 @@ void GraphingWindow::loadDefinitions()
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setDirectory(settings.value("Graphing/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("Graphing/LoadSaveDirectory", dialog.directory().path());
QFile *inFile = new QFile(filename);
QByteArray line;
+21 -11
View File
@@ -93,8 +93,8 @@ void NewGraphDialog::checkSignalAgreement()
GraphParams testingParams;
bool bAgree = true;
bool sigSigned = false;
DBC_SIGNAL *sig;
DBC_MESSAGE *msg;
DBC_SIGNAL *sig = nullptr;
DBC_MESSAGE *msg = nullptr;
if (dbcHandler == nullptr) return;
if (dbcHandler->getFileCount() == 0) return;
@@ -104,6 +104,11 @@ void NewGraphDialog::checkSignalAgreement()
{
sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
}
else
{
ui->lblMsgStatus->setText("Msg ID doesn't exist in DBC");
return;
}
if (sig)
{
@@ -118,13 +123,19 @@ void NewGraphDialog::checkSignalAgreement()
testingParams.numBits = dataLen;
if (testingParams.ID != msg->ID) bAgree = false;
if (abs(testingParams.bias - sig->bias) > 0.01) bAgree = false;
if (fabs(testingParams.bias - sig->bias) > 0.01) bAgree = false;
if (testingParams.isSigned != sigSigned) bAgree = false;
if (testingParams.intelFormat != sig->intelByteOrder) bAgree = false;
if (abs(testingParams.scale - sig->factor) > 0.01) bAgree = false;
if (fabs(testingParams.scale - sig->factor) > 0.01) bAgree = false;
if (testingParams.startBit != sig->startBit) bAgree = false;
if (testingParams.numBits != sig->signalSize) bAgree = false;
}
else
{
ui->lblMsgStatus->setText("Signal name doesn't exist in DBC");
return;
}
if (bAgree)
{
ui->lblMsgStatus->setText("Graph params match this signal");
@@ -214,21 +225,19 @@ void NewGraphDialog::loadMessages()
if (assocSignal && msg->name == assocSignal->parentMessage->name)
{
ui->cbMessages->setCurrentIndex(ui->cbMessages->count() -1);
qDebug() << "Found my parent";
//qDebug() << "Found my parent";
}
}
}
}
ui->cbMessages->model()->sort(0);
}
void NewGraphDialog::loadSignals(int idx)
{
Q_UNUSED(idx);
//messages were placed into the list in the same order as they exist
//in the data structure so it should have been possible to just
//look it up based on index but by name is probably safer and this operation
//is not time critical at all.
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
//search through all DBC files in order to try to find a message with the given name
DBC_MESSAGE *msg = dbcHandler->findMessage(ui->cbMessages->currentText());
DBC_SIGNAL *sig;
if (msg == NULL) return;
@@ -243,10 +252,11 @@ void NewGraphDialog::loadSignals(int idx)
if (assocSignal && sig->name == assocSignal->name)
{
ui->cbSignals->setCurrentIndex(ui->cbSignals->count() - 1);
qDebug() << "Found me";
//qDebug() << "Found me";
}
}
}
ui->cbSignals->model()->sort(0);
checkSignalAgreement();
}
+407
View File
@@ -0,0 +1,407 @@
#include "temporalgraphwindow.h"
#include "ui_temporalgraphwindow.h"
#include "helpwindow.h"
#include "mainwindow.h"
QString HexTicker::getTickLabel (double tick, const QLocale& locale, QChar formatChar, int precision)
{
int valu = static_cast<int>(tick);
//qDebug() << valu;
return "0x" + QString::number(valu, 16).toUpper().rightJustified(3,'0');
}
TemporalGraphWindow::TemporalGraphWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::TemporalGraphWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Window);
readSettings();
modelFrames = frames;
ui->graphingView->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes);
ui->graphingView->xAxis->setRange(0, 8);
ui->graphingView->yAxis->setRange(0, 255);
ui->graphingView->axisRect()->setupFullAxesBox();
ui->graphingView->xAxis->setLabel("Elapsed Time");
ui->graphingView->yAxis->setLabel("ID");
ui->graphingView->xAxis->setNumberFormat("f");
ui->graphingView->xAxis->setNumberPrecision(6);
HexTicker *tick = new HexTicker;
QSharedPointer<QCPAxisTicker> sharedTicker(tick);
tick->setTickCount(10);
ui->graphingView->yAxis->setTicker(sharedTicker);
// connect slot that ties some axis selections together (especially opposite axes):
connect(ui->graphingView, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
connect(ui->graphingView, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress()));
connect(ui->graphingView, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel()));
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
// make bottom and left axes transfer their ranges to top and right axes:
connect(ui->graphingView->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->graphingView->xAxis2, SLOT(setRange(QCPRange)));
connect(ui->graphingView->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->graphingView->yAxis2, SLOT(setRange(QCPRange)));
if (useOpenGL)
{
ui->graphingView->setAntialiasedElements(QCP::aeAll);
//ui->graphingView->setNoAntialiasingOnDrag(true);
ui->graphingView->setOpenGl(true);
}
else
{
ui->graphingView->setOpenGl(false);
ui->graphingView->setAntialiasedElements(QCP::aeNone);
}
}
TemporalGraphWindow::~TemporalGraphWindow()
{
delete ui;
}
void TemporalGraphWindow::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
installEventFilter(this);
readSettings();
generateGraph();
ui->graphingView->replot();
}
void TemporalGraphWindow::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
removeEventFilter(this);
writeSettings();
}
void TemporalGraphWindow::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("Temporal/WindowSize", QSize(800, 600)).toSize());
move(settings.value("Temporal/WindowPos", QPoint(50, 50)).toPoint());
}
useOpenGL = settings.value("Main/UseOpenGL", false).toBool();
}
void TemporalGraphWindow::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("Temporal/WindowSize", size());
settings.setValue("Temporal/WindowPos", pos());
}
}
void TemporalGraphWindow::updatedFrames(int numFrames)
{
CANFrame thisFrame;
QVector<double> x, y;
bool appendedToGraph = false;
bool needReplot = false;
if (numFrames == -1) //all frames deleted. Kill the display
{
//removeAllGraphs();
//now instead of removing the graphs regenerate them which will blank them out but leave them there in case
//more traffic that matches comes in or someone otherwise loads more data
ui->graphingView->clearGraphs(); //temporarily remove the graphs from the graph view
ui->graphingView->clearPlottables();
ui->graphingView->replot(); //now, redisplay them all
}
else if (numFrames == -2) //all new set of frames. Reset
{
//there shouldn't be any need to actually remove the graphs.
//regenerate them instead
ui->graphingView->clearGraphs(); //temporarily remove the graphs from the graph view
//needScaleSetup = true;
generateGraph();
//ui->graphingView->replot(); //now, redisplay them all
}
else //just got some new frames. See if they are relevant.
{
if (numFrames > modelFrames->count()) return;
appendedToGraph = false;
x.clear();
y.clear();
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
/*
if (graphParams[j].ID == thisFrame.ID)
{
appendToGraph(graphParams[j], thisFrame, x, y);
appendedToGraph = true;
}*/
}
if (appendedToGraph)
{
//graphParams[j].ref->addData(x, y);
needReplot = true;
}
if (needReplot)
{
if (followGraphEnd)
{
//find the current X span and maintain that span but move the end of it over to match the new end
//of the actual graph. This causes the view to move with the data to always show the end
QCPRange range = ui->graphingView->xAxis->range();
double size = range.size();
bool foundRange;
QCPRange keyRange = ui->graphingView->graph()->getKeyRange(foundRange);
if (foundRange)
{
double end, start;
end = keyRange.upper;
start = end - size;
ui->graphingView->xAxis->setRange(start, end);
}
}
ui->graphingView->replot();
}
}
}
void TemporalGraphWindow::generateGraph()
{
if (modelFrames->count() == 0) return;
ui->graphingView->clearGraphs();
ui->graphingView->clearPlottables();
qDebug() << "Regenerating the graph";
ui->graphingView->addGraph();
graph = ui->graphingView->graph();
QVector<double> x, y;
int frameCount = modelFrames->count();
x.reserve(frameCount);
y.reserve(frameCount);
xminval = xmaxval = modelFrames->at(0).timestamp / 1000000.0;
yminval = ymaxval = modelFrames->at(0).ID;
for (int i = 0; i < frameCount; i++)
{
x.append(modelFrames->at(i).timestamp / 1000000.0);
y.append(modelFrames->at(i).ID);
if (x[i] > xmaxval) xmaxval = x[i];
if (x[i] < xminval) xminval = x[i];
if (y[i] > ymaxval) ymaxval = y[i];
if (y[i] < yminval) yminval = y[i];
}
ui->graphingView->graph()->setData(x,y);
ui->graphingView->graph()->setLineStyle(QCPGraph::lsNone); //no lines
ui->graphingView->graph()->setScatterStyle(QCPScatterStyle::ssCircle);
QPen graphPen;
graphPen.setColor(Qt::blue);
graphPen.setWidth(2);
ui->graphingView->graph()->setPen(graphPen);
qDebug() << "xmin: " << xminval;
qDebug() << "xmax: " << xmaxval;
qDebug() << "ymin: " << yminval;
qDebug() << "ymax: " << ymaxval;
ui->graphingView->xAxis->setRange(xminval, xmaxval);
ui->graphingView->yAxis->setRange(yminval, ymaxval);
ui->graphingView->axisRect()->setupFullAxesBox();
ui->graphingView->replot();
QCPColorMap *colorMap = new QCPColorMap(ui->graphingView->xAxis, ui->graphingView->yAxis);
int ySize = static_cast<int>(ymaxval - yminval) / 30 + 1;
int xSize = static_cast<int>((xmaxval - xminval) * 4.0) + 1;
colorMap->data()->setSize(xSize, ySize);
colorMap->data()->setRange(QCPRange(xminval, xmaxval), QCPRange(yminval, ymaxval));
for (int x = 0; x < xSize; ++x)
{
for (int y = 0; y < ySize; ++y)
{
colorMap->data()->setAlpha(x, y, 180);
colorMap->data()->setCell(x, y, 0.0);
}
}
for (int i = 0; i < frameCount; i++)
{
int x = static_cast<int>(((modelFrames->at(i).timestamp / 1000000.0) - xminval) * 4.0);
int y = static_cast<int>(modelFrames->at(i).ID - yminval) / 30;
double val = colorMap->data()->cell(x, y);
double inc;
inc = 1 / (val + 1); //logarithmic decay
inc = inc * inc; //square the increment to make it even more stark
val = val + inc;
qDebug() << "X: " << x << " Y: " << y << "Val: " << val;
colorMap->data()->setCell(x, y, val);
}
colorMap->setGradient(QCPColorGradient::gpJet);
colorMap->rescaleDataRange(true);
ui->graphingView->rescaleAxes();
ui->graphingView->replot();
}
void TemporalGraphWindow::selectionChanged()
{
/*
normally, axis base line, axis tick labels and axis labels are selectable separately, but we want
the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels
and the axis base line together. However, the axis label shall be selectable individually.
The selection state of the left and right axes shall be synchronized as well as the state of the
bottom and top axes.
Further, we want to synchronize the selection of the graphs with the selection state of the respective
legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself
or on its legend item.
*/
qDebug() << "SelectionChanged";
// make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
ui->graphingView->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
{
ui->graphingView->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
ui->graphingView->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
}
// make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
ui->graphingView->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
{
ui->graphingView->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
ui->graphingView->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
}
}
void TemporalGraphWindow::mousePress()
{
// if an axis is selected, only allow the direction of that axis to be dragged
// if no axis is selected, both directions may be dragged
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->axisRect()->setRangeDrag(ui->graphingView->xAxis->orientation());
}
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->axisRect()->setRangeDrag(ui->graphingView->yAxis->orientation());
}
else
{
ui->graphingView->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
}
}
void TemporalGraphWindow::mouseWheel()
{
qDebug() << "Mouse WHeel";
// if an axis is selected, only allow the direction of that axis to be zoomed
// if no axis is selected, both directions may be zoomed
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
ui->graphingView->axisRect()->setRangeZoom(ui->graphingView->xAxis->orientation());
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
ui->graphingView->axisRect()->setRangeZoom(ui->graphingView->yAxis->orientation());
else
ui->graphingView->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
}
bool TemporalGraphWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyRelease) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch (keyEvent->key())
{
case Qt::Key_Plus:
zoomIn();
break;
case Qt::Key_Minus:
zoomOut();
break;
case Qt::Key_R:
resetView();
break;
case Qt::Key_F1:
HelpWindow::getRef()->showHelp("temporalwindow.html");
break;
}
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
return false;
}
void TemporalGraphWindow::resetView()
{
ui->graphingView->xAxis->setRange(xminval, xmaxval);
ui->graphingView->yAxis->setRange(yminval, ymaxval);
ui->graphingView->axisRect()->setupFullAxesBox();
ui->graphingView->replot();
}
void TemporalGraphWindow::zoomIn()
{
QCPRange xrange = ui->graphingView->xAxis->range();
QCPRange yrange = ui->graphingView->yAxis->range();
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->xAxis->scaleRange(0.666, xrange.center());
}
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->yAxis->scaleRange(0.666, yrange.center());
}
else
{
ui->graphingView->xAxis->scaleRange(0.666, xrange.center());
ui->graphingView->yAxis->scaleRange(0.666, yrange.center());
}
ui->graphingView->replot();
}
void TemporalGraphWindow::zoomOut()
{
QCPRange xrange = ui->graphingView->xAxis->range();
QCPRange yrange = ui->graphingView->yAxis->range();
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->xAxis->scaleRange(1.5, xrange.center());
}
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
{
ui->graphingView->yAxis->scaleRange(1.5, yrange.center());
}
else
{
ui->graphingView->xAxis->scaleRange(1.5, xrange.center());
ui->graphingView->yAxis->scaleRange(1.5, yrange.center());
}
ui->graphingView->replot();
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef TEMPORALGRAPHWINDOW_H
#define TEMPORALGRAPHWINDOW_H
#include <QDialog>
#include "qcustomplot.h"
#include "can_structs.h"
namespace Ui {
class TemporalGraphWindow;
}
class HexTicker : public QCPAxisTicker
{
QString getTickLabel (double tick, const QLocale& locale, QChar formatChar, int precision);
};
class TemporalGraphWindow : public QDialog
{
Q_OBJECT
public:
explicit TemporalGraphWindow(const QVector<CANFrame> *, QWidget *parent = nullptr);
~TemporalGraphWindow();
void showEvent(QShowEvent*);
private slots:
void updatedFrames(int);
void mousePress();
void mouseWheel();
void resetView();
void zoomIn();
void zoomOut();
void selectionChanged();
private:
Ui::TemporalGraphWindow *ui;
const QVector<CANFrame> *modelFrames;
bool useOpenGL;
bool followGraphEnd;
QCPGraph *graph;
double xminval, xmaxval, yminval, ymaxval;
void closeEvent(QCloseEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
void readSettings();
void writeSettings();
void generateGraph();
};
#endif // TEMPORALGRAPHWINDOW_H
+4
View File
@@ -145,6 +145,7 @@ void UDSScanWindow::saveResults()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
@@ -153,10 +154,13 @@ void UDSScanWindow::saveResults()
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("UDSScan/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("UDSScan/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".txt";
if (dialog.selectedNameFilter() == filters[0])
{
+6
View File
@@ -180,11 +180,13 @@ void ScriptingWindow::loadNewScript()
{
QString filename;
QFileDialog dialog;
QSettings settings;
ScriptContainer *container;
QStringList filters;
filters.append(QString(tr("Javascript File (*.js)")));
dialog.setDirectory(settings.value("ScriptingWindow/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -215,6 +217,7 @@ void ScriptingWindow::loadNewScript()
ui->listLoadedScripts->setCurrentRow(ui->listLoadedScripts->count() - 1);
changeCurrentScript();
settings.setValue("ScriptingWindow/LoadSaveDirectory", dialog.directory().path());
}
}
}
@@ -287,10 +290,12 @@ void ScriptingWindow::saveScript()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Javascript File (*.js)")));
dialog.setDirectory(settings.value("ScriptingWindow/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
@@ -312,6 +317,7 @@ void ScriptingWindow::saveScript()
outFile->write(editor->toPlainText().toUtf8());
outFile->close();
delete outFile;
settings.setValue("ScriptingWindow/LoadSaveDirectory", dialog.directory().path());
}
}
}
+79 -8
View File
@@ -1,14 +1,18 @@
#include "signalviewerwindow.h"
#include "ui_signalviewerwindow.h"
#include "helpwindow.h"
#include "mainwindow.h"
#include <QDebug>
SignalViewerWindow::SignalViewerWindow(QWidget *parent) :
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 << "Signal" << "Value";
ui->tableViewer->setHorizontalHeaderLabels(headers);
@@ -21,6 +25,8 @@ SignalViewerWindow::SignalViewerWindow(QWidget *parent) :
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()));
loadMessages();
}
@@ -30,14 +36,79 @@ 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.ID)
{
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, 1);
if (!item)
{
item = new QTableWidgetItem(sigString);
ui->tableViewer->setItem(i, 1, 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::loadMessages()
{
int numFiles;
ui->cbMessages->clear();
if (dbcHandler == NULL) return;
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
for (int x = 0; x < dbcHandler->getFileByIdx(0)->messageHandler->getCount(); x++)
if (dbcHandler == nullptr) return;
if ((numFiles = dbcHandler->getFileCount()) == 0) return;
qDebug() << numFiles;
for (int f = 0; f < numFiles; f++)
{
ui->cbMessages->addItem(dbcHandler->getFileByIdx(0)->messageHandler->findMsgByIdx(x)->name);
qDebug() << dbcHandler->getFileByIdx(f)->messageHandler->getCount();
for (int x = 0; x < dbcHandler->getFileByIdx(f)->messageHandler->getCount(); x++)
{
ui->cbMessages->addItem(dbcHandler->getFileByIdx(f)->messageHandler->findMsgByIdx(x)->name);
}
}
}
@@ -48,9 +119,9 @@ void SignalViewerWindow::loadSignals(int idx)
//in the data structure so it should have been possible to just
//look it up based on index but by name is probably safer and this operation
//is not time critical at all.
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
DBC_MESSAGE *msg = dbcHandler->findMessage(ui->cbMessages->currentText());
if (msg == NULL) return;
if (msg == nullptr) return;
ui->cbSignals->clear();
for (int x = 0; x < msg->sigHandler->getCount(); x++)
{
@@ -60,7 +131,7 @@ void SignalViewerWindow::loadSignals(int idx)
void SignalViewerWindow::addSignal()
{
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
DBC_MESSAGE *msg = dbcHandler->findMessage(ui->cbMessages->currentText());
if (!msg) return;
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
if (!sig) return;
+6 -1
View File
@@ -13,19 +13,24 @@ class SignalViewerWindow : public QDialog
Q_OBJECT
public:
explicit SignalViewerWindow(QWidget *parent = 0);
explicit SignalViewerWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
~SignalViewerWindow();
private slots:
void loadMessages();
void loadSignals(int idx);
void addSignal();
void removeSelectedSignal();
void updatedFrames(int);
private:
Ui::SignalViewerWindow *ui;
DBCHandler *dbcHandler;
QList<DBC_SIGNAL *> signalList;
const QVector<CANFrame> *modelFrames;
void processFrame(CANFrame &frame);
};
#endif // SIGNALVIEWERWINDOW_H
+13 -20
View File
@@ -43,6 +43,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnResetConn">
<property name="text">
<string>Reset Selected Device</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDisconnect">
<property name="text">
@@ -68,58 +75,44 @@
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>CAN Bus Number:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblBusNum">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Speed:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="0" column="1">
<widget class="QComboBox" name="cbBusSpeed"/>
</item>
<item row="2" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Listen Only:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="1">
<widget class="QCheckBox" name="ckListenOnly">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Enable Bus:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="ckEnable">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="btnSaveBus">
<property name="text">
<string>Save Bus Settings</string>
+7 -1
View File
@@ -282,6 +282,7 @@
<addaction name="actionSniffer"/>
<addaction name="actionCapture_Bisector"/>
<addaction name="actionSignal_Viewer"/>
<addaction name="actionTemporal_Graph"/>
</widget>
<widget class="QMenu" name="menuSend_Frames">
<property name="title">
@@ -424,7 +425,7 @@
</action>
<action name="actionSetup">
<property name="text">
<string>Open Connection WIndow</string>
<string>Open Connection Window</string>
</property>
</action>
<action name="actionConnect">
@@ -497,6 +498,11 @@
<string>Start Continuous Logging</string>
</property>
</action>
<action name="actionTemporal_Graph">
<property name="text">
<string>Temporal Graph</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
+27 -16
View File
@@ -15,22 +15,33 @@
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,1">
<item>
<widget class="QTableWidget" name="tableViewer">
<property name="columnCount">
<number>2</number>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>300</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<column/>
<column/>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableWidget" name="tableViewer">
<property name="columnCount">
<number>2</number>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>300</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<column/>
<column/>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemove">
<property name="text">
<string>Remove Selected Signal</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TemporalGraphWindow</class>
<widget class="QDialog" name="TemporalGraphWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>886</width>
<height>683</height>
</rect>
</property>
<property name="windowTitle">
<string>Temporal Graph</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCustomPlot" name="graphingView" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>