Merge pull request #200 from collin80/WIP
Merge WIP changes into Master
This commit is contained in:
@@ -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
@@ -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 +=
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ¤t, 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;
|
||||
|
||||
@@ -46,6 +46,7 @@ private slots:
|
||||
void consoleEnableChanged(bool checked);
|
||||
void handleRemoveConn();
|
||||
void handleNewConn();
|
||||
void handleResetConn();
|
||||
void handleClearDebugText();
|
||||
void handleSendHex();
|
||||
void handleSendText();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 |
@@ -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.
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ public slots:
|
||||
|
||||
private:
|
||||
Ui::MainSettingsDialog *ui;
|
||||
QSettings *settings;
|
||||
|
||||
void closeEvent(QCloseEvent *event);
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
+34
-13
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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])
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user