@@ -27,3 +27,13 @@ of this program. It can load and save in several formats:
|
||||
|
||||
5. Generic CSV file (ID,D0 D1 D2 D3 D4 D5 D6 D7)
|
||||
|
||||
Requires QScintilla library available at:
|
||||
|
||||
https://www.riverbankcomputing.com/software/qscintilla/download
|
||||
|
||||
Also uses QCustomPlot available at:
|
||||
|
||||
http://www.qcustomplot.com/
|
||||
|
||||
However, this source code is integrated into the source for SavvyCAN and one isn't required to download it separately.
|
||||
|
||||
|
||||
+29
-5
@@ -6,11 +6,11 @@
|
||||
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets serialport printsupport
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets serialport printsupport qml
|
||||
|
||||
CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT
|
||||
|
||||
CONFIG += c++11
|
||||
CONFIG += c++11 qscintilla2
|
||||
|
||||
TARGET = SavvyCAN
|
||||
TEMPLATE = app
|
||||
@@ -36,7 +36,17 @@ SOURCES += main.cpp\
|
||||
filecomparatorwindow.cpp \
|
||||
mainsettingsdialog.cpp \
|
||||
firmwareuploaderwindow.cpp \
|
||||
discretestatewindow.cpp
|
||||
discretestatewindow.cpp \
|
||||
connectionwindow.cpp \
|
||||
scriptingwindow.cpp \
|
||||
scriptcontainer.cpp \
|
||||
canfilter.cpp \
|
||||
rangestatewindow.cpp \
|
||||
dbc_classes.cpp \
|
||||
dbcloadsavewindow.cpp \
|
||||
fuzzingwindow.cpp \
|
||||
udsscanwindow.cpp \
|
||||
can_structs.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
can_structs.h \
|
||||
@@ -61,7 +71,15 @@ HEADERS += mainwindow.h \
|
||||
filecomparatorwindow.h \
|
||||
mainsettingsdialog.h \
|
||||
firmwareuploaderwindow.h \
|
||||
discretestatewindow.h
|
||||
discretestatewindow.h \
|
||||
connectionwindow.h \
|
||||
scriptingwindow.h \
|
||||
scriptcontainer.h \
|
||||
canfilter.h \
|
||||
rangestatewindow.h \
|
||||
dbcloadsavewindow.h \
|
||||
fuzzingwindow.h \
|
||||
udsscanwindow.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
graphingwindow.ui \
|
||||
@@ -76,7 +94,13 @@ FORMS += mainwindow.ui \
|
||||
filecomparatorwindow.ui \
|
||||
mainsettingsdialog.ui \
|
||||
firmwareuploaderwindow.ui \
|
||||
discretestatewindow.ui
|
||||
discretestatewindow.ui \
|
||||
connectionwindow.ui \
|
||||
scriptingwindow.ui \
|
||||
rangestatewindow.ui \
|
||||
dbcloadsavewindow.ui \
|
||||
fuzzingwindow.ui \
|
||||
udsscanwindow.ui
|
||||
|
||||
DISTFILES +=
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "can_structs.h"
|
||||
|
||||
+17
-1
@@ -1,14 +1,16 @@
|
||||
#ifndef CAN_STRUCTS_H
|
||||
#define CAN_STRUCTS_H
|
||||
|
||||
#include <QVector>
|
||||
#include <stdint.h>
|
||||
|
||||
struct CANFrame
|
||||
class CANFrame
|
||||
{
|
||||
public:
|
||||
int ID;
|
||||
int bus;
|
||||
bool extended;
|
||||
bool isReceived; //did we receive this or send it?
|
||||
int len;
|
||||
unsigned char data[8];
|
||||
uint64_t timestamp;
|
||||
@@ -25,5 +27,19 @@ public:
|
||||
int priority;
|
||||
bool isBroadcast;
|
||||
};
|
||||
|
||||
//the same as the CANFrame struct but with arbitrary data size.
|
||||
struct ISOTP_FRAME
|
||||
{
|
||||
public:
|
||||
int ID;
|
||||
int bus;
|
||||
bool extended;
|
||||
bool isReceived;
|
||||
int len;
|
||||
QVector<unsigned char> data;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
#endif // CAN_STRUCTS_H
|
||||
|
||||
|
||||
+12
-3
@@ -13,6 +13,7 @@ CANDataGrid::CANDataGrid(QWidget *parent) :
|
||||
|
||||
memset(data, 0, 8);
|
||||
memset(refData, 0, 8);
|
||||
memset(usedData, 0, 8);
|
||||
}
|
||||
|
||||
CANDataGrid::~CANDataGrid()
|
||||
@@ -45,7 +46,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
|
||||
int x, y;
|
||||
unsigned char prevByte, thisByte;
|
||||
bool thisBit, prevBit;
|
||||
QBrush blackBrush, whiteBrush, redBrush, greenBrush;
|
||||
QBrush blackBrush, whiteBrush, redBrush, greenBrush, grayBrush;
|
||||
QPainter painter(this);
|
||||
|
||||
QRect viewport = painter.viewport();
|
||||
@@ -60,6 +61,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
|
||||
whiteBrush = QBrush(Qt::white);
|
||||
redBrush = QBrush(Qt::red);
|
||||
greenBrush = QBrush(Qt::green);
|
||||
grayBrush = QBrush(QColor(230,230,230));
|
||||
|
||||
//the whole thing is broken up into 100 chunks which are allocated as such:
|
||||
//The entirety of the upper row is taken up by "BITS"
|
||||
@@ -109,7 +111,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
|
||||
thisBit = false;
|
||||
prevBit = false;
|
||||
if ((thisByte & (1 << (7-x))) == (1 << (7-x))) thisBit = true;
|
||||
if ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true;
|
||||
if ((prevByte & (1 << (7-x))) == (1 << (7-x))) prevBit = true;
|
||||
|
||||
if (thisBit)
|
||||
{
|
||||
@@ -130,7 +132,8 @@ void CANDataGrid::paintEvent(QPaintEvent *event)
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.setBrush(whiteBrush);
|
||||
if ((usedData[y] & (1 << (7-x))) == (1 << (7-x))) painter.setBrush(grayBrush);
|
||||
else painter.setBrush(whiteBrush);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,3 +183,9 @@ void CANDataGrid::updateData(unsigned char *newData, bool bUpdate = true)
|
||||
memcpy(data, newData, 8); //on a 64 bit processor this is probably optimized to a single instruction
|
||||
if (bUpdate) this->update();
|
||||
}
|
||||
|
||||
void CANDataGrid::setUsed(unsigned char *newData, bool bUpdate = false)
|
||||
{
|
||||
memcpy(usedData, newData, 8);
|
||||
if (bUpdate) this->update();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void setReference(unsigned char *, bool);
|
||||
void updateData(unsigned char *, bool);
|
||||
void setUsed(unsigned char *, bool);
|
||||
void saveImage(QString filename, int width, int height);
|
||||
|
||||
protected:
|
||||
@@ -29,6 +30,7 @@ private:
|
||||
Ui::CANDataGrid *ui;
|
||||
unsigned char refData[8];
|
||||
unsigned char data[8];
|
||||
unsigned char usedData[8];
|
||||
QPoint upperLeft, gridSize;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "canfilter.h"
|
||||
|
||||
CANFilter::CANFilter()
|
||||
{
|
||||
ID = 0;
|
||||
mask = 0;
|
||||
bus = -1;
|
||||
}
|
||||
|
||||
void CANFilter::setFilter(uint32_t id, uint32_t mask, int bus)
|
||||
{
|
||||
this->ID = id;
|
||||
this->mask = mask;
|
||||
this->bus = bus;
|
||||
}
|
||||
|
||||
bool CANFilter::checkFilter(uint32_t id, int bus)
|
||||
{
|
||||
if (bus == -1 || bus == this->bus)
|
||||
{
|
||||
uint32_t result = id & this->mask;
|
||||
if (result == this->ID) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#ifndef CANFILTER_H
|
||||
#define CANFILTER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class CANFilter
|
||||
{
|
||||
public:
|
||||
CANFilter();
|
||||
void setFilter(uint32_t id, uint32_t mask, int bus);
|
||||
bool checkFilter(uint32_t id, int bus);
|
||||
|
||||
private:
|
||||
uint32_t ID;
|
||||
uint32_t mask;
|
||||
int bus;
|
||||
};
|
||||
|
||||
#endif // CANFILTER_H
|
||||
+77
-41
@@ -17,7 +17,7 @@ int CANFrameModel::totalFrameCount()
|
||||
int CANFrameModel::columnCount(const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
return 6;
|
||||
return 7;
|
||||
}
|
||||
|
||||
CANFrameModel::CANFrameModel(QObject *parent)
|
||||
@@ -115,6 +115,8 @@ void CANFrameModel::recalcOverwrite()
|
||||
{
|
||||
if (!overwriteDups) return; //no need to do a thing if mode is disabled
|
||||
|
||||
qDebug() << "recalcOverwrite called in model";
|
||||
|
||||
int lastUnique = 0;
|
||||
bool found;
|
||||
|
||||
@@ -159,7 +161,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() >= filteredFrames.count())
|
||||
if (index.row() >= (filteredFrames.count()))
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
@@ -168,7 +170,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
case 0: //timestamp
|
||||
if (!timeSeconds) return QString::number(thisFrame.timestamp);
|
||||
else return QString::number(thisFrame.timestamp / 1000000.0f);
|
||||
else return QString::number((double)thisFrame.timestamp / 1000000.0, 'f', 6);
|
||||
break;
|
||||
case 1: //id
|
||||
return Utility::formatNumber(thisFrame.ID);
|
||||
@@ -176,13 +178,17 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
case 2: //ext
|
||||
return QString::number(thisFrame.extended);
|
||||
break;
|
||||
case 3: //bus
|
||||
case 3: //direction
|
||||
if (thisFrame.isReceived) return QString(tr("Rx"));
|
||||
else return QString(tr("Tx"));
|
||||
break;
|
||||
case 4: //bus
|
||||
return QString::number(thisFrame.bus);
|
||||
break;
|
||||
case 4: //len
|
||||
case 5: //len
|
||||
return QString::number(thisFrame.len);
|
||||
break;
|
||||
case 5: //data
|
||||
case 6: //data
|
||||
for (int i = 0; i < thisFrame.len; i++)
|
||||
{
|
||||
tempString.append(Utility::formatNumber(thisFrame.data[i]));
|
||||
@@ -191,16 +197,19 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
//now, if we're supposed to interpret the data and the DBC handler is loaded then use it
|
||||
if (dbcHandler != NULL && interpretFrames)
|
||||
{
|
||||
DBC_MESSAGE *msg = dbcHandler->findMsgByID(thisFrame.ID);
|
||||
DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
|
||||
if (msg != NULL)
|
||||
{
|
||||
tempString.append("\r\n");
|
||||
tempString.append(msg->name + " " + msg->comment + "\r\n");
|
||||
for (int j = 0; j < msg->msgSignals.length(); j++)
|
||||
for (int j = 0; j < msg->sigHandler->getCount(); j++)
|
||||
{
|
||||
|
||||
tempString.append(dbcHandler->processSignal(thisFrame, msg->msgSignals.at(j)));
|
||||
tempString.append("\r\n");
|
||||
QString sigString;
|
||||
if (msg->sigHandler->findSignalByIdx(j)->processAsText(thisFrame, sigString))
|
||||
{
|
||||
tempString.append(sigString);
|
||||
tempString.append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,12 +243,15 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
|
||||
return QString(tr("Ext"));
|
||||
break;
|
||||
case 3:
|
||||
return QString(tr("Bus"));
|
||||
return QString(tr("Dir"));
|
||||
break;
|
||||
case 4:
|
||||
return QString(tr("Len"));
|
||||
return QString(tr("Bus"));
|
||||
break;
|
||||
case 5:
|
||||
return QString(tr("Len"));
|
||||
break;
|
||||
case 6:
|
||||
return QString(tr("Data"));
|
||||
break;
|
||||
}
|
||||
@@ -251,25 +263,27 @@ QVariant CANFrameModel::headerData(int section, Qt::Orientation orientation,
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
void CANFrameModel::addFrame(const CANFrame &frame, bool autoRefresh = false)
|
||||
{
|
||||
mutex.lock();
|
||||
frame.timestamp -= timeOffset;
|
||||
CANFrame tempFrame;
|
||||
tempFrame = frame;
|
||||
tempFrame.timestamp -= timeOffset;
|
||||
|
||||
//if this ID isn't found in the filters list then add it and show it by default
|
||||
if (!filters.contains(frame.ID))
|
||||
if (!filters.contains(tempFrame.ID))
|
||||
{
|
||||
filters.insert(frame.ID, true);
|
||||
filters.insert(tempFrame.ID, true);
|
||||
needFilterRefresh = true;
|
||||
}
|
||||
|
||||
if (!overwriteDups)
|
||||
{
|
||||
frames.append(frame);
|
||||
if (filters[frame.ID])
|
||||
frames.append(tempFrame);
|
||||
if (filters[tempFrame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
filteredFrames.append(frame);
|
||||
filteredFrames.append(tempFrame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
}
|
||||
@@ -278,20 +292,20 @@ void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
bool found = false;
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
if (frames[i].ID == frame.ID)
|
||||
if (frames[i].ID == tempFrame.ID)
|
||||
{
|
||||
frames.replace(i, frame);
|
||||
frames.replace(i, tempFrame);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
frames.append(frame);
|
||||
if (filters[frame.ID])
|
||||
frames.append(tempFrame);
|
||||
if (filters[tempFrame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
filteredFrames.append(frame);
|
||||
filteredFrames.append(tempFrame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
}
|
||||
@@ -299,10 +313,10 @@ void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
{
|
||||
for (int j = 0; j < filteredFrames.count(); j++)
|
||||
{
|
||||
if (filteredFrames[j].ID == frame.ID)
|
||||
if (filteredFrames[j].ID == tempFrame.ID)
|
||||
{
|
||||
if (autoRefresh) beginResetModel();
|
||||
filteredFrames.replace(j, frame);
|
||||
filteredFrames.replace(j, tempFrame);
|
||||
if (autoRefresh) endResetModel();
|
||||
}
|
||||
}
|
||||
@@ -314,18 +328,23 @@ void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
|
||||
void CANFrameModel::sendRefresh()
|
||||
{
|
||||
mutex.lock();
|
||||
qDebug() << "Sending mass refresh";
|
||||
QVector<CANFrame> tempContainer;
|
||||
beginResetModel();
|
||||
filteredFrames.clear();
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
int count = frames.count();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (filters[frames[i].ID])
|
||||
{
|
||||
filteredFrames.append(frames[i]);
|
||||
tempContainer.append(frames[i]);
|
||||
}
|
||||
}
|
||||
filteredFrames.clear();
|
||||
filteredFrames = tempContainer;
|
||||
lastUpdateNumFrames = filteredFrames.count();
|
||||
endResetModel();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void CANFrameModel::sendRefresh(int pos)
|
||||
@@ -343,23 +362,34 @@ void CANFrameModel::sendBulkRefresh(int num)
|
||||
//of how many by tracking the number we last knew about as opposed to how many rows there
|
||||
//are now.
|
||||
num = filteredFrames.count() - lastUpdateNumFrames;
|
||||
|
||||
if (num < 0) return;
|
||||
|
||||
//qDebug() << "Num: " << num;
|
||||
|
||||
if (num == 0 && !overwriteDups) return;
|
||||
if (filteredFrames.count() == 0) return;
|
||||
|
||||
lastUpdateNumFrames += num; //done this way to avoid asking for filteredFrames.count() again
|
||||
|
||||
//qDebug() << "Bulk refresh of " << num;
|
||||
|
||||
if (num == 0) return;
|
||||
if (filteredFrames.count() == 0) return;
|
||||
qDebug() << "Bulk refresh of " << num;
|
||||
|
||||
if (!overwriteDups)
|
||||
{
|
||||
mutex.lock();
|
||||
if (num > filteredFrames.count()) num = filteredFrames.count();
|
||||
beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1);
|
||||
endInsertRows();
|
||||
//qDebug() << "From " << (filteredFrames.count() - num) << " to " << (filteredFrames.count() - 1);
|
||||
//beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1);
|
||||
//endInsertRows();
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
mutex.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRefresh();
|
||||
}
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
void CANFrameModel::clearFrames()
|
||||
@@ -383,6 +413,11 @@ void CANFrameModel::clearFrames()
|
||||
*/
|
||||
void CANFrameModel::insertFrames(const QVector<CANFrame> &newFrames)
|
||||
{
|
||||
//not resetting the model here because the serial worker automatically does a bulk refresh every 1/4 second
|
||||
//and that refresh will cause the view to update. If you do both it usually ends up thinking you have
|
||||
//double the number of frames.
|
||||
//beginResetModel();
|
||||
mutex.lock();
|
||||
int insertedFiltered = 0;
|
||||
for (int i = 0; i < newFrames.count(); i++)
|
||||
{
|
||||
@@ -398,9 +433,10 @@ void CANFrameModel::insertFrames(const QVector<CANFrame> &newFrames)
|
||||
filteredFrames.append(newFrames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered);
|
||||
endInsertRows();
|
||||
mutex.unlock();
|
||||
//endResetModel();
|
||||
//beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered);
|
||||
//endInsertRows();
|
||||
if (needFilterRefresh) emit updatedFiltersList();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ public:
|
||||
int columnCount(const QModelIndex &) const;
|
||||
int totalFrameCount();
|
||||
|
||||
void addFrame(CANFrame &, bool);
|
||||
void addFrame(const CANFrame &, bool);
|
||||
void sendRefresh();
|
||||
void sendRefresh(int);
|
||||
void sendBulkRefresh(int);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef CONFIG
|
||||
#define CONFIG
|
||||
|
||||
#define VERSION 141
|
||||
#define VERSION 151
|
||||
|
||||
//try to keep this in sync.
|
||||
//SavvyCAN will complain if you connect a GVRET board with a revision
|
||||
//less than this number.
|
||||
#define CURRENT_GVRET_VER 325 //330 is the newest but it is WIP
|
||||
#define CURRENT_GVRET_VER 331
|
||||
|
||||
#endif // CONFIG
|
||||
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
#include "connectionwindow.h"
|
||||
#include "ui_connectionwindow.h"
|
||||
#include <QtNetwork/QNetworkInterface>
|
||||
|
||||
ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ConnectionWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
settings = new QSettings();
|
||||
|
||||
int temp = settings->value("Main/DefaultConnectionType", 0).toInt();
|
||||
|
||||
if (temp == 0) currentConnType = ConnectionType::GVRET_SERIAL;
|
||||
if (temp == 1) currentConnType = ConnectionType::KVASER;
|
||||
if (temp == 2) currentConnType = ConnectionType::SOCKETCAN;
|
||||
|
||||
currentPortName = settings->value("Main/DefaultConnectionPort", "").toString();
|
||||
|
||||
currentSpeed1 = -1;
|
||||
currentSpeed2 = -1;
|
||||
|
||||
ui->ckSingleWire->setChecked(settings->value("Main/SingleWireMode", false).toBool());
|
||||
|
||||
ui->cbSpeed0->addItem(tr("<Default>"));
|
||||
ui->cbSpeed0->addItem(tr("Disabled"));
|
||||
ui->cbSpeed0->addItem(tr("125000"));
|
||||
ui->cbSpeed0->addItem(tr("250000"));
|
||||
ui->cbSpeed0->addItem(tr("500000"));
|
||||
ui->cbSpeed0->addItem(tr("1000000"));
|
||||
ui->cbSpeed0->addItem(tr("33333"));
|
||||
|
||||
ui->cbSpeed1->addItem(tr("<Default>"));
|
||||
ui->cbSpeed1->addItem(tr("Disabled"));
|
||||
ui->cbSpeed1->addItem(tr("125000"));
|
||||
ui->cbSpeed1->addItem(tr("250000"));
|
||||
ui->cbSpeed1->addItem(tr("500000"));
|
||||
ui->cbSpeed1->addItem(tr("1000000"));
|
||||
ui->cbSpeed1->addItem(tr("33333"));
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
ui->rbSocketCAN->setEnabled(true);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
ui->rbKvaser->setEnabled(true);
|
||||
#endif
|
||||
|
||||
connect(ui->btnOK, SIGNAL(clicked(bool)), this, SLOT(handleOKButton()));
|
||||
}
|
||||
|
||||
ConnectionWindow::~ConnectionWindow()
|
||||
{
|
||||
delete settings;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConnectionWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
qDebug() << "Show connectionwindow";
|
||||
if (ui->rbGVRET->isChecked()) getSerialPorts();
|
||||
if (ui->rbKvaser->isChecked()) getKvaserPorts();
|
||||
if (ui->rbSocketCAN->isChecked()) getSocketcanPorts();
|
||||
}
|
||||
|
||||
void ConnectionWindow::handleOKButton()
|
||||
{
|
||||
QString conn;
|
||||
int connType = 0;
|
||||
|
||||
if (ui->rbGVRET->isChecked())
|
||||
{
|
||||
conn = "GVRET";
|
||||
connType = 0;
|
||||
currentConnType = ConnectionType::GVRET_SERIAL;
|
||||
}
|
||||
|
||||
if (ui->rbKvaser->isChecked())
|
||||
{
|
||||
conn = "KVASER";
|
||||
connType = 1;
|
||||
currentConnType = ConnectionType::KVASER;
|
||||
}
|
||||
|
||||
if (ui->rbSocketCAN->isChecked())
|
||||
{
|
||||
conn = "SOCKETCAN";
|
||||
connType = 2;
|
||||
currentConnType = ConnectionType::SOCKETCAN;
|
||||
}
|
||||
|
||||
currentPortName = getPortName();
|
||||
currentSpeed1 = getSpeed0();
|
||||
currentSpeed2 = getSpeed1();
|
||||
|
||||
settings->setValue("Main/DefaultConnectionPort", currentPortName);
|
||||
settings->setValue("Main/DefaultConnectionType", connType);
|
||||
settings->setValue("Main/SingleWireMode", ui->ckSingleWire->isChecked());
|
||||
|
||||
emit updateConnectionSettings(conn, getPortName(), getSpeed0(), getSpeed1());
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
void ConnectionWindow::getSerialPorts()
|
||||
{
|
||||
ui->cbPort->clear();
|
||||
ports = QSerialPortInfo::availablePorts();
|
||||
|
||||
for (int i = 0; i < ports.count(); i++)
|
||||
{
|
||||
ui->cbPort->addItem(ports[i].portName());
|
||||
if (currentPortName == ports[i].portName()) ui->cbPort->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionWindow::getKvaserPorts()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ConnectionWindow::getSocketcanPorts()
|
||||
{
|
||||
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
|
||||
QString interfaceName;
|
||||
|
||||
ui->cbPort->clear();
|
||||
|
||||
foreach (QNetworkInterface interface, interfaces)
|
||||
{
|
||||
interfaceName = interface.name().toLower();
|
||||
qDebug() << "Interface: " << interface.name();
|
||||
if (interfaceName.contains("can"))
|
||||
{
|
||||
ui->cbPort->addItem(interfaceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionWindow::setSpeeds(int speed0, int speed1)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
qDebug() << speed0 << "X" << speed1;
|
||||
|
||||
for (int i = 0; i < ui->cbSpeed0->count(); i++)
|
||||
{
|
||||
if (ui->cbSpeed0->itemText(i).toInt() == speed0)
|
||||
{
|
||||
ui->cbSpeed0->setCurrentIndex(i);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
ui->cbSpeed0->addItem(QString::number(speed0));
|
||||
ui->cbSpeed0->setCurrentIndex(ui->cbSpeed0->count() - 1);
|
||||
}
|
||||
|
||||
found = false;
|
||||
for (int i = 0; i < ui->cbSpeed1->count(); i++)
|
||||
{
|
||||
if (ui->cbSpeed1->itemText(i).toInt() == speed1)
|
||||
{
|
||||
ui->cbSpeed1->setCurrentIndex(i);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
ui->cbSpeed1->addItem(QString::number(speed1));
|
||||
ui->cbSpeed1->setCurrentIndex(ui->cbSpeed1->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-1 means leave it at whatever it booted up to. 0 means disable. Otherwise the actual rate we want.
|
||||
int ConnectionWindow::getSpeed0()
|
||||
{
|
||||
switch (ui->cbSpeed0->currentIndex())
|
||||
{
|
||||
case -1:
|
||||
return -1;
|
||||
break;
|
||||
case 0:
|
||||
return -1;
|
||||
break;
|
||||
case 1:
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return (ui->cbSpeed0->currentText().toInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ConnectionWindow::getSpeed1()
|
||||
{
|
||||
switch (ui->cbSpeed1->currentIndex())
|
||||
{
|
||||
case -1:
|
||||
return -1;
|
||||
break;
|
||||
case 0:
|
||||
return -1;
|
||||
break;
|
||||
case 1:
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return (ui->cbSpeed1->currentText().toInt());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString ConnectionWindow::getPortName()
|
||||
{
|
||||
return (ui->cbPort->currentText());
|
||||
}
|
||||
|
||||
ConnectionType::ConnectionType ConnectionWindow::getConnectionType()
|
||||
{
|
||||
if (ui->rbGVRET->isChecked()) return ConnectionType::GVRET_SERIAL;
|
||||
if (ui->rbKvaser->isChecked()) return ConnectionType::KVASER;
|
||||
if (ui->rbSocketCAN->isChecked()) return ConnectionType::SOCKETCAN;
|
||||
}
|
||||
|
||||
void ConnectionWindow::setCAN1SWMode(bool mode)
|
||||
{
|
||||
ui->ckSingleWire->setChecked(mode);
|
||||
}
|
||||
|
||||
bool ConnectionWindow::getCAN1SWMode()
|
||||
{
|
||||
if (ui->ckSingleWire->checkState() == Qt::Checked) return true;
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef CONNECTIONWINDOW_H
|
||||
#define CONNECTIONWINDOW_H
|
||||
|
||||
#include <QSerialPortInfo>
|
||||
#include <QDialog>
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
|
||||
namespace Ui {
|
||||
class ConnectionWindow;
|
||||
}
|
||||
|
||||
namespace ConnectionType
|
||||
{
|
||||
enum ConnectionType
|
||||
{
|
||||
GVRET_SERIAL,
|
||||
KVASER,
|
||||
SOCKETCAN
|
||||
};
|
||||
}
|
||||
|
||||
class ConnectionWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionWindow(QWidget *parent = 0);
|
||||
~ConnectionWindow();
|
||||
void showEvent(QShowEvent *);
|
||||
int getSpeed0();
|
||||
int getSpeed1();
|
||||
QString getPortName(); //name of port to connect to
|
||||
ConnectionType::ConnectionType getConnectionType();
|
||||
bool getCAN1SWMode();
|
||||
|
||||
signals:
|
||||
void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1);
|
||||
|
||||
public slots:
|
||||
void setSpeeds(int speed0, int speed1);
|
||||
void setCAN1SWMode(bool mode);
|
||||
|
||||
private slots:
|
||||
void handleOKButton();
|
||||
|
||||
private:
|
||||
Ui::ConnectionWindow *ui;
|
||||
QList<QSerialPortInfo> ports;
|
||||
QSettings *settings;
|
||||
|
||||
ConnectionType::ConnectionType currentConnType;
|
||||
QString currentPortName;
|
||||
int currentSpeed1, currentSpeed2;
|
||||
|
||||
void getSerialPorts();
|
||||
void getKvaserPorts();
|
||||
void getSocketcanPorts();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONWINDOW_H
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConnectionWindow</class>
|
||||
<widget class="QWidget" name="ConnectionWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>335</width>
|
||||
<height>235</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Connection Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Connection Type</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbGVRET">
|
||||
<property name="text">
|
||||
<string>GVRET Serial</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbKvaser">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Kvaser</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSocketCAN">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SocketCAN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbPort"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>CAN0 Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>CAN1 Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="cbSpeed0"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cbSpeed1"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ckSingleWire">
|
||||
<property name="text">
|
||||
<string>Set CAN1 to Single Wire Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnOK">
|
||||
<property name="text">
|
||||
<string>Update Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
#include "dbc_classes.h"
|
||||
#include "dbchandler.h"
|
||||
#include "utility.h"
|
||||
|
||||
DBC_MESSAGE::DBC_MESSAGE()
|
||||
{
|
||||
sigHandler = new DBCSignalHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
The way that the DBC file format works is kind of weird... For intel format signals you count up
|
||||
from the start bit to the end bit which is (startbit + signallength - 1). At each point
|
||||
bits are numbered in a sawtooth manner. What that means is that the very first bit is 0 and you count up
|
||||
from there all of the way to 63 with each byte being 8 bits so bit 0 is the lowest bit in the first byte
|
||||
and 8 is the lowest bit in the next byte up. The whole thing looks like this:
|
||||
Bits
|
||||
7 6 5 4 3 2 1 0
|
||||
|
||||
0 7 6 5 4 3 2 1 0
|
||||
b 1 15 14 13 12 11 10 9 8
|
||||
y 2 23 22 21 20 19 18 17 16
|
||||
t 3 31 30 29 28 27 26 25 24
|
||||
e 4 39 38 37 36 35 34 33 32
|
||||
s 5 47 46 45 44 43 42 41 40
|
||||
6 55 54 53 52 51 50 49 48
|
||||
7 63 62 61 60 59 58 57 56
|
||||
|
||||
For intel format you start at the start bit and keep counting up. If you have a signal size of 8
|
||||
and start at bit 12 then the bits are 12, 13, 14, 15, 16, 17, 18, 19 which spans across two bytes.
|
||||
In this format each bit is worth twice as much as the last and you just keep counting up.
|
||||
Bit 12 is worth 1, 13 is worth 2, 14 is worth 4, etc all of the way to bit 19 is worth 128.
|
||||
|
||||
Motorola format turns most everything on its head. You count backward from the start bit but
|
||||
only within the current byte. If you are about to exit the current byte you go one higher and then keep
|
||||
going backward as before. Using the same example as for intel, start bit of 12 and a signal length of 8.
|
||||
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)
|
||||
{
|
||||
int64_t result = 0;
|
||||
bool isSigned = false;
|
||||
double endResult;
|
||||
|
||||
if (valType == STRING)
|
||||
{
|
||||
QString buildString;
|
||||
int startByte = signalSize / 8;
|
||||
int bytes = signalSize / 8;
|
||||
for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]);
|
||||
outString = buildString;
|
||||
return true;
|
||||
}
|
||||
|
||||
//if this is a multiplexed signal then we have to see if it is even found in the current message
|
||||
if (isMultiplexed)
|
||||
{
|
||||
if (parentMessage->multiplexorSignal != NULL)
|
||||
{
|
||||
int val;
|
||||
if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false;
|
||||
if (val != multiplexValue) return false; //signal not found in this message
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (valType == SIGNED_INT) isSigned = true;
|
||||
if (valType == SIGNED_INT || valType == UNSIGNED_INT)
|
||||
{
|
||||
result = Utility::processIntegerSignal(frame.data, startBit, signalSize, intelByteOrder, isSigned);
|
||||
endResult = ((double)result * factor) + bias;
|
||||
result = (int64_t)endResult;
|
||||
}
|
||||
else if (valType == SP_FLOAT)
|
||||
{
|
||||
//The theory here is that we force the integer signal code to treat this as
|
||||
//a 32 bit unsigned integer. This integer is then cast into a float in such a way
|
||||
//that the bytes that make up the integer are instead treated as having made up
|
||||
//a 32 bit single precision float. That's evil incarnate but it is very fast and small
|
||||
//in terms of new code.
|
||||
result = Utility::processIntegerSignal(frame.data, startBit, 32, false, false);
|
||||
endResult = (*((float *)(&result)) * factor) + bias;
|
||||
}
|
||||
else //double precision float
|
||||
{
|
||||
//like the above, this is rotten and evil and wrong in so many ways. Force
|
||||
//calculation of a 64 bit integer and then cast it into a double.
|
||||
result = Utility::processIntegerSignal(frame.data, 0, 64, false, false);
|
||||
endResult = (*((double *)(&result)) * factor) + bias;
|
||||
}
|
||||
|
||||
QString outputString;
|
||||
|
||||
outputString = name + ": ";
|
||||
|
||||
if (valList.count() > 0) //if this is a value list type then look it up and display the proper string
|
||||
{
|
||||
for (int x = 0; x < valList.count(); x++)
|
||||
{
|
||||
if (valList.at(x).value == result) outputString += valList.at(x).descript;
|
||||
}
|
||||
}
|
||||
else //otherwise display the actual number and unit (if it exists)
|
||||
{
|
||||
outputString += QString::number(endResult) + unitName;
|
||||
}
|
||||
|
||||
outString = outputString;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Works quite a bit like the above version but this one is cut down and only will return int32_t which is perfect for
|
||||
//uses like calculating a multiplexor value or if you know you are going to get an integer returned
|
||||
//from a signal and you want to use it as-is and not have to convert back from a string. Use with caution though
|
||||
//as this basically assumes the signal is an integer.
|
||||
//The call syntax is different from the more generic processSignal. Instead of returning the value we return
|
||||
//true or false to show whether the function succeeded. The variable to fill out is passed by reference.
|
||||
bool DBC_SIGNAL::processAsInt(const CANFrame &frame, int32_t &outValue)
|
||||
{
|
||||
int32_t result = 0;
|
||||
bool isSigned = false;
|
||||
if (valType == STRING || valType == SP_FLOAT || valType == DP_FLOAT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//if this is a multiplexed signal then we have to see if it is even found in the current message
|
||||
if (isMultiplexed)
|
||||
{
|
||||
if (parentMessage->multiplexorSignal != NULL)
|
||||
{
|
||||
int val;
|
||||
if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false;
|
||||
if (val != multiplexValue) return false; //signal not found in this message
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (valType == SIGNED_INT) isSigned = true;
|
||||
result = Utility::processIntegerSignal(frame.data, startBit, signalSize, intelByteOrder, isSigned);
|
||||
|
||||
double endResult = ((double)result * factor) + bias;
|
||||
result = (int32_t)endResult;
|
||||
|
||||
outValue = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Another cut down version that will only return double precision data. This can be used on any of the types
|
||||
//except STRING. Useful for when you know you'll need floating point data and don't want to incur a conversion
|
||||
//back and forth to double or float. Such a use is the graphing window.
|
||||
//Similar syntax to processSignalInt but with double instead.
|
||||
bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue)
|
||||
{
|
||||
int64_t result = 0;
|
||||
bool isSigned = false;
|
||||
double endResult;
|
||||
|
||||
if (valType == STRING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//if this is a multiplexed signal then we have to see if it is even found in the current message
|
||||
if (isMultiplexed)
|
||||
{
|
||||
if (parentMessage->multiplexorSignal != NULL)
|
||||
{
|
||||
int val;
|
||||
if (!parentMessage->multiplexorSignal->processAsInt(frame, val)) return false;
|
||||
if (val != multiplexValue) return false; //signal not found in this message
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (valType == SIGNED_INT) isSigned = true;
|
||||
if (valType == SIGNED_INT || valType == UNSIGNED_INT)
|
||||
{
|
||||
result = Utility::processIntegerSignal(frame.data, startBit, signalSize, intelByteOrder, isSigned);
|
||||
endResult = ((double)result * factor) + bias;
|
||||
result = (int64_t)endResult;
|
||||
}
|
||||
else if (valType == SP_FLOAT)
|
||||
{
|
||||
//The theory here is that we force the integer signal code to treat this as
|
||||
//a 32 bit unsigned integer. This integer is then cast into a float in such a way
|
||||
//that the bytes that make up the integer are instead treated as having made up
|
||||
//a 32 bit single precision float. That's evil incarnate but it is very fast and small
|
||||
//in terms of new code.
|
||||
result = Utility::processIntegerSignal(frame.data, startBit, 32, false, false);
|
||||
endResult = (*((float *)(&result)) * factor) + bias;
|
||||
}
|
||||
else //double precision float
|
||||
{
|
||||
//like the above, this is rotten and evil and wrong in so many ways. Force
|
||||
//calculation of a 64 bit integer and then cast it into a double.
|
||||
result = Utility::processIntegerSignal(frame.data, 0, 64, false, false);
|
||||
endResult = (*((double *)(&result)) * factor) + bias;
|
||||
}
|
||||
|
||||
outValue = endResult;
|
||||
return true;
|
||||
}
|
||||
+19
-3
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include "can_structs.h"
|
||||
|
||||
/*classes to encapsulate data from a DBC file. Really, the stuff of interest
|
||||
are the nodes, messages, signals, attributes, and comments.
|
||||
@@ -54,35 +55,50 @@ public:
|
||||
QList<DBC_ATTRIBUTE> attributes;
|
||||
};
|
||||
|
||||
class DBC_MESSAGE; //forward reference so that DBC_SIGNAL can compile before we get to real definition of DBC_MESSAGE
|
||||
|
||||
class DBC_SIGNAL
|
||||
{
|
||||
public:
|
||||
public: //TODO: this is sloppy. It shouldn't all be public!
|
||||
QString name;
|
||||
int startBit;
|
||||
int signalSize;
|
||||
bool intelByteOrder; //true is obviously little endian. False is big endian
|
||||
bool isMultiplexor;
|
||||
bool isMultiplexed;
|
||||
int multiplexValue;
|
||||
DBC_SIG_VAL_TYPE valType;
|
||||
double factor;
|
||||
double bias;
|
||||
double min;
|
||||
double max;
|
||||
DBC_NODE *receiver;
|
||||
DBC_NODE *receiver; //it is fast to have a pointer but dangerous... Make sure to walk the whole tree and delete everything so nobody has stale references.
|
||||
DBC_MESSAGE *parentMessage;
|
||||
QString unitName;
|
||||
QString comment;
|
||||
QList<DBC_ATTRIBUTE> attributes;
|
||||
QList<DBC_VAL> valList;
|
||||
|
||||
bool processAsText(const CANFrame &frame, QString &outString);
|
||||
bool processAsInt(const CANFrame &frame, int32_t &outValue);
|
||||
bool processAsDouble(const CANFrame &frame, double &outValue);
|
||||
};
|
||||
|
||||
class DBCSignalHandler; //forward declaration to keep from having to include dbchandler.h in this file and thus create a loop
|
||||
|
||||
class DBC_MESSAGE
|
||||
{
|
||||
public:
|
||||
DBC_MESSAGE();
|
||||
|
||||
int ID;
|
||||
QString name;
|
||||
QString comment;
|
||||
int len;
|
||||
DBC_NODE *sender;
|
||||
QList<DBC_ATTRIBUTE> attributes;
|
||||
QList<DBC_SIGNAL> msgSignals;
|
||||
DBCSignalHandler *sigHandler;
|
||||
DBC_SIGNAL* multiplexorSignal;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+483
-290
@@ -3,21 +3,262 @@
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include "utility.h"
|
||||
|
||||
DBCHandler::DBCHandler(QObject *parent) : QObject(parent)
|
||||
DBC_SIGNAL* DBCSignalHandler::findSignalByIdx(int idx)
|
||||
{
|
||||
if (sigs.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= sigs.count()) return NULL;
|
||||
|
||||
return &sigs[idx];
|
||||
}
|
||||
|
||||
void DBCHandler::loadDBCFile(QString filename)
|
||||
DBC_SIGNAL* DBCSignalHandler::findSignalByName(QString name)
|
||||
{
|
||||
QFile *inFile = new QFile(filename);
|
||||
if (sigs.count() == 0) return NULL;
|
||||
for (int i = 0; i < sigs.count(); i++)
|
||||
{
|
||||
if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &sigs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DBCSignalHandler::addSignal(DBC_SIGNAL &sig)
|
||||
{
|
||||
sigs.append(sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBCSignalHandler::removeSignal(DBC_SIGNAL *sig)
|
||||
{
|
||||
//if (sigs.removeAll(*sig) > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBCSignalHandler::removeSignal(int idx)
|
||||
{
|
||||
if (sigs.count() == 0) return false;
|
||||
if (idx < 0) return false;
|
||||
if (idx >= sigs.count()) return false;
|
||||
sigs.removeAt(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBCSignalHandler::removeSignal(QString name)
|
||||
{
|
||||
bool foundSome = false;
|
||||
if (sigs.count() == 0) return false;
|
||||
for (int i = sigs.count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (sigs[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
sigs.removeAt(i);
|
||||
foundSome = true;
|
||||
}
|
||||
}
|
||||
return foundSome;
|
||||
}
|
||||
|
||||
void DBCSignalHandler::removeAllSignals()
|
||||
{
|
||||
sigs.clear();
|
||||
}
|
||||
|
||||
int DBCSignalHandler::getCount()
|
||||
{
|
||||
return sigs.count();
|
||||
}
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByID(int id)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
for (int i = 0; i < messages.count(); i++)
|
||||
{
|
||||
if (messages[i].ID == id)
|
||||
{
|
||||
return &messages[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByIdx(int idx)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= messages.count()) return NULL;
|
||||
return &messages[idx];
|
||||
}
|
||||
|
||||
DBC_MESSAGE* DBCMessageHandler::findMsgByName(QString name)
|
||||
{
|
||||
if (messages.count() == 0) return NULL;
|
||||
for (int i = 0; i < messages.count(); i++)
|
||||
{
|
||||
if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &messages[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::addMessage(DBC_MESSAGE &msg)
|
||||
{
|
||||
messages.append(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::removeMessage(DBC_MESSAGE *msg)
|
||||
{
|
||||
//if (messages.removeAll(*msg) > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::removeMessageByIndex(int idx)
|
||||
{
|
||||
if (messages.count() == 0) return false;
|
||||
if (idx < 0) return false;
|
||||
if (idx >= messages.count()) return false;
|
||||
messages.removeAt(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::removeMessage(int ID)
|
||||
{
|
||||
bool foundSome = false;
|
||||
if (messages.count() == 0) return false;
|
||||
for (int i = messages.count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (messages[i].ID == ID)
|
||||
{
|
||||
messages.removeAt(i);
|
||||
foundSome = true;
|
||||
}
|
||||
}
|
||||
return foundSome;
|
||||
}
|
||||
|
||||
bool DBCMessageHandler::removeMessage(QString name)
|
||||
{
|
||||
bool foundSome = false;
|
||||
if (messages.count() == 0) return false;
|
||||
for (int i = messages.count() - 1; i >= 0; i--)
|
||||
{
|
||||
if (messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
messages.removeAt(i);
|
||||
foundSome = true;
|
||||
}
|
||||
}
|
||||
return foundSome;
|
||||
}
|
||||
|
||||
void DBCMessageHandler::removeAllMessages()
|
||||
{
|
||||
messages.clear();
|
||||
}
|
||||
|
||||
int DBCMessageHandler::getCount()
|
||||
{
|
||||
return messages.count();
|
||||
}
|
||||
|
||||
DBCFile::DBCFile()
|
||||
{
|
||||
messageHandler = new DBCMessageHandler;
|
||||
}
|
||||
|
||||
DBCFile::DBCFile(const DBCFile& cpy)
|
||||
{
|
||||
messageHandler = new DBCMessageHandler;
|
||||
for (int i = 0 ; i < cpy.messageHandler->getCount() ; i++)
|
||||
messageHandler->addMessage(*cpy.messageHandler->findMsgByIdx(i));
|
||||
|
||||
fileName = cpy.fileName;
|
||||
filePath = cpy.filePath;
|
||||
assocBuses = cpy.assocBuses;
|
||||
dbc_nodes.clear();
|
||||
dbc_nodes.append(cpy.dbc_nodes);
|
||||
}
|
||||
|
||||
DBCFile& DBCFile::operator=(const DBCFile& cpy)
|
||||
{
|
||||
if (this != &cpy) // protect against invalid self-assignment
|
||||
{
|
||||
messageHandler = cpy.messageHandler;
|
||||
fileName = cpy.fileName;
|
||||
filePath = cpy.filePath;
|
||||
assocBuses = cpy.assocBuses;
|
||||
dbc_nodes.clear();
|
||||
dbc_nodes.append(cpy.dbc_nodes);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DBC_NODE* DBCFile::findNodeByIdx(int idx)
|
||||
{
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= dbc_nodes.count()) return NULL;
|
||||
return &dbc_nodes[idx];
|
||||
}
|
||||
|
||||
DBC_NODE* DBCFile::findNodeByName(QString name)
|
||||
{
|
||||
if (dbc_nodes.length() == 0) return NULL;
|
||||
for (int i = 0; i < dbc_nodes.length(); i++)
|
||||
{
|
||||
if (dbc_nodes[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &dbc_nodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString DBCFile::getFullFilename()
|
||||
{
|
||||
return filePath + fileName;
|
||||
}
|
||||
|
||||
QString DBCFile::getFilename()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
QString DBCFile::getPath()
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
|
||||
int DBCFile::getAssocBus()
|
||||
{
|
||||
return assocBuses;
|
||||
}
|
||||
|
||||
void DBCFile::setAssocBus(int bus)
|
||||
{
|
||||
if (bus < -1) return;
|
||||
if (bus > 1) return;
|
||||
assocBuses = bus;
|
||||
}
|
||||
|
||||
void DBCFile::loadFile(QString fileName)
|
||||
{
|
||||
QFile *inFile = new QFile(fileName);
|
||||
QString line;
|
||||
QRegularExpression regex;
|
||||
QRegularExpressionMatch match;
|
||||
DBC_MESSAGE *currentMessage = NULL;
|
||||
int numSigFaults = 0, numMsgFaults = 0;
|
||||
|
||||
qDebug() << "DBC File: " << filename;
|
||||
qDebug() << "DBC File: " << fileName;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -27,7 +268,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
|
||||
qDebug() << "Starting DBC load";
|
||||
dbc_nodes.clear();
|
||||
dbc_messages.clear();
|
||||
messageHandler->removeAllMessages();
|
||||
|
||||
DBC_NODE falseNode;
|
||||
falseNode.name = "Vector__XXX";
|
||||
@@ -36,9 +277,9 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
line = QString(inFile->readLine().simplified());
|
||||
if (line.startsWith("BO_ "))
|
||||
if (line.startsWith("BO_ ")) //defines a message
|
||||
{
|
||||
//qDebug() << "Found a BO line";
|
||||
qDebug() << "Found a BO line";
|
||||
regex.setPattern("^BO\\_ (\\w+) (\\w+) *: (\\w+) (\\w+)");
|
||||
match = regex.match(line);
|
||||
//captured 1 = the ID in decimal
|
||||
@@ -52,16 +293,55 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
msg.name = match.captured(2);
|
||||
msg.len = match.captured(3).toInt();
|
||||
msg.sender = findNodeByName(match.captured(4));
|
||||
dbc_messages.append(msg);
|
||||
currentMessage = &dbc_messages.last();
|
||||
messageHandler->addMessage(msg);
|
||||
currentMessage = messageHandler->findMsgByID(msg.ID);
|
||||
}
|
||||
else numMsgFaults++;
|
||||
}
|
||||
if (line.startsWith("SG_ "))
|
||||
if (line.startsWith("SG_ ")) //defines a signal
|
||||
{
|
||||
//qDebug() << "Found a SG line";
|
||||
regex.setPattern("^SG\\_ (\\w+) : (\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)");
|
||||
int offset = 0;
|
||||
bool isMultiplexor = false;
|
||||
bool isMultiplexed = false;
|
||||
DBC_SIGNAL sig;
|
||||
|
||||
sig.multiplexValue = 0;
|
||||
sig.isMultiplexed = false;
|
||||
sig.isMultiplexor = false;
|
||||
|
||||
qDebug() << "Found a SG line";
|
||||
regex.setPattern("^SG\\_ *(\\w+) *M *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)");
|
||||
|
||||
match = regex.match(line);
|
||||
if (match.hasMatch())
|
||||
{
|
||||
qDebug() << "Multiplexor signal";
|
||||
isMultiplexor = true;
|
||||
sig.isMultiplexor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
regex.setPattern("^SG\\_ *(\\w+) *m(\\d+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)");
|
||||
match = regex.match(line);
|
||||
if (match.hasMatch())
|
||||
{
|
||||
qDebug() << "Multiplexed signal";
|
||||
isMultiplexed = true;
|
||||
sig.isMultiplexed = true;
|
||||
sig.multiplexValue = match.captured(2).toInt();
|
||||
offset = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
regex.setPattern("^SG\\_ *(\\w+) *: *(\\d+)\\|(\\d+)@(\\d+)([\\+|\\-]) \\(([0-9.+\\-eE]+),([0-9.+\\-eE]+)\\) \\[([0-9.+\\-eE]+)\\|([0-9.+\\-eE]+)\\] \\\"(.*)\\\" (.*)");
|
||||
match = regex.match(line);
|
||||
sig.isMultiplexed = false;
|
||||
sig.isMultiplexor = false;
|
||||
}
|
||||
}
|
||||
|
||||
//captured 1 is the signal name
|
||||
//captured 2 would be multiplex value if this is a multiplex signal. Then offset the rest of these by 1
|
||||
//captured 2 is the starting bit
|
||||
//captured 3 is the length in bits
|
||||
//captured 4 is the byte order / value type
|
||||
@@ -75,14 +355,13 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
|
||||
if (match.hasMatch())
|
||||
{
|
||||
DBC_SIGNAL sig;
|
||||
sig.name = match.captured(1);
|
||||
sig.startBit = match.captured(2).toInt();
|
||||
sig.signalSize = match.captured(3).toInt();
|
||||
int val = match.captured(4).toInt();
|
||||
sig.startBit = match.captured(2 + offset).toInt();
|
||||
sig.signalSize = match.captured(3 + offset).toInt();
|
||||
int val = match.captured(4 + offset).toInt();
|
||||
if (val < 2)
|
||||
{
|
||||
if (match.captured(5) == "+") sig.valType = UNSIGNED_INT;
|
||||
if (match.captured(5 + offset) == "+") sig.valType = UNSIGNED_INT;
|
||||
else sig.valType = SIGNED_INT;
|
||||
}
|
||||
switch (val)
|
||||
@@ -103,23 +382,26 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
sig.valType = STRING;
|
||||
break;
|
||||
}
|
||||
sig.factor = match.captured(6).toDouble();
|
||||
sig.bias = match.captured(7).toDouble();
|
||||
sig.min = match.captured(8).toDouble();
|
||||
sig.max = match.captured(9).toDouble();
|
||||
sig.unitName = match.captured(10);
|
||||
if (match.captured(11).contains(','))
|
||||
sig.factor = match.captured(6 + offset).toDouble();
|
||||
sig.bias = match.captured(7 + offset).toDouble();
|
||||
sig.min = match.captured(8 + offset).toDouble();
|
||||
sig.max = match.captured(9 + offset).toDouble();
|
||||
sig.unitName = match.captured(10 + offset);
|
||||
if (match.captured(11 + offset).contains(','))
|
||||
{
|
||||
QString tmp = match.captured(11).split(',')[0];
|
||||
sig.receiver = findNodeByName(tmp);
|
||||
}
|
||||
else sig.receiver = findNodeByName(match.captured(11));
|
||||
currentMessage->msgSignals.append(sig);
|
||||
else sig.receiver = findNodeByName(match.captured(11 + offset));
|
||||
sig.parentMessage = currentMessage;
|
||||
currentMessage->sigHandler->addSignal(sig);
|
||||
if (isMultiplexor) currentMessage->multiplexorSignal = currentMessage->sigHandler->findSignalByName(sig.name);
|
||||
}
|
||||
else numSigFaults++;
|
||||
}
|
||||
if (line.startsWith("BU_:"))
|
||||
if (line.startsWith("BU_:")) //line specifies the nodes on this canbus
|
||||
{
|
||||
//qDebug() << "Found a BU line";
|
||||
qDebug() << "Found a BU line";
|
||||
regex.setPattern("^BU\\_\\:(.*)");
|
||||
match = regex.match(line);
|
||||
//captured 1 = a list of node names separated by spaces. No idea how many yet
|
||||
@@ -141,7 +423,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
}
|
||||
if (line.startsWith("CM_ SG_ "))
|
||||
{
|
||||
//qDebug() << "Found an SG comment line";
|
||||
qDebug() << "Found an SG comment line";
|
||||
regex.setPattern("^CM\\_ SG\\_ *(\\w+) *(\\w+) *\\\"(.*)\\\";");
|
||||
match = regex.match(line);
|
||||
//captured 1 is the ID to match against to get to the message
|
||||
@@ -150,10 +432,10 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Comment was: " << match.captured(3);
|
||||
DBC_MESSAGE *msg = findMsgByID(match.captured(1).toInt());
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
{
|
||||
DBC_SIGNAL *sig = findSignalByName(msg, match.captured(2));
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
|
||||
if (sig != NULL)
|
||||
{
|
||||
sig->comment = match.captured(3);
|
||||
@@ -163,7 +445,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
}
|
||||
if (line.startsWith("CM_ BO_ "))
|
||||
{
|
||||
//qDebug() << "Found a BO comment line";
|
||||
qDebug() << "Found a BO comment line";
|
||||
regex.setPattern("^CM\\_ BO\\_ *(\\w+) *\\\"(.*)\\\";");
|
||||
match = regex.match(line);
|
||||
//captured 1 is the ID to match against to get to the message
|
||||
@@ -171,7 +453,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Comment was: " << match.captured(2);
|
||||
DBC_MESSAGE *msg = findMsgByID(match.captured(1).toInt());
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
{
|
||||
msg->comment = match.captured(2);
|
||||
@@ -180,7 +462,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
}
|
||||
if (line.startsWith("CM_ BU_ "))
|
||||
{
|
||||
//qDebug() << "Found a BU comment line";
|
||||
qDebug() << "Found a BU comment line";
|
||||
regex.setPattern("^CM\\_ BU\\_ *(\\w+) *\\\"(.*)\\\";");
|
||||
match = regex.match(line);
|
||||
//captured 1 is the Node name
|
||||
@@ -198,7 +480,7 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
//VAL_ (1090) (VCUPresentParkLightOC) (1 "Error present" 0 "Error not present") ;
|
||||
if (line.startsWith("VAL_ "))
|
||||
{
|
||||
//qDebug() << "Found a value definition line";
|
||||
qDebug() << "Found a value definition line";
|
||||
regex.setPattern("^VAL\\_ (\\w+) (\\w+) (.*);");
|
||||
match = regex.match(line);
|
||||
//captured 1 is the ID to match against
|
||||
@@ -207,10 +489,10 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
if (match.hasMatch())
|
||||
{
|
||||
//qDebug() << "Data was: " << match.captured(3);
|
||||
DBC_MESSAGE *msg = findMsgByID(match.captured(1).toInt());
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByID(match.captured(1).toInt());
|
||||
if (msg != NULL)
|
||||
{
|
||||
DBC_SIGNAL *sig = findSignalByName(msg, match.captured(2));
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(match.captured(2));
|
||||
if (sig != NULL)
|
||||
{
|
||||
QString tokenString = match.captured(3);
|
||||
@@ -260,16 +542,28 @@ void DBCHandler::loadDBCFile(QString filename)
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (numSigFaults > 0 || numMsgFaults > 0)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
QString msg = "DBC file loaded with errors!\n";
|
||||
msg += "Number of faulty message entries: " + QString::number(numMsgFaults) + "\n";
|
||||
msg += "Number of faulty signal entries: " + QString::number(numSigFaults) + "\n\n";
|
||||
msg += "Faulty entries have not been loaded.";
|
||||
msgBox.setText(msg);
|
||||
msgBox.exec();
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
QStringList fileList = fileName.split('/');
|
||||
this->fileName = fileList[fileList.length() - 1]; //whoops... same name as parameter in this function.
|
||||
filePath = fileName.left(fileName.length() - this->fileName.length());
|
||||
assocBuses = -1;
|
||||
|
||||
}
|
||||
|
||||
/*Yes, this is really hard to follow and all of the sections are mixed up in code
|
||||
* believe it or not I think this is actually the easiest, simplest way to do it.
|
||||
*/
|
||||
void DBCHandler::saveDBCFile(QString filename)
|
||||
void DBCFile::saveFile(QString fileName)
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
QFile *outFile = new QFile(fileName);
|
||||
QString nodesOutput, msgOutput, commentsOutput, valuesOutput;
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
@@ -330,27 +624,36 @@ void DBCHandler::saveDBCFile(QString filename)
|
||||
nodesOutput.append("\n");
|
||||
outFile->write(nodesOutput.toUtf8());
|
||||
|
||||
for (int x = 0; x < dbc_messages.count(); x++)
|
||||
for (int x = 0; x < messageHandler->getCount(); x++)
|
||||
{
|
||||
DBC_MESSAGE msg = dbc_messages[x];
|
||||
msgOutput.append("BO_ " + QString::number(msg.ID) + " " + msg.name + ": " + QString::number(msg.len) +
|
||||
" " + msg.sender->name + "\n");
|
||||
if (msg.comment.length() > 0)
|
||||
DBC_MESSAGE *msg = messageHandler->findMsgByIdx(x);
|
||||
msgOutput.append("BO_ " + QString::number(msg->ID) + " " + msg->name + ": " + QString::number(msg->len) +
|
||||
" " + msg->sender->name + "\n");
|
||||
if (msg->comment.length() > 0)
|
||||
{
|
||||
commentsOutput.append("CM_ BO_ " + QString::number(msg.ID) + " \"" + msg.comment + "\";\n");
|
||||
commentsOutput.append("CM_ BO_ " + QString::number(msg->ID) + " \"" + msg->comment + "\";\n");
|
||||
}
|
||||
for (int s = 0; s < msg.msgSignals.count(); s++)
|
||||
for (int s = 0; s < msg->sigHandler->getCount(); s++)
|
||||
{
|
||||
DBC_SIGNAL sig = msg.msgSignals[s];
|
||||
msgOutput.append(" SG_ " + sig.name + " : " + QString::number(sig.startBit) + "|" + QString::number(sig.signalSize) + "@");
|
||||
switch (sig.valType)
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByIdx(s);
|
||||
msgOutput.append(" SG_ " + sig->name);
|
||||
|
||||
if (sig->isMultiplexor) msgOutput.append(" M");
|
||||
if (sig->isMultiplexed)
|
||||
{
|
||||
msgOutput.append(" m" + QString::number(sig->multiplexValue));
|
||||
}
|
||||
|
||||
msgOutput.append(" : " + QString::number(sig->startBit) + "|" + QString::number(sig->signalSize) + "@");
|
||||
|
||||
switch (sig->valType)
|
||||
{
|
||||
case UNSIGNED_INT:
|
||||
if (sig.intelByteOrder) msgOutput.append("1+");
|
||||
if (sig->intelByteOrder) msgOutput.append("1+");
|
||||
else msgOutput.append("0+");
|
||||
break;
|
||||
case SIGNED_INT:
|
||||
if (sig.intelByteOrder) msgOutput.append("1-");
|
||||
if (sig->intelByteOrder) msgOutput.append("1-");
|
||||
else msgOutput.append("0-");
|
||||
break;
|
||||
case SP_FLOAT:
|
||||
@@ -366,19 +669,19 @@ void DBCHandler::saveDBCFile(QString filename)
|
||||
msgOutput.append("0-");
|
||||
break;
|
||||
}
|
||||
msgOutput.append(" (" + QString::number(sig.factor) + "," + QString::number(sig.bias) + ") [" +
|
||||
QString::number(sig.min) + "|" + QString::number(sig.max) + "] \"" + sig.unitName
|
||||
+ "\" " + sig.receiver->name + "\n");
|
||||
if (sig.comment.length() > 0)
|
||||
msgOutput.append(" (" + QString::number(sig->factor) + "," + QString::number(sig->bias) + ") [" +
|
||||
QString::number(sig->min) + "|" + QString::number(sig->max) + "] \"" + sig->unitName
|
||||
+ "\" " + sig->receiver->name + "\n");
|
||||
if (sig->comment.length() > 0)
|
||||
{
|
||||
commentsOutput.append("CM_ SG_ " + QString::number(msg.ID) + " " + sig.name + " \"" + sig.comment + "\";\n");
|
||||
commentsOutput.append("CM_ SG_ " + QString::number(msg->ID) + " " + sig->name + " \"" + sig->comment + "\";\n");
|
||||
}
|
||||
if (sig.valList.count() > 0)
|
||||
if (sig->valList.count() > 0)
|
||||
{
|
||||
valuesOutput.append("VAL_ " + QString::number(msg.ID) + " " + sig.name);
|
||||
for (int v = 0; v < sig.valList.count(); v++)
|
||||
valuesOutput.append("VAL_ " + QString::number(msg->ID) + " " + sig->name);
|
||||
for (int v = 0; v < sig->valList.count(); v++)
|
||||
{
|
||||
DBC_VAL val = sig.valList[v];
|
||||
DBC_VAL val = sig->valList[v];
|
||||
valuesOutput.append(" " + QString::number(val.value) + " \"" + val.descript +"\"");
|
||||
}
|
||||
valuesOutput.append(";\n");
|
||||
@@ -396,250 +699,140 @@ void DBCHandler::saveDBCFile(QString filename)
|
||||
|
||||
outFile->close();
|
||||
delete outFile;
|
||||
|
||||
QStringList fileList = fileName.split('/');
|
||||
this->fileName = fileList[fileList.length() - 1]; //whoops... same name as parameter in this function.
|
||||
filePath = fileName.left(fileName.length() - this->fileName.length());
|
||||
}
|
||||
|
||||
|
||||
DBC_NODE *DBCHandler::findNodeByName(QString name)
|
||||
void DBCHandler::saveDBCFile(int idx)
|
||||
{
|
||||
if (dbc_nodes.length() == 0) return NULL;
|
||||
for (int i = 0; i < dbc_nodes.length(); i++)
|
||||
if (loadedFiles.count() == 0) return;
|
||||
if (idx < 0) return;
|
||||
if (idx >= loadedFiles.count()) return;
|
||||
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("DBC File (*.dbc)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.selectFile(loadedFiles[idx].getFullFilename());
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
if (dbc_nodes[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &dbc_nodes[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBC_NODE *DBCHandler::findNodeByIdx(int idx)
|
||||
{
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= dbc_nodes.count()) return NULL;
|
||||
return &dbc_nodes[idx];
|
||||
}
|
||||
|
||||
DBC_MESSAGE *DBCHandler::findMsgByID(int id)
|
||||
{
|
||||
if (dbc_messages.length() == 0) return NULL;
|
||||
for (int i = 0; i < dbc_messages.length(); i++)
|
||||
{
|
||||
if (dbc_messages[i].ID == id)
|
||||
{
|
||||
return &dbc_messages[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBC_MESSAGE *DBCHandler::findMsgByIdx(int idx)
|
||||
{
|
||||
if (dbc_messages.length() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= dbc_messages.count()) return NULL;
|
||||
return &dbc_messages[idx];
|
||||
}
|
||||
|
||||
DBC_MESSAGE *DBCHandler::findMsgByName(QString name)
|
||||
{
|
||||
if (dbc_messages.length() == 0) return NULL;
|
||||
for (int i = 0; i < dbc_messages.length(); i++)
|
||||
{
|
||||
if (dbc_messages[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &dbc_messages[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBC_SIGNAL *DBCHandler::findSignalByName(DBC_MESSAGE *msg, QString name)
|
||||
{
|
||||
if (msg == NULL) return NULL;
|
||||
if (msg->msgSignals.length() == 0) return NULL;
|
||||
for (int i = 0; i < msg->msgSignals.length(); i++)
|
||||
{
|
||||
if (msg->msgSignals[i].name.compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &msg->msgSignals[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBC_SIGNAL *DBCHandler::findSignalByIdx(DBC_MESSAGE *msg, int idx)
|
||||
{
|
||||
if (msg == NULL) return NULL;
|
||||
if (msg->msgSignals.length() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= msg->msgSignals.count()) return NULL;
|
||||
return &msg->msgSignals[idx];
|
||||
}
|
||||
|
||||
//Dumps the messages, signals, values structs out in order to debugging console. Used only for debugging
|
||||
//not really meant for general consumption.
|
||||
void DBCHandler::listDebugging()
|
||||
{
|
||||
for (int i = 0; i < dbc_messages.length(); i++)
|
||||
{
|
||||
DBC_MESSAGE msg = dbc_messages.at(i);
|
||||
qDebug() << " ";
|
||||
qDebug() << "Msg ID: " << msg.ID << " Name: " << msg.name;
|
||||
|
||||
for (int j = 0; j < msg.msgSignals.length(); j++)
|
||||
{
|
||||
DBC_SIGNAL sig;
|
||||
sig = msg.msgSignals.at(j);
|
||||
qDebug() << " Signal Name: " << sig.name;
|
||||
qDebug() << " Start bit: " << sig.startBit;
|
||||
qDebug() << " Bit Length: " << sig.signalSize;
|
||||
if (sig.valList.length() > 1) qDebug() << " Values: ";
|
||||
for (int k = 0; k < sig.valList.length(); k++)
|
||||
{
|
||||
DBC_VAL val = sig.valList.at(k);
|
||||
qDebug() << " " << val.value << " Description: " << val.descript;
|
||||
}
|
||||
}
|
||||
filename = dialog.selectedFiles()[0];
|
||||
if (!filename.contains('.')) filename += ".dbc";
|
||||
loadedFiles[idx].saveFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
int DBCHandler::createBlankFile()
|
||||
{
|
||||
DBCFile newFile;
|
||||
loadedFiles.append(newFile);
|
||||
return loadedFiles.count();
|
||||
}
|
||||
|
||||
//the only reason to even bother sending the index is to see if
|
||||
//the user wants to replace an already loaded DBC.
|
||||
//Otherwise add a new one. Well, always add a new one.
|
||||
//If a valid index is passed we'll remove that one and then commence
|
||||
//adding. Otherwise, just go straight to adding.
|
||||
DBCFile* DBCHandler::loadDBCFile(int idx)
|
||||
{
|
||||
if (idx > -1 && idx < loadedFiles.count()) removeDBCFile(idx);
|
||||
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("DBC File (*.dbc)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
//right now there is only one file type that can be loaded here so just do it.
|
||||
DBCFile newFile;
|
||||
newFile.loadFile(filename);
|
||||
loadedFiles.append(newFile);
|
||||
}
|
||||
return &loadedFiles.last();
|
||||
}
|
||||
|
||||
void DBCHandler::removeDBCFile(int idx)
|
||||
{
|
||||
if (loadedFiles.count() == 0) return;
|
||||
if (idx < 0) return;
|
||||
if (idx >= loadedFiles.count()) return;
|
||||
loadedFiles.removeAt(idx);
|
||||
}
|
||||
|
||||
void DBCHandler::removeAllFiles()
|
||||
{
|
||||
loadedFiles.clear();
|
||||
}
|
||||
|
||||
void DBCHandler::swapFiles(int pos1, int pos2)
|
||||
{
|
||||
if (loadedFiles.count() < 2) return;
|
||||
if (pos1 < 0) return;
|
||||
if (pos1 >= loadedFiles.count()) return;
|
||||
if (pos2 < 0) return;
|
||||
if (pos2 >= loadedFiles.count()) return;
|
||||
|
||||
loadedFiles.swap(pos1, pos2);
|
||||
}
|
||||
|
||||
/*
|
||||
The way that the DBC file format works is kind of weird... For intel format signals you count up
|
||||
from the start bit to the end bit which is (startbit + signallength - 1). At each point
|
||||
bits are numbered in a sawtooth manner. What that means is that the very first bit is 0 and you count up
|
||||
from there all of the way to 63 with each byte being 8 bits so bit 0 is the lowest bit in the first byte
|
||||
and 8 is the lowest bit in the next byte up. The whole thing looks like this:
|
||||
Bits
|
||||
7 6 5 4 3 2 1 0
|
||||
|
||||
0 7 6 5 4 3 2 1 0
|
||||
b 1 15 14 13 12 11 10 9 8
|
||||
y 2 23 22 21 20 19 18 17 16
|
||||
t 3 31 30 29 28 27 26 25 24
|
||||
e 4 39 38 37 36 35 34 33 32
|
||||
s 5 47 46 45 44 43 42 41 40
|
||||
6 55 54 53 52 51 50 49 48
|
||||
7 63 62 61 60 59 58 57 56
|
||||
|
||||
For intel format you start at the start bit and keep counting up. If you have a signal size of 8
|
||||
and start at bit 12 then the bits are 12, 13, 14, 15, 16, 17, 18, 19 which spans across two bytes.
|
||||
In this format each bit is worth twice as much as the last and you just keep counting up.
|
||||
Bit 12 is worth 1, 13 is worth 2, 14 is worth 4, etc all of the way to bit 19 is worth 128.
|
||||
|
||||
Motorola format turns most everything on its head. You count backward from the start bit but
|
||||
only within the current byte. If you are about to exit the current byte you go one higher and then keep
|
||||
going backward as before. Using the same example as for intel, start bit of 12 and a signal length of 8.
|
||||
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.
|
||||
* Convenience function that encapsulates a whole lot of the details.
|
||||
* You give it a canbus frame and it'll tell you whether there is a loaded DBC file that can
|
||||
* interpret that frame for you.
|
||||
* Returns NULL if there is no message definition that matches.
|
||||
*/
|
||||
|
||||
QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig)
|
||||
DBC_MESSAGE* DBCHandler::findMessage(const CANFrame &frame)
|
||||
{
|
||||
|
||||
int64_t result = 0;
|
||||
int bit;
|
||||
int sigSize;
|
||||
if (sig.valType == STRING)
|
||||
for(int i = 0; i < loadedFiles.count(); i++)
|
||||
{
|
||||
QString buildString;
|
||||
int startByte = sig.signalSize / 8;
|
||||
int bytes = sig.signalSize / 8;
|
||||
for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]);
|
||||
return buildString;
|
||||
}
|
||||
|
||||
sigSize = sig.signalSize;
|
||||
|
||||
if (sig.intelByteOrder)
|
||||
{
|
||||
bit = sig.startBit;
|
||||
for (int bitpos = 0; bitpos < sigSize; bitpos++)
|
||||
if (loadedFiles[i].getAssocBus() == -1 || frame.bus == loadedFiles[i].getAssocBus())
|
||||
{
|
||||
if (frame.data[bit / 8] & (1 << (bit % 8)))
|
||||
result += (1ULL << bitpos);
|
||||
|
||||
bit++;
|
||||
DBC_MESSAGE* msg = loadedFiles[i].messageHandler->findMsgByID(frame.ID);
|
||||
if (msg != NULL) return msg;
|
||||
}
|
||||
}
|
||||
else //motorola / big endian mode
|
||||
{
|
||||
bit = sig.startBit;
|
||||
for (int bitpos = 0; bitpos < sigSize; bitpos++)
|
||||
{
|
||||
if (frame.data[bit / 8] & (1 << (bit % 8)))
|
||||
result += (1ULL << (sigSize - bitpos - 1));
|
||||
|
||||
if ((bit % 8) == 0)
|
||||
bit += 15;
|
||||
else bit--;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (sig.valType == SIGNED_INT)
|
||||
{
|
||||
int mask = (1 << (sig.signalSize - 1));
|
||||
if ((result & mask) == mask) //is the highest bit possible for this signal size set?
|
||||
{
|
||||
/*
|
||||
* if so we need to also set every bit higher in the result int too.
|
||||
* This leads to the below two lines that are nasty. Here's the theory behind that...
|
||||
* If the value is signed and the highest bit is set then it is negative. To create
|
||||
* a negative value out of this even though the variable result is 64 bit we have to
|
||||
* run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer
|
||||
* you have. So, it's 64 1's in this case.
|
||||
* signedMask is done this way:
|
||||
* first you take the signal size and shift 1 up that far. Then subtract one. Lets
|
||||
* see that for a 16 bit signal:
|
||||
* (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole
|
||||
* thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal
|
||||
* doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on
|
||||
* it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the
|
||||
* actual signal. This extends the sign bits out so that the integer result reads as the proper negative
|
||||
* value. We dont need to do any of this if the sign bit wasn't set.
|
||||
*/
|
||||
int signedMask = ~((1 << sig.signalSize) - 1);
|
||||
result = (-1 & signedMask) | result;
|
||||
}
|
||||
}
|
||||
|
||||
double endResult = ((double)result * sig.factor) + sig.bias;
|
||||
result = (int) endResult;
|
||||
|
||||
QString outputString;
|
||||
|
||||
outputString = sig.name + ": ";
|
||||
|
||||
if (sig.valList.count() > 0) //if this is a value list type then look it up and display the proper string
|
||||
{
|
||||
for (int x = 0; x < sig.valList.count(); x++)
|
||||
{
|
||||
if (sig.valList.at(x).value == result) outputString += sig.valList.at(x).descript;
|
||||
}
|
||||
}
|
||||
else //otherwise display the actual number and unit (if it exists)
|
||||
{
|
||||
outputString += QString::number(endResult) + sig.unitName;
|
||||
}
|
||||
|
||||
return outputString;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//given a byte it will reverse the bit order in that byte
|
||||
unsigned char DBCHandler::reverseBits(unsigned char b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
unsigned char DBCHandler::processByte(unsigned char input, int start, int end)
|
||||
int DBCHandler::getFileCount()
|
||||
{
|
||||
unsigned char output = 0, size = end - start + 1;
|
||||
//first knock it down so that bottom is is start
|
||||
output = input >> start;
|
||||
//then mask off all bits above the proper ending
|
||||
output &= ((1 << size) - 1);
|
||||
return output;
|
||||
return loadedFiles.count();
|
||||
}
|
||||
|
||||
DBCFile* DBCHandler::getFileByIdx(int idx)
|
||||
{
|
||||
if (loadedFiles.count() == 0) return NULL;
|
||||
if (idx < 0) return NULL;
|
||||
if (idx >= loadedFiles.count()) return NULL;
|
||||
return &loadedFiles[idx];
|
||||
}
|
||||
|
||||
DBCFile* DBCHandler::getFileByName(QString name)
|
||||
{
|
||||
if (loadedFiles.count() == 0) return NULL;
|
||||
for (int i = 0; i < loadedFiles.count(); i++)
|
||||
{
|
||||
if (loadedFiles[i].getFilename().compare(name, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
return &loadedFiles[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+69
-19
@@ -6,40 +6,90 @@
|
||||
#include "can_structs.h"
|
||||
|
||||
/*
|
||||
* For ease of quick testing and development this is all run together.
|
||||
* It should be decoupled once the functionality is confirmed.
|
||||
* TODO:
|
||||
* Finish coding up the decoupled design
|
||||
*
|
||||
*/
|
||||
|
||||
class DBCHandler : public QObject
|
||||
|
||||
class DBCSignalHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DBCHandler(QObject *parent = 0);
|
||||
void loadDBCFile(QString);
|
||||
void saveDBCFile(QString);
|
||||
void listDebugging();
|
||||
QString processSignal(const CANFrame &frame, const DBC_SIGNAL &sig);
|
||||
DBC_NODE *findNodeByName(QString name);
|
||||
DBC_NODE *findNodeByIdx(int idx);
|
||||
DBC_SIGNAL *findSignalByName(QString name);
|
||||
DBC_SIGNAL *findSignalByIdx(int idx);
|
||||
bool addSignal(DBC_SIGNAL &sig);
|
||||
bool removeSignal(DBC_SIGNAL *sig);
|
||||
bool removeSignal(int idx);
|
||||
bool removeSignal(QString name);
|
||||
void removeAllSignals();
|
||||
int getCount();
|
||||
private:
|
||||
QList<DBC_SIGNAL> sigs; //signals is a reserved word or I'd have used that
|
||||
};
|
||||
|
||||
class DBCMessageHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DBC_MESSAGE *findMsgByID(int id);
|
||||
DBC_MESSAGE *findMsgByIdx(int idx);
|
||||
DBC_MESSAGE *findMsgByName(QString name);
|
||||
bool addMessage(DBC_MESSAGE &msg);
|
||||
bool removeMessage(DBC_MESSAGE *msg);
|
||||
bool removeMessageByIndex(int idx);
|
||||
bool removeMessage(int ID);
|
||||
bool removeMessage(QString name);
|
||||
void removeAllMessages();
|
||||
int getCount();
|
||||
private:
|
||||
QList<DBC_MESSAGE> messages;
|
||||
};
|
||||
|
||||
DBC_SIGNAL *findSignalByName(DBC_MESSAGE *msg, QString name);
|
||||
DBC_SIGNAL *findSignalByIdx(DBC_MESSAGE *msg, int idx);
|
||||
//technically there should be a node handler too but I'm sort of treating nodes as second class
|
||||
//citizens since they aren't really all that important (to me anyway)
|
||||
class DBCFile: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DBCFile();
|
||||
DBCFile(const DBCFile& cpy);
|
||||
DBCFile& operator=(const DBCFile& cpy);
|
||||
DBC_NODE *findNodeByName(QString name);
|
||||
DBC_NODE *findNodeByIdx(int idx);
|
||||
void saveFile(QString);
|
||||
void loadFile(QString);
|
||||
QString getFullFilename();
|
||||
QString getFilename();
|
||||
QString getPath();
|
||||
int getAssocBus();
|
||||
void setAssocBus(int bus);
|
||||
|
||||
DBCMessageHandler *messageHandler;
|
||||
QList<DBC_NODE> dbc_nodes;
|
||||
QList<DBC_MESSAGE> dbc_messages;
|
||||
private:
|
||||
QString fileName;
|
||||
QString filePath;
|
||||
int assocBuses; //-1 = all buses, 0 = first bus, 1 = second bus
|
||||
};
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
class DBCHandler: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DBCFile* loadDBCFile(int);
|
||||
void saveDBCFile(int);
|
||||
void removeDBCFile(int);
|
||||
void removeAllFiles();
|
||||
void swapFiles(int pos1, int pos2);
|
||||
DBC_MESSAGE* findMessage(const CANFrame &frame);
|
||||
int getFileCount();
|
||||
DBCFile* getFileByIdx(int idx);
|
||||
DBCFile* getFileByName(QString name);
|
||||
int createBlankFile();
|
||||
|
||||
private:
|
||||
|
||||
unsigned char reverseBits(unsigned char);
|
||||
unsigned char processByte(unsigned char, int, int);
|
||||
QList<DBCFile> loadedFiles;
|
||||
};
|
||||
|
||||
#endif // DBCHANDLER_H
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "dbcloadsavewindow.h"
|
||||
#include "ui_dbcloadsavewindow.h"
|
||||
|
||||
DBCLoadSaveWindow::DBCLoadSaveWindow(DBCHandler *handler, const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::DBCLoadSaveWindow)
|
||||
{
|
||||
|
||||
dbcHandler = handler;
|
||||
referenceFrames = frames;
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
QStringList header;
|
||||
header << "Filename" << "Associated Bus";
|
||||
ui->tableFiles->setColumnCount(2);
|
||||
ui->tableFiles->setHorizontalHeaderLabels(header);
|
||||
ui->tableFiles->setColumnWidth(0, 355);
|
||||
ui->tableFiles->setColumnWidth(1, 125);
|
||||
|
||||
connect(ui->btnEdit, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::editFile);
|
||||
connect(ui->btnLoad, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::loadFile);
|
||||
connect(ui->btnMoveDown, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::moveDown);
|
||||
connect(ui->btnMoveUp, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::moveUp);
|
||||
connect(ui->btnRemove, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::removeFile);
|
||||
connect(ui->btnSave, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::saveFile);
|
||||
connect(ui->btnNewDBC, &QAbstractButton::clicked, this, &DBCLoadSaveWindow::newFile);
|
||||
connect(ui->tableFiles, &QTableWidget::cellChanged, this, &DBCLoadSaveWindow::cellChanged);
|
||||
connect(ui->tableFiles, &QTableWidget::cellDoubleClicked, this, &DBCLoadSaveWindow::cellDoubleClicked);
|
||||
|
||||
editorWindow = new DBCMainEditor(handler, frames);
|
||||
}
|
||||
|
||||
DBCLoadSaveWindow::~DBCLoadSaveWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::newFile()
|
||||
{
|
||||
int idx = dbcHandler->createBlankFile();
|
||||
idx = ui->tableFiles->rowCount();
|
||||
ui->tableFiles->insertRow(ui->tableFiles->rowCount());
|
||||
ui->tableFiles->setItem(idx, 0, new QTableWidgetItem("UNNAMEDFILE"));
|
||||
ui->tableFiles->setItem(idx, 1, new QTableWidgetItem("-1"));
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::loadFile()
|
||||
{
|
||||
DBCFile *file = dbcHandler->loadDBCFile(-1);
|
||||
int idx = ui->tableFiles->rowCount();
|
||||
ui->tableFiles->insertRow(ui->tableFiles->rowCount());
|
||||
ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(file->getFullFilename()));
|
||||
ui->tableFiles->setItem(idx, 1, new QTableWidgetItem("-1"));
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::saveFile()
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 0) return;
|
||||
dbcHandler->saveDBCFile(idx);
|
||||
//then update the list to show the new file name (if it changed)
|
||||
ui->tableFiles->setItem(idx, 0, new QTableWidgetItem(dbcHandler->getFileByIdx(idx)->getFullFilename()));
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::removeFile()
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 0) return;
|
||||
dbcHandler->removeDBCFile(idx);
|
||||
ui->tableFiles->removeRow(idx);
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::moveUp()
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 1) return;
|
||||
dbcHandler->swapFiles(idx - 1, idx);
|
||||
swapTableRows(true);
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::moveDown()
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 0) return;
|
||||
if (idx > (dbcHandler->getFileCount() - 2)) return;
|
||||
dbcHandler->swapFiles(idx, idx + 1);
|
||||
swapTableRows(false);
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::editFile()
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
if (idx < 0) return;
|
||||
|
||||
editorWindow->setFileIdx(idx);
|
||||
editorWindow->show();
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::cellChanged(int row, int col)
|
||||
{
|
||||
if (col == 1) //the bus column
|
||||
{
|
||||
DBCFile *file = dbcHandler->getFileByIdx(row);
|
||||
int bus = ui->tableFiles->item(row, col)->text().toInt();
|
||||
if (bus > -2 && bus < 2)
|
||||
{
|
||||
file->setAssocBus(bus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::cellDoubleClicked(int row, int col)
|
||||
{
|
||||
editorWindow->setFileIdx(row);
|
||||
editorWindow->show();
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::swapTableRows(bool up)
|
||||
{
|
||||
int idx = ui->tableFiles->currentRow();
|
||||
const int destIdx = (up ? idx-1 : idx+1);
|
||||
Q_ASSERT(destIdx >= 0 && destIdx < ui->tableFiles->rowCount());
|
||||
|
||||
// take whole rows
|
||||
QList<QTableWidgetItem*> sourceItems = takeRow(idx);
|
||||
QList<QTableWidgetItem*> destItems = takeRow(destIdx);
|
||||
|
||||
// set back in reverse order
|
||||
setRow(idx, destItems);
|
||||
setRow(destIdx, sourceItems);
|
||||
}
|
||||
|
||||
QList<QTableWidgetItem*> DBCLoadSaveWindow::takeRow(int row)
|
||||
{
|
||||
QList<QTableWidgetItem*> rowItems;
|
||||
for (int col = 0; col < ui->tableFiles->columnCount(); ++col)
|
||||
{
|
||||
rowItems << ui->tableFiles->takeItem(row, col);
|
||||
}
|
||||
return rowItems;
|
||||
}
|
||||
|
||||
void DBCLoadSaveWindow::setRow(int row, const QList<QTableWidgetItem*>& rowItems)
|
||||
{
|
||||
for (int col = 0; col < ui->tableFiles->columnCount(); ++col)
|
||||
{
|
||||
ui->tableFiles->setItem(row, col, rowItems.at(col));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef DBCLOADSAVEWINDOW_H
|
||||
#define DBCLOADSAVEWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTableWidget>
|
||||
#include "dbchandler.h"
|
||||
#include "dbcmaineditor.h"
|
||||
|
||||
namespace Ui {
|
||||
class DBCLoadSaveWindow;
|
||||
}
|
||||
|
||||
class DBCLoadSaveWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DBCLoadSaveWindow(DBCHandler *handler, const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
~DBCLoadSaveWindow();
|
||||
|
||||
private slots:
|
||||
void loadFile();
|
||||
void saveFile();
|
||||
void removeFile();
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
void editFile();
|
||||
void cellChanged(int row, int col);
|
||||
void cellDoubleClicked(int row, int col);
|
||||
void newFile();
|
||||
|
||||
private:
|
||||
Ui::DBCLoadSaveWindow *ui;
|
||||
DBCHandler *dbcHandler;
|
||||
const QVector<CANFrame> *referenceFrames;
|
||||
DBCMainEditor *editorWindow;
|
||||
|
||||
void swapTableRows(bool up);
|
||||
QList<QTableWidgetItem*> takeRow(int row);
|
||||
void setRow(int row, const QList<QTableWidgetItem*>& rowItems);
|
||||
};
|
||||
|
||||
#endif // DBCLOADSAVEWINDOW_H
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DBCLoadSaveWindow</class>
|
||||
<widget class="QDialog" name="DBCLoadSaveWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>506</width>
|
||||
<height>665</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>DBC File Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableFiles"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNewDBC">
|
||||
<property name="text">
|
||||
<string>Create new DBC</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnLoad">
|
||||
<property name="text">
|
||||
<string>Load</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRemove">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMoveUp">
|
||||
<property name="text">
|
||||
<string>Move Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnEdit">
|
||||
<property name="text">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnMoveDown">
|
||||
<property name="text">
|
||||
<string>Move Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+42
-34
@@ -54,8 +54,8 @@ void DBCMainEditor::showEvent(QShowEvent* event)
|
||||
|
||||
inhibitCellChanged = true;
|
||||
refreshNodesTable();
|
||||
if (dbcHandler->dbc_nodes.count() > 0)
|
||||
refreshMessagesTable(&dbcHandler->dbc_nodes.at(0));
|
||||
if (dbcFile->dbc_nodes.count() > 0)
|
||||
refreshMessagesTable(&dbcFile->dbc_nodes.at(0));
|
||||
|
||||
currRow = 0;
|
||||
inhibitCellChanged = false;
|
||||
@@ -67,6 +67,13 @@ DBCMainEditor::~DBCMainEditor()
|
||||
delete sigEditor;
|
||||
}
|
||||
|
||||
void DBCMainEditor::setFileIdx(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return;
|
||||
dbcFile = dbcHandler->getFileByIdx(idx);
|
||||
fileIdx = idx;
|
||||
}
|
||||
|
||||
void DBCMainEditor::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
@@ -123,9 +130,9 @@ void DBCMainEditor::deleteCurrentNode()
|
||||
if (nodeName.length() > 0 && nodeName.compare("Vector__XXX", Qt::CaseInsensitive) != 0)
|
||||
{
|
||||
ui->NodesTable->removeRow(thisRow);
|
||||
dbcHandler->dbc_nodes.removeAt(thisRow);
|
||||
dbcFile->dbc_nodes.removeAt(thisRow);
|
||||
inhibitCellChanged = true;
|
||||
refreshMessagesTable(&dbcHandler->dbc_nodes[0]);
|
||||
refreshMessagesTable(&dbcFile->dbc_nodes[0]);
|
||||
ui->NodesTable->selectRow(0);
|
||||
inhibitCellChanged = false;
|
||||
}
|
||||
@@ -137,7 +144,7 @@ void DBCMainEditor::deleteCurrentMessage()
|
||||
if (ui->MessagesTable->item(thisRow, 0)->text().length() > 0)
|
||||
{
|
||||
ui->MessagesTable->removeRow(thisRow);
|
||||
dbcHandler->dbc_messages.removeAt(thisRow);
|
||||
dbcFile->messageHandler->removeMessageByIndex(thisRow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +163,7 @@ void DBCMainEditor::onCellChangedNode(int row,int col)
|
||||
QString newName = ui->NodesTable->item(row, col)->text().simplified().replace(' ', '_');
|
||||
qDebug() << "new name: " << newName;
|
||||
if (newName.length() == 0) return;
|
||||
if (dbcHandler->findNodeByName(newName) != NULL) //duplicates an existing node!
|
||||
if (dbcFile->findNodeByName(newName) != NULL) //duplicates an existing node!
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setParent(0);
|
||||
@@ -165,8 +172,8 @@ void DBCMainEditor::onCellChangedNode(int row,int col)
|
||||
return;
|
||||
}
|
||||
newNode.name = newName;
|
||||
dbcHandler->dbc_nodes.append(newNode);
|
||||
qDebug() << "# of nodes now " << dbcHandler->dbc_nodes.count();
|
||||
dbcFile->dbc_nodes.append(newNode);
|
||||
qDebug() << "# of nodes now " << dbcFile->dbc_nodes.count();
|
||||
QTableWidgetItem *widgetName = new QTableWidgetItem(newName);
|
||||
inhibitCellChanged = true;
|
||||
ui->NodesTable->setItem(row, col, widgetName);
|
||||
@@ -178,7 +185,7 @@ void DBCMainEditor::onCellChangedNode(int row,int col)
|
||||
{
|
||||
if (col == 0)
|
||||
{
|
||||
DBC_NODE *oldNode = dbcHandler->findNodeByIdx(row);
|
||||
DBC_NODE *oldNode = dbcFile->findNodeByIdx(row);
|
||||
QString nodeName = ui->NodesTable->item(row, col)->text().simplified().replace(' ', '_');
|
||||
if (oldNode == NULL) return;
|
||||
if (row != 0) oldNode->name = nodeName;
|
||||
@@ -192,7 +199,7 @@ void DBCMainEditor::onCellChangedNode(int row,int col)
|
||||
{
|
||||
QString nodeName = ui->NodesTable->item(row, 0)->text().simplified().replace(' ', '_');
|
||||
qDebug() << "searching for node " << nodeName;
|
||||
DBC_NODE *thisNode = dbcHandler->findNodeByName(nodeName);
|
||||
DBC_NODE *thisNode = dbcFile->findNodeByName(nodeName);
|
||||
if (thisNode == NULL) return;
|
||||
thisNode->comment = ui->NodesTable->item(row, col)->text().simplified();
|
||||
qDebug() << "New comment: " << thisNode->comment;
|
||||
@@ -213,7 +220,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
int msgLen;
|
||||
QString msgComment;
|
||||
DBC_MESSAGE newMsg;
|
||||
DBC_NODE *node = dbcHandler->findNodeByIdx(ui->NodesTable->currentRow());
|
||||
DBC_NODE *node = dbcFile->findNodeByIdx(ui->NodesTable->currentRow());
|
||||
DBC_MESSAGE *msg;
|
||||
if (node == NULL)
|
||||
{
|
||||
@@ -224,14 +231,14 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
|
||||
msgID = Utility::ParseStringToNum(ui->MessagesTable->item(row, 0)->text());
|
||||
qDebug() << "Msg ID of edited: " << msgID;
|
||||
msg = dbcHandler->findMsgByID(msgID);
|
||||
msg = dbcFile->messageHandler->findMsgByID(msgID);
|
||||
|
||||
switch(col)
|
||||
{
|
||||
case 0: //msg id
|
||||
if (row == ui->MessagesTable->rowCount() - 1) //new record
|
||||
{
|
||||
if (dbcHandler->findMsgByID(msgID) != NULL)
|
||||
if (dbcFile->messageHandler->findMsgByID(msgID) != NULL)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setParent(0);
|
||||
@@ -251,7 +258,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
break;
|
||||
}
|
||||
}
|
||||
dbcHandler->dbc_messages.append(newMsg);
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
else //editing an existing record
|
||||
{
|
||||
@@ -270,7 +277,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
if (msgName.length() == 0) return;
|
||||
if (row == ui->MessagesTable->rowCount() - 1) //new record
|
||||
{
|
||||
if (dbcHandler->findMsgByName(msgName) != NULL)
|
||||
if (dbcFile->messageHandler->findMsgByName(msgName) != NULL)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setParent(0);
|
||||
@@ -281,7 +288,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
newMsg.ID = -1;
|
||||
newMsg.name = msgName;
|
||||
newMsg.sender = node;
|
||||
dbcHandler->dbc_messages.append(newMsg);
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -304,7 +311,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
newMsg.name = "";
|
||||
newMsg.len = msgLen;
|
||||
newMsg.sender = node;
|
||||
dbcHandler->dbc_messages.append(newMsg);
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
else //editing an existing record
|
||||
{
|
||||
@@ -328,7 +335,7 @@ void DBCMainEditor::onCellChangedMessage(int row,int col)
|
||||
newMsg.len = 0;
|
||||
newMsg.comment = msgComment;
|
||||
newMsg.sender = node;
|
||||
dbcHandler->dbc_messages.append(newMsg);
|
||||
dbcFile->messageHandler->addMessage(newMsg);
|
||||
}
|
||||
else //editing an existing record
|
||||
{
|
||||
@@ -363,7 +370,7 @@ void DBCMainEditor::onCellClickedNode(int row, int col)
|
||||
|
||||
nodeName = item->text();
|
||||
qDebug() << "Trying to find node with name " << nodeName;
|
||||
DBC_NODE *node = dbcHandler->findNodeByName(nodeName);
|
||||
DBC_NODE *node = dbcFile->findNodeByName(nodeName);
|
||||
//qDebug() << "Address of node: " << (int)node;
|
||||
inhibitCellChanged = true;
|
||||
refreshMessagesTable(node);
|
||||
@@ -376,12 +383,13 @@ void DBCMainEditor::onCellClickedMessage(int row, int col)
|
||||
if (col == 3) //3 is the signals field. If clicked we go to the signals dialog
|
||||
{
|
||||
QString idString = ui->MessagesTable->item(row, 0)->text();
|
||||
DBC_MESSAGE *message = dbcHandler->findMsgByID(Utility::ParseStringToNum(idString));
|
||||
DBC_MESSAGE *message = dbcFile->messageHandler->findMsgByID(Utility::ParseStringToNum(idString));
|
||||
sigEditor->setMessageRef(message);
|
||||
sigEditor->setFileIdx(fileIdx);
|
||||
sigEditor->exec(); //blocks this window from being active until we're done
|
||||
//now update the displayed # of signals
|
||||
inhibitCellChanged = true;
|
||||
QTableWidgetItem *replacement = new QTableWidgetItem(QString::number(message->msgSignals.count()));
|
||||
inhibitCellChanged = true;
|
||||
QTableWidgetItem *replacement = new QTableWidgetItem(QString::number(message->sigHandler->getCount()));
|
||||
ui->MessagesTable->setItem(row, col, replacement);
|
||||
inhibitCellChanged = false;
|
||||
}
|
||||
@@ -394,17 +402,17 @@ void DBCMainEditor::refreshNodesTable()
|
||||
|
||||
int rowIdx;
|
||||
|
||||
if (dbcHandler->findNodeByName("Vector__XXX") == NULL)
|
||||
if (dbcFile->findNodeByName("Vector__XXX") == NULL)
|
||||
{
|
||||
DBC_NODE newNode;
|
||||
newNode.name = "Vector__XXX";
|
||||
newNode.comment = "Default node if no other node is specified";
|
||||
dbcHandler->dbc_nodes.append(newNode);
|
||||
dbcFile->dbc_nodes.append(newNode);
|
||||
}
|
||||
|
||||
for (int x = 0; x < dbcHandler->dbc_nodes.count(); x++)
|
||||
for (int x = 0; x < dbcFile->dbc_nodes.count(); x++)
|
||||
{
|
||||
DBC_NODE node = dbcHandler->dbc_nodes.at(x);
|
||||
DBC_NODE node = dbcFile->dbc_nodes.at(x);
|
||||
QTableWidgetItem *nodeName = new QTableWidgetItem(node.name);
|
||||
QTableWidgetItem *nodeComment = new QTableWidgetItem(node.comment);
|
||||
rowIdx = ui->NodesTable->rowCount();
|
||||
@@ -428,17 +436,17 @@ void DBCMainEditor::refreshMessagesTable(const DBC_NODE *node)
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
for (int x = 0; x < dbcHandler->dbc_messages.count(); x++)
|
||||
for (int x = 0; x < dbcFile->messageHandler->getCount(); x++)
|
||||
{
|
||||
DBC_MESSAGE msg = dbcHandler->dbc_messages.at(x);
|
||||
if (msg.sender == node)
|
||||
DBC_MESSAGE *msg = dbcFile->messageHandler->findMsgByIdx(x);
|
||||
if (msg->sender == node)
|
||||
{
|
||||
//many of these are simplistic first versions just to test functionality.
|
||||
QTableWidgetItem *msgID = new QTableWidgetItem(Utility::formatNumber(msg.ID));
|
||||
QTableWidgetItem *msgName = new QTableWidgetItem(msg.name);
|
||||
QTableWidgetItem *msgLen = new QTableWidgetItem(QString::number(msg.len));
|
||||
QTableWidgetItem *msgSignals = new QTableWidgetItem(QString::number(msg.msgSignals.count()));
|
||||
QTableWidgetItem *msgComment = new QTableWidgetItem(msg.comment);
|
||||
QTableWidgetItem *msgID = new QTableWidgetItem(Utility::formatNumber(msg->ID));
|
||||
QTableWidgetItem *msgName = new QTableWidgetItem(msg->name);
|
||||
QTableWidgetItem *msgLen = new QTableWidgetItem(QString::number(msg->len));
|
||||
QTableWidgetItem *msgSignals = new QTableWidgetItem(QString::number(msg->sigHandler->getCount()));
|
||||
QTableWidgetItem *msgComment = new QTableWidgetItem(msg->comment);
|
||||
|
||||
rowIdx = ui->MessagesTable->rowCount();
|
||||
ui->MessagesTable->insertRow(rowIdx);
|
||||
|
||||
@@ -18,6 +18,7 @@ class DBCMainEditor : public QDialog
|
||||
public:
|
||||
explicit DBCMainEditor(DBCHandler *handler, const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
~DBCMainEditor();
|
||||
void setFileIdx(int idx);
|
||||
|
||||
private slots:
|
||||
void onCellChangedNode(int,int);
|
||||
@@ -35,6 +36,8 @@ private:
|
||||
const QVector<CANFrame> *referenceFrames;
|
||||
DBCSignalEditor *sigEditor;
|
||||
int currRow;
|
||||
DBCFile *dbcFile;
|
||||
int fileIdx;
|
||||
bool inhibitCellChanged;
|
||||
|
||||
void refreshNodesTable();
|
||||
|
||||
+144
-20
@@ -33,11 +33,6 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
ui->comboType->addItem("DOUBLE PRECISION");
|
||||
ui->comboType->addItem("STRING");
|
||||
|
||||
for (int x = 0; x < dbcHandler->dbc_nodes.count(); x++)
|
||||
{
|
||||
ui->comboReceiver->addItem(dbcHandler->dbc_nodes[x].name);
|
||||
}
|
||||
|
||||
connect(ui->signalsList, SIGNAL(currentRowChanged(int)), this, SLOT(clickSignalList(int)));
|
||||
connect(ui->bitfield, SIGNAL(gridClicked(int,int)), this, SLOT(bitfieldClicked(int,int)));
|
||||
connect(ui->signalsList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomMenuSignals(QPoint)));
|
||||
@@ -52,6 +47,8 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
{
|
||||
if (currentSignal == NULL) return;
|
||||
currentSignal->intelByteOrder = ui->cbIntelFormat->isChecked();
|
||||
if (currentSignal->valType == SP_FLOAT || currentSignal->valType == DP_FLOAT)
|
||||
currentSignal->intelByteOrder = false;
|
||||
fillSignalForm(currentSignal);
|
||||
});
|
||||
|
||||
@@ -59,7 +56,7 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
[=]()
|
||||
{
|
||||
if (currentSignal == NULL) return;
|
||||
currentSignal->receiver = dbcHandler->findNodeByName(ui->comboReceiver->currentText());
|
||||
currentSignal->receiver = dbcFile->findNodeByName(ui->comboReceiver->currentText());
|
||||
});
|
||||
connect(ui->comboType, &QComboBox::currentTextChanged,
|
||||
[=]()
|
||||
@@ -75,14 +72,21 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
break;
|
||||
case 2:
|
||||
currentSignal->valType = SP_FLOAT;
|
||||
currentSignal->intelByteOrder = false;
|
||||
if (currentSignal->startBit > 39) currentSignal->startBit = 39;
|
||||
currentSignal->signalSize = 32;
|
||||
break;
|
||||
case 3:
|
||||
currentSignal->valType = DP_FLOAT;
|
||||
currentSignal->intelByteOrder = false;
|
||||
currentSignal->startBit = 7; //has to be!
|
||||
currentSignal->signalSize = 64;
|
||||
break;
|
||||
case 4:
|
||||
currentSignal->valType = STRING;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
fillSignalForm(currentSignal);
|
||||
});
|
||||
connect(ui->txtBias, &QLineEdit::editingFinished,
|
||||
[=]()
|
||||
@@ -143,7 +147,8 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
temp = Utility::ParseStringToNum(ui->txtBitLength->text());
|
||||
if (temp < 0) return;
|
||||
if (temp > 63) return;
|
||||
currentSignal->signalSize = temp;
|
||||
if (currentSignal->valType != SP_FLOAT && currentSignal->valType != DP_FLOAT)
|
||||
currentSignal->signalSize = temp;
|
||||
fillSignalForm(currentSignal);
|
||||
});
|
||||
connect(ui->txtName, &QLineEdit::editingFinished,
|
||||
@@ -154,6 +159,52 @@ DBCSignalEditor::DBCSignalEditor(DBCHandler *handler, QWidget *parent) :
|
||||
//need to update the list too.
|
||||
ui->signalsList->currentItem()->setText(currentSignal->name);
|
||||
});
|
||||
|
||||
connect(ui->txtMultiplexValue, &QLineEdit::editingFinished,
|
||||
[=]()
|
||||
{
|
||||
if (currentSignal == NULL) return;
|
||||
int temp;
|
||||
temp = Utility::ParseStringToNum(ui->txtMultiplexValue->text());
|
||||
//TODO: could look up the multiplexor and ensure that the value is within a range that the multiplexor could return
|
||||
currentSignal->multiplexValue = temp;
|
||||
});
|
||||
connect(ui->rbMultiplexed, &QRadioButton::toggled,
|
||||
[=](bool state)
|
||||
{
|
||||
if (state) //signal is now set as a multiplexed signal
|
||||
{
|
||||
currentSignal->isMultiplexed = true;
|
||||
currentSignal->isMultiplexor = false;
|
||||
//if the set multiplexor for the message was this signal then clear it
|
||||
if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = NULL;
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->rbMultiplexor, &QRadioButton::toggled,
|
||||
[=](bool state)
|
||||
{
|
||||
if (state) //signal is now set as a multiplexed signal
|
||||
{
|
||||
//don't allow this signal to be a multiplexor if there is already one for this message.
|
||||
//if (dbcMessage->multiplexorSignal != currentSignal && dbcMessage->multiplexorSignal != NULL) return; //I spoke too soon above...
|
||||
currentSignal->isMultiplexed = false;
|
||||
currentSignal->isMultiplexor = true;
|
||||
//we just set that this is the multiplexor so update the message to show that as well.
|
||||
dbcMessage->multiplexorSignal = currentSignal;
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->rbNotMulti, &QRadioButton::toggled,
|
||||
[=](bool state)
|
||||
{
|
||||
if (state) //signal is now set as a multiplexed signal
|
||||
{
|
||||
currentSignal->isMultiplexed = false;
|
||||
currentSignal->isMultiplexor = false;
|
||||
if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = NULL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DBCSignalEditor::~DBCSignalEditor()
|
||||
@@ -167,6 +218,17 @@ void DBCSignalEditor::closeEvent(QCloseEvent *event)
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
void DBCSignalEditor::setFileIdx(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > dbcHandler->getFileCount() - 1) return;
|
||||
dbcFile = dbcHandler->getFileByIdx(idx);
|
||||
|
||||
for (int x = 0; x < dbcFile->dbc_nodes.count(); x++)
|
||||
{
|
||||
ui->comboReceiver->addItem(dbcFile->dbc_nodes[x].name);
|
||||
}
|
||||
}
|
||||
|
||||
void DBCSignalEditor::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
@@ -200,9 +262,9 @@ void DBCSignalEditor::showEvent(QShowEvent* event)
|
||||
|
||||
refreshSignalsList();
|
||||
currentSignal = NULL;
|
||||
if (dbcMessage->msgSignals.count() > 0)
|
||||
if (dbcMessage->sigHandler->getCount() > 0)
|
||||
{
|
||||
currentSignal = &dbcMessage->msgSignals[0];
|
||||
currentSignal = dbcMessage->sigHandler->findSignalByIdx(0);
|
||||
fillSignalForm(currentSignal);
|
||||
fillValueTable(currentSignal);
|
||||
}
|
||||
@@ -270,12 +332,17 @@ void DBCSignalEditor::addNewSignal()
|
||||
newSig.intelByteOrder = true;
|
||||
newSig.max = 0.0;
|
||||
newSig.min = 0.0;
|
||||
newSig.receiver = &dbcHandler->dbc_nodes[0];
|
||||
newSig.receiver = dbcFile->findNodeByIdx(0);
|
||||
newSig.signalSize = 1;
|
||||
newSig.startBit = 0;
|
||||
newSig.valType = UNSIGNED_INT;
|
||||
newSig.isMultiplexed = false;
|
||||
newSig.isMultiplexor = false;
|
||||
newSig.multiplexValue = 0;
|
||||
newSig.parentMessage = dbcMessage;
|
||||
ui->signalsList->addItem(newName);
|
||||
dbcMessage->msgSignals.append(newSig);
|
||||
dbcMessage->sigHandler->addSignal(newSig);
|
||||
if (dbcMessage->sigHandler->getCount() == 1) clickSignalList(0);
|
||||
}
|
||||
|
||||
void DBCSignalEditor::deleteCurrentSignal()
|
||||
@@ -284,10 +351,10 @@ void DBCSignalEditor::deleteCurrentSignal()
|
||||
if (currIdx > -1)
|
||||
{
|
||||
delete(ui->signalsList->item(currIdx));
|
||||
dbcMessage->msgSignals.removeAt(currIdx);
|
||||
dbcMessage->sigHandler->removeSignal(currIdx);
|
||||
currentSignal = NULL;
|
||||
currIdx = ui->signalsList->currentRow();
|
||||
if (currIdx > -1) currentSignal = &dbcMessage->msgSignals[currIdx];
|
||||
if (currIdx > -1) currentSignal = dbcMessage->sigHandler->findSignalByIdx(currIdx);
|
||||
fillSignalForm(currentSignal);
|
||||
fillValueTable(currentSignal);
|
||||
}
|
||||
@@ -306,10 +373,10 @@ void DBCSignalEditor::deleteCurrentValue()
|
||||
void DBCSignalEditor::refreshSignalsList()
|
||||
{
|
||||
ui->signalsList->clear();
|
||||
for (int x = 0; x < dbcMessage->msgSignals.count(); x++)
|
||||
for (int x = 0; x < dbcMessage->sigHandler->getCount(); x++)
|
||||
{
|
||||
DBC_SIGNAL sig = dbcMessage->msgSignals.at(x);
|
||||
ui->signalsList->addItem(sig.name);
|
||||
DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x);
|
||||
ui->signalsList->addItem(sig->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +384,8 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig)
|
||||
{
|
||||
unsigned char bitpattern[8];
|
||||
|
||||
generateUsedBits();
|
||||
|
||||
if (sig == NULL)
|
||||
{
|
||||
ui->txtName->setText("");
|
||||
@@ -327,6 +396,10 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig)
|
||||
ui->txtMinVal->setText("");
|
||||
ui->txtScale->setText("");
|
||||
ui->txtUnitName->setText("");
|
||||
ui->txtMultiplexValue->setText("");
|
||||
ui->rbMultiplexed->setChecked(false);
|
||||
ui->rbMultiplexor->setChecked(false);
|
||||
ui->rbNotMulti->setChecked(true);
|
||||
memset(bitpattern, 0, 8); //clear it out
|
||||
ui->bitfield->setReference(bitpattern, false);
|
||||
ui->bitfield->updateData(bitpattern, true);
|
||||
@@ -338,11 +411,16 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig)
|
||||
ui->txtName->setText(sig->name);
|
||||
ui->txtBias->setText(QString::number(sig->bias));
|
||||
ui->txtBitLength->setText(QString::number(sig->signalSize));
|
||||
ui->txtMultiplexValue->setText(QString::number(sig->multiplexValue));
|
||||
ui->txtComment->setText(sig->comment);
|
||||
ui->txtMaxVal->setText(QString::number(sig->max));
|
||||
ui->txtMinVal->setText(QString::number(sig->min));
|
||||
ui->txtScale->setText(QString::number(sig->factor));
|
||||
ui->txtUnitName->setText(sig->unitName);
|
||||
ui->rbMultiplexed->setChecked(sig->isMultiplexed);
|
||||
ui->rbMultiplexor->setChecked(sig->isMultiplexor);
|
||||
ui->rbNotMulti->setChecked( !(sig->isMultiplexor | sig->isMultiplexed) );
|
||||
qDebug() << sig->isMultiplexor << "*" << sig->isMultiplexed;
|
||||
|
||||
memset(bitpattern, 0, 8); //clear it out first.
|
||||
|
||||
@@ -379,7 +457,6 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ui->bitfield->updateData(bitpattern, true);
|
||||
ui->cbIntelFormat->setChecked(sig->intelByteOrder);
|
||||
|
||||
@@ -446,12 +523,12 @@ void DBCSignalEditor::clickSignalList(int row)
|
||||
{
|
||||
if (row < 0) return;
|
||||
//qDebug() << ui->signalsList->item(row)->text();
|
||||
DBC_SIGNAL *thisSig = dbcHandler->findSignalByName(dbcMessage, ui->signalsList->item(row)->text());
|
||||
|
||||
DBC_SIGNAL *thisSig = dbcMessage->sigHandler->findSignalByName(ui->signalsList->item(row)->text());
|
||||
if (thisSig == NULL) return;
|
||||
currentSignal = thisSig;
|
||||
fillSignalForm(thisSig);
|
||||
fillValueTable(thisSig);
|
||||
|
||||
}
|
||||
|
||||
void DBCSignalEditor::bitfieldClicked(int x, int y)
|
||||
@@ -459,5 +536,52 @@ void DBCSignalEditor::bitfieldClicked(int x, int y)
|
||||
int bit = (7 - x) + (y * 8);
|
||||
if (currentSignal == NULL) return;
|
||||
currentSignal->startBit = bit;
|
||||
if (currentSignal->valType == SP_FLOAT)
|
||||
{
|
||||
if (currentSignal->startBit > 31) currentSignal->startBit = 39;
|
||||
}
|
||||
|
||||
if (currentSignal->valType == DP_FLOAT)
|
||||
currentSignal->startBit = 7;
|
||||
fillSignalForm(currentSignal);
|
||||
}
|
||||
|
||||
void DBCSignalEditor::generateUsedBits()
|
||||
{
|
||||
uint8_t usedBits[8] = {0,0,0,0,0,0,0,0};
|
||||
int startBit, endBit;
|
||||
|
||||
for (int x = 0; x < dbcMessage->sigHandler->getCount(); x++)
|
||||
{
|
||||
DBC_SIGNAL *sig = dbcMessage->sigHandler->findSignalByIdx(x);
|
||||
|
||||
startBit = sig->startBit;
|
||||
|
||||
if (sig->intelByteOrder)
|
||||
{
|
||||
endBit = startBit + sig->signalSize - 1;
|
||||
if (startBit < 0) startBit = 0;
|
||||
if (endBit > 63) endBit = 63;
|
||||
for (int y = startBit; y <= endBit; y++)
|
||||
{
|
||||
int byt = y / 8;
|
||||
usedBits[byt] |= 1 << (y % 8);
|
||||
}
|
||||
}
|
||||
else //big endian / motorola format
|
||||
{
|
||||
//much more irritating than the intel version...
|
||||
int size = sig->signalSize;
|
||||
while (size > 0)
|
||||
{
|
||||
int byt = startBit / 8;
|
||||
usedBits[byt] |= 1 << (startBit % 8);
|
||||
size--;
|
||||
if ((startBit % 8) == 0) startBit += 15;
|
||||
else startBit--;
|
||||
if (startBit > 63) startBit = 63;
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->bitfield->setUsed(usedBits, false);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
explicit DBCSignalEditor(DBCHandler *handler, QWidget *parent = 0);
|
||||
void setMessageRef(DBC_MESSAGE *msg);
|
||||
void showEvent(QShowEvent*);
|
||||
void setFileIdx(int idx);
|
||||
~DBCSignalEditor();
|
||||
|
||||
private slots:
|
||||
@@ -34,11 +35,13 @@ private:
|
||||
DBCHandler *dbcHandler;
|
||||
DBC_MESSAGE *dbcMessage;
|
||||
DBC_SIGNAL *currentSignal;
|
||||
DBCFile *dbcFile;
|
||||
bool inhibitCellChanged;
|
||||
|
||||
void refreshSignalsList();
|
||||
void fillSignalForm(DBC_SIGNAL *sig);
|
||||
void fillValueTable(DBC_SIGNAL *sig);
|
||||
void generateUsedBits();
|
||||
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
|
||||
+45
-3
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>884</width>
|
||||
<height>791</height>
|
||||
<height>915</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -118,7 +118,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Comment:</string>
|
||||
@@ -153,9 +153,51 @@
|
||||
<item row="10" column="1">
|
||||
<widget class="QComboBox" name="comboReceiver"/>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QLineEdit" name="txtComment"/>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Multiplexing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNotMulti">
|
||||
<property name="text">
|
||||
<string>Not multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexed">
|
||||
<property name="text">
|
||||
<string>Multiplexed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbMultiplexor">
|
||||
<property name="text">
|
||||
<string>Multiplexor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Multiplex Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QLineEdit" name="txtMultiplexValue"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -44,6 +44,7 @@ void DiscreteStateWindow::updatedFrames(int numFrames)
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -58,11 +58,11 @@ void FileComparatorWindow::writeSettings()
|
||||
void FileComparatorWindow::loadInterestedFile()
|
||||
{
|
||||
interestedFrames.clear();
|
||||
QString result = FrameFileIO::loadFrameFile(&interestedFrames);
|
||||
if (result.length() > 0)
|
||||
QString resultingFileName;
|
||||
if (FrameFileIO::loadFrameFile(resultingFileName, &interestedFrames))
|
||||
{
|
||||
ui->lblFirstFile->setText(result);
|
||||
interestedFilename = result;
|
||||
ui->lblFirstFile->setText(resultingFileName);
|
||||
interestedFilename = resultingFileName;
|
||||
if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails();
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,8 @@ void FileComparatorWindow::loadInterestedFile()
|
||||
void FileComparatorWindow::loadReferenceFile()
|
||||
{
|
||||
//secondFileFrames.clear();
|
||||
QString result = FrameFileIO::loadFrameFile(&referenceFrames);
|
||||
if (result.length() > 0)
|
||||
QString resultingFileName;
|
||||
if (FrameFileIO::loadFrameFile(resultingFileName, &referenceFrames))
|
||||
{
|
||||
ui->lblRefFrames->setText(QString::number(referenceFrames.length()));
|
||||
if (interestedFrames.count() > 0 && referenceFrames.count() > 0) calculateDetails();
|
||||
|
||||
@@ -370,6 +370,7 @@ void FlowViewWindow::updatedFrames(int numFrames)
|
||||
}
|
||||
else //just got some new frames. See if they are relevant.
|
||||
{
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
int refID = frameCache[0].ID;
|
||||
bool needRefresh = false;
|
||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||
|
||||
+1
-1
@@ -799,7 +799,7 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Trigger Values</string>
|
||||
<string>Data Seek Values</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
|
||||
+460
-31
@@ -7,19 +7,121 @@ FrameFileIO::FrameFileIO()
|
||||
|
||||
}
|
||||
|
||||
QString FrameFileIO::loadFrameFile(QVector<CANFrame>* frameCache)
|
||||
bool FrameFileIO::saveFrameFile(QString &fileName, const QVector<CANFrame>* frameCache)
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(qApp->activeWindow());
|
||||
bool result = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("GVRET Logs (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("CRTD Logs (*.txt *.TXT)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log *.LOG)")));
|
||||
filters.append(QString(tr("Microchip Log (*.can *.CAN)")));
|
||||
filters.append(QString(tr("Vector Trace Files (*.trace *.TRACE)")));
|
||||
filters.append(QString(tr("IXXAT MiniLog (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("CAN-DO Log (*.can *.avc *.evc *.qcc *.CAN *.AVC *.EVC *.QCC)")));
|
||||
filters.append(QString(tr("Vehicle Spy (*.csv *.CSV)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
|
||||
QProgressDialog progress(qApp->activeWindow());
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setLabelText("Saving file...");
|
||||
progress.setCancelButton(0);
|
||||
progress.setRange(0,0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = saveNativeCSVFile(filename, frameCache);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[1])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".txt";
|
||||
result = saveCRTDFile(filename, frameCache);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[2])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = saveGenericCSVFile(filename, frameCache);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[3])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = saveLogFile(filename, frameCache);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[4])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = saveMicrochipFile(filename, frameCache);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[5])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".trace";
|
||||
result = saveTraceFile(filename, frameCache);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[6])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = saveIXXATFile(filename, frameCache);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[7])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".can";
|
||||
result = saveCANDOFile(filename, frameCache);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[8])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = saveVehicleSpyFile(filename, frameCache);
|
||||
}
|
||||
|
||||
progress.cancel();
|
||||
|
||||
if (result)
|
||||
{
|
||||
QStringList fileList = filename.split('/');
|
||||
fileName = fileList[fileList.length() - 1];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache)
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
bool result = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("CRTD Logs (*.txt)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log)")));
|
||||
filters.append(QString(tr("Microchip Log (*.can)")));
|
||||
filters.append(QString(tr("Vector trace files (*.trace)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("CRTD Logs (*.txt *.TXT)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log *.LOG)")));
|
||||
filters.append(QString(tr("Microchip Log (*.can *.CAN)")));
|
||||
filters.append(QString(tr("Vector trace files (*.trace *.TRACE)")));
|
||||
filters.append(QString(tr("IXXAT MiniLog (*.csv *.CSV)")));
|
||||
filters.append(QString(tr("CAN-DO Log (*.avc *.can *.evc *.qcc *.AVC *.CAN *.EVC *.QCC)")));
|
||||
filters.append(QString(tr("Vehicle Spy (*.csv *.CSV)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
@@ -39,24 +141,93 @@ QString FrameFileIO::loadFrameFile(QVector<CANFrame>* frameCache)
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0]) result = loadCRTDFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[1]) result = loadNativeCSVFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[0]) result = loadNativeCSVFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[1]) result = loadCRTDFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[2]) result = loadGenericCSVFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[3]) result = loadLogFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[4]) result = loadMicrochipFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[5]) result = loadTraceFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[6]) result = loadIXXATFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[7]) result = loadCANDOFile(filename, frameCache);
|
||||
if (dialog.selectedNameFilter() == filters[8]) result = loadVehicleSpyFile(filename, frameCache);
|
||||
|
||||
progress.cancel();
|
||||
|
||||
if (result)
|
||||
{
|
||||
QStringList fileList = filename.split('/');
|
||||
filename = fileList[fileList.length() - 1];
|
||||
return filename;
|
||||
fileName = fileList[fileList.length() - 1];
|
||||
return true;
|
||||
}
|
||||
else return QString("");
|
||||
else return false;
|
||||
}
|
||||
return QString("");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//2,2550.368293675,0.003818174999651092,67371008,F,F,HS CAN $119,HS CAN,,119,F,F,00,00,00,00,00,00,0D,8B,,,
|
||||
//Line,Abs Time(Sec),Rel Time (Sec),Status,Er,Tx,Description,Network,Node,Arb ID,Remote,Xtd,B1,B2,B3,B4,B5,B6,B7,B8,Value,Trigger,Signals
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
||||
bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames)
|
||||
{
|
||||
QFile *inFile = new QFile(filename);
|
||||
CANFrame thisFrame;
|
||||
QByteArray line;
|
||||
int lineCounter = 0;
|
||||
bool pastHeader = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
delete inFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!inFile->atEnd() && !pastHeader)
|
||||
{
|
||||
line = inFile->readLine().simplified().toUpper();
|
||||
if (line.startsWith("LINE")) lineCounter++;
|
||||
if (lineCounter == 2) pastHeader = true;
|
||||
}
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
{
|
||||
qApp->processEvents();
|
||||
lineCounter = 0;
|
||||
}
|
||||
line = inFile->readLine().simplified().toUpper();
|
||||
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.timestamp = tokens[1].toDouble() * 1000000.0;
|
||||
if (tokens[5].startsWith("T")) thisFrame.isReceived = false;
|
||||
else thisFrame.isReceived = true;
|
||||
thisFrame.ID = tokens[9].toInt(NULL, 16);
|
||||
if (tokens[11].startsWith("T")) thisFrame.extended = true;
|
||||
else thisFrame.extended = false;
|
||||
|
||||
thisFrame.len = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (tokens[12 + i].length() > 0)
|
||||
{
|
||||
thisFrame.data[i] = tokens[12 + i].toInt(NULL, 16);
|
||||
thisFrame.len++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector<CANFrame> *frames)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//CRTD format from Mark Webb-Johnson / OVMS project
|
||||
@@ -94,7 +265,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
||||
return false;
|
||||
}
|
||||
|
||||
line = inFile->readLine(); //read out the header first and discard it.
|
||||
line = inFile->readLine().toUpper(); //read out the header first and discard it.
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
lineCounter++;
|
||||
@@ -121,11 +292,14 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
||||
}
|
||||
//qDebug() << "decimal places " << decimalPlaces;
|
||||
thisFrame.timestamp = (int64_t)(tokens[0].toDouble() * multiplier);
|
||||
if (tokens[1] == "R11" || tokens[1] == "R29")
|
||||
char firstChar = tokens[1].left(1)[0];
|
||||
if (firstChar == 'R' || firstChar == 'T')
|
||||
{
|
||||
thisFrame.ID = tokens[2].toInt(NULL, 16);
|
||||
if (tokens[1] == "R29") thisFrame.extended = true;
|
||||
if (tokens[1] == "R29" || tokens[1] == "T29") thisFrame.extended = true;
|
||||
else thisFrame.extended = false;
|
||||
if (firstChar == 'T') thisFrame.isReceived = false;
|
||||
else thisFrame.isReceived = true;
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.len = tokens.length() - 3;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
@@ -171,11 +345,15 @@ bool FrameFileIO::saveCRTDFile(QString filename, const QVector<CANFrame>* frames
|
||||
|
||||
outFile->write(QString::number(frames->at(c).timestamp / 1000000.0, 'f', 6).toUtf8());
|
||||
outFile->putChar(' ');
|
||||
|
||||
if (frames->at(c).isReceived) outFile->putChar('R');
|
||||
else outFile->putChar('T');
|
||||
|
||||
if (frames->at(c).extended)
|
||||
{
|
||||
outFile->write("R29 ");
|
||||
outFile->write("29 ");
|
||||
}
|
||||
else outFile->write("R11 ");
|
||||
else outFile->write("11 ");
|
||||
outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8());
|
||||
outFile->putChar(' ');
|
||||
|
||||
@@ -199,6 +377,7 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||
QFile *inFile = new QFile(filename);
|
||||
CANFrame thisFrame;
|
||||
QByteArray line;
|
||||
int fileVersion = 1;
|
||||
long long timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
|
||||
@@ -208,7 +387,8 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||
return false;
|
||||
}
|
||||
|
||||
line = inFile->readLine(); //read out the header first and discard it.
|
||||
line = inFile->readLine().toUpper(); //read out the header first and discard it.
|
||||
if (line.at(23) == 'D') fileVersion = 2; //Dir is found starting at position 23 if this is a V2 file
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
lineCounter++;
|
||||
@@ -236,11 +416,27 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||
thisFrame.ID = tokens[1].toInt(NULL, 16);
|
||||
if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1;
|
||||
else thisFrame.extended = 0;
|
||||
thisFrame.bus = tokens[3].toInt();
|
||||
thisFrame.len = tokens[4].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
||||
|
||||
if (fileVersion == 1)
|
||||
{
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = tokens[3].toInt();
|
||||
thisFrame.len = tokens[4].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
||||
}
|
||||
else if (fileVersion == 2)
|
||||
{
|
||||
if (tokens[3].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.bus = tokens[4].toInt();
|
||||
thisFrame.len = tokens[5].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16);
|
||||
}
|
||||
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
}
|
||||
@@ -260,7 +456,7 @@ bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector<CANFrame>* f
|
||||
return false;
|
||||
}
|
||||
|
||||
outFile->write("Time Stamp,ID,Extended,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8");
|
||||
outFile->write("Time Stamp,ID,Extended,Dir,Bus,LEN,D1,D2,D3,D4,D5,D6,D7,D8");
|
||||
outFile->write("\n");
|
||||
|
||||
for (int c = 0; c < frames->count(); c++)
|
||||
@@ -281,6 +477,9 @@ bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector<CANFrame>* f
|
||||
if (frames->at(c).extended) outFile->write("true,");
|
||||
else outFile->write("false,");
|
||||
|
||||
if (frames->at(c).isReceived) outFile->write("Rx,");
|
||||
else outFile->write("Tx,");
|
||||
|
||||
outFile->write(QString::number(frames->at(c).bus).toUtf8());
|
||||
outFile->putChar(44);
|
||||
|
||||
@@ -449,7 +648,7 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
||||
lineCounter = 0;
|
||||
}
|
||||
|
||||
line = inFile->readLine();
|
||||
line = inFile->readLine().toUpper();
|
||||
if (line.startsWith("***")) continue;
|
||||
if (line.length() > 1)
|
||||
{
|
||||
@@ -458,6 +657,8 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||
+ (timeToks[2].toInt() * (1000ul * 1000ul)) + (timeToks[3].toInt() * 100ul);
|
||||
thisFrame.timestamp = timeStamp;
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16);
|
||||
if (tokens[4] == "s") thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
@@ -513,7 +714,8 @@ bool FrameFileIO::saveLogFile(QString filename, const QVector<CANFrame>* frames)
|
||||
|
||||
tempStamp = timestamp.addMSecs(frames->at(c).timestamp / 1000);
|
||||
outFile->write(tempStamp.toString("h:m:s:z").toUtf8());
|
||||
outFile->write(" Rx ");
|
||||
if (frames->at(c).isReceived) outFile->write(" Rx ");
|
||||
else outFile->write(" Tx ");
|
||||
outFile->write(QString::number(frames->at(c).bus).toUtf8() + " ");
|
||||
outFile->write(QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8());
|
||||
if (frames->at(c).extended) outFile->write(" x ");
|
||||
@@ -534,6 +736,226 @@ bool FrameFileIO::saveLogFile(QString filename, const QVector<CANFrame>* frames)
|
||||
return true;
|
||||
}
|
||||
|
||||
//"00:01:03.03","223","Std","","00 00 00 00 49 00 00 01 "
|
||||
bool FrameFileIO::loadIXXATFile(QString filename, QVector<CANFrame>* frames)
|
||||
{
|
||||
QFile *inFile = new QFile(filename);
|
||||
CANFrame thisFrame;
|
||||
QByteArray line;
|
||||
uint64_t timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
delete inFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) line = inFile->readLine(); //read out the header first and discard it.
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
{
|
||||
qApp->processEvents();
|
||||
lineCounter = 0;
|
||||
}
|
||||
|
||||
line = inFile->readLine().toUpper();
|
||||
if (line.length() > 1)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
QString timePortion = unQuote(tokens[0]);
|
||||
QStringList timeToks = timePortion.split(':');
|
||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||
+ (timeToks[2].toDouble() * (1000.0 * 1000.0));
|
||||
thisFrame.timestamp = timeStamp;
|
||||
thisFrame.ID = unQuote(tokens[1]).toInt(NULL, 16);
|
||||
if (unQuote(tokens[2]).toUpper().at(0) == 'S') thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = 0;
|
||||
|
||||
QStringList dataToks = unQuote(tokens[4]).simplified().split(' ');
|
||||
thisFrame.len = dataToks.length();
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16);
|
||||
}
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveIXXATFile(QString filename, const QVector<CANFrame>* frames)
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
QDateTime timestamp, tempStamp;
|
||||
int lineCounter = 0;
|
||||
|
||||
timestamp = QDateTime::currentDateTime();
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
delete outFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
outFile->write("ASCII Trace IXXAT SavvyCAN V" + QString::number(VERSION).toUtf8() + "\n");
|
||||
outFile->write("Date: " + timestamp.toString("d:M:yyyy").toUtf8() + "\n");
|
||||
outFile->write("Start time: " + timestamp.toString("h:m:s").toUtf8() + "\n");
|
||||
timestamp.addMSecs((frames->last().timestamp - frames->first().timestamp) / 1000);
|
||||
outFile->write("Stop time: " + timestamp.toString("h:m:s").toUtf8() + "\n");
|
||||
outFile->write("Overruns: 0\n");
|
||||
outFile->write("Baudrate: 500 kbit/s\n"); //could be a lie... this code has no way to know the baud rate (at the moment)
|
||||
outFile->write("\"Time\",\"Identifier (hex)\",\"Format\",\"Flags\",\"Data (hex)\"\n");
|
||||
|
||||
for (int c = 0; c < frames->count(); c++)
|
||||
{
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
{
|
||||
qApp->processEvents();
|
||||
lineCounter = 0;
|
||||
}
|
||||
|
||||
timestamp.setTime(QTime());
|
||||
|
||||
tempStamp = timestamp.addMSecs(frames->at(c).timestamp / 1000);
|
||||
outFile->write("\"" + tempStamp.toString("h:m:s.").toUtf8() + tempStamp.toString("z").rightJustified(3, '0').toUtf8() + "\"");
|
||||
|
||||
outFile->write(",\"" + QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8() + "\"");
|
||||
if (frames->at(c).extended) outFile->write(",\"Ext\"");
|
||||
else outFile->write(",\"Std\"");
|
||||
outFile->write(",\"\",\"");
|
||||
|
||||
for (int temp = 0; temp < frames->at(c).len; temp++)
|
||||
{
|
||||
outFile->write(QString::number(frames->at(c).data[temp], 16).toUpper().rightJustified(2, '0').toUtf8());
|
||||
outFile->putChar(' ');
|
||||
}
|
||||
|
||||
outFile->write("\"\n");
|
||||
|
||||
}
|
||||
outFile->close();
|
||||
delete outFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
||||
{
|
||||
QFile *inFile = new QFile(filename);
|
||||
CANFrame thisFrame;
|
||||
int lineCounter = 0;
|
||||
QByteArray data;
|
||||
int timeOffset = 0;
|
||||
uint64_t lastTimeStamp = 0;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly))
|
||||
{
|
||||
delete inFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
//this file format is in static 12 byte blocks.
|
||||
//Bytes 0 - 1 are a time stamp
|
||||
//Bytes 2 - 3 are the data length (top 4 bits) then ID (bottom 11 bits)
|
||||
//Bytes 4 - 11 are the data bytes (padded with FF for bytes not used)
|
||||
|
||||
while (!inFile->atEnd())
|
||||
{
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
{
|
||||
qApp->processEvents();
|
||||
lineCounter = 0;
|
||||
}
|
||||
|
||||
data = inFile->read(12);
|
||||
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.extended = false; //format is incapable of extended frames
|
||||
|
||||
thisFrame.timestamp = 1000000ul * ((unsigned char)data[0] >> 2);
|
||||
thisFrame.timestamp += (((data[0] & 3) << 8) + (unsigned char)data[1]) * 1000;
|
||||
thisFrame.timestamp += timeOffset;
|
||||
if (thisFrame.timestamp < lastTimeStamp)
|
||||
{
|
||||
timeOffset += 60000000ul;
|
||||
}
|
||||
lastTimeStamp = thisFrame.timestamp;
|
||||
thisFrame.ID = ((unsigned char)data[3] * 256 + (unsigned char)data[2]) & 0x7FF;
|
||||
thisFrame.len = (unsigned char)data[3] >> 4;
|
||||
|
||||
if (thisFrame.len <= 8 && thisFrame.ID <= 0x7FF)
|
||||
{
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d];
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
}
|
||||
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveCANDOFile(QString filename, const QVector<CANFrame>* frames)
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
int lineCounter = 0;
|
||||
QByteArray data;
|
||||
CANFrame thisFrame;
|
||||
int ms, id;
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly))
|
||||
{
|
||||
delete outFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
data.reserve(13);
|
||||
|
||||
//The initial frame in official files sets the global time but I don't care so it is set all zeros here.
|
||||
thisFrame = frames->at(0);
|
||||
ms = (thisFrame.timestamp / 1000);
|
||||
data[0] = (((ms / 1000) % 60) << 2) + ((ms % 1000) >> 8);
|
||||
data[1] = (char)(ms & 0xFF);
|
||||
data[2] = 0xFF;
|
||||
data[3] = 0xFF;
|
||||
for (int l = 0; l < 8; l++) data[4 + l] = 0;
|
||||
outFile->write(data);
|
||||
|
||||
for (int c = 0; c < frames->count(); c++)
|
||||
{
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
{
|
||||
qApp->processEvents();
|
||||
lineCounter = 0;
|
||||
}
|
||||
for (int j = 0; j < 8; j++) data[4 + j] = 0xFF;
|
||||
|
||||
thisFrame = frames->at(c);
|
||||
if (!thisFrame.extended)
|
||||
{
|
||||
ms = (thisFrame.timestamp / 1000);
|
||||
id = thisFrame.ID & 0x7FF;
|
||||
data[0] = (((ms / 1000) % 60) << 2) + ((ms % 1000) >> 8);
|
||||
data[1] = (char)(ms & 0xFF);
|
||||
data[2] = (char)(id & 0xFF);
|
||||
data[3] = (char)((id >> 8) + (thisFrame.len << 4));
|
||||
for (int d = 0; d < thisFrame.len; d++) data[4 + d] = (char)thisFrame.data[d];
|
||||
outFile->write(data);
|
||||
}
|
||||
}
|
||||
outFile->close();
|
||||
delete outFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
//log file from microchip tool
|
||||
/*
|
||||
tokens:
|
||||
@@ -549,7 +971,7 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
||||
CANFrame thisFrame;
|
||||
QByteArray line;
|
||||
bool inComment = false;
|
||||
long long timeStamp = Utility::GetTimeMS();
|
||||
long long timeStamp;
|
||||
int lineCounter = 0;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
@@ -580,9 +1002,10 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
||||
if (!inComment)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(';');
|
||||
timeStamp += 5;
|
||||
timeStamp = tokens[0].toInt() * 1000;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = Utility::ParseStringToNum(tokens[2]);
|
||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
@@ -643,7 +1066,8 @@ bool FrameFileIO::saveMicrochipFile(QString filename, const QVector<CANFrame>* f
|
||||
}
|
||||
|
||||
outFile->write(QString::number((int)(frames->at(c).timestamp / 1000)).toUtf8());
|
||||
outFile->write(";RX;");
|
||||
if (frames->at(c).isReceived) outFile->write(";RX;");
|
||||
else outFile->write(";TX;");
|
||||
outFile->write("0x" + QString::number(frames->at(c).ID, 16).toUpper().rightJustified(8, '0').toUtf8() + ";");
|
||||
outFile->write(QString::number(frames->at(c).len).toUtf8() + ";");
|
||||
|
||||
@@ -839,3 +1263,8 @@ bool FrameFileIO::saveTraceFile(QString filename, const QVector<CANFrame> * fram
|
||||
delete outFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString FrameFileIO::unQuote(QString inStr)
|
||||
{
|
||||
return inStr.split('\"')[1];
|
||||
}
|
||||
|
||||
+12
-2
@@ -28,13 +28,23 @@ public:
|
||||
static bool loadLogFile(QString, QVector<CANFrame>*);
|
||||
static bool loadMicrochipFile(QString, QVector<CANFrame>*);
|
||||
static bool loadTraceFile(QString, QVector<CANFrame>*);
|
||||
static bool saveCRTDFile(QString, const QVector<CANFrame>*);
|
||||
static bool loadIXXATFile(QString, QVector<CANFrame>*);
|
||||
static bool loadCANDOFile(QString, QVector<CANFrame>*);
|
||||
static bool loadVehicleSpyFile(QString, QVector<CANFrame>*);
|
||||
static bool saveCRTDFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveNativeCSVFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveGenericCSVFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveLogFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveMicrochipFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveTraceFile(QString, const QVector<CANFrame>*);
|
||||
static QString loadFrameFile(QVector<CANFrame>*);
|
||||
static bool saveIXXATFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveCANDOFile(QString, const QVector<CANFrame>*);
|
||||
static bool saveVehicleSpyFile(QString, const QVector<CANFrame>*);
|
||||
static bool loadFrameFile(QString &, QVector<CANFrame>*);
|
||||
static bool saveFrameFile(QString &, const QVector<CANFrame>*);
|
||||
|
||||
private:
|
||||
static QString unQuote(QString);
|
||||
};
|
||||
|
||||
#endif // FRAMEFILEIO_H
|
||||
|
||||
+78
-4
@@ -13,8 +13,10 @@ FrameInfoWindow::FrameInfoWindow(const QVector<CANFrame> *frames, QWidget *paren
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
connect(ui->listFrameID, SIGNAL(currentTextChanged(QString)), this, SLOT(updateDetailsWindow(QString)));
|
||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||
connect(ui->listFrameID, &QListWidget::currentTextChanged, this, &FrameInfoWindow::updateDetailsWindow);
|
||||
connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &FrameInfoWindow::updatedFrames);
|
||||
connect(ui->btnSave, &QAbstractButton::clicked, this, &FrameInfoWindow::saveDetails);
|
||||
|
||||
}
|
||||
|
||||
void FrameInfoWindow::showEvent(QShowEvent* event)
|
||||
@@ -81,6 +83,7 @@ void FrameInfoWindow::updatedFrames(int numFrames)
|
||||
}
|
||||
else //just got some new frames. See if they are relevant.
|
||||
{
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
int currID = ui->listFrameID->currentItem()->text().toInt(NULL, 16);
|
||||
bool foundID = false;
|
||||
for (int x = modelFrames->count() - numFrames; x < modelFrames->count(); x++)
|
||||
@@ -113,6 +116,8 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
int maxData[8];
|
||||
int dataHistogram[256][8];
|
||||
int bitfieldHistogram[64];
|
||||
uint8_t changedBits[8];
|
||||
uint8_t referenceBits[8];
|
||||
QTreeWidgetItem *baseNode, *dataBase, *histBase, *tempItem;
|
||||
|
||||
targettedID = Utility::ParseStringToNum(newID);
|
||||
@@ -196,6 +201,13 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
}
|
||||
for (int j = 0; j < 64; j++) bitfieldHistogram[j] = 0;
|
||||
|
||||
for (int c = 0; c < 8; c++)
|
||||
{
|
||||
changedBits[c] = 0;
|
||||
referenceBits[c] = frameCache.at(0).data[c];
|
||||
qDebug() << referenceBits[c];
|
||||
}
|
||||
|
||||
//then find all data points
|
||||
for (int j = 0; j < frameCache.count(); j++)
|
||||
{
|
||||
@@ -217,10 +229,13 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
bitfieldHistogram[c * 8 + l]++;
|
||||
}
|
||||
}
|
||||
changedBits[c] |= referenceBits[c] ^ dat;
|
||||
}
|
||||
}
|
||||
|
||||
avgInterval = avgInterval / (frameCache.count() - 1);
|
||||
if (frameCache.count() > 1)
|
||||
avgInterval = avgInterval / (frameCache.count() - 1);
|
||||
else avgInterval = 0;
|
||||
|
||||
tempItem = new QTreeWidgetItem();
|
||||
|
||||
@@ -242,6 +257,13 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
|
||||
dataBase->setText(0, tr("Data Byte ") + QString::number(c));
|
||||
baseNode->addChild(dataBase);
|
||||
|
||||
tempItem = new QTreeWidgetItem();
|
||||
QString builder;
|
||||
builder = tr("Changed bits: 0x") + QString::number(changedBits[c], 16) + " (" + Utility::formatByteAsBinary(changedBits[c]) + ")";
|
||||
tempItem->setText(0, builder);
|
||||
dataBase->addChild(tempItem);
|
||||
|
||||
tempItem = new QTreeWidgetItem();
|
||||
tempItem->setText(0, tr("Range: ") + Utility::formatNumber(minData[c]) + tr(" to ") + Utility::formatNumber(maxData[c]));
|
||||
dataBase->addChild(tempItem);
|
||||
@@ -253,7 +275,7 @@ void FrameInfoWindow::updateDetailsWindow(QString newID)
|
||||
if (dataHistogram[d][c] > 0)
|
||||
{
|
||||
tempItem = new QTreeWidgetItem();
|
||||
tempItem->setText(0, QString::number(d) + "/0x" + QString::number(d, 16) +": " + QString::number(dataHistogram[d][c]));
|
||||
tempItem->setText(0, QString::number(d) + "/0x" + QString::number(d, 16) +" (" + Utility::formatByteAsBinary(d) +") -> " + QString::number(dataHistogram[d][c]));
|
||||
histBase->addChild(tempItem);
|
||||
}
|
||||
}
|
||||
@@ -300,3 +322,55 @@ void FrameInfoWindow::refreshIDList()
|
||||
ui->listFrameID->sortItems();
|
||||
ui->lblFrameID->setText(tr("Frame IDs: (") + QString::number(ui->listFrameID->count()) + tr(" unique ids)"));
|
||||
}
|
||||
|
||||
void FrameInfoWindow::saveDetails()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Text File (*.txt)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
if (!filename.contains('.')) filename += ".txt";
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
delete outFile;
|
||||
return;
|
||||
}
|
||||
|
||||
//go through all IDs, recalculate the data, and then save it to file
|
||||
for (int i = 0; i < ui->listFrameID->count(); i++)
|
||||
{
|
||||
updateDetailsWindow(ui->listFrameID->item(i)->text());
|
||||
dumpNode(ui->treeDetails->invisibleRootItem(), outFile, 0);
|
||||
outFile->write("\n\n");
|
||||
}
|
||||
|
||||
outFile->close();
|
||||
delete outFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FrameInfoWindow::dumpNode(QTreeWidgetItem* item, QFile *file, int indent)
|
||||
{
|
||||
for (int i = 0; i < indent; i++) file->write("\t");
|
||||
file->write(item->text(0).toUtf8());
|
||||
file->write("\n");
|
||||
for( int i = 0; i < item->childCount(); ++i )
|
||||
dumpNode( item->child(i), file, indent + 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#define FRAMEINFOWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFile>
|
||||
#include <QListWidget>
|
||||
#include <QTreeWidget>
|
||||
#include "can_structs.h"
|
||||
|
||||
namespace Ui {
|
||||
@@ -21,6 +23,7 @@ public:
|
||||
private slots:
|
||||
void updateDetailsWindow(QString);
|
||||
void updatedFrames(int);
|
||||
void saveDetails();
|
||||
|
||||
private:
|
||||
Ui::FrameInfoWindow *ui;
|
||||
@@ -33,6 +36,7 @@ private:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void dumpNode(QTreeWidgetItem* item, QFile *file, int indent);
|
||||
};
|
||||
|
||||
#endif // FRAMEINFOWINDOW_H
|
||||
|
||||
+50
-39
@@ -13,53 +13,64 @@
|
||||
<property name="windowTitle">
|
||||
<string>Detailed Frame Information</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFrameID">
|
||||
<property name="text">
|
||||
<string>Frame IDs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblFrameID">
|
||||
<property name="text">
|
||||
<string>Frame IDs:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFrameID">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFrameID">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Details:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeDetails">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Details:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeDetails">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QPushButton" name="btnSave">
|
||||
<property name="text">
|
||||
<string>Save details to file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
+22
-44
@@ -342,56 +342,33 @@ void FramePlaybackWindow::btnDeleteCurrSeq()
|
||||
void FramePlaybackWindow::btnLoadFile()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
bool result = false;
|
||||
SequenceItem item;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("CRTD Logs (*.txt)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log)")));
|
||||
filters.append(QString(tr("Microchip Log (*.log)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
if (FrameFileIO::loadFrameFile(filename, &item.data))
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0]) result = FrameFileIO::loadCRTDFile(filename, &item.data);
|
||||
if (dialog.selectedNameFilter() == filters[1]) result = FrameFileIO::loadNativeCSVFile(filename, &item.data);
|
||||
if (dialog.selectedNameFilter() == filters[2]) result = FrameFileIO::loadGenericCSVFile(filename, &item.data);
|
||||
if (dialog.selectedNameFilter() == filters[3]) result = FrameFileIO::loadLogFile(filename, &item.data);
|
||||
if (dialog.selectedNameFilter() == filters[4]) result = FrameFileIO::loadMicrochipFile(filename, &item.data);
|
||||
if (result)
|
||||
QStringList fileList = filename.split('/');
|
||||
item.filename = fileList[fileList.length() - 1];
|
||||
item.currentLoopCount = 0;
|
||||
item.maxLoops = 1;
|
||||
fillIDHash(item);
|
||||
if (ui->tblSequence->currentRow() == -1)
|
||||
{
|
||||
QStringList fileList = filename.split('/');
|
||||
item.filename = fileList[fileList.length() - 1];
|
||||
item.currentLoopCount = 0;
|
||||
item.maxLoops = 1;
|
||||
fillIDHash(item);
|
||||
if (ui->tblSequence->currentRow() == -1)
|
||||
{
|
||||
ui->tblSequence->setCurrentCell(0,0);
|
||||
}
|
||||
seqItems.append(item);
|
||||
int row = ui->tblSequence->rowCount();
|
||||
ui->tblSequence->insertRow(row);
|
||||
ui->tblSequence->setItem(row, 0, new QTableWidgetItem(item.filename));
|
||||
ui->tblSequence->setItem(row, 1, new QTableWidgetItem(QString::number(item.maxLoops)));
|
||||
qDebug() << currentSeqNum;
|
||||
if (currentSeqNum == -1)
|
||||
{
|
||||
currentSeqNum = 0;
|
||||
currentSeqItem = &seqItems[0];
|
||||
}
|
||||
updateFrameLabel();
|
||||
ui->tblSequence->setCurrentCell(0,0);
|
||||
}
|
||||
seqItems.append(item);
|
||||
int row = ui->tblSequence->rowCount();
|
||||
ui->tblSequence->insertRow(row);
|
||||
ui->tblSequence->setItem(row, 0, new QTableWidgetItem(item.filename));
|
||||
ui->tblSequence->setItem(row, 1, new QTableWidgetItem(QString::number(item.maxLoops)));
|
||||
qDebug() << currentSeqNum;
|
||||
if (currentSeqNum == -1)
|
||||
{
|
||||
currentSeqNum = 0;
|
||||
currentSeqItem = &seqItems[0];
|
||||
}
|
||||
refreshIDList();
|
||||
updateFrameLabel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnLoadLive()
|
||||
@@ -416,6 +393,7 @@ void FramePlaybackWindow::btnLoadLive()
|
||||
currentSeqNum = 0;
|
||||
currentSeqItem = &seqItems[0];
|
||||
}
|
||||
refreshIDList();
|
||||
updateFrameLabel();
|
||||
btnStopClick();
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ void FrameSenderWindow::updatedFrames(int numFrames)
|
||||
buildFrameCache();
|
||||
}
|
||||
else //just got some new frames. See if they are relevant.
|
||||
{
|
||||
{
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
qDebug() << "New frames in sender window";
|
||||
//run through the supposedly new frames in order
|
||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
#include "fuzzingwindow.h"
|
||||
#include "ui_fuzzingwindow.h"
|
||||
#include "utility.h"
|
||||
#include <QDebug>
|
||||
#include "mainwindow.h"
|
||||
|
||||
FuzzingWindow::FuzzingWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FuzzingWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
fuzzTimer = new QTimer();
|
||||
|
||||
connect(ui->btnStartStop, &QPushButton::clicked, this, &FuzzingWindow::toggleFuzzing);
|
||||
connect(ui->btnAllFilters, &QPushButton::clicked, this, &FuzzingWindow::setAllFilters);
|
||||
connect(ui->btnNoFilters, &QPushButton::clicked, this, &FuzzingWindow::clearAllFilters);
|
||||
connect(fuzzTimer, &QTimer::timeout, this, &FuzzingWindow::timerTriggered);
|
||||
connect(ui->spinTiming, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int)));
|
||||
connect(ui->listID, &QListWidget::itemChanged, this, &FuzzingWindow::idListChanged);
|
||||
connect(ui->spinBytes, SIGNAL(valueChanged(int)), this, SLOT(changedNumDataBytes(int)));
|
||||
connect(ui->bitfield, SIGNAL(gridClicked(int,int)), this, SLOT(bitfieldClicked(int,int)));
|
||||
|
||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||
|
||||
refreshIDList();
|
||||
|
||||
currentlyFuzzing = false;
|
||||
|
||||
for (int j = 0; j < 64; j++) bitGrid[j] = 1;
|
||||
numBits = 64;
|
||||
bitAccum = 0;
|
||||
redrawGrid();
|
||||
|
||||
fuzzTimer->setInterval(ui->spinTiming->value());
|
||||
|
||||
ui->cbBuses->addItem(tr("0"));
|
||||
ui->cbBuses->addItem(tr("1"));
|
||||
ui->cbBuses->addItem(tr("Both"));
|
||||
}
|
||||
|
||||
FuzzingWindow::~FuzzingWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FuzzingWindow::updatedFrames(int numFrames)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
int id;
|
||||
if (numFrames == -1) //all frames deleted. Kill the display
|
||||
{
|
||||
ui->listID->clear();
|
||||
foundIDs.clear();
|
||||
refreshIDList();
|
||||
}
|
||||
else if (numFrames == -2) //all new set of frames. Reset
|
||||
{
|
||||
ui->listID->clear();
|
||||
foundIDs.clear();
|
||||
refreshIDList();
|
||||
}
|
||||
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++)
|
||||
{
|
||||
id = modelFrames->at(i).ID;
|
||||
if (!foundIDs.contains(id))
|
||||
{
|
||||
foundIDs.append(id);
|
||||
selectedIDs.append(id);
|
||||
QListWidgetItem *thisItem = new QListWidgetItem();
|
||||
thisItem->setText(Utility::formatNumber(id));
|
||||
thisItem->setFlags(thisItem->flags() | Qt::ItemIsUserCheckable);
|
||||
thisItem->setCheckState(Qt::Checked);
|
||||
ui->listID->addItem(thisItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::changePlaybackSpeed(int newSpeed)
|
||||
{
|
||||
fuzzTimer->setInterval(newSpeed);
|
||||
}
|
||||
|
||||
void FuzzingWindow::changedNumDataBytes(int newVal)
|
||||
{
|
||||
qDebug() << "new num bytes: " << newVal;
|
||||
int byt;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
byt = i / 8;
|
||||
if (byt >= newVal)
|
||||
{
|
||||
bitGrid[i] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bitGrid[i] == 3) bitGrid[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
redrawGrid();
|
||||
}
|
||||
|
||||
void FuzzingWindow::timerTriggered()
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
sendingBuffer.clear();
|
||||
int buses = ui->cbBuses->currentIndex() + 1;
|
||||
if (buses == 0) buses = 1;
|
||||
for (int count = 0; count < ui->spinBurst->value(); count++)
|
||||
{
|
||||
thisFrame.ID = currentID;
|
||||
for (int i = 0; i < 8; i++) thisFrame.data[i] = currentBytes[i];
|
||||
if (currentID > 0x7FF) thisFrame.extended = true;
|
||||
else thisFrame.extended = false;
|
||||
thisFrame.bus = 0; //hard coded for now. TODO: do not hard code
|
||||
thisFrame.len = ui->spinBytes->value();
|
||||
if (buses & 1)
|
||||
{
|
||||
thisFrame.bus = 0;
|
||||
sendingBuffer.append(thisFrame);
|
||||
}
|
||||
if (buses & 2)
|
||||
{
|
||||
thisFrame.bus = 1;
|
||||
sendingBuffer.append(thisFrame);
|
||||
}
|
||||
|
||||
calcNextID();
|
||||
calcNextBitPattern();
|
||||
numSentFrames++;
|
||||
}
|
||||
emit sendFrameBatch(&sendingBuffer);
|
||||
ui->lblNumFrames->setText("# of sent frames: " + QString::number(numSentFrames));
|
||||
}
|
||||
|
||||
void FuzzingWindow::clearAllFilters()
|
||||
{
|
||||
for (int i = 0; i < ui->listID->count(); i++)
|
||||
{
|
||||
ui->listID->item(i)->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::setAllFilters()
|
||||
{
|
||||
for (int i = 0; i < ui->listID->count(); i++)
|
||||
{
|
||||
ui->listID->item(i)->setCheckState(Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::calcNextID()
|
||||
{
|
||||
if (seqIDScan)
|
||||
{
|
||||
if (rangeIDSelect)
|
||||
{
|
||||
currentID++;
|
||||
if (currentID > endID) currentID = startID;
|
||||
}
|
||||
else //IDs by filter. So, select the first filter
|
||||
{
|
||||
currentIdx++;
|
||||
if (currentIdx >= selectedIDs.length()) currentIdx = 0;
|
||||
currentID = selectedIDs[currentIdx];
|
||||
qDebug() << "idx id: " << currentID;
|
||||
}
|
||||
}
|
||||
else //random IDs
|
||||
{
|
||||
if (rangeIDSelect)
|
||||
{
|
||||
int range = endID - startID;
|
||||
if (range != 0) currentID = startID + qrand() % range;
|
||||
else currentID = startID;
|
||||
}
|
||||
else //IDs by filter so pick a random selected ID from the filter list
|
||||
{
|
||||
currentIdx = qrand() % selectedIDs.length();
|
||||
currentID = selectedIDs[currentIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::calcNextBitPattern()
|
||||
{
|
||||
uint64_t accum;
|
||||
|
||||
switch (bitSequenceType)
|
||||
{
|
||||
case BitSequenceType::Random:
|
||||
int thisBit;
|
||||
for (int byt = 0; byt < ui->spinBytes->value(); byt++)
|
||||
{
|
||||
currentBytes[byt] = 0;
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
thisBit = bitGrid[byt * 8 + bit];
|
||||
if (thisBit == 1)
|
||||
{
|
||||
if ((qrand() % 2) == 1) currentBytes[byt] |= (1 << bit);
|
||||
}
|
||||
if (thisBit == 2) currentBytes[byt] |= (1 << bit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BitSequenceType::Sequential:
|
||||
bitAccum++;
|
||||
bitAccum &= ((1 << numBits) - 1);
|
||||
accum = bitAccum;
|
||||
for (int byt = 0; byt < ui->spinBytes->value(); byt++)
|
||||
{
|
||||
currentBytes[byt] = 0;
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
thisBit = bitGrid[byt * 8 + bit];
|
||||
if (thisBit == 1)
|
||||
{
|
||||
if (accum & 1) currentBytes[byt] |= (1 << bit);
|
||||
accum >>= 1;
|
||||
}
|
||||
if (thisBit == 2) currentBytes[byt] |= (1 << bit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BitSequenceType::Sweeping:
|
||||
qDebug() << "Start " << bitAccum;
|
||||
accum = bitAccum;
|
||||
|
||||
int offset;
|
||||
for (int i = 1; i < 64; i++)
|
||||
{
|
||||
offset = (i + bitAccum) % 64;
|
||||
if (bitGrid[offset] == 1)
|
||||
{
|
||||
bitAccum = offset;
|
||||
qDebug() << "End " << bitAccum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int byt = 0; byt < ui->spinBytes->value(); byt++)
|
||||
{
|
||||
currentBytes[byt] = 0;
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
thisBit = bitGrid[byt * 8 + bit];
|
||||
if (thisBit == 1 && (byt * 8 + bit) == bitAccum)
|
||||
{
|
||||
currentBytes[byt] |= (1 << bit);
|
||||
}
|
||||
if (thisBit == 2) currentBytes[byt] |= (1 << bit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::toggleFuzzing()
|
||||
{
|
||||
if (currentlyFuzzing) //stop it then
|
||||
{
|
||||
ui->btnStartStop->setText("Start Fuzzing");
|
||||
currentlyFuzzing = false;
|
||||
fuzzTimer->stop();
|
||||
}
|
||||
else //start it then
|
||||
{
|
||||
ui->btnStartStop->setText("Stop Fuzzing");
|
||||
currentlyFuzzing = true;
|
||||
|
||||
startID = Utility::ParseStringToNum(ui->txtStartID->text());
|
||||
endID = Utility::ParseStringToNum(ui->txtEndID->text());
|
||||
|
||||
seqIDScan = ui->rbSequentialID->isChecked();
|
||||
rangeIDSelect = ui->rbRangeIDSel->isChecked();
|
||||
if (ui->rbSequentialBits->isChecked()) bitSequenceType = BitSequenceType::Sequential;
|
||||
if (ui->rbRandomBits->isChecked())
|
||||
{
|
||||
bitSequenceType = BitSequenceType::Random;
|
||||
bitAccum = 0;
|
||||
}
|
||||
if (ui->rbSweep->isChecked())
|
||||
{
|
||||
bitSequenceType = BitSequenceType::Sweeping;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
if (bitGrid[i] == 1)
|
||||
{
|
||||
bitAccum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numSentFrames = 0;
|
||||
|
||||
if (seqIDScan)
|
||||
{
|
||||
if (rangeIDSelect)
|
||||
{
|
||||
currentID = startID;
|
||||
}
|
||||
else //IDs by filter. So, select the first filter
|
||||
{
|
||||
currentIdx = 0;
|
||||
currentID = selectedIDs[currentIdx];
|
||||
}
|
||||
}
|
||||
else //random IDs
|
||||
{
|
||||
if (rangeIDSelect)
|
||||
{
|
||||
int range = endID - startID;
|
||||
if (range != 0) currentID = startID + qrand() % range;
|
||||
else currentID = startID;
|
||||
}
|
||||
else //IDs by filter so pick a random selected ID from the filter list
|
||||
{
|
||||
currentIdx = qrand() % selectedIDs.length();
|
||||
currentID = selectedIDs[currentIdx];
|
||||
}
|
||||
}
|
||||
|
||||
calcNextBitPattern();
|
||||
|
||||
fuzzTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzingWindow::refreshIDList()
|
||||
{
|
||||
ui->listID->clear();
|
||||
foundIDs.clear();
|
||||
|
||||
int id;
|
||||
for (int i = 0; i < modelFrames->count(); i++)
|
||||
{
|
||||
id = modelFrames->at(i).ID;
|
||||
if (!foundIDs.contains(id))
|
||||
{
|
||||
foundIDs.append(id);
|
||||
selectedIDs.append(id);
|
||||
QListWidgetItem *thisItem = new QListWidgetItem();
|
||||
thisItem->setText(Utility::formatNumber(id));
|
||||
thisItem->setFlags(thisItem->flags() | Qt::ItemIsUserCheckable);
|
||||
thisItem->setCheckState(Qt::Checked);
|
||||
ui->listID->addItem(thisItem);
|
||||
}
|
||||
}
|
||||
//default is to sort in ascending order
|
||||
ui->listID->sortItems();
|
||||
}
|
||||
|
||||
void FuzzingWindow::idListChanged(QListWidgetItem *item)
|
||||
{
|
||||
int id = Utility::ParseStringToNum(item->text());
|
||||
if (item->checkState() == Qt::Checked)
|
||||
{
|
||||
if (!selectedIDs.contains(id))
|
||||
{
|
||||
qDebug() << "adding " << id << " to list of selected IDs";
|
||||
selectedIDs.append(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "removing " << id << " from the list of selected ids";
|
||||
selectedIDs.removeOne(id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bitGrid stores the state of all 64 bits.
|
||||
The grid is capable of showing the following colors:
|
||||
White = not used (left as 0)
|
||||
Gray = past the end of the valid bits (because of # of data bytes requested)
|
||||
Green = fuzz it
|
||||
black = always keep it set to 1
|
||||
*/
|
||||
void FuzzingWindow::bitfieldClicked(int x, int y)
|
||||
{
|
||||
qDebug() << "X: " << x << " Y: " << y;
|
||||
int bit = (7 - x) + (y * 8);
|
||||
if (bitGrid[bit] == 3) return; //naughty!
|
||||
bitGrid[bit]++;
|
||||
if (bitGrid[bit] > 2) bitGrid[bit] = 0;
|
||||
|
||||
redrawGrid();
|
||||
}
|
||||
|
||||
void FuzzingWindow::redrawGrid()
|
||||
{
|
||||
//now update the bits in the bitfield control
|
||||
uint8_t refBytes[8];
|
||||
uint8_t dataBytes[8];
|
||||
uint8_t usedBytes[8];
|
||||
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
refBytes[j] = 0;
|
||||
dataBytes[j] = 0;
|
||||
usedBytes[j] = 0;
|
||||
}
|
||||
|
||||
numBits = 0;
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
int byt = i / 8;
|
||||
int bit = i % 8;
|
||||
switch (bitGrid[i])
|
||||
{
|
||||
case 0: //white, keep this bit off always
|
||||
break;
|
||||
case 1: //Green, fuzz this bit
|
||||
dataBytes[byt] |= (1 << bit);
|
||||
numBits++;
|
||||
break;
|
||||
case 2: //black, bit always set
|
||||
dataBytes[byt] |= (1 << bit);
|
||||
refBytes[byt] |= (1 << bit);
|
||||
break;
|
||||
case 3: //gray, this bit doesn't exist
|
||||
usedBytes[byt] |= (1 << bit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ui->bitfield->setUsed(usedBytes, false);
|
||||
ui->bitfield->setReference(refBytes, false);
|
||||
ui->bitfield->updateData(dataBytes, true);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef FUZZINGWINDOW_H
|
||||
#define FUZZINGWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
#include <QTimer>
|
||||
#include "can_structs.h"
|
||||
|
||||
namespace Ui {
|
||||
class FuzzingWindow;
|
||||
}
|
||||
|
||||
namespace BitSequenceType
|
||||
{
|
||||
enum
|
||||
{
|
||||
Sequential,
|
||||
Sweeping,
|
||||
Random
|
||||
};
|
||||
}
|
||||
|
||||
class FuzzingWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FuzzingWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
~FuzzingWindow();
|
||||
|
||||
signals:
|
||||
void sendCANFrame(const CANFrame *, int);
|
||||
void sendFrameBatch(const QList<CANFrame> *);
|
||||
|
||||
private slots:
|
||||
void changePlaybackSpeed(int newSpeed);
|
||||
void timerTriggered();
|
||||
void clearAllFilters();
|
||||
void setAllFilters();
|
||||
void toggleFuzzing();
|
||||
void idListChanged(QListWidgetItem *item);
|
||||
void bitfieldClicked(int, int);
|
||||
void changedNumDataBytes(int newVal);
|
||||
void updatedFrames(int numFrames);
|
||||
|
||||
private:
|
||||
Ui::FuzzingWindow *ui;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
QTimer *fuzzTimer;
|
||||
QList<int> foundIDs;
|
||||
QList<int> selectedIDs;
|
||||
QList<CANFrame> sendingBuffer;
|
||||
int startID, endID, currentID, currentIdx;
|
||||
bool seqIDScan, rangeIDSelect;
|
||||
int bitSequenceType;
|
||||
bool currentlyFuzzing;
|
||||
uint8_t currentBytes[8];
|
||||
uint8_t bitGrid[64];
|
||||
uint8_t numBits;
|
||||
uint64_t bitAccum;
|
||||
int numSentFrames;
|
||||
|
||||
void refreshIDList();
|
||||
void calcNextID();
|
||||
void calcNextBitPattern();
|
||||
void redrawGrid();
|
||||
};
|
||||
|
||||
#endif // FUZZINGWINDOW_H
|
||||
@@ -0,0 +1,306 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FuzzingWindow</class>
|
||||
<widget class="QDialog" name="FuzzingWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>671</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fuzzing Window</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,3,6,0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Interframe Timing (ms)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinTiming">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Number of data bytes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBytes">
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Burst Rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBurst">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Bus or Buses to Send On</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbBuses"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>ID Scanning</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSequentialID">
|
||||
<property name="text">
|
||||
<string>Seqential</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRandomID">
|
||||
<property name="text">
|
||||
<string>Random</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>ID Selection</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRangeIDSel">
|
||||
<property name="text">
|
||||
<string>Range of IDs</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbFilterIDSel">
|
||||
<property name="text">
|
||||
<string>Filter List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Bit Scanning</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSequentialBits">
|
||||
<property name="text">
|
||||
<string>Sequential</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSweep">
|
||||
<property name="text">
|
||||
<string>Sweep</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRandomBits">
|
||||
<property name="text">
|
||||
<string>Random</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>IDs</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Start ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtStartID"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>End ID:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtEndID"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listID"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAllFilters">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNoFilters">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="CANDataGrid" name="bitfield" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>White = Bit always 0, Green = Fuzz Bit, Black = Bit always set, Gray = Past end of data bytes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnStartStop">
|
||||
<property name="text">
|
||||
<string>Start Fuzzing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblNumFrames">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string># of sent frames:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CANDataGrid</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>candatagrid.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+329
-215
@@ -142,6 +142,7 @@ void GraphingWindow::updatedFrames(int numFrames)
|
||||
}
|
||||
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);
|
||||
@@ -686,21 +687,31 @@ void GraphingWindow::saveDefinitions()
|
||||
{
|
||||
outFile->write(QString::number(iter->ID, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->startByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->endByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isSigned) outFile->putChar('Y');
|
||||
else outFile->putChar('N');
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->bias).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->scale).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->stride).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isDBCSignal)
|
||||
{
|
||||
outFile->putChar('S');
|
||||
outFile->putChar(',');
|
||||
outFile->write(iter->signal.toUtf8());
|
||||
outFile->putChar(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->startByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->endByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isSigned) outFile->putChar('Y');
|
||||
else outFile->putChar('N');
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->bias).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->scale).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->stride).toUtf8());
|
||||
outFile->putChar(',');
|
||||
}
|
||||
outFile->write(QString::number(iter->color.red()).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->color.green()).toUtf8());
|
||||
@@ -718,10 +729,14 @@ void GraphingWindow::loadDefinitions()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
bool dbcMissing = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Graph definition (*.gdf)")));
|
||||
|
||||
if (dbcHandler == NULL) return;
|
||||
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
@@ -741,28 +756,65 @@ void GraphingWindow::loadDefinitions()
|
||||
{
|
||||
GraphParams gp;
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
gp.isDBCSignal = false;
|
||||
|
||||
gp.ID = tokens[0].toInt(NULL, 16);
|
||||
gp.mask = tokens[1].toULongLong(NULL, 16);
|
||||
qDebug() << gp.mask;
|
||||
gp.startByte = tokens[2].toInt();
|
||||
gp.endByte = tokens[3].toInt();
|
||||
if (tokens[4] == "Y") gp.isSigned = true;
|
||||
else gp.isSigned = false;
|
||||
gp.bias = tokens[5].toFloat();
|
||||
gp.scale = tokens[6].toFloat();
|
||||
gp.stride = tokens[7].toInt();
|
||||
gp.color.setRed(tokens[8].toInt());
|
||||
gp.color.setGreen(tokens[9].toInt());
|
||||
gp.color.setBlue(tokens[10].toInt());
|
||||
if (tokens.length() > 11)
|
||||
gp.graphName = tokens[11];
|
||||
if (tokens[1] == "S")
|
||||
{
|
||||
gp.isDBCSignal = true;
|
||||
//tokens[2] is the signal name. Need to use the message ID and this name to look it up
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
|
||||
if (msg != NULL)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
|
||||
if (sig == NULL) dbcMissing = true;
|
||||
gp.signal = tokens[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
gp.signal = "";
|
||||
dbcMissing = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
gp.graphName = QString();
|
||||
{
|
||||
gp.mask = tokens[1].toULongLong(NULL, 16);
|
||||
qDebug() << gp.mask;
|
||||
gp.startByte = tokens[2].toInt();
|
||||
gp.endByte = tokens[3].toInt();
|
||||
if (tokens[4] == "Y") gp.isSigned = true;
|
||||
else gp.isSigned = false;
|
||||
gp.bias = tokens[5].toFloat();
|
||||
gp.scale = tokens[6].toFloat();
|
||||
gp.stride = tokens[7].toInt();
|
||||
}
|
||||
if (!gp.isDBCSignal)
|
||||
{
|
||||
gp.color.setRed(tokens[8].toInt());
|
||||
gp.color.setGreen(tokens[9].toInt());
|
||||
gp.color.setBlue(tokens[10].toInt());
|
||||
if (tokens.length() > 11)
|
||||
gp.graphName = tokens[11];
|
||||
else
|
||||
gp.graphName = QString();
|
||||
}
|
||||
else
|
||||
{
|
||||
gp.color.setRed(tokens[3].toInt());
|
||||
gp.color.setGreen(tokens[4].toInt());
|
||||
gp.color.setBlue(tokens[5].toInt());
|
||||
gp.graphName = tokens[6];
|
||||
}
|
||||
createGraph(gp, true);
|
||||
}
|
||||
}
|
||||
inFile->close();
|
||||
if (dbcMissing)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setText("One or more graphs could not be loaded\r\nbecause the signal could not be found.\r\nPerhaps you forgot to load\r\nthe DBC file?");
|
||||
msg.exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,178 +851,61 @@ void GraphingWindow::addNewGraph()
|
||||
void GraphingWindow::appendToGraph(GraphParams ¶ms, CANFrame &frame)
|
||||
{
|
||||
int64_t tempVal; //64 bit temp value.
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
tempVal = (frame.data[params.startByte] & params.mask);
|
||||
if (params.isSigned && tempVal > 127)
|
||||
double tempValue;
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(params.ID);
|
||||
DBC_SIGNAL *sig = NULL;
|
||||
if (msg) sig = msg->sigHandler->findSignalByName(params.signal);
|
||||
if (sig == NULL) return;
|
||||
//if the given signal was found and successfully processed in this frame then add it to the graph
|
||||
if (sig->processAsDouble(frame, tempValue))
|
||||
{
|
||||
tempVal = tempVal - 256;
|
||||
}
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
params.y.append((tempVal * params.scale) + params.bias);
|
||||
//qDebug() << "tempValue: " << tempValue;
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
params.y.append(tempValue);
|
||||
}
|
||||
}
|
||||
else if (params.endByte > params.startByte) //big endian
|
||||
else
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.endByte - params.startByte) + 1;
|
||||
int64_t shiftRef = 1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
{
|
||||
tempByte = frame.data[params.endByte - c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += (tempByte * expon);
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
|
||||
params.y.append((tempValue * params.scale) + params.bias);
|
||||
}
|
||||
else //little endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.startByte - params.endByte) + 1;
|
||||
int64_t shiftRef = 1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frame.data[params.endByte + c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += tempByte * expon;
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
|
||||
params.y.append((tempValue * params.scale) + params.bias);
|
||||
}
|
||||
|
||||
params.ref->setData(params.x,params.y);
|
||||
}
|
||||
|
||||
void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||
{
|
||||
int64_t tempVal; //64 bit temp value.
|
||||
float yminval=10000000.0, ymaxval = -1000000.0;
|
||||
float xminval=10000000000.0, xmaxval = -10000000000.0;
|
||||
GraphParams *refParam = ¶ms;
|
||||
|
||||
qDebug() << "New Graph ID: " << params.ID;
|
||||
qDebug() << "Start byte: " << params.startByte;
|
||||
qDebug() << "End Byte: " << params.endByte;
|
||||
qDebug() << "Mask: " << params.mask;
|
||||
|
||||
frameCache.clear();
|
||||
for (int i = 0; i < modelFrames->count(); i++)
|
||||
{
|
||||
CANFrame thisFrame = modelFrames->at(i);
|
||||
if (thisFrame.ID == params.ID) frameCache.append(thisFrame);
|
||||
}
|
||||
|
||||
int numEntries = frameCache.count() / params.stride;
|
||||
|
||||
params.x.reserve(numEntries);
|
||||
params.y.reserve(numEntries);
|
||||
params.x.fill(0, numEntries);
|
||||
params.y.fill(0, numEntries);
|
||||
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
{
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempVal = (frameCache[j * params.stride].data[params.startByte] & params.mask);
|
||||
tempVal = (frame.data[params.startByte] & params.mask);
|
||||
if (params.isSigned && tempVal > 127)
|
||||
{
|
||||
tempVal = tempVal - 256;
|
||||
}
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
params.y[j] = (tempVal * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
params.y.append((tempVal * params.scale) + params.bias);
|
||||
}
|
||||
}
|
||||
else if (params.endByte > params.startByte) //big endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.endByte - params.startByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
else if (params.endByte > params.startByte) //big endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.endByte - params.startByte) + 1;
|
||||
int64_t shiftRef = 1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte - c];
|
||||
tempByte = frame.data[params.endByte - c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += (tempByte * expon);
|
||||
expon *= 256;
|
||||
@@ -991,36 +926,29 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
params.y.append((tempValue * params.scale) + params.bias);
|
||||
}
|
||||
}
|
||||
else //little endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.startByte - params.endByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
else //little endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.startByte - params.endByte) + 1;
|
||||
int64_t shiftRef = 1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte + c];
|
||||
tempByte = frame.data[params.endByte + c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += tempByte * expon;
|
||||
expon *= 256;
|
||||
@@ -1040,33 +968,219 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
params.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
params.y.append((tempValue * params.scale) + params.bias);
|
||||
}
|
||||
}
|
||||
|
||||
params.ref->setData(params.x,params.y);
|
||||
}
|
||||
|
||||
void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||
{
|
||||
int64_t tempVal; //64 bit temp value.
|
||||
float yminval=10000000.0, ymaxval = -1000000.0;
|
||||
float xminval=10000000000.0, xmaxval = -10000000000.0;
|
||||
GraphParams *refParam = ¶ms;
|
||||
DBC_MESSAGE *msg = NULL;
|
||||
DBC_SIGNAL *sig = NULL;
|
||||
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(params.ID);
|
||||
if (msg) sig = msg->sigHandler->findSignalByName(params.signal);
|
||||
if (sig == NULL) return;
|
||||
qDebug() << "New signal graph: " << params.signal <<" in ID:" << params.ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "New Graph ID: " << params.ID;
|
||||
qDebug() << "Start byte: " << params.startByte;
|
||||
qDebug() << "End Byte: " << params.endByte;
|
||||
qDebug() << "Mask: " << params.mask;
|
||||
}
|
||||
|
||||
frameCache.clear();
|
||||
for (int i = 0; i < modelFrames->count(); i++)
|
||||
{
|
||||
CANFrame thisFrame = modelFrames->at(i);
|
||||
if (thisFrame.ID == params.ID) frameCache.append(thisFrame);
|
||||
}
|
||||
|
||||
int numEntries = frameCache.count() / params.stride;
|
||||
|
||||
params.x.reserve(numEntries);
|
||||
params.y.reserve(numEntries);
|
||||
params.x.fill(0, numEntries);
|
||||
params.y.fill(0, numEntries);
|
||||
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
double tempValue;
|
||||
int l = 0;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
//if the given signal was found and successfully processed in this frame then add it to the graph
|
||||
if (sig->processAsDouble(frameCache[j], tempValue))
|
||||
{
|
||||
//qDebug() << "tempValue: " << tempValue;
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[l] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[l] = frameCache[j].timestamp;
|
||||
}
|
||||
params.y[l] = tempValue;
|
||||
if (params.y[l] < yminval) yminval = params.y[l];
|
||||
if (params.y[l] > ymaxval) ymaxval = params.y[l];
|
||||
if (params.x[l] < xminval) xminval = params.x[l];
|
||||
if (params.x[l] > xmaxval) xmaxval = params.x[l];
|
||||
l++;
|
||||
}
|
||||
}
|
||||
params.x.resize(l);
|
||||
params.y.resize(l);
|
||||
params.x.squeeze();
|
||||
params.y.squeeze();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
{
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempVal = (frameCache[j * params.stride].data[params.startByte] & params.mask);
|
||||
if (params.isSigned && tempVal > 127)
|
||||
{
|
||||
tempVal = tempVal - 256;
|
||||
}
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
params.y[j] = (tempVal * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
}
|
||||
else if (params.endByte > params.startByte) //big endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.endByte - params.startByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte - c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += (tempByte * expon);
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
}
|
||||
else //little endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.startByte - params.endByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte + c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += tempByte * expon;
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.xbias = 0;
|
||||
|
||||
/*
|
||||
for (int ct = 0; ct < params.x.count(); ct++)
|
||||
{
|
||||
params.x[ct] -= xminval;
|
||||
}
|
||||
params.xbias = xminval;
|
||||
xmaxval -= xminval;
|
||||
xminval = 0;
|
||||
*/
|
||||
|
||||
ui->graphingView->addGraph();
|
||||
params.ref = ui->graphingView->graph();
|
||||
if (createGraphParam)
|
||||
|
||||
+3
-1
@@ -24,7 +24,9 @@ public:
|
||||
QColor color;
|
||||
QCPGraph *ref;
|
||||
QString graphName;
|
||||
//the below stuff is used for internal purposes only
|
||||
bool isDBCSignal; //is this graph actually a DBC signal? If so the below pointer should be filled out
|
||||
QString signal;
|
||||
//the below stuff is used for internal purposes only - code should be refactored so these can be private
|
||||
QVector<double> x, y;
|
||||
double xbias;
|
||||
};
|
||||
|
||||
@@ -29,7 +29,6 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
|
||||
ui->cbTimeSeconds->setChecked(settings->value("Main/TimeSeconds", false).toBool());
|
||||
ui->comboSendingBus->setCurrentIndex(settings->value("Playback/SendingBus", 4).toInt());
|
||||
ui->cbUseFiltered->setChecked(settings->value("Main/UseFiltered", false).toBool());
|
||||
ui->cbSingleWire->setChecked(settings->value("Main/SingleWireMode", 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()));
|
||||
@@ -44,7 +43,6 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
|
||||
connect(ui->cbTimeSeconds, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
connect(ui->comboSendingBus, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSettings()));
|
||||
connect(ui->cbUseFiltered, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
connect(ui->cbSingleWire, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
}
|
||||
|
||||
MainSettingsDialog::~MainSettingsDialog()
|
||||
@@ -73,7 +71,6 @@ void MainSettingsDialog::updateSettings()
|
||||
settings->setValue("Main/TimeSeconds", ui->cbTimeSeconds->isChecked());
|
||||
settings->setValue("Playback/SendingBus", ui->comboSendingBus->currentIndex());
|
||||
settings->setValue("Main/UseFiltered", ui->cbUseFiltered->isChecked());
|
||||
settings->setValue("Main/SingleWireMode", ui->cbSingleWire->isChecked());
|
||||
|
||||
settings->sync();
|
||||
}
|
||||
|
||||
@@ -55,13 +55,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbSingleWire">
|
||||
<property name="text">
|
||||
<string>Put second canbus in single wire mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
+264
-348
@@ -9,14 +9,17 @@
|
||||
#include "serialworker.h"
|
||||
|
||||
/*
|
||||
Things that were planned for the GVRET-PC project but never completed.
|
||||
Compile for all platforms and create release (remember to include QScintilla libs) and make Win32 binary.
|
||||
|
||||
Some notes on things I'd like to put into the program but haven't put on github (yet)
|
||||
|
||||
Single / Multi state - The goal is to find bits that change based on toggles or discrete state items (shifters, etc)
|
||||
|
||||
Range state - Find things that range like accelerator pedal inputs, road speed, tach, etc
|
||||
|
||||
fuzzy scope - Try to find potential places where a given value might be stored - offer guesses and the program tries to find candidates for you
|
||||
or, try to find things that appear to be multi-byte integers
|
||||
|
||||
Allow scripts to read/write signals from DBC files
|
||||
allow scripts to load DBC files in support of the script - maybe the graphing system too.
|
||||
*/
|
||||
|
||||
QString MainWindow::loadedFileName = "";
|
||||
@@ -49,43 +52,22 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
readSettings();
|
||||
|
||||
QStringList headers;
|
||||
headers << "Timestamp" << "ID" << "Ext" << "Bus" << "Len" << "Data";
|
||||
//model->setHorizontalHeaderLabels(headers);
|
||||
ui->canFramesView->setColumnWidth(0, 110);
|
||||
ui->canFramesView->setColumnWidth(1, 70);
|
||||
ui->canFramesView->setColumnWidth(2, 40);
|
||||
ui->canFramesView->setColumnWidth(3, 40);
|
||||
ui->canFramesView->setColumnWidth(4, 40);
|
||||
ui->canFramesView->setColumnWidth(5, 275);
|
||||
ui->canFramesView->setColumnWidth(5, 40);
|
||||
ui->canFramesView->setColumnWidth(6, 275);
|
||||
QHeaderView *HorzHdr = ui->canFramesView->horizontalHeader();
|
||||
HorzHdr->setStretchLastSection(true); //causes the data column to automatically fill the tableview
|
||||
//enabling the below line kills performance in every way imaginable. Left here as a warning. Do not do this.
|
||||
//ui->canFramesView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
|
||||
ports = QSerialPortInfo::availablePorts();
|
||||
|
||||
for (int i = 0; i < ports.count(); i++)
|
||||
{
|
||||
ui->cbSerialPorts->addItem(ports[i].portName());
|
||||
}
|
||||
|
||||
ui->cbSpeed1->addItem(tr("Disabled"));
|
||||
ui->cbSpeed1->addItem(tr("125000"));
|
||||
ui->cbSpeed1->addItem(tr("250000"));
|
||||
ui->cbSpeed1->addItem(tr("500000"));
|
||||
ui->cbSpeed1->addItem(tr("1000000"));
|
||||
ui->cbSpeed1->addItem(tr("33333"));
|
||||
ui->cbSpeed2->addItem(tr("Disabled"));
|
||||
ui->cbSpeed2->addItem(tr("125000"));
|
||||
ui->cbSpeed2->addItem(tr("250000"));
|
||||
ui->cbSpeed2->addItem(tr("500000"));
|
||||
ui->cbSpeed2->addItem(tr("1000000"));
|
||||
ui->cbSpeed2->addItem(tr("33333"));
|
||||
|
||||
worker = new SerialWorker(model);
|
||||
worker->moveToThread(&serialWorkerThread);
|
||||
connect(&serialWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
|
||||
connect(&serialWorkerThread, &QThread::started, worker, &SerialWorker::run); //setup timers within the proper thread
|
||||
connect(this, &MainWindow::sendSerialPort, worker, &SerialWorker::setSerialPort, Qt::QueuedConnection);
|
||||
connect(worker, &SerialWorker::frameUpdateTick, this, &MainWindow::gotFrames, Qt::QueuedConnection);
|
||||
connect(this, &MainWindow::updateBaudRates, worker, &SerialWorker::updateBaudRates, Qt::QueuedConnection);
|
||||
@@ -98,7 +80,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(this, &MainWindow::stopFrameCapturing, worker, &SerialWorker::stopFrameCapture);
|
||||
connect(this, &MainWindow::settingsUpdated, worker, &SerialWorker::readSettings);
|
||||
serialWorkerThread.start();
|
||||
serialWorkerThread.setPriority(QThread::HighPriority);
|
||||
serialWorkerThread.setPriority(QThread::HighPriority);
|
||||
|
||||
graphingWindow = NULL;
|
||||
frameInfoWindow = NULL;
|
||||
@@ -110,46 +92,53 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
settingsDialog = NULL;
|
||||
firmwareUploaderWindow = NULL;
|
||||
discreteStateWindow = NULL;
|
||||
connectionWindow = NULL;
|
||||
scriptingWindow = NULL;
|
||||
rangeWindow = NULL;
|
||||
dbcFileWindow = NULL;
|
||||
fuzzingWindow = NULL;
|
||||
udsScanWindow = NULL;
|
||||
dbcHandler = new DBCHandler;
|
||||
bDirty = false;
|
||||
inhibitFilterUpdate = false;
|
||||
|
||||
model->setDBCHandler(dbcHandler);
|
||||
|
||||
connect(ui->btnConnect, SIGNAL(clicked(bool)), this, SLOT(connButtonPress()));
|
||||
connect(ui->actionOpen_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadFile()));
|
||||
connect(ui->actionGraph_Dta, SIGNAL(triggered(bool)), this, SLOT(showGraphingWindow()));
|
||||
connect(ui->actionFrame_Data_Analysis, SIGNAL(triggered(bool)), this, SLOT(showFrameDataAnalysis()));
|
||||
connect(ui->btnClearFrames, SIGNAL(clicked(bool)), this, SLOT(clearFrames()));
|
||||
connect(ui->actionSave_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveFile()));
|
||||
connect(ui->actionSave_Filtered_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveFilteredFile()));
|
||||
connect(ui->actionLoad_Filter_Definition, SIGNAL(triggered(bool)), this, SLOT(handleLoadFilters()));
|
||||
connect(ui->actionSave_Filter_Definition, SIGNAL(triggered(bool)), this, SLOT(handleSaveFilters()));
|
||||
connect(ui->action_Playback, SIGNAL(triggered(bool)), this, SLOT(showPlaybackWindow()));
|
||||
connect(ui->btnBaudSet, SIGNAL(clicked(bool)), this, SLOT(changeBaudRates()));
|
||||
connect(ui->actionFlow_View, SIGNAL(triggered(bool)), this, SLOT(showFlowViewWindow()));
|
||||
connect(ui->action_Custom, SIGNAL(triggered(bool)), this, SLOT(showFrameSenderWindow()));
|
||||
connect(ui->actionLoad_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadDBC()));
|
||||
connect(ui->actionSave_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveDBC()));
|
||||
connect(ui->canFramesView, SIGNAL(clicked(QModelIndex)), this, SLOT(gridClicked(QModelIndex)));
|
||||
connect(ui->canFramesView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(gridDoubleClicked(QModelIndex)));
|
||||
connect(ui->cbInterpret, SIGNAL(toggled(bool)), this, SLOT(interpretToggled(bool)));
|
||||
connect(ui->cbOverwrite, SIGNAL(toggled(bool)), this, SLOT(overwriteToggled(bool)));
|
||||
connect(ui->actionEdit_Messages_Signals, SIGNAL(triggered(bool)), this, SLOT(showDBCEditor()));
|
||||
connect(ui->btnCaptureToggle, SIGNAL(clicked(bool)), this, SLOT(toggleCapture()));
|
||||
connect(ui->actionExit_Application, SIGNAL(triggered(bool)), this, SLOT(exitApp()));
|
||||
connect(ui->actionFuzzy_Scope, SIGNAL(triggered(bool)), this, SLOT(showFuzzyScopeWindow()));
|
||||
connect(ui->actionRange_State, SIGNAL(triggered(bool)), this, SLOT(showRangeWindow()));
|
||||
connect(ui->actionSave_Decoded_Frames, SIGNAL(triggered(bool)), this, SLOT(handleSaveDecoded()));
|
||||
connect(ui->actionSingle_Multi_State, SIGNAL(triggered(bool)), this, SLOT(showSingleMultiWindow()));
|
||||
connect(ui->actionFile_Comparison, SIGNAL(triggered(bool)), this, SLOT(showComparisonWindow()));
|
||||
connect(ui->btnNormalize, SIGNAL(clicked(bool)), this, SLOT(normalizeTiming()));
|
||||
connect(ui->actionPreferences, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog()));
|
||||
connect(model, SIGNAL(updatedFiltersList()), this, SLOT(updateFilterList()));
|
||||
connect(ui->listFilters, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(filterListItemChanged(QListWidgetItem*)));
|
||||
connect(ui->btnFilterAll, SIGNAL(clicked(bool)), this, SLOT(filterSetAll()));
|
||||
connect(ui->btnFilterNone, SIGNAL(clicked(bool)), this, SLOT(filterClearAll()));
|
||||
connect(ui->actionFirmware_Uploader, SIGNAL(triggered(bool)), this, SLOT(showFirmwareUploaderWindow()));
|
||||
connect(ui->actionSetup, SIGNAL(triggered(bool)), SLOT(showConnectionSettingsWindow()));
|
||||
connect(ui->actionConnect, SIGNAL(triggered(bool)), this, SLOT(connButtonPress()));
|
||||
connect(ui->actionOpen_Log_File, &QAction::triggered, this, &MainWindow::handleLoadFile);
|
||||
connect(ui->actionGraph_Dta, &QAction::triggered, this, &MainWindow::showGraphingWindow);
|
||||
connect(ui->actionFrame_Data_Analysis, &QAction::triggered, this, &MainWindow::showFrameDataAnalysis);
|
||||
connect(ui->btnClearFrames, &QAbstractButton::clicked, this, &MainWindow::clearFrames);
|
||||
connect(ui->actionSave_Log_File, &QAction::triggered, this, &MainWindow::handleSaveFile);
|
||||
connect(ui->actionSave_Filtered_Log_File, &QAction::triggered, this, &MainWindow::handleSaveFilteredFile);
|
||||
connect(ui->actionLoad_Filter_Definition, &QAction::triggered, this, &MainWindow::handleLoadFilters);
|
||||
connect(ui->actionSave_Filter_Definition, &QAction::triggered, this, &MainWindow::handleSaveFilters);
|
||||
connect(ui->action_Playback, &QAction::triggered, this, &MainWindow::showPlaybackWindow);
|
||||
connect(ui->actionFlow_View, &QAction::triggered, this, &MainWindow::showFlowViewWindow);
|
||||
connect(ui->action_Custom, &QAction::triggered, this, &MainWindow::showFrameSenderWindow);
|
||||
connect(ui->canFramesView, &QAbstractItemView::clicked, this, &MainWindow::gridClicked);
|
||||
connect(ui->canFramesView, &QAbstractItemView::doubleClicked, this, &MainWindow::gridDoubleClicked);
|
||||
connect(ui->cbInterpret, &QAbstractButton::toggled, this, &MainWindow::interpretToggled);
|
||||
connect(ui->cbOverwrite, &QAbstractButton::toggled, this, &MainWindow::overwriteToggled);
|
||||
connect(ui->btnCaptureToggle, &QAbstractButton::clicked, this, &MainWindow::toggleCapture);
|
||||
connect(ui->actionExit_Application, &QAction::triggered, this, &MainWindow::exitApp);
|
||||
connect(ui->actionFuzzy_Scope, &QAction::triggered, this, &MainWindow::showFuzzyScopeWindow);
|
||||
connect(ui->actionRange_State_2, &QAction::triggered, this, &MainWindow::showRangeWindow);
|
||||
connect(ui->actionSave_Decoded_Frames, &QAction::triggered, this, &MainWindow::handleSaveDecoded);
|
||||
connect(ui->actionSingle_Multi_State_2, &QAction::triggered, this, &MainWindow::showSingleMultiWindow);
|
||||
connect(ui->actionFile_Comparison, &QAction::triggered, this, &MainWindow::showComparisonWindow);
|
||||
connect(ui->actionScripting_INterface, &QAction::triggered, this, &MainWindow::showScriptingWindow);
|
||||
connect(ui->btnNormalize, &QAbstractButton::clicked, this, &MainWindow::normalizeTiming);
|
||||
connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::showSettingsDialog);
|
||||
connect(model, &CANFrameModel::updatedFiltersList, this, &MainWindow::updateFilterList);
|
||||
connect(ui->listFilters, &QListWidget::itemChanged, this, &MainWindow::filterListItemChanged);
|
||||
connect(ui->btnFilterAll, &QAbstractButton::clicked, this, &MainWindow::filterSetAll);
|
||||
connect(ui->btnFilterNone, &QAbstractButton::clicked, this, &MainWindow::filterClearAll);
|
||||
connect(ui->actionFirmware_Uploader, &QAction::triggered, this, &MainWindow::showFirmwareUploaderWindow);
|
||||
connect(ui->actionDBC_File_Manager, &QAction::triggered, this, &MainWindow::showDBCFileWindow);
|
||||
connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow);
|
||||
connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow);
|
||||
|
||||
lbStatusConnected.setText(tr("Not connected"));
|
||||
updateFileStatus();
|
||||
@@ -175,6 +164,10 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
normalRowHeight = ui->canFramesView->rowHeight(0);
|
||||
qDebug() << "normal row height = " << normalRowHeight;
|
||||
model->clearFrames();
|
||||
|
||||
//Automatically create the connection window so it can be updated even if we never opened it.
|
||||
connectionWindow = new ConnectionWindow();
|
||||
connect(connectionWindow, SIGNAL(updateConnectionSettings(QString,QString,int,int)), this, SLOT(updateConnectionSettings(QString,QString,int,int)));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
@@ -237,12 +230,68 @@ MainWindow::~MainWindow()
|
||||
delete discreteStateWindow;
|
||||
}
|
||||
|
||||
if (connectionWindow)
|
||||
{
|
||||
connectionWindow->close();
|
||||
delete connectionWindow;
|
||||
}
|
||||
|
||||
if (scriptingWindow)
|
||||
{
|
||||
scriptingWindow->close();
|
||||
delete scriptingWindow;
|
||||
}
|
||||
|
||||
if (rangeWindow)
|
||||
{
|
||||
rangeWindow->close();
|
||||
delete rangeWindow;
|
||||
}
|
||||
|
||||
if (dbcFileWindow)
|
||||
{
|
||||
dbcFileWindow->close();
|
||||
delete dbcFileWindow;
|
||||
}
|
||||
|
||||
if (fuzzingWindow)
|
||||
{
|
||||
fuzzingWindow->close();
|
||||
delete fuzzingWindow;
|
||||
}
|
||||
|
||||
if (udsScanWindow)
|
||||
{
|
||||
udsScanWindow->close();
|
||||
delete udsScanWindow;
|
||||
}
|
||||
|
||||
delete ui;
|
||||
delete dbcHandler;
|
||||
model->clearFrames();
|
||||
delete model;
|
||||
}
|
||||
|
||||
void MainWindow::exitApp()
|
||||
{
|
||||
if (graphingWindow) graphingWindow->close();
|
||||
if (frameInfoWindow) frameInfoWindow->close();
|
||||
if (playbackWindow) playbackWindow->close();
|
||||
if (flowViewWindow) flowViewWindow->close();
|
||||
if (frameSenderWindow) frameSenderWindow->close();
|
||||
if (dbcMainEditor) dbcMainEditor->close();
|
||||
if (comparatorWindow) comparatorWindow->close();
|
||||
if (connectionWindow) connectionWindow->close();
|
||||
if (settingsDialog) settingsDialog->close();
|
||||
if (discreteStateWindow) discreteStateWindow->close();
|
||||
if (scriptingWindow) scriptingWindow->close();
|
||||
if (rangeWindow) rangeWindow->close();
|
||||
if (dbcFileWindow) dbcFileWindow->close();
|
||||
if (fuzzingWindow) fuzzingWindow->close();
|
||||
if (udsScanWindow) udsScanWindow->close();
|
||||
this->close();
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
@@ -268,6 +317,20 @@ void MainWindow::readSettings()
|
||||
{
|
||||
ui->cbAutoScroll->setChecked(true);
|
||||
}
|
||||
|
||||
int cType = settings.value("Main/DefaultConnectionType", 0).toInt();
|
||||
if (cType == 0) connType = "GVRET";
|
||||
if (cType == 1) connType = "KVASER";
|
||||
if (cType == 2) connType = "SOCKETCAN";
|
||||
portName = settings.value("Main/DefaultConnectionPort", "").toString();
|
||||
canSpeed0 = -1;
|
||||
canSpeed1 = -1;
|
||||
|
||||
qDebug() << connType;
|
||||
qDebug() << portName;
|
||||
|
||||
//"Main/SingleWireMode"
|
||||
|
||||
readUpdateableSettings();
|
||||
}
|
||||
|
||||
@@ -293,6 +356,57 @@ void MainWindow::writeSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1)
|
||||
{
|
||||
connType = connectionType;
|
||||
portName = port;
|
||||
|
||||
canSpeed0 = speed0;
|
||||
canSpeed1 = speed1;
|
||||
if (isConnected)
|
||||
{
|
||||
emit updateBaudRates(speed0, speed1);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::connButtonPress()
|
||||
{
|
||||
if (!isConnected)
|
||||
{
|
||||
if (connType == "GVRET")
|
||||
{
|
||||
QList<QSerialPortInfo> ports;
|
||||
ports = QSerialPortInfo::availablePorts();
|
||||
|
||||
for (int i = 0; i < ports.count(); i++)
|
||||
{
|
||||
if (ports[i].portName() == portName)
|
||||
{
|
||||
portInfo = ports[i];
|
||||
//need to create some way to send single wire mode to serial port code
|
||||
emit sendSerialPort(&portInfo);
|
||||
lbStatusConnected.setText(tr("Attempting to connect to port ") + portName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (connType == "KVASER")
|
||||
{
|
||||
|
||||
}
|
||||
else if (connType == "SOCKETCAN")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
emit closeSerialPort();
|
||||
isConnected = false;
|
||||
lbStatusConnected.setText(tr("Not Connected"));
|
||||
ui->actionConnect->setText(tr("Connect"));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::gridClicked(QModelIndex idx)
|
||||
{
|
||||
if (ui->canFramesView->rowHeight(idx.row()) > normalRowHeight)
|
||||
@@ -437,8 +551,8 @@ void MainWindow::changeBaudRates()
|
||||
{
|
||||
int Speed1 = 0, Speed2 = 0;
|
||||
|
||||
Speed1 = ui->cbSpeed1->currentText().toInt();
|
||||
Speed2 = ui->cbSpeed2->currentText().toInt();
|
||||
//Speed1 = ui->cbSpeed1->currentText().toInt();
|
||||
//Speed2 = ui->cbSpeed2->currentText().toInt();
|
||||
|
||||
emit updateBaudRates(Speed1, Speed2);
|
||||
}
|
||||
@@ -446,216 +560,42 @@ void MainWindow::changeBaudRates()
|
||||
void MainWindow::handleLoadFile()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
bool result = false;
|
||||
QVector<CANFrame> tempFrames;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("CRTD Logs (*.txt)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log)")));
|
||||
filters.append(QString(tr("Microchip Log (*.can)")));
|
||||
filters.append(QString(tr("Vector Trace Files (*.trace)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
if (FrameFileIO::loadFrameFile(filename, &tempFrames))
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
ui->canFramesView->scrollToTop();
|
||||
model->clearFrames();
|
||||
model->insertFrames(tempFrames);
|
||||
loadedFileName = filename;
|
||||
model->recalcOverwrite();
|
||||
ui->lbNumFrames->setText(QString::number(model->rowCount()));
|
||||
if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||
|
||||
QVector<CANFrame> tempFrames;
|
||||
|
||||
QProgressDialog progress(this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setLabelText("Loading file...");
|
||||
progress.setCancelButton(0);
|
||||
progress.setRange(0,0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0]) result = FrameFileIO::loadCRTDFile(filename, &tempFrames);
|
||||
if (dialog.selectedNameFilter() == filters[1]) result = FrameFileIO::loadNativeCSVFile(filename, &tempFrames);
|
||||
if (dialog.selectedNameFilter() == filters[2]) result = FrameFileIO::loadGenericCSVFile(filename, &tempFrames);
|
||||
if (dialog.selectedNameFilter() == filters[3]) result = FrameFileIO::loadLogFile(filename, &tempFrames);
|
||||
if (dialog.selectedNameFilter() == filters[4]) result = FrameFileIO::loadMicrochipFile(filename, &tempFrames);
|
||||
if (dialog.selectedNameFilter() == filters[5]) result = FrameFileIO::loadTraceFile(filename, &tempFrames);
|
||||
|
||||
progress.cancel();
|
||||
|
||||
if (result)
|
||||
{
|
||||
model->insertFrames(tempFrames);
|
||||
|
||||
QStringList fileList = filename.split('/');
|
||||
loadedFileName = fileList[fileList.length() - 1];
|
||||
|
||||
model->recalcOverwrite();
|
||||
ui->lbNumFrames->setText(QString::number(model->rowCount()));
|
||||
if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||
|
||||
updateFileStatus();
|
||||
emit framesUpdated(-2);
|
||||
}
|
||||
updateFileStatus();
|
||||
emit framesUpdated(-2);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleSaveFile()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
bool result = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("CRTD Logs (*.txt)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log)")));
|
||||
filters.append(QString(tr("Microchip Log (*.can)")));
|
||||
filters.append(QString(tr("Vector Trace Files (*.trace)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
if (FrameFileIO::saveFrameFile(filename, model->getListReference()))
|
||||
{
|
||||
const QVector<CANFrame> *frames = model->getListReference();
|
||||
filename = dialog.selectedFiles()[0];
|
||||
|
||||
QProgressDialog progress(this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setLabelText("Saving file...");
|
||||
progress.setCancelButton(0);
|
||||
progress.setRange(0,0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".txt";
|
||||
result = FrameFileIO::saveCRTDFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[1])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = FrameFileIO::saveNativeCSVFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[2])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = FrameFileIO::saveGenericCSVFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[3])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = FrameFileIO::saveLogFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[4])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = FrameFileIO::saveMicrochipFile(filename, frames);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[5])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".trace";
|
||||
result = FrameFileIO::saveTraceFile(filename, frames);
|
||||
}
|
||||
|
||||
progress.cancel();
|
||||
|
||||
if (result)
|
||||
{
|
||||
QStringList fileList = filename.split('/');
|
||||
loadedFileName = fileList[fileList.length() - 1];
|
||||
updateFileStatus();
|
||||
}
|
||||
loadedFileName = filename;
|
||||
updateFileStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleSaveFilteredFile()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
bool result = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("CRTD Logs (*.txt)")));
|
||||
filters.append(QString(tr("GVRET Logs (*.csv)")));
|
||||
filters.append(QString(tr("Generic ID/Data CSV (*.csv)")));
|
||||
filters.append(QString(tr("BusMaster Log (*.log)")));
|
||||
filters.append(QString(tr("Microchip Log (*.log)")));
|
||||
filters.append(QString(tr("Vector Trace Files (*.trace)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
if (FrameFileIO::saveFrameFile(filename, model->getFilteredListReference()))
|
||||
{
|
||||
const QVector<CANFrame> *frames = model->getFilteredListReference();
|
||||
filename = dialog.selectedFiles()[0];
|
||||
|
||||
QProgressDialog progress(this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
progress.setLabelText("Saving filtered file...");
|
||||
progress.setCancelButton(0);
|
||||
progress.setRange(0,0);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".txt";
|
||||
result = FrameFileIO::saveCRTDFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[1])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = FrameFileIO::saveNativeCSVFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[2])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".csv";
|
||||
result = FrameFileIO::saveGenericCSVFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[3])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = FrameFileIO::saveLogFile(filename, frames);
|
||||
}
|
||||
if (dialog.selectedNameFilter() == filters[4])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".log";
|
||||
result = FrameFileIO::saveMicrochipFile(filename, frames);
|
||||
}
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[5])
|
||||
{
|
||||
if (!filename.contains('.')) filename += ".trace";
|
||||
result = FrameFileIO::saveTraceFile(filename, frames);
|
||||
}
|
||||
|
||||
progress.cancel();
|
||||
|
||||
if (result)
|
||||
{
|
||||
QStringList fileList = filename.split('/');
|
||||
loadedFileName = fileList[fileList.length() - 1];
|
||||
updateFileStatus();
|
||||
}
|
||||
loadedFileName = filename;
|
||||
updateFileStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,52 +640,7 @@ void MainWindow::handleLoadFilters()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleLoadDBC()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("DBC File (*.dbc)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
//right now there is only one file type that can be loaded here so just do it.
|
||||
dbcHandler->loadDBCFile(filename);
|
||||
//dbcHandler->listDebugging();
|
||||
QStringList fileList = filename.split('/');
|
||||
lbStatusDatabase.setText(fileList[fileList.length() - 1] + tr(" loaded."));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleSaveDBC()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("DBC File (*.dbc)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
if (!filename.contains('.')) filename += ".dbc";
|
||||
dbcHandler->saveDBCFile(filename);
|
||||
QStringList fileList = filename.split('/');
|
||||
lbStatusDatabase.setText(fileList[fileList.length() - 1] + tr(" loaded."));
|
||||
}
|
||||
|
||||
}
|
||||
//lbStatusDatabase.setText(fileList[fileList.length() - 1] + tr(" loaded."));
|
||||
|
||||
void MainWindow::handleSaveDecoded()
|
||||
{
|
||||
@@ -771,7 +666,7 @@ void MainWindow::handleSaveDecoded()
|
||||
void MainWindow::saveDecodedTextFile(QString filename)
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
const QVector<CANFrame> *frames = model->getListReference();
|
||||
const QVector<CANFrame> *frames = model->getFilteredListReference();
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
@@ -803,14 +698,18 @@ Data Bytes: 88 10 00 13 BB 00 06 00
|
||||
builderString = "";
|
||||
if (dbcHandler != NULL)
|
||||
{
|
||||
DBC_MESSAGE *msg = dbcHandler->findMsgByID(thisFrame.ID);
|
||||
DBC_MESSAGE *msg = dbcHandler->findMessage(thisFrame);
|
||||
if (msg != NULL)
|
||||
{
|
||||
for (int j = 0; j < msg->msgSignals.length(); j++)
|
||||
for (int j = 0; j < msg->sigHandler->getCount(); j++)
|
||||
{
|
||||
|
||||
builderString.append("\t" + dbcHandler->processSignal(thisFrame, msg->msgSignals.at(j)));
|
||||
builderString.append("\n");
|
||||
QString temp;
|
||||
if (msg->sigHandler->findSignalByIdx(j)->processAsText(thisFrame, temp))
|
||||
{
|
||||
builderString.append("\t" + temp);
|
||||
builderString.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
builderString.append("\n");
|
||||
@@ -820,29 +719,6 @@ Data Bytes: 88 10 00 13 BB 00 06 00
|
||||
outFile->close();
|
||||
}
|
||||
|
||||
void MainWindow::connButtonPress()
|
||||
{
|
||||
if (!isConnected)
|
||||
{
|
||||
for (int x = 0; x < ports.count(); x++)
|
||||
{
|
||||
if (ports.at(x).portName() == ui->cbSerialPorts->currentText())
|
||||
{
|
||||
emit sendSerialPort(&ports[x]);
|
||||
lbStatusConnected.setText(tr("Attempting to connect to port ") + ports[x].portName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
emit closeSerialPort();
|
||||
isConnected = false;
|
||||
lbStatusConnected.setText(tr("Not Connected"));
|
||||
ui->btnConnect->setText(tr("Connect to GVRET"));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::toggleCapture()
|
||||
{
|
||||
allowCapture = !allowCapture;
|
||||
@@ -863,7 +739,7 @@ void MainWindow::connectionSucceeded(int baud0, int baud1)
|
||||
lbStatusConnected.setText(tr("Connected to GVRET"));
|
||||
//finally, find the baud rate in the list of rates or
|
||||
//add it to the bottom if needed (that'll be weird though...
|
||||
|
||||
/*
|
||||
int idx = ui->cbSpeed1->findText(QString::number(baud0));
|
||||
if (idx > -1) ui->cbSpeed1->setCurrentIndex(idx);
|
||||
else
|
||||
@@ -879,8 +755,10 @@ void MainWindow::connectionSucceeded(int baud0, int baud1)
|
||||
ui->cbSpeed2->addItem(QString::number(baud1));
|
||||
ui->cbSpeed2->setCurrentIndex(ui->cbSpeed2->count() - 1);
|
||||
}
|
||||
*/
|
||||
if (connectionWindow) connectionWindow->setSpeeds(baud0, baud1);
|
||||
//ui->btnConnect->setEnabled(false);
|
||||
ui->btnConnect->setText(tr("Disconnect from GVRET"));
|
||||
ui->actionConnect->setText(tr("Disconnect"));
|
||||
isConnected = true;
|
||||
}
|
||||
|
||||
@@ -933,6 +811,12 @@ void MainWindow::gotDeviceInfo(int build, int swCAN)
|
||||
+ "\n\nPlease upgrade your firmware version.\nOtherwise, you may experience difficulties.");
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
if (connectionWindow)
|
||||
{
|
||||
if (swCAN == 1) connectionWindow->setCAN1SWMode(true);
|
||||
else connectionWindow->setCAN1SWMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setTargettedID(int id)
|
||||
@@ -989,7 +873,7 @@ void MainWindow::showFrameSenderWindow()
|
||||
else
|
||||
frameSenderWindow = new FrameSenderWindow(model->getFilteredListReference());
|
||||
|
||||
connect(frameSenderWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int)));
|
||||
connect(frameSenderWindow, &FrameSenderWindow::sendCANFrame, worker, &SerialWorker::sendFrame);
|
||||
}
|
||||
frameSenderWindow->show();
|
||||
}
|
||||
@@ -1035,9 +919,44 @@ void MainWindow::showSingleMultiWindow()
|
||||
discreteStateWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showFuzzingWindow()
|
||||
{
|
||||
if (!fuzzingWindow)
|
||||
{
|
||||
fuzzingWindow = new FuzzingWindow(model->getListReference());
|
||||
connect(fuzzingWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int)));
|
||||
connect(fuzzingWindow, SIGNAL(sendFrameBatch(const QList<CANFrame>*)), worker, SLOT(sendFrameBatch(const QList<CANFrame>*)));
|
||||
}
|
||||
fuzzingWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showUDSScanWindow()
|
||||
{
|
||||
if (!udsScanWindow)
|
||||
{
|
||||
udsScanWindow = new UDSScanWindow(model->getListReference());
|
||||
connect(udsScanWindow, SIGNAL(sendCANFrame(const CANFrame*,int)), worker, SLOT(sendFrame(const CANFrame*,int)));
|
||||
}
|
||||
udsScanWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showScriptingWindow()
|
||||
{
|
||||
if (!scriptingWindow)
|
||||
{
|
||||
scriptingWindow = new ScriptingWindow(model->getListReference());
|
||||
connect(scriptingWindow, &ScriptingWindow::sendCANFrame, worker, &SerialWorker::sendFrame);
|
||||
}
|
||||
scriptingWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showRangeWindow()
|
||||
{
|
||||
//not done yet
|
||||
if (!rangeWindow)
|
||||
{
|
||||
rangeWindow = new RangeStateWindow(model->getListReference());
|
||||
}
|
||||
rangeWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showFuzzyScopeWindow()
|
||||
@@ -1045,18 +964,6 @@ void MainWindow::showFuzzyScopeWindow()
|
||||
//not done yet
|
||||
}
|
||||
|
||||
void MainWindow::exitApp()
|
||||
{
|
||||
if (graphingWindow) graphingWindow->close();
|
||||
if (frameInfoWindow) frameInfoWindow->close();
|
||||
if (playbackWindow) playbackWindow->close();
|
||||
if (flowViewWindow) flowViewWindow->close();
|
||||
if (frameSenderWindow) frameSenderWindow->close();
|
||||
if (dbcMainEditor) dbcMainEditor->close();
|
||||
if (comparatorWindow) comparatorWindow->close();
|
||||
this->close();
|
||||
}
|
||||
|
||||
void MainWindow::showFlowViewWindow()
|
||||
{
|
||||
if (!flowViewWindow)
|
||||
@@ -1078,12 +985,21 @@ void MainWindow::showFlowViewWindow()
|
||||
flowViewWindow->show();
|
||||
}
|
||||
|
||||
//this one always gets the unfiltered list intentionally.
|
||||
void MainWindow::showDBCEditor()
|
||||
void MainWindow::showDBCFileWindow()
|
||||
{
|
||||
if (!dbcMainEditor)
|
||||
if (!dbcFileWindow)
|
||||
{
|
||||
dbcMainEditor = new DBCMainEditor(dbcHandler, model->getListReference());
|
||||
dbcFileWindow = new DBCLoadSaveWindow(dbcHandler, model->getListReference());
|
||||
}
|
||||
dbcMainEditor->show();
|
||||
dbcFileWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::showConnectionSettingsWindow()
|
||||
{
|
||||
if (!connectionWindow)
|
||||
{
|
||||
connectionWindow = new ConnectionWindow();
|
||||
connect(connectionWindow, SIGNAL(updateConnectionSettings(QString,QString,int,int)), this, SLOT(updateConnectionSettings(QString,QString,int,int)));
|
||||
}
|
||||
connectionWindow->show();
|
||||
}
|
||||
|
||||
+22
-5
@@ -19,6 +19,12 @@
|
||||
#include "mainsettingsdialog.h"
|
||||
#include "firmwareuploaderwindow.h"
|
||||
#include "discretestatewindow.h"
|
||||
#include "connectionwindow.h"
|
||||
#include "scriptingwindow.h"
|
||||
#include "rangestatewindow.h"
|
||||
#include "dbcloadsavewindow.h"
|
||||
#include "fuzzingwindow.h"
|
||||
#include "udsscanwindow.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
@@ -39,8 +45,6 @@ private slots:
|
||||
void handleLoadFile();
|
||||
void handleSaveFile();
|
||||
void handleSaveFilteredFile();
|
||||
void handleLoadDBC();
|
||||
void handleSaveDBC();
|
||||
void handleSaveFilters();
|
||||
void handleLoadFilters();
|
||||
void connButtonPress();
|
||||
@@ -56,6 +60,11 @@ private slots:
|
||||
void showComparisonWindow();
|
||||
void showSettingsDialog();
|
||||
void showFirmwareUploaderWindow();
|
||||
void showConnectionSettingsWindow();
|
||||
void showScriptingWindow();
|
||||
void showDBCFileWindow();
|
||||
void showFuzzingWindow();
|
||||
void showUDSScanWindow();
|
||||
void exitApp();
|
||||
void handleSaveDecoded();
|
||||
void changeBaudRates();
|
||||
@@ -66,7 +75,6 @@ private slots:
|
||||
void gridDoubleClicked(QModelIndex);
|
||||
void interpretToggled(bool);
|
||||
void overwriteToggled(bool);
|
||||
void showDBCEditor();
|
||||
void toggleCapture();
|
||||
void normalizeTiming();
|
||||
void updateFilterList();
|
||||
@@ -78,6 +86,7 @@ public slots:
|
||||
void gotFrames(int, int);
|
||||
void updateSettings();
|
||||
void gotCenterTimeID(int32_t ID, double timestamp);
|
||||
void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1);
|
||||
|
||||
signals:
|
||||
void sendSerialPort(QSerialPortInfo *port);
|
||||
@@ -98,8 +107,7 @@ private:
|
||||
|
||||
//canbus related data
|
||||
CANFrameModel *model;
|
||||
DBCHandler *dbcHandler;
|
||||
QList<QSerialPortInfo> ports;
|
||||
DBCHandler *dbcHandler;
|
||||
QThread serialWorkerThread;
|
||||
SerialWorker *worker;
|
||||
QByteArray inputBuffer;
|
||||
@@ -121,6 +129,12 @@ private:
|
||||
MainSettingsDialog *settingsDialog;
|
||||
DiscreteStateWindow *discreteStateWindow;
|
||||
FirmwareUploaderWindow *firmwareUploaderWindow;
|
||||
ConnectionWindow *connectionWindow;
|
||||
ScriptingWindow *scriptingWindow;
|
||||
RangeStateWindow *rangeWindow;
|
||||
DBCLoadSaveWindow *dbcFileWindow;
|
||||
FuzzingWindow *fuzzingWindow;
|
||||
UDSScanWindow *udsScanWindow;
|
||||
|
||||
//various private storage
|
||||
QLabel lbStatusConnected;
|
||||
@@ -128,6 +142,9 @@ private:
|
||||
QLabel lbStatusDatabase;
|
||||
int normalRowHeight;
|
||||
bool isConnected;
|
||||
QSerialPortInfo portInfo;
|
||||
QString connType, portName;
|
||||
int canSpeed0, canSpeed1;
|
||||
|
||||
//private methods
|
||||
void saveDecodedTextFile(QString);
|
||||
|
||||
+55
-110
@@ -46,102 +46,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Serial Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSerialPorts"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnConnect">
|
||||
<property name="text">
|
||||
<string>Connect To GVRET</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CANBus Speeds:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>First Bus:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSpeed1"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Second Bus:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSpeed2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnBaudSet">
|
||||
<property name="text">
|
||||
<string>Set CANBUS Speeds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
@@ -293,7 +197,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>21</height>
|
||||
<height>27</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_RE_Tools">
|
||||
@@ -304,6 +208,8 @@
|
||||
<addaction name="actionGraph_Dta"/>
|
||||
<addaction name="actionFrame_Data_Analysis"/>
|
||||
<addaction name="actionFile_Comparison"/>
|
||||
<addaction name="actionRange_State_2"/>
|
||||
<addaction name="actionSingle_Multi_State_2"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSend_Frames">
|
||||
<property name="title">
|
||||
@@ -311,6 +217,9 @@
|
||||
</property>
|
||||
<addaction name="action_Playback"/>
|
||||
<addaction name="action_Custom"/>
|
||||
<addaction name="actionScripting_INterface"/>
|
||||
<addaction name="actionFuzzing"/>
|
||||
<addaction name="actionUDS_Scanner"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
@@ -323,18 +232,24 @@
|
||||
<addaction name="actionLoad_Filter_Definition"/>
|
||||
<addaction name="actionSave_Filter_Definition"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoad_DBC_File"/>
|
||||
<addaction name="actionEdit_Messages_Signals"/>
|
||||
<addaction name="actionSave_DBC_File"/>
|
||||
<addaction name="actionDBC_File_Manager"/>
|
||||
<addaction name="actionSave_Decoded_Frames"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreferences"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit_Application"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuConnection">
|
||||
<property name="title">
|
||||
<string>Connection</string>
|
||||
</property>
|
||||
<addaction name="actionSetup"/>
|
||||
<addaction name="actionConnect"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menu_RE_Tools"/>
|
||||
<addaction name="menuSend_Frames"/>
|
||||
<addaction name="menuConnection"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="action_Playback">
|
||||
@@ -347,16 +262,6 @@
|
||||
<string>Custom</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSingle_Multi_State">
|
||||
<property name="text">
|
||||
<string>Single / Multi State</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRange_State">
|
||||
<property name="text">
|
||||
<string>Range State</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFlow_View">
|
||||
<property name="text">
|
||||
<string>Flow View</string>
|
||||
@@ -442,6 +347,46 @@
|
||||
<string>Firmware Uploader</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSetup">
|
||||
<property name="text">
|
||||
<string>Set Port</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConnect">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionScripting_INterface">
|
||||
<property name="text">
|
||||
<string>Scripting Interface</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRange_State_2">
|
||||
<property name="text">
|
||||
<string>Range State</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSingle_Multi_State_2">
|
||||
<property name="text">
|
||||
<string>Single/Multi State</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDBC_File_Manager">
|
||||
<property name="text">
|
||||
<string>DBC File Manager</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFuzzing">
|
||||
<property name="text">
|
||||
<string>Fuzzing</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUDS_Scanner">
|
||||
<property name="text">
|
||||
<string>UDS Scanner</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
+114
-48
@@ -25,6 +25,8 @@ NewGraphDialog::NewGraphDialog(DBCHandler *handler, QWidget *parent) :
|
||||
|
||||
connect(ui->cbMessages, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSignals(int)));
|
||||
connect(ui->cbSignals, SIGNAL(currentIndexChanged(int)), this, SLOT(fillFormFromSignal(int)));
|
||||
connect(ui->rbSignalGraph, SIGNAL(toggled(bool)), this, SLOT(setSignalActive(bool)));
|
||||
connect(ui->rbStandardGraph, SIGNAL(toggled(bool)), this, SLOT(setStandardActive(bool)));
|
||||
|
||||
loadMessages();
|
||||
}
|
||||
@@ -58,28 +60,41 @@ void NewGraphDialog::clearParams()
|
||||
ui->txtStride->clear();
|
||||
ui->txtName->clear();
|
||||
ui->txtData->clear();
|
||||
ui->rbStandardGraph->setChecked(true);
|
||||
setStandardActive(true);
|
||||
|
||||
}
|
||||
|
||||
void NewGraphDialog::setParams(GraphParams ¶ms)
|
||||
{
|
||||
ui->txtID->setText(Utility::formatNumber(params.ID));
|
||||
ui->txtBias->setText(QString::number(params.bias));
|
||||
ui->txtMask->setText(Utility::formatNumber(params.mask));
|
||||
ui->txtScale->setText(QString::number(params.scale));
|
||||
ui->txtStride->setText(QString::number(params.stride));
|
||||
ui->cbSigned->setChecked(params.isSigned);
|
||||
ui->txtName->setText(params.graphName);
|
||||
|
||||
if (params.endByte > -1)
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
ui->txtData->setText(QString::number(params.startByte) + "-" + QString::number(params.endByte));
|
||||
clearParams();
|
||||
setSignalActive(true);
|
||||
//loadMessages();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->txtData->setText(QString::number(params.startByte));
|
||||
setStandardActive(true);
|
||||
ui->txtBias->setText(QString::number(params.bias));
|
||||
ui->txtMask->setText(Utility::formatNumber(params.mask));
|
||||
ui->txtScale->setText(QString::number(params.scale));
|
||||
ui->txtStride->setText(QString::number(params.stride));
|
||||
ui->cbSigned->setChecked(params.isSigned);
|
||||
|
||||
if (params.endByte > -1)
|
||||
{
|
||||
ui->txtData->setText(QString::number(params.startByte) + "-" + QString::number(params.endByte));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->txtData->setText(QString::number(params.startByte));
|
||||
}
|
||||
}
|
||||
|
||||
ui->txtID->setText(Utility::formatNumber(params.ID));
|
||||
ui->txtName->setText(params.graphName);
|
||||
QPalette p = ui->colorSwatch->palette();
|
||||
p.setColor(QPalette::Button, params.color);
|
||||
ui->colorSwatch->setPalette(p);
|
||||
@@ -87,40 +102,58 @@ void NewGraphDialog::setParams(GraphParams ¶ms)
|
||||
|
||||
void NewGraphDialog::getParams(GraphParams ¶ms)
|
||||
{
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = ui->txtBias->text().toFloat();
|
||||
params.isDBCSignal = ui->rbSignalGraph->isChecked();
|
||||
params.color = ui->colorSwatch->palette().button().color();
|
||||
params.isSigned = ui->cbSigned->isChecked();
|
||||
params.mask = Utility::ParseStringToNum(ui->txtMask->text());
|
||||
params.scale = ui->txtScale->text().toFloat();
|
||||
params.stride = Utility::ParseStringToNum(ui->txtStride->text());
|
||||
|
||||
QStringList values = ui->txtData->text().split('-');
|
||||
params.startByte = -1;
|
||||
params.endByte = -1;
|
||||
if (values.count() > 0)
|
||||
{
|
||||
params.startByte = values[0].toInt();
|
||||
if (values.count() > 1)
|
||||
{
|
||||
params.endByte = values[1].toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//now catch stupidity and bring it to defaults
|
||||
if (params.mask == 0) params.mask = 0xFFFFFFFF;
|
||||
if (fabs(params.scale) < 0.00000001) params.scale = 1.0f;
|
||||
if (params.stride < 1) params.stride = 1;
|
||||
params.graphName = ui->txtName->text();
|
||||
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
params.signal = ui->cbSignals->currentText();
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = 0;
|
||||
params.isSigned = false;
|
||||
params.mask = 0;
|
||||
params.scale = 1;
|
||||
params.bias = 0;
|
||||
params.stride = 1;
|
||||
|
||||
}
|
||||
else {
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = ui->txtBias->text().toFloat();
|
||||
params.isSigned = ui->cbSigned->isChecked();
|
||||
params.mask = Utility::ParseStringToNum(ui->txtMask->text());
|
||||
params.scale = ui->txtScale->text().toFloat();
|
||||
params.stride = Utility::ParseStringToNum(ui->txtStride->text());
|
||||
params.signal = "";
|
||||
|
||||
QStringList values = ui->txtData->text().split('-');
|
||||
params.startByte = -1;
|
||||
params.endByte = -1;
|
||||
if (values.count() > 0)
|
||||
{
|
||||
params.startByte = values[0].toInt();
|
||||
if (values.count() > 1)
|
||||
{
|
||||
params.endByte = values[1].toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//now catch stupidity and bring it to defaults
|
||||
if (params.mask == 0) params.mask = 0xFFFFFFFF;
|
||||
if (fabs(params.scale) < 0.00000001) params.scale = 1.0f;
|
||||
if (params.stride < 1) params.stride = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NewGraphDialog::loadMessages()
|
||||
{
|
||||
ui->cbMessages->clear();
|
||||
if (dbcHandler == NULL) return;
|
||||
for (int x = 0; x < dbcHandler->dbc_messages.count(); x++)
|
||||
if (dbcHandler->getFileCount() == 0) dbcHandler->createBlankFile();
|
||||
for (int x = 0; x < dbcHandler->getFileByIdx(0)->messageHandler->getCount(); x++)
|
||||
{
|
||||
ui->cbMessages->addItem(dbcHandler->dbc_messages[x].name);
|
||||
ui->cbMessages->addItem(dbcHandler->getFileByIdx(0)->messageHandler->findMsgByIdx(x)->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,13 +164,13 @@ void NewGraphDialog::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->findMsgByName(ui->cbMessages->currentText());
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
|
||||
|
||||
if (msg == NULL) return;
|
||||
ui->cbSignals->clear();
|
||||
for (int x = 0; x < msg->msgSignals.count(); x++)
|
||||
for (int x = 0; x < msg->sigHandler->getCount(); x++)
|
||||
{
|
||||
ui->cbSignals->addItem(msg->msgSignals[x].name);
|
||||
ui->cbSignals->addItem(msg->sigHandler->findSignalByIdx(x)->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,23 +178,24 @@ void NewGraphDialog::fillFormFromSignal(int idx)
|
||||
{
|
||||
Q_UNUSED(idx);
|
||||
GraphParams params;
|
||||
DBC_MESSAGE *msg = dbcHandler->findMsgByName(ui->cbMessages->currentText());
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
|
||||
|
||||
if (msg == NULL) return;
|
||||
|
||||
DBC_SIGNAL *sig = dbcHandler->findSignalByName(msg, ui->cbSignals->currentText());
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
|
||||
|
||||
if (sig == NULL) return;
|
||||
|
||||
params.graphName = sig->name;
|
||||
params.ID = msg->ID;
|
||||
params.bias = sig->bias;
|
||||
params.scale = sig->factor;
|
||||
params.stride = 1;
|
||||
params.mask = (1 << (sig->signalSize)) - 1;
|
||||
if (sig->valType == SIGNED_INT) params.isSigned = true;
|
||||
else params.isSigned = false;
|
||||
//params.bias = sig->bias;
|
||||
//params.scale = sig->factor;
|
||||
//params.stride = 1;
|
||||
//params.mask = (1 << (sig->signalSize)) - 1;
|
||||
//if (sig->valType == SIGNED_INT) params.isSigned = true;
|
||||
//else params.isSigned = false;
|
||||
params.color = ui->colorSwatch->palette().color(QPalette::Button);
|
||||
/*
|
||||
if (sig->intelByteOrder)
|
||||
{
|
||||
//for this ordering the byte order is reserved and starting byte
|
||||
@@ -175,6 +209,38 @@ void NewGraphDialog::fillFormFromSignal(int idx)
|
||||
params.startByte = sig->startBit / 8;
|
||||
params.endByte = (sig->startBit + sig->signalSize - 1) / 8;
|
||||
}
|
||||
|
||||
*/
|
||||
setParams(params);
|
||||
}
|
||||
|
||||
void NewGraphDialog::setSignalActive(bool state)
|
||||
{
|
||||
if (!state) return;
|
||||
ui->rbSignalGraph->setChecked(true);
|
||||
ui->rbStandardGraph->setChecked(false);
|
||||
ui->cbMessages->setEnabled(true);
|
||||
ui->cbSignals->setEnabled(true);
|
||||
ui->cbSigned->setEnabled(false);
|
||||
ui->txtBias->setEnabled(false);
|
||||
ui->txtData->setEnabled(false);
|
||||
ui->txtID->setEnabled(false);
|
||||
ui->txtMask->setEnabled(false);
|
||||
ui->txtScale->setEnabled(false);
|
||||
ui->txtStride->setEnabled(false);
|
||||
}
|
||||
|
||||
void NewGraphDialog::setStandardActive(bool state)
|
||||
{
|
||||
if (!state) return;
|
||||
ui->rbStandardGraph->setChecked(true);
|
||||
ui->rbSignalGraph->setChecked(false);
|
||||
ui->cbMessages->setEnabled(false);
|
||||
ui->cbSignals->setEnabled(false);
|
||||
ui->cbSigned->setEnabled(true);
|
||||
ui->txtBias->setEnabled(true);
|
||||
ui->txtData->setEnabled(true);
|
||||
ui->txtID->setEnabled(true);
|
||||
ui->txtMask->setEnabled(true);
|
||||
ui->txtScale->setEnabled(true);
|
||||
ui->txtStride->setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ private slots:
|
||||
void loadMessages();
|
||||
void loadSignals(int idx);
|
||||
void fillFormFromSignal(int idx);
|
||||
void setSignalActive(bool);
|
||||
void setStandardActive(bool);
|
||||
|
||||
private:
|
||||
Ui::NewGraphDialog *ui;
|
||||
|
||||
+25
-1
@@ -7,13 +7,37 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>492</width>
|
||||
<height>309</height>
|
||||
<height>340</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Graph Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbStandardGraph">
|
||||
<property name="text">
|
||||
<string>Standard Graph</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSignalGraph">
|
||||
<property name="text">
|
||||
<string>DBC Signal Graph</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
|
||||
<item>
|
||||
|
||||
@@ -0,0 +1,430 @@
|
||||
#include "rangestatewindow.h"
|
||||
#include "ui_rangestatewindow.h"
|
||||
#include "mainwindow.h"
|
||||
#include "utility.h"
|
||||
|
||||
RangeStateWindow::RangeStateWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RangeStateWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
ui->graphSignal->xAxis->setRange(0, 8);
|
||||
ui->graphSignal->yAxis->setRange(-10, 265); //run range a bit outside possible number so they aren't plotted in a hard to see place
|
||||
ui->graphSignal->xAxis->setVisible(false);
|
||||
ui->graphSignal->yAxis->setVisible(false);
|
||||
|
||||
//ui->graphSignal->axisRect()->setupFullAxesBox();
|
||||
|
||||
ui->cbSignalMode->addItem(tr("Big Endian"));
|
||||
ui->cbSignalMode->addItem(tr("Little Endian"));
|
||||
ui->cbSignalMode->addItem(tr("Try Both"));
|
||||
|
||||
ui->cbSignedMode->addItem(tr("Signed Value"));
|
||||
ui->cbSignedMode->addItem(tr("Unsigned Value"));
|
||||
ui->cbSignedMode->addItem(tr("Try Both"));
|
||||
|
||||
//lambda expressions used here because these are tiny functions that don't have any reason to be full named functions
|
||||
//unfortunately the fact that valueChanged is overloaded makes the syntax here HORRIBLE. That sucks.
|
||||
connect(ui->spinMaxSigSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||
[=](int newVal)
|
||||
{
|
||||
if (newVal < ui->spinMinSigSize->value()) ui->spinMinSigSize->setValue(newVal);
|
||||
});
|
||||
|
||||
connect(ui->spinMinSigSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||
[=](int newVal)
|
||||
{
|
||||
if (newVal > ui->spinMaxSigSize->value()) ui->spinMaxSigSize->setValue(newVal);
|
||||
});
|
||||
|
||||
connect(ui->btnAllFilter, &QAbstractButton::clicked,
|
||||
[=]()
|
||||
{
|
||||
for (int i = 0; i < ui->listFilter->count(); i++)
|
||||
{
|
||||
QListWidgetItem *item = ui->listFilter->item(i);
|
||||
item->setCheckState(Qt::Checked);
|
||||
idFilters[Utility::ParseStringToNum(item->text())] = true;
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnNoneFilter, &QAbstractButton::clicked,
|
||||
[=]()
|
||||
{
|
||||
for (int i = 0; i < ui->listFilter->count(); i++)
|
||||
{
|
||||
QListWidgetItem *item = ui->listFilter->item(i);
|
||||
item->setCheckState(Qt::Unchecked);
|
||||
idFilters[Utility::ParseStringToNum(item->text())] = false;
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->listFilter, &QListWidget::itemChanged,
|
||||
[=](QListWidgetItem *item)
|
||||
{
|
||||
bool isChecked = false;
|
||||
int id = Utility::ParseStringToNum(item->text());
|
||||
if (item->checkState() == Qt::Checked) isChecked = true;
|
||||
idFilters[id] = isChecked;
|
||||
});
|
||||
|
||||
connect(ui->btnRecalc, &QAbstractButton::clicked, this, &RangeStateWindow::recalcButton);
|
||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||
connect(ui->listCandidates, &QListWidget::currentRowChanged, this, &RangeStateWindow::clickedSignalList);
|
||||
}
|
||||
|
||||
RangeStateWindow::~RangeStateWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RangeStateWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
|
||||
readSettings();
|
||||
|
||||
refreshFilterList();
|
||||
}
|
||||
|
||||
void RangeStateWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
void RangeStateWindow::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
resize(settings.value("RangeStateView/WindowSize", QSize(765, 615)).toSize());
|
||||
move(settings.value("RangeStateView/WindowPos", QPoint(50, 50)).toPoint());
|
||||
}
|
||||
}
|
||||
|
||||
void RangeStateWindow::writeSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
settings.setValue("RangeStateView/WindowSize", size());
|
||||
settings.setValue("RangeStateView/WindowPos", pos());
|
||||
}
|
||||
}
|
||||
|
||||
void RangeStateWindow::updatedFrames(int numFrames)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
if (numFrames == -1) //all frames deleted. We don't need to do a thing on this window but erase everything in the filters section
|
||||
{
|
||||
ui->listFilter->clear();
|
||||
idFilters.clear();
|
||||
}
|
||||
else if (numFrames == -2) //all new set of frames. Reset
|
||||
{
|
||||
refreshFilterList();
|
||||
}
|
||||
else //just got some new frames. See if we need to update the filters list. Otherwise nothing to do - no recalc happens until the button is pressed
|
||||
{
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||
{
|
||||
thisFrame = modelFrames->at(i);
|
||||
if (!idFilters.contains(thisFrame.ID))
|
||||
{
|
||||
idFilters.insert(thisFrame.ID, true);
|
||||
QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listFilter);
|
||||
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
|
||||
listItem->setCheckState(Qt::Checked); //default all filters to be set active
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RangeStateWindow::refreshFilterList()
|
||||
{
|
||||
int id;
|
||||
|
||||
idFilters.clear();
|
||||
ui->listFilter->clear();
|
||||
|
||||
for (int i = 0; i < modelFrames->length(); i++)
|
||||
{
|
||||
id = modelFrames->at(i).ID;
|
||||
if (!idFilters.contains(id))
|
||||
{
|
||||
idFilters.insert(id, true);
|
||||
QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(id), ui->listFilter);
|
||||
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
|
||||
listItem->setCheckState(Qt::Checked); //default all filters to be set active
|
||||
}
|
||||
}
|
||||
|
||||
ui->listFilter->sortItems();
|
||||
}
|
||||
|
||||
void RangeStateWindow::recalcButton()
|
||||
{
|
||||
QHash<int, bool>::iterator iter;
|
||||
int id;
|
||||
|
||||
ui->listCandidates->clear();
|
||||
foundSignals.clear();
|
||||
|
||||
for (iter = idFilters.begin(); iter != idFilters.end(); ++iter)
|
||||
{
|
||||
if (iter.value() == true)
|
||||
{
|
||||
qDebug() << "Processing for ID: " << iter.key();
|
||||
//so, we're supposed to process this frame ID. We'll need to create a frame cache for it
|
||||
frameCache.clear();
|
||||
frameCache.reserve(modelFrames->count()); //block allocate more than enough space
|
||||
id = iter.key();
|
||||
for (int j = 0; j < modelFrames->count(); j++)
|
||||
{
|
||||
if (modelFrames->at(j).ID == id) frameCache.append(modelFrames->at(j));
|
||||
}
|
||||
//now we've got a list with all the same ID. Time to send it off for processing
|
||||
signalsFactory();
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Found " << foundSignals.count() << " signals total.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Uses the settings exposed to the user to generate a set of candidate signals that should be checked.
|
||||
* The user could specify signal sizes, granularity, endian type and we generate all the permutations from there
|
||||
* Should process from max to min and stop when a valid signal is found (at least as an option) to declutter a bit.
|
||||
* Mostly what we're interested in is the largest signal that matches
|
||||
*/
|
||||
void RangeStateWindow::signalsFactory()
|
||||
{
|
||||
int minSig = ui->spinMinSigSize->value();
|
||||
int maxSig = ui->spinMaxSigSize->value();
|
||||
int granularity = ui->spinGranularity->value();
|
||||
int sigType = ui->cbSignalMode->currentIndex() + 1;
|
||||
int signedType = ui->cbSignedMode->currentIndex() + 1;
|
||||
int maxBits = frameCache.at(0).len * 8;
|
||||
int sens = ui->slideSensitivity->value();
|
||||
|
||||
for (int sigSize = maxSig; sigSize >= minSig; sigSize--)
|
||||
{
|
||||
for (int startBit = 0; startBit < maxBits; startBit += granularity)
|
||||
{
|
||||
if (sigType & 1)
|
||||
{
|
||||
if (signedType & 1) processSignal(startBit, sigSize, sens, true, true);
|
||||
if (signedType & 2) processSignal(startBit, sigSize, sens, true, false);
|
||||
}
|
||||
if (sigType & 2)
|
||||
{
|
||||
if (signedType & 1) processSignal(startBit, sigSize, sens, false, true);
|
||||
if (signedType & 2) processSignal(startBit, sigSize, sens, false, false);
|
||||
}
|
||||
//have to try both types even with 8 bit and smaller signals
|
||||
//because they could cross byte boundaries. Could check whether they
|
||||
//do and not try both types if it is impossible.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given the signal we generate the relevant data and figure out whether this signal seems to be a smooth range signal
|
||||
*/
|
||||
bool RangeStateWindow::processSignal(int startBit, int bitLength, int sensitivity, bool bigEndian, bool isSigned)
|
||||
{
|
||||
qDebug() << "";
|
||||
qDebug() << "S:" << startBit << " B:" << bitLength << " Sens:" << sensitivity << " Big E:" << bigEndian << " Signed: " << isSigned;
|
||||
|
||||
QVector<int> scaledVals;
|
||||
QVector<int> diff1;
|
||||
QVector<int> diff2;
|
||||
int64_t valu;
|
||||
int64_t highestValue = -1000000000000LL;
|
||||
int64_t lowestValue = 1000000000000LL;
|
||||
double multiplier;
|
||||
int numFrames = frameCache.count();
|
||||
|
||||
scaledVals.reserve(frameCache.count());
|
||||
diff1.reserve(frameCache.count() - 1);
|
||||
diff2.reserve(frameCache.count() - 2);
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numFrames; i++)
|
||||
{
|
||||
valu = Utility::processIntegerSignal(frameCache.at(i).data, startBit, bitLength, !bigEndian, isSigned);
|
||||
if (valu < lowestValue) lowestValue = valu;
|
||||
if (valu > highestValue) highestValue = valu;
|
||||
}
|
||||
|
||||
qDebug() << "Min: " << lowestValue << " Max: " << highestValue;
|
||||
|
||||
if (lowestValue == highestValue) return false; //a signal that never changes is worthless and not a range signal
|
||||
|
||||
//multiplier is calculated such that the range of the signal is scaled down to the value of sensitivity.
|
||||
//so, if we have a sensitivity of 50 then the range is scaled so that it is 50
|
||||
//this has the effect of smoothing the data a bit by completely removing the fine detail. It's irrelevant to
|
||||
//an algorithm like this anyway and just gets in the way.
|
||||
//Also, we're going to offset by lowest value so that everything is based at a value of 0 as the low end.
|
||||
//All of this drastically modifies the actual signal but that's OK, we're looking for patterns here not
|
||||
//being faithful to the signal (what a dirty cheater)
|
||||
int range = highestValue - lowestValue;
|
||||
multiplier = (double)sensitivity / (double)range;
|
||||
|
||||
for (i = 0; i < numFrames; i++) scaledVals.append((int)((Utility::processIntegerSignal(frameCache.at(i).data, startBit, bitLength, !bigEndian, isSigned) - lowestValue) * multiplier));
|
||||
|
||||
for (i = 1; i < numFrames; i++)
|
||||
{
|
||||
valu = scaledVals[i-1] - scaledVals[i];
|
||||
diff1.append(valu);
|
||||
}
|
||||
|
||||
for (i = 1; i < diff1.count(); i++)
|
||||
{
|
||||
valu = diff1[i-1] - diff1[i];
|
||||
diff2.append(valu);
|
||||
}
|
||||
|
||||
//now the differences are all stored so let's go through and see if they seem to suggest a ramping sort of signal or not.
|
||||
//for a first test lets let through any signal where the acceleration values are all much smaller than the signal range
|
||||
bool isGood = true;
|
||||
int comparisonValue = Utility::Lerp(sensitivity / 5, sensitivity / 40, (sensitivity - 10) / 240.0);
|
||||
qDebug() << "range: " << sensitivity << " comparisonvalue: " << comparisonValue;
|
||||
int overValues = 0;
|
||||
for (i = 0; i < diff2.count(); i++)
|
||||
{
|
||||
if (abs(diff1[i]) > comparisonValue) overValues++;
|
||||
}
|
||||
int maxOvers = Utility::Lerp(4, numFrames / 50.0, 1.0 - ((sensitivity -10) / 240.0));
|
||||
qDebug() << "Max Overs: " << maxOvers;
|
||||
if (overValues > maxOvers) isGood = false;
|
||||
qDebug() << "Is this signal good: " << isGood << " Num overs: " << overValues;
|
||||
if (isGood)
|
||||
{
|
||||
//createGraph(scaledVals);
|
||||
QString temp;
|
||||
temp = "ID: " + QString::number(frameCache.at(0).ID, 16) + " startBit: " + QString::number(startBit) + " len: " + QString::number(bitLength);
|
||||
int64_t foundSig;
|
||||
foundSig = frameCache.at(0).ID;
|
||||
foundSig += (int64_t)startBit << 32;
|
||||
foundSig += (int64_t)bitLength << 40;
|
||||
|
||||
if (isSigned)
|
||||
{
|
||||
temp += " Signed";
|
||||
foundSig += (int64_t)1 << 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += " Unsigned";
|
||||
}
|
||||
|
||||
if (bigEndian)
|
||||
{
|
||||
temp += " BigEndian";
|
||||
foundSig += (int64_t)1 << 49;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += " LittleEndian";
|
||||
}
|
||||
|
||||
ui->listCandidates->addItem(temp);
|
||||
foundSignals.append(foundSig);
|
||||
}
|
||||
return isGood;
|
||||
}
|
||||
|
||||
//graphs the vector such that the X axis is just the index into the vector and Y is perfectly graphed within the window
|
||||
void RangeStateWindow::createGraph(QVector<int> values)
|
||||
{
|
||||
|
||||
int tempVal;
|
||||
float minval=1000000, maxval = -100000;
|
||||
|
||||
int numEntries = values.count();
|
||||
|
||||
ui->graphSignal->clearGraphs();
|
||||
|
||||
QVector<double> x(numEntries), y(numEntries);
|
||||
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempVal = values[j];
|
||||
|
||||
x[j] = j;
|
||||
|
||||
y[j] = tempVal;
|
||||
if (y[j] < minval) minval = y[j];
|
||||
if (y[j] > maxval) maxval = y[j];
|
||||
}
|
||||
|
||||
qDebug() << "YMin: " << minval << " YMax: " << maxval;
|
||||
|
||||
double ymin, ymax;
|
||||
|
||||
ymin = minval;
|
||||
|
||||
if (ymin < 0) ymin *= 1.2;
|
||||
else ymin *= 0.8;
|
||||
|
||||
ymax = maxval;
|
||||
if (ymax < 0) ymax * 0.8;
|
||||
else ymax *= 1.2;
|
||||
|
||||
if (fabs(ymin) < 0.01) ymin -= (ymax / 60.0);
|
||||
if (fabs(ymax) < 0.01) ymax -= (ymin / 60.0);
|
||||
|
||||
qDebug() << "YFm: " << ymin << " YFM: " << ymax;
|
||||
|
||||
ui->graphSignal->addGraph();
|
||||
ui->graphSignal->graph()->setName("Graph");
|
||||
ui->graphSignal->graph()->setData(x,y);
|
||||
ui->graphSignal->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines
|
||||
QPen graphPen;
|
||||
graphPen.setColor(Qt::black);
|
||||
graphPen.setWidth(1);
|
||||
ui->graphSignal->graph()->setPen(graphPen);
|
||||
ui->graphSignal->xAxis->setRange(0, numEntries);
|
||||
ui->graphSignal->yAxis->setRange(ymin, ymax);
|
||||
ui->graphSignal->replot();
|
||||
}
|
||||
|
||||
void RangeStateWindow::clickedSignalList(int idx)
|
||||
{
|
||||
if (idx == -1) return; //just in case...
|
||||
|
||||
int id, startBit, bitLength;
|
||||
bool isSigned = false, isBigEndian = false;
|
||||
int64_t valu;
|
||||
|
||||
valu = foundSignals.at(idx);
|
||||
id = valu & 0xFFFFFFFFULL;
|
||||
startBit = (valu >> 32) & 0xFF;
|
||||
bitLength = (valu >> 40) & 0xFF;
|
||||
if (valu & (1LL << 48)) isSigned = true;
|
||||
if (valu & (1LL << 49)) isBigEndian = true;
|
||||
|
||||
qDebug() << "I:" << id << " sb:" << startBit << " len:" << bitLength << " signed:" << isSigned << " big:" << isBigEndian;
|
||||
|
||||
frameCache.clear();
|
||||
frameCache.reserve(modelFrames->count()); //block allocate more than enough space
|
||||
|
||||
for (int j = 0; j < modelFrames->count(); j++)
|
||||
{
|
||||
if (modelFrames->at(j).ID == id) frameCache.append(modelFrames->at(j));
|
||||
}
|
||||
|
||||
int numFrames = frameCache.count();
|
||||
QVector<int> values;
|
||||
values.reserve(numFrames);
|
||||
for (int i = 0; i < numFrames; i++) values.append((int)((Utility::processIntegerSignal(frameCache.at(i).data, startBit, bitLength, !isBigEndian, isSigned))));
|
||||
createGraph(values);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef RANGESTATEWINDOW_H
|
||||
#define RANGESTATEWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "can_structs.h"
|
||||
|
||||
namespace Ui {
|
||||
class RangeStateWindow;
|
||||
}
|
||||
|
||||
class RangeStateWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RangeStateWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
~RangeStateWindow();
|
||||
void showEvent(QShowEvent*);
|
||||
|
||||
private slots:
|
||||
void updatedFrames(int);
|
||||
void recalcButton();
|
||||
void clickedSignalList(int idx);
|
||||
|
||||
private:
|
||||
Ui::RangeStateWindow *ui;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
QVector<CANFrame> frameCache;
|
||||
QList<int64_t> foundSignals;
|
||||
QHash<int, bool> idFilters;
|
||||
|
||||
void refreshFilterList();
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
void signalsFactory();
|
||||
bool processSignal(int startBit, int bitLength, int sensitivity, bool bigEndian, bool isSigned);
|
||||
void createGraph(QVector<int> values);
|
||||
};
|
||||
|
||||
#endif // RANGESTATEWINDOW_H
|
||||
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RangeStateWindow</class>
|
||||
<widget class="QDialog" name="RangeStateWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>763</width>
|
||||
<height>938</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Range State Window</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,2,0,2">
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Candidate Signals:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listCandidates"/>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Graphical Representation of Selected Signal:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCustomPlot" name="graphSignal" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Sensitivity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slideSensitivity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Min Signal Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinMinSigSize">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Max Signal Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinMaxSigSize">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Granularity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinGranularity">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Signal Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSignalMode"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Signed Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSignedMode"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>ID Filter:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFilter"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAllFilter">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNoneFilter">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRecalc">
|
||||
<property name="text">
|
||||
<string>Recalculate Candidate Signals</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QCustomPlot</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qcustomplot.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,148 @@
|
||||
#include "scriptcontainer.h"
|
||||
|
||||
#include <QJSValueIterator>
|
||||
#include <QDebug>
|
||||
|
||||
ScriptContainer::ScriptContainer()
|
||||
{
|
||||
fileName = QString();
|
||||
filePath = QString();
|
||||
scriptText = QString();
|
||||
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(tick()));
|
||||
}
|
||||
|
||||
void ScriptContainer::compileScript()
|
||||
{
|
||||
QJSValue result = scriptEngine.evaluate(scriptText, fileName);
|
||||
|
||||
errorWidget->clear();
|
||||
|
||||
if (result.isError() && errorWidget)
|
||||
{
|
||||
errorWidget->addItem("SCRIPT EXCEPTION!");
|
||||
errorWidget->addItem("Line: " + result.property("lineNumber").toString());
|
||||
errorWidget->addItem(result.property("message").toString());
|
||||
errorWidget->addItem("Stack:");
|
||||
errorWidget->addItem(result.property("stack").toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
compiledScript = result;
|
||||
|
||||
QJSValue hostObj = scriptEngine.newQObject(this);
|
||||
scriptEngine.globalObject().setProperty("host", hostObj);
|
||||
|
||||
setupFunction = scriptEngine.globalObject().property("setup");
|
||||
gotFrameFunction = scriptEngine.globalObject().property("gotFrame");
|
||||
tickFunction = scriptEngine.globalObject().property("tick");
|
||||
|
||||
if (setupFunction.isCallable())
|
||||
{
|
||||
qDebug() << "setup exists";
|
||||
QJSValue res = setupFunction.call();
|
||||
if (res.isError())
|
||||
{
|
||||
errorWidget->addItem("Error in setup function on line " + res.property("lineNumber").toString());
|
||||
errorWidget->addItem(res.property("message").toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (gotFrameFunction.isCallable()) qDebug() << "gotFrame exists";
|
||||
if (tickFunction.isCallable()) qDebug() << "tick exists";
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptContainer::setErrorWidget(QListWidget *list)
|
||||
{
|
||||
errorWidget = list;
|
||||
}
|
||||
|
||||
void ScriptContainer::setFilter(QJSValue id, QJSValue mask, QJSValue bus)
|
||||
{
|
||||
uint32_t idVal = id.toUInt();
|
||||
uint32_t maskVal = mask.toUInt();
|
||||
int busVal = bus.toInt();
|
||||
qDebug() << "Called set filter";
|
||||
qDebug() << idVal << "*" << maskVal << "*" << busVal;
|
||||
CANFilter filter;
|
||||
filter.setFilter(idVal, maskVal, busVal);
|
||||
filters.append(filter);
|
||||
}
|
||||
|
||||
void ScriptContainer::setTickInterval(QJSValue interval)
|
||||
{
|
||||
int intervalValue = interval.toInt();
|
||||
qDebug() << "called set tick interval with value " << intervalValue;
|
||||
if (intervalValue > 0)
|
||||
{
|
||||
timer.setInterval(intervalValue);
|
||||
timer.start();
|
||||
}
|
||||
else timer.stop();
|
||||
}
|
||||
|
||||
void ScriptContainer::clearFilters()
|
||||
{
|
||||
qDebug() << "Called clear filters";
|
||||
filters.clear();
|
||||
}
|
||||
|
||||
void ScriptContainer::sendFrame(QJSValue bus, QJSValue id, QJSValue length, QJSValue data)
|
||||
{
|
||||
CANFrame frame;
|
||||
frame.extended = false;
|
||||
frame.ID = id.toInt();
|
||||
frame.len = length.toInt();
|
||||
if (frame.len < 0) frame.len = 0;
|
||||
if (frame.len > 8) frame.len = 8;
|
||||
|
||||
if (!data.isArray()) qDebug() << "data isn't an array";
|
||||
|
||||
for (int i = 0; i < frame.len; i++)
|
||||
{
|
||||
frame.data[i] = (uint8_t)data.property(i).toInt();
|
||||
}
|
||||
|
||||
frame.bus = bus.toInt();
|
||||
if (frame.bus < 0) frame.bus = 0;
|
||||
if (frame.bus > 1) frame.bus = 1;
|
||||
|
||||
if (frame.ID > 0x7FF) frame.extended = true;
|
||||
|
||||
//qDebug() << "Sending frame from script";
|
||||
emit sendCANFrame(&frame, frame.bus);
|
||||
}
|
||||
|
||||
void ScriptContainer::gotFrame(const CANFrame &frame)
|
||||
{
|
||||
if (!gotFrameFunction.isCallable()) return; //nothing to do if we can't even call the function
|
||||
//qDebug() << "Got frame in script interface";
|
||||
for (int i = 0; i < filters.length(); i++)
|
||||
{
|
||||
if (filters[i].checkFilter(frame.ID, frame.bus))
|
||||
{
|
||||
QJSValueList args;
|
||||
args << frame.bus << frame.ID << frame.len;
|
||||
QJSValue dataBytes = scriptEngine.newArray(frame.len);
|
||||
for (int j = 0; j < frame.len; j++) dataBytes.setProperty(j, QJSValue(frame.data[j]));
|
||||
args.append(dataBytes);
|
||||
gotFrameFunction.call(args);
|
||||
return; //as soon as one filter matches we jump out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptContainer::tick()
|
||||
{
|
||||
if (tickFunction.isCallable())
|
||||
{
|
||||
//qDebug() << "Calling tick function";
|
||||
QJSValue res = tickFunction.call();
|
||||
if (res.isError())
|
||||
{
|
||||
errorWidget->addItem("Error in tick function on line " + res.property("lineNumber").toString());
|
||||
errorWidget->addItem(res.property("message").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef SCRIPTCONTAINER_H
|
||||
#define SCRIPTCONTAINER_H
|
||||
|
||||
#include "can_structs.h"
|
||||
#include "canfilter.h"
|
||||
|
||||
#include <QJSEngine>
|
||||
#include <QTimer>
|
||||
#include <qlistwidget.h>
|
||||
|
||||
class ScriptContainer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScriptContainer();
|
||||
void gotFrame(const CANFrame &frame);
|
||||
|
||||
QString fileName;
|
||||
QString filePath;
|
||||
QString scriptText;
|
||||
|
||||
public slots:
|
||||
void compileScript();
|
||||
void setErrorWidget(QListWidget *list);
|
||||
void setFilter(QJSValue id, QJSValue mask, QJSValue bus);
|
||||
void setTickInterval(QJSValue interval);
|
||||
void clearFilters();
|
||||
void sendFrame(QJSValue bus, QJSValue id, QJSValue length, QJSValue data);
|
||||
|
||||
private slots:
|
||||
void tick();
|
||||
|
||||
signals:
|
||||
void sendCANFrame(const CANFrame *, int);
|
||||
|
||||
private:
|
||||
QJSEngine scriptEngine;
|
||||
QJSValue compiledScript;
|
||||
QJSValue setupFunction;
|
||||
QJSValue gotFrameFunction;
|
||||
QJSValue tickFunction;
|
||||
QTimer timer;
|
||||
QListWidget *errorWidget;
|
||||
QList<CANFilter> filters;
|
||||
};
|
||||
|
||||
#endif // SCRIPTCONTAINER_H
|
||||
@@ -0,0 +1,204 @@
|
||||
#include "scriptingwindow.h"
|
||||
#include "ui_scriptingwindow.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <Qsci/qscilexerjavascript.h>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
ScriptingWindow::ScriptingWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ScriptingWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
readSettings();
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
connect(ui->btnLoadScript, &QAbstractButton::pressed, this, &ScriptingWindow::loadNewScript);
|
||||
connect(ui->btnNewScript, &QAbstractButton::pressed, this, &ScriptingWindow::createNewScript);
|
||||
connect(ui->btnRecompile, &QAbstractButton::pressed, this, &ScriptingWindow::recompileScript);
|
||||
connect(ui->btnRemoveScript, &QAbstractButton::pressed, this, &ScriptingWindow::deleteCurrentScript);
|
||||
connect(ui->btnRevertScript, &QAbstractButton::pressed, this, &ScriptingWindow::revertScript);
|
||||
connect(ui->btnSaveScript, &QAbstractButton::pressed, this, &ScriptingWindow::saveScript);
|
||||
connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ScriptingWindow::updatedFrames);
|
||||
|
||||
ui->txtScriptSource->setLexer(new QsciLexerJavaScript(ui->txtScriptSource));
|
||||
}
|
||||
|
||||
ScriptingWindow::~ScriptingWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ScriptingWindow::updatedFrames(int numFrames)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
//-1 means all frames deleted and -2 means a full refresh, neither of which we care about here.
|
||||
if (numFrames > 0)
|
||||
{
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
qDebug() << "Got frames into script window: " << numFrames;
|
||||
//for every new frame pass it on to each script container. The container will determine if it needs to actually
|
||||
//notify the script and do that if applicable.
|
||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||
{
|
||||
thisFrame = modelFrames->at(i);
|
||||
for (int j = 0; j < scripts.length(); j++)
|
||||
{
|
||||
scripts[j]->gotFrame(thisFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
void ScriptingWindow::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
resize(settings.value("ScriptingWindow/WindowSize", QSize(860, 650)).toSize());
|
||||
move(settings.value("ScriptingWindow/WindowPos", QPoint(100, 100)).toPoint());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingWindow::writeSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||
{
|
||||
settings.setValue("ScriptingWindow/WindowSize", size());
|
||||
settings.setValue("ScriptingWindow/WindowPos", pos());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void ScriptingWindow::loadNewScript()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
bool result = false;
|
||||
ScriptContainer *container;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Javascript File (*.js)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
QFile scriptFile(filename);
|
||||
|
||||
if (scriptFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QString contents = scriptFile.readAll();
|
||||
scriptFile.close();
|
||||
QStringList fileList = filename.split('/');
|
||||
QString justFileName = fileList[fileList.length() - 1];
|
||||
ui->listLoadedScripts->addItem(justFileName);
|
||||
container = new ScriptContainer();
|
||||
container->fileName = justFileName;
|
||||
container->filePath = filename;
|
||||
container->scriptText = contents;
|
||||
container->setErrorWidget(ui->listErrors);
|
||||
container->compileScript();
|
||||
connect(container, &ScriptContainer::sendCANFrame, this, &ScriptingWindow::sendCANFrame);
|
||||
scripts.append(container);
|
||||
currentScript = container;
|
||||
ui->txtScriptSource->setText(container->scriptText);
|
||||
ui->txtScriptSource->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingWindow::createNewScript()
|
||||
{
|
||||
ScriptContainer *container;
|
||||
|
||||
container = new ScriptContainer();
|
||||
|
||||
container->fileName = "UNNAMED_" + QString::number((qrand() % 10000)) + ".js";
|
||||
container->filePath = QString();
|
||||
container->scriptText = QString();
|
||||
container->setErrorWidget(ui->listErrors);
|
||||
connect(container, &ScriptContainer::sendCANFrame, this, &ScriptingWindow::sendCANFrame);
|
||||
scripts.append(container);
|
||||
ui->listLoadedScripts->addItem(container->fileName);
|
||||
currentScript = container;
|
||||
ui->txtScriptSource->setText(container->scriptText);
|
||||
ui->txtScriptSource->setEnabled(true);
|
||||
}
|
||||
|
||||
void ScriptingWindow::deleteCurrentScript()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ScriptingWindow::refreshSourceWindow()
|
||||
{
|
||||
ui->txtScriptSource->setText(currentScript->scriptText);
|
||||
}
|
||||
|
||||
void ScriptingWindow::saveScript()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog(this);
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Javascript File (*.js)")));
|
||||
|
||||
dialog.setFileMode(QFileDialog::AnyFile);
|
||||
dialog.setNameFilters(filters);
|
||||
dialog.setViewMode(QFileDialog::Detail);
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
filename = dialog.selectedFiles()[0];
|
||||
if (!filename.contains('.')) filename += ".js";
|
||||
if (dialog.selectedNameFilter() == filters[0])
|
||||
{
|
||||
QFile *outFile = new QFile(filename);
|
||||
|
||||
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
delete outFile;
|
||||
return;
|
||||
}
|
||||
outFile->write(ui->txtScriptSource->text().toUtf8());
|
||||
outFile->close();
|
||||
delete outFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingWindow::revertScript()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ScriptingWindow::recompileScript()
|
||||
{
|
||||
currentScript->scriptText = ui->txtScriptSource->text();
|
||||
currentScript->compileScript();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef SCRIPTINGWINDOW_H
|
||||
#define SCRIPTINGWINDOW_H
|
||||
|
||||
#include "can_structs.h"
|
||||
#include "scriptcontainer.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QJSEngine>
|
||||
|
||||
namespace Ui {
|
||||
class ScriptingWindow;
|
||||
}
|
||||
|
||||
class ScriptingWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptingWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
void showEvent(QShowEvent*);
|
||||
~ScriptingWindow();
|
||||
|
||||
private slots:
|
||||
void loadNewScript();
|
||||
void createNewScript();
|
||||
void deleteCurrentScript();
|
||||
void refreshSourceWindow();
|
||||
void saveScript();
|
||||
void revertScript();
|
||||
void recompileScript();
|
||||
void updatedFrames(int);
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
void sendCANFrame(const CANFrame *, int);
|
||||
|
||||
private:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
Ui::ScriptingWindow *ui;
|
||||
QList<ScriptContainer *> scripts;
|
||||
ScriptContainer *currentScript;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // SCRIPTINGWINDOW_H
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScriptingWindow</class>
|
||||
<widget class="QDialog" name="ScriptingWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>862</width>
|
||||
<height>651</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Scripting Interface</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,4">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Loaded Scripts</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listLoadedScripts"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnLoadScript">
|
||||
<property name="text">
|
||||
<string>Load New Script</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnNewScript">
|
||||
<property name="text">
|
||||
<string>Create New Script</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRemoveScript">
|
||||
<property name="text">
|
||||
<string>Remove Current Script</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,10,0,0,4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Script Editing Window</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QsciScintilla" name="txtScriptSource">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSaveScript">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRevertScript">
|
||||
<property name="text">
|
||||
<string>Revert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRecompile">
|
||||
<property name="text">
|
||||
<string>Recompile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Current Scripting Errors</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listErrors"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QsciScintilla</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>Qsci/qsciscintilla.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+44
-25
@@ -40,6 +40,19 @@ SerialWorker::~SerialWorker()
|
||||
if (ticker != NULL) ticker->stop();
|
||||
}
|
||||
|
||||
void SerialWorker::run()
|
||||
{
|
||||
ticker = new QTimer;
|
||||
connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
|
||||
elapsedTime = new QTime;
|
||||
elapsedTime->start();
|
||||
|
||||
ticker->setInterval(250); //tick four times per second
|
||||
ticker->setSingleShot(false); //keep ticking
|
||||
ticker->start();
|
||||
}
|
||||
|
||||
void SerialWorker::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
@@ -69,7 +82,7 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port)
|
||||
delete serial;
|
||||
}
|
||||
|
||||
serial = new QSerialPort(*port);
|
||||
serial = new QSerialPort(*port);
|
||||
|
||||
qDebug() << "Serial port name is " << port->portName();
|
||||
//serial->setBaudRate(10000000); //more speed! probably does nothing for USB serial
|
||||
@@ -110,19 +123,6 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port)
|
||||
else connected = true;
|
||||
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
|
||||
if (doValidation) QTimer::singleShot(1000, this, SLOT(connectionTimeout()));
|
||||
if (ticker == NULL)
|
||||
{
|
||||
ticker = new QTimer;
|
||||
connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
}
|
||||
if (elapsedTime == NULL)
|
||||
{
|
||||
elapsedTime = new QTime;
|
||||
elapsedTime->start();
|
||||
}
|
||||
ticker->setInterval(250); //tick four times per second
|
||||
ticker->setSingleShot(false); //keep ticking
|
||||
ticker->start();
|
||||
}
|
||||
|
||||
void SerialWorker::connectionTimeout()
|
||||
@@ -132,7 +132,7 @@ void SerialWorker::connectionTimeout()
|
||||
{
|
||||
//then emit the the failure signal and see if anyone cares
|
||||
qDebug() << "Failed to connect to GVRET at that com port";
|
||||
ticker->stop();
|
||||
//ticker->stop();
|
||||
closeSerialPort(); //make sure it's properly closed anyway
|
||||
emit connectionFailure();
|
||||
}
|
||||
@@ -155,9 +155,17 @@ void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
||||
QByteArray buffer;
|
||||
int c;
|
||||
int ID;
|
||||
CANFrame tempFrame = *frame;
|
||||
tempFrame.isReceived = false;
|
||||
|
||||
//qDebug() << "Sending out frame with id " << frame->ID;
|
||||
|
||||
//show our sent frames in the list too. This happens even if we're not connected.
|
||||
canModel->addFrame(tempFrame, false);
|
||||
gotFrames++;
|
||||
|
||||
if (serial == NULL) return;
|
||||
if (!serial->isOpen()) return;
|
||||
if (!connected) return;
|
||||
|
||||
ID = frame->ID;
|
||||
@@ -177,8 +185,6 @@ void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
||||
}
|
||||
buffer[8 + frame->len] = 0;
|
||||
|
||||
if (serial == NULL) return;
|
||||
if (!serial->isOpen()) return;
|
||||
//qDebug() << "writing " << buffer.length() << " bytes to serial port";
|
||||
serial->write(buffer);
|
||||
}
|
||||
@@ -188,7 +194,9 @@ void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
||||
//buffers and besides, the other end will get buried in traffic.
|
||||
void SerialWorker::sendFrameBatch(const QList<CANFrame> *frames)
|
||||
{
|
||||
sendBulkMutex.lock();
|
||||
for (int i = 0; i < frames->length(); i++) sendFrame(&frames->at(i), frames->at(i).bus);
|
||||
sendBulkMutex.unlock();
|
||||
}
|
||||
|
||||
void SerialWorker::updateBaudRates(int Speed1, int Speed2)
|
||||
@@ -306,6 +314,7 @@ void SerialWorker::procRXChar(unsigned char c)
|
||||
//qDebug() << "emit from serial handler to main form id: " << buildFrame->ID;
|
||||
if (capturing)
|
||||
{
|
||||
buildFrame->isReceived = true;
|
||||
canModel->addFrame(*buildFrame, false);
|
||||
gotFrames++;
|
||||
if (buildFrame->ID == targetID) emit gotTargettedFrame(canModel->rowCount() - 1);
|
||||
@@ -422,14 +431,19 @@ void SerialWorker::handleTick()
|
||||
{
|
||||
//qDebug() << "Tick!";
|
||||
|
||||
if (!gotValidated)
|
||||
if (connected)
|
||||
{
|
||||
if (serial->isOpen()) //if it's still false we have a problem...
|
||||
if (!gotValidated && doValidation)
|
||||
{
|
||||
qDebug() << "Comm validation failed. ";
|
||||
closeSerialPort(); //start by stopping everything.
|
||||
QTimer::singleShot(500, this, SLOT(handleReconnect()));
|
||||
return;
|
||||
if (serial == NULL) return;
|
||||
if (serial->isOpen()) //if it's still false we have a problem...
|
||||
{
|
||||
qDebug() << "Comm validation failed. ";
|
||||
closeSerialPort(); //start by stopping everything.
|
||||
//Then wait 500ms and restart the connection automatically
|
||||
QTimer::singleShot(500, this, SLOT(handleReconnect()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +452,7 @@ void SerialWorker::handleTick()
|
||||
emit frameUpdateTick(framesPerSec / 4, gotFrames); //sends stats to interested parties
|
||||
canModel->sendBulkRefresh(gotFrames);
|
||||
gotFrames = 0;
|
||||
if (doValidation) sendCommValidation();
|
||||
if (doValidation && serial && serial->isOpen()) sendCommValidation();
|
||||
}
|
||||
|
||||
void SerialWorker::handleReconnect()
|
||||
@@ -454,6 +468,10 @@ void SerialWorker::sendCommValidation()
|
||||
gotValidated = false;
|
||||
output.append((char)0xF1); //another command to the GVRET
|
||||
output.append((char)0x09); //request a reply to get validation
|
||||
//send it twice for good measure.
|
||||
output.append((char)0xF1); //another command to the GVRET
|
||||
output.append((char)0x09); //request a reply to get validation
|
||||
|
||||
serial->write(output);
|
||||
}
|
||||
|
||||
@@ -467,7 +485,8 @@ void SerialWorker::closeSerialPort()
|
||||
serial->close();
|
||||
}
|
||||
serial->disconnect();
|
||||
ticker->stop();
|
||||
//do not stop the ticker here. It always stays running now.
|
||||
//ticker->stop();
|
||||
delete serial;
|
||||
serial = NULL;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ private slots: //we receive things in slots
|
||||
void handleReconnect();
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
void setSerialPort(QSerialPortInfo*);
|
||||
void closeSerialPort();
|
||||
void sendFrame(const CANFrame *, int);
|
||||
@@ -75,6 +76,7 @@ private:
|
||||
CANFrameModel *canModel;
|
||||
QTimer *ticker;
|
||||
QTime *elapsedTime;
|
||||
QMutex sendBulkMutex;
|
||||
int framesPerSec;
|
||||
int gotFrames;
|
||||
int targetID;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "udsscanwindow.h"
|
||||
#include "ui_udsscanwindow.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::UDSScanWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
waitTimer = new QTimer;
|
||||
waitTimer->setInterval(500);
|
||||
|
||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||
connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS);
|
||||
connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
|
||||
|
||||
ui->cbBuses->addItem("0");
|
||||
ui->cbBuses->addItem("1");
|
||||
ui->cbBuses->addItem("Both");
|
||||
|
||||
}
|
||||
|
||||
UDSScanWindow::~UDSScanWindow()
|
||||
{
|
||||
delete ui;
|
||||
waitTimer->stop();
|
||||
delete waitTimer;
|
||||
}
|
||||
|
||||
void UDSScanWindow::scanUDS()
|
||||
{
|
||||
ui->listResults->clear();
|
||||
sendingFrames.clear();
|
||||
|
||||
CANFrame frame;
|
||||
int startID, endID;
|
||||
startID = Utility::ParseStringToNum(ui->txtStartID->text());
|
||||
endID = Utility::ParseStringToNum(ui->txtEndID->text());
|
||||
|
||||
int buses = ui->cbBuses->currentIndex();
|
||||
buses++;
|
||||
if (buses < 1) buses = 1;
|
||||
for (int typ = 1; typ < 5; typ++)
|
||||
{
|
||||
for (int id = startID; id < endID; id++)
|
||||
{
|
||||
frame.ID = id;
|
||||
frame.len = 8;
|
||||
frame.extended = false;
|
||||
frame.data[0] = 2;
|
||||
frame.data[1] = 0x10;
|
||||
frame.data[2] = typ;
|
||||
frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0;
|
||||
frame.data[6] = 0;frame.data[7] = 0;
|
||||
|
||||
if (buses & 1)
|
||||
{
|
||||
frame.bus = 0;
|
||||
sendingFrames.append(frame);
|
||||
}
|
||||
if (buses & 2)
|
||||
{
|
||||
frame.bus = 1;
|
||||
sendingFrames.append(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waitTimer->start();
|
||||
currIdx = -1;
|
||||
sendNextMsg();
|
||||
}
|
||||
|
||||
void UDSScanWindow::updatedFrames(int numFrames)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
QString result;
|
||||
int id;
|
||||
if (numFrames == -1) //all frames deleted. We don't care
|
||||
{
|
||||
}
|
||||
else if (numFrames == -2) //all new set of frames. Don't care.
|
||||
{
|
||||
}
|
||||
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);
|
||||
id = thisFrame.ID;
|
||||
if (id >= 0x7E8 && id <= 0x7EF)
|
||||
{
|
||||
id -= 8; //back to original ECU id
|
||||
result = "ECU at bus " + QString::number(thisFrame.bus) + " ID: " + QString::number(id, 16) + " responds to mode "
|
||||
+ QString::number(sendingFrames[currIdx].data[2]) + " with: " + QString::number(thisFrame.data[0], 16) + " "
|
||||
+ QString::number(thisFrame.data[1], 16) + " " + QString::number(thisFrame.data[2], 16)
|
||||
+ " " + QString::number(thisFrame.data[3], 16);
|
||||
ui->listResults->addItem(result);
|
||||
sendNextMsg();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UDSScanWindow::timeOut()
|
||||
{
|
||||
QString result;
|
||||
result = "ECU at bus " + QString::number(sendingFrames[currIdx].bus) + " ID: " + QString::number(sendingFrames[currIdx].ID, 16) + " did not respond to mode "
|
||||
+ QString::number(sendingFrames[currIdx].data[2]);
|
||||
ui->listResults->addItem(result);
|
||||
|
||||
sendNextMsg();
|
||||
}
|
||||
|
||||
void UDSScanWindow::sendNextMsg()
|
||||
{
|
||||
currIdx++;
|
||||
if (currIdx < sendingFrames.count())
|
||||
{
|
||||
emit sendCANFrame(&sendingFrames[currIdx], sendingFrames[currIdx].bus);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitTimer->stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef UDSSCANWINDOW_H
|
||||
#define UDSSCANWINDOW_H
|
||||
|
||||
#include "can_structs.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class UDSScanWindow;
|
||||
}
|
||||
|
||||
class UDSScanWindow : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||
~UDSScanWindow();
|
||||
|
||||
signals:
|
||||
void sendCANFrame(const CANFrame *, int);
|
||||
|
||||
private slots:
|
||||
void updatedFrames(int numFrames);
|
||||
void scanUDS();
|
||||
void timeOut();
|
||||
|
||||
private:
|
||||
Ui::UDSScanWindow *ui;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
QTimer *waitTimer;
|
||||
QList<CANFrame> sendingFrames;
|
||||
int currIdx = 0;
|
||||
|
||||
void sendNextMsg();
|
||||
};
|
||||
|
||||
#endif // UDSSCANWINDOW_H
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UDSScanWindow</class>
|
||||
<widget class="QDialog" name="UDSScanWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>742</width>
|
||||
<height>527</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Results</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listResults"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Starting ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtStartID">
|
||||
<property name="text">
|
||||
<string>0x7E0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Ending ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtEndID">
|
||||
<property name="text">
|
||||
<string>0x7E7</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Buses to scan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbBuses"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnScan">
|
||||
<property name="text">
|
||||
<string>Start Scan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -73,6 +73,17 @@ public:
|
||||
else return formatHexNum(value);
|
||||
}
|
||||
|
||||
static QString formatByteAsBinary(uint8_t value)
|
||||
{
|
||||
QString output;
|
||||
for (int b = 7; b >= 0; b--)
|
||||
{
|
||||
if (value & (1 << b)) output += "1";
|
||||
else output += "0";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
//parses the input string to grab as much of it as possible while staying alpha numeric
|
||||
static QString grabAlphaNumeric(QString &input)
|
||||
{
|
||||
@@ -113,6 +124,67 @@ public:
|
||||
{
|
||||
return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint);
|
||||
}
|
||||
|
||||
static int64_t processIntegerSignal(const uint8_t *data, int startBit, int sigSize, bool littleEndian, bool isSigned)
|
||||
{
|
||||
|
||||
int64_t result = 0;
|
||||
int bit;
|
||||
|
||||
if (littleEndian)
|
||||
{
|
||||
bit = startBit;
|
||||
for (int bitpos = 0; bitpos < sigSize; bitpos++)
|
||||
{
|
||||
if (data[bit / 8] & (1 << (bit % 8)))
|
||||
result += (1ULL << bitpos);
|
||||
bit++;
|
||||
}
|
||||
}
|
||||
else //motorola / big endian mode
|
||||
{
|
||||
bit = startBit;
|
||||
for (int bitpos = 0; bitpos < sigSize; bitpos++)
|
||||
{
|
||||
if (data[bit / 8] & (1 << (bit % 8)))
|
||||
result += (1ULL << (sigSize - bitpos - 1));
|
||||
|
||||
if ((bit % 8) == 0)
|
||||
bit += 15;
|
||||
else bit--;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (isSigned)
|
||||
{
|
||||
int64_t mask = (1ULL << (sigSize - 1));
|
||||
if ((result & mask) == mask) //is the highest bit possible for this signal size set?
|
||||
{
|
||||
/*
|
||||
* if so we need to also set every bit higher in the result int too.
|
||||
* This leads to the below two lines that are nasty. Here's the theory behind that...
|
||||
* If the value is signed and the highest bit is set then it is negative. To create
|
||||
* a negative value out of this even though the variable result is 64 bit we have to
|
||||
* run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer
|
||||
* you have. So, it's 64 1's in this case.
|
||||
* signedMask is done this way:
|
||||
* first you take the signal size and shift 1 up that far. Then subtract one. Lets
|
||||
* see that for a 16 bit signal:
|
||||
* (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole
|
||||
* thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal
|
||||
* doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on
|
||||
* it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the
|
||||
* actual signal. This extends the sign bits out so that the integer result reads as the proper negative
|
||||
* value. We dont need to do any of this if the sign bit wasn't set.
|
||||
*/
|
||||
int64_t signedMask = ~((1ULL << sigSize) - 1);
|
||||
result = (-1LL & signedMask) | result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // UTILITY_H
|
||||
|
||||
Reference in New Issue
Block a user