@@ -1,6 +1,6 @@
|
|||||||
# SavvyCAN
|
# SavvyCAN
|
||||||
QT based cross platform canbus tool
|
QT based cross platform canbus tool
|
||||||
(C) 2015 EVTV and Collin Kidder
|
(C) 2015-2016 EVTV and Collin Kidder
|
||||||
|
|
||||||
A QT5 based cross platform tool which can be used to load, save, and capture canbus frames.
|
A QT5 based cross platform tool which can be used to load, save, and capture canbus frames.
|
||||||
This tool is designed to help with visualization, reverse engineering, debugging, and
|
This tool is designed to help with visualization, reverse engineering, debugging, and
|
||||||
@@ -8,12 +8,17 @@ capturing of canbus frames.
|
|||||||
|
|
||||||
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable.
|
Really requires at a resolution of at least 1024x768. Fully multi-monitor capable.
|
||||||
|
|
||||||
Currently canbus capture requires a CANDue board from EVTV:
|
You are highly recommended to use the CANDue board from EVTV:
|
||||||
(http://store.evtv.me/proddetail.php?prod=ArduinoDueCANBUS&cat=23)
|
(http://store.evtv.me/proddetail.php?prod=ArduinoDueCANBUS&cat=23)
|
||||||
|
|
||||||
The CANDue board must be running the GVRET firmware which can also be found
|
The CANDue board must be running the GVRET firmware which can also be found
|
||||||
within the collin80 repos.
|
within the collin80 repos.
|
||||||
|
|
||||||
|
It is very soon to be possible to use any SocketCAN compatible device
|
||||||
|
under LINUX. There may, however, be some loss of some functionality as
|
||||||
|
some functions of SavvyCAN are designed for use directly with the
|
||||||
|
EVTVDue and CANDue 2.0 boards.
|
||||||
|
|
||||||
It should, however, be noted that use of a capture device is not required to make use
|
It should, however, be noted that use of a capture device is not required to make use
|
||||||
of this program. It can load and save in several formats:
|
of this program. It can load and save in several formats:
|
||||||
|
|
||||||
@@ -27,6 +32,14 @@ of this program. It can load and save in several formats:
|
|||||||
|
|
||||||
5. Generic CSV file (ID,D0 D1 D2 D3 D4 D5 D6 D7)
|
5. Generic CSV file (ID,D0 D1 D2 D3 D4 D5 D6 D7)
|
||||||
|
|
||||||
|
6. Vector Trace files
|
||||||
|
|
||||||
|
7. IXXAT Minilog files
|
||||||
|
|
||||||
|
8. CAN-DO Logs
|
||||||
|
|
||||||
|
9. Vehicle Spy log files
|
||||||
|
|
||||||
Requires QScintilla library available at:
|
Requires QScintilla library available at:
|
||||||
|
|
||||||
https://www.riverbankcomputing.com/software/qscintilla/download
|
https://www.riverbankcomputing.com/software/qscintilla/download
|
||||||
@@ -37,6 +50,9 @@ http://www.qcustomplot.com/
|
|||||||
|
|
||||||
However, this source code is integrated into the source for SavvyCAN and one isn't required to download it separately.
|
However, this source code is integrated into the source for SavvyCAN and one isn't required to download it separately.
|
||||||
|
|
||||||
|
This project will soon require 5.6.0 or higher because of an upcoming dependency on QSerialBus but currently
|
||||||
|
should compile with QT 5.5
|
||||||
|
|
||||||
Instructions for compiling with Ubuntu:
|
Instructions for compiling with Ubuntu:
|
||||||
|
|
||||||
sudo apt-get install qt5-default qtdeclarative5-dev libqt5serialport5-dev libudev-dev
|
sudo apt-get install qt5-default qtdeclarative5-dev libqt5serialport5-dev libudev-dev
|
||||||
|
|||||||
+13
-3
@@ -46,7 +46,11 @@ SOURCES += main.cpp\
|
|||||||
dbcloadsavewindow.cpp \
|
dbcloadsavewindow.cpp \
|
||||||
fuzzingwindow.cpp \
|
fuzzingwindow.cpp \
|
||||||
udsscanwindow.cpp \
|
udsscanwindow.cpp \
|
||||||
can_structs.cpp
|
can_structs.cpp \
|
||||||
|
isotp_interpreterwindow.cpp \
|
||||||
|
isotp_handler.cpp \
|
||||||
|
deltawindow.cpp \
|
||||||
|
deltamodel.cpp
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
@@ -79,7 +83,11 @@ HEADERS += mainwindow.h \
|
|||||||
rangestatewindow.h \
|
rangestatewindow.h \
|
||||||
dbcloadsavewindow.h \
|
dbcloadsavewindow.h \
|
||||||
fuzzingwindow.h \
|
fuzzingwindow.h \
|
||||||
udsscanwindow.h
|
udsscanwindow.h \
|
||||||
|
isotp_interpreterwindow.h \
|
||||||
|
isotp_handler.h \
|
||||||
|
deltawindow.h \
|
||||||
|
deltamodel.h
|
||||||
|
|
||||||
FORMS += mainwindow.ui \
|
FORMS += mainwindow.ui \
|
||||||
graphingwindow.ui \
|
graphingwindow.ui \
|
||||||
@@ -100,7 +108,9 @@ FORMS += mainwindow.ui \
|
|||||||
rangestatewindow.ui \
|
rangestatewindow.ui \
|
||||||
dbcloadsavewindow.ui \
|
dbcloadsavewindow.ui \
|
||||||
fuzzingwindow.ui \
|
fuzzingwindow.ui \
|
||||||
udsscanwindow.ui
|
udsscanwindow.ui \
|
||||||
|
isotp_interpreterwindow.ui \
|
||||||
|
deltawindow.ui
|
||||||
|
|
||||||
DISTFILES +=
|
DISTFILES +=
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -29,14 +29,15 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//the same as the CANFrame struct but with arbitrary data size.
|
//the same as the CANFrame struct but with arbitrary data size.
|
||||||
struct ISOTP_FRAME
|
struct ISOTP_MESSAGE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int ID;
|
int ID;
|
||||||
int bus;
|
int bus;
|
||||||
bool extended;
|
bool extended;
|
||||||
bool isReceived;
|
bool isReceived;
|
||||||
int len;
|
int len; //# of bytes this message should have (as reported)
|
||||||
|
int actualSize; //# we actually got
|
||||||
QVector<unsigned char> data;
|
QVector<unsigned char> data;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
};
|
};
|
||||||
|
|||||||
+31
-12
@@ -6,12 +6,23 @@
|
|||||||
int CANFrameModel::rowCount(const QModelIndex &parent) const
|
int CANFrameModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent);
|
||||||
return filteredFrames.count();
|
if (filteredFrames.data())
|
||||||
|
{
|
||||||
|
int rows = filteredFrames.count();
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
//just in case somehow data is invalid which I have seen before.
|
||||||
|
//But, this should not happen so issue a debugging message too
|
||||||
|
qDebug() << "Invalid data for filteredFrames. Returning 0.";
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CANFrameModel::totalFrameCount()
|
int CANFrameModel::totalFrameCount()
|
||||||
{
|
{
|
||||||
return frames.count();
|
int count;
|
||||||
|
count = frames.count();
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CANFrameModel::columnCount(const QModelIndex &index) const
|
int CANFrameModel::columnCount(const QModelIndex &index) const
|
||||||
@@ -23,8 +34,8 @@ int CANFrameModel::columnCount(const QModelIndex &index) const
|
|||||||
CANFrameModel::CANFrameModel(QObject *parent)
|
CANFrameModel::CANFrameModel(QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractTableModel(parent)
|
||||||
{
|
{
|
||||||
frames.reserve(10000000); //yes, I'm preallocating 10 million entries in this list. I don't think anyone will exceed this.
|
frames.reserve(50000000); //yes, preallocating a huge number of frames.
|
||||||
filteredFrames.reserve(10000000);
|
filteredFrames.reserve(50000000); //the goal is to prevent a reallocation from ever happening
|
||||||
dbcHandler = NULL;
|
dbcHandler = NULL;
|
||||||
interpretFrames = false;
|
interpretFrames = false;
|
||||||
overwriteDups = false;
|
overwriteDups = false;
|
||||||
@@ -75,6 +86,7 @@ void CANFrameModel::setInterpetMode(bool mode)
|
|||||||
|
|
||||||
void CANFrameModel::normalizeTiming()
|
void CANFrameModel::normalizeTiming()
|
||||||
{
|
{
|
||||||
|
mutex.lock();
|
||||||
if (frames.count() == 0) return;
|
if (frames.count() == 0) return;
|
||||||
timeOffset = frames[0].timestamp;
|
timeOffset = frames[0].timestamp;
|
||||||
for (int i = 0; i < frames.count(); i++)
|
for (int i = 0; i < frames.count(); i++)
|
||||||
@@ -87,11 +99,14 @@ void CANFrameModel::normalizeTiming()
|
|||||||
filteredFrames[i].timestamp -= timeOffset;
|
filteredFrames[i].timestamp -= timeOffset;
|
||||||
}
|
}
|
||||||
this->endResetModel();
|
this->endResetModel();
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CANFrameModel::setOverwriteMode(bool mode)
|
void CANFrameModel::setOverwriteMode(bool mode)
|
||||||
{
|
{
|
||||||
|
beginResetModel();
|
||||||
overwriteDups = mode;
|
overwriteDups = mode;
|
||||||
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CANFrameModel::setFilterState(int ID, bool state)
|
void CANFrameModel::setFilterState(int ID, bool state)
|
||||||
@@ -120,6 +135,7 @@ void CANFrameModel::recalcOverwrite()
|
|||||||
int lastUnique = 0;
|
int lastUnique = 0;
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
for (int i = 1; i < frames.count(); i++)
|
for (int i = 1; i < frames.count(); i++)
|
||||||
{
|
{
|
||||||
@@ -143,6 +159,7 @@ void CANFrameModel::recalcOverwrite()
|
|||||||
while (frames.count() > lastUnique) frames.removeLast();
|
while (frames.count() > lastUnique) frames.removeLast();
|
||||||
|
|
||||||
filteredFrames.clear();
|
filteredFrames.clear();
|
||||||
|
filteredFrames.reserve(50000000);
|
||||||
|
|
||||||
for (int i = 0; i < frames.count(); i++)
|
for (int i = 0; i < frames.count(); i++)
|
||||||
{
|
{
|
||||||
@@ -153,6 +170,7 @@ void CANFrameModel::recalcOverwrite()
|
|||||||
}
|
}
|
||||||
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||||
@@ -327,11 +345,9 @@ void CANFrameModel::addFrame(const CANFrame &frame, bool autoRefresh = false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CANFrameModel::sendRefresh()
|
void CANFrameModel::sendRefresh()
|
||||||
{
|
{
|
||||||
mutex.lock();
|
|
||||||
qDebug() << "Sending mass refresh";
|
qDebug() << "Sending mass refresh";
|
||||||
QVector<CANFrame> tempContainer;
|
QVector<CANFrame> tempContainer;
|
||||||
beginResetModel();
|
|
||||||
int count = frames.count();
|
int count = frames.count();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -340,8 +356,11 @@ void CANFrameModel::sendRefresh()
|
|||||||
tempContainer.append(frames[i]);
|
tempContainer.append(frames[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex.lock();
|
||||||
|
beginResetModel();
|
||||||
filteredFrames.clear();
|
filteredFrames.clear();
|
||||||
filteredFrames = tempContainer;
|
filteredFrames.append(tempContainer);
|
||||||
|
filteredFrames.reserve(50000000);
|
||||||
lastUpdateNumFrames = filteredFrames.count();
|
lastUpdateNumFrames = filteredFrames.count();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
@@ -376,14 +395,12 @@ void CANFrameModel::sendBulkRefresh(int num)
|
|||||||
|
|
||||||
if (!overwriteDups)
|
if (!overwriteDups)
|
||||||
{
|
{
|
||||||
mutex.lock();
|
//if (num > filteredFrames.count()) num = filteredFrames.count();
|
||||||
if (num > filteredFrames.count()) num = filteredFrames.count();
|
|
||||||
//qDebug() << "From " << (filteredFrames.count() - num) << " to " << (filteredFrames.count() - 1);
|
//qDebug() << "From " << (filteredFrames.count() - num) << " to " << (filteredFrames.count() - 1);
|
||||||
//beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1);
|
//beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1);
|
||||||
//endInsertRows();
|
//endInsertRows();
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
mutex.unlock();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -399,6 +416,8 @@ void CANFrameModel::clearFrames()
|
|||||||
frames.clear();
|
frames.clear();
|
||||||
filteredFrames.clear();
|
filteredFrames.clear();
|
||||||
filters.clear();
|
filters.clear();
|
||||||
|
frames.reserve(50000000);
|
||||||
|
filteredFrames.reserve(50000000);
|
||||||
this->endResetModel();
|
this->endResetModel();
|
||||||
lastUpdateNumFrames = 0;
|
lastUpdateNumFrames = 0;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ public:
|
|||||||
QVariant headerData(int section, Qt::Orientation orientation,
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
int columnCount(const QModelIndex &) const;
|
int columnCount(const QModelIndex &) const;
|
||||||
int totalFrameCount();
|
int totalFrameCount();
|
||||||
|
|
||||||
void addFrame(const CANFrame &, bool);
|
void addFrame(const CANFrame &, bool);
|
||||||
void sendRefresh();
|
void sendRefresh();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef CONFIG
|
#ifndef CONFIG
|
||||||
#define CONFIG
|
#define CONFIG
|
||||||
|
|
||||||
#define VERSION 151
|
#define VERSION 156
|
||||||
|
|
||||||
//try to keep this in sync.
|
//try to keep this in sync.
|
||||||
//SavvyCAN will complain if you connect a GVRET board with a revision
|
//SavvyCAN will complain if you connect a GVRET board with a revision
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(ui->btnOK, SIGNAL(clicked(bool)), this, SLOT(handleOKButton()));
|
connect(ui->btnOK, SIGNAL(clicked(bool)), this, SLOT(handleOKButton()));
|
||||||
|
connect(ui->rbGVRET, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged()));
|
||||||
|
connect(ui->rbKvaser, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged()));
|
||||||
|
connect(ui->rbSocketCAN, SIGNAL(toggled(bool)), this, SLOT(handleConnTypeChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionWindow::~ConnectionWindow()
|
ConnectionWindow::~ConnectionWindow()
|
||||||
@@ -60,6 +63,11 @@ void ConnectionWindow::showEvent(QShowEvent* event)
|
|||||||
{
|
{
|
||||||
QDialog::showEvent(event);
|
QDialog::showEvent(event);
|
||||||
qDebug() << "Show connectionwindow";
|
qDebug() << "Show connectionwindow";
|
||||||
|
handleConnTypeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionWindow::handleConnTypeChanged()
|
||||||
|
{
|
||||||
if (ui->rbGVRET->isChecked()) getSerialPorts();
|
if (ui->rbGVRET->isChecked()) getSerialPorts();
|
||||||
if (ui->rbKvaser->isChecked()) getKvaserPorts();
|
if (ui->rbKvaser->isChecked()) getKvaserPorts();
|
||||||
if (ui->rbSocketCAN->isChecked()) getSocketcanPorts();
|
if (ui->rbSocketCAN->isChecked()) getSocketcanPorts();
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public slots:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleOKButton();
|
void handleOKButton();
|
||||||
|
void handleConnTypeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ConnectionWindow *ui;
|
Ui::ConnectionWindow *ui;
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue)
|
|||||||
endResult = ((double)result * factor) + bias;
|
endResult = ((double)result * factor) + bias;
|
||||||
result = (int64_t)endResult;
|
result = (int64_t)endResult;
|
||||||
}
|
}
|
||||||
|
/*TODO: It should be noted that the below floating point has not even been tested. For shame! Test it!*/
|
||||||
else if (valType == SP_FLOAT)
|
else if (valType == SP_FLOAT)
|
||||||
{
|
{
|
||||||
//The theory here is that we force the integer signal code to treat this as
|
//The theory here is that we force the integer signal code to treat this as
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include "deltamodel.h"
|
||||||
|
|
||||||
|
DeltaModel::DeltaModel(QObject *parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DeltaModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
// FIXME: Implement me!
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeltaModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// FIXME: Implement me!
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeltaModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// FIXME: Implement me!
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DeltaModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// FIXME: Implement me!
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef DELTAMODEL_H
|
||||||
|
#define DELTAMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
class DeltaModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeltaModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
// Header:
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
// Basic functionality:
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DELTAMODEL_H
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "deltawindow.h"
|
||||||
|
#include "ui_deltawindow.h"
|
||||||
|
|
||||||
|
DeltaWindow::DeltaWindow(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::DeltaWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeltaWindow::~DeltaWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef DELTAWINDOW_H
|
||||||
|
#define DELTAWINDOW_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class DeltaWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeltaWindow : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeltaWindow(QWidget *parent = 0);
|
||||||
|
~DeltaWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::DeltaWindow *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DELTAWINDOW_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DeltaWindow</class>
|
||||||
|
<widget class="QDialog" name="DeltaWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>978</width>
|
||||||
|
<height>654</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
+171
-22
@@ -14,9 +14,47 @@ DiscreteStateWindow::DiscreteStateWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
timer = new QTimer();
|
timer = new QTimer();
|
||||||
timer->setInterval(100);
|
timer->setInterval(100);
|
||||||
|
|
||||||
|
isRealtime = ui->rbRealtime->isChecked();
|
||||||
|
typeChanged();
|
||||||
|
|
||||||
connect(ui->btnStart, SIGNAL(clicked(bool)), this, SLOT(handleStartButton()));
|
connect(ui->btnStart, SIGNAL(clicked(bool)), this, SLOT(handleStartButton()));
|
||||||
connect(timer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
connect(timer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
|
connect(ui->rbLogged, SIGNAL(clicked(bool)), this, SLOT(typeChanged()));
|
||||||
|
connect(ui->rbRealtime, SIGNAL(clicked(bool)), this, SLOT(typeChanged()));
|
||||||
|
|
||||||
|
connect(ui->btnAll, &QAbstractButton::clicked,
|
||||||
|
[=]()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->listID->count(); i++)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->listID->item(i);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
|
idFilters[Utility::ParseStringToNum(item->text())] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->btnNone, &QAbstractButton::clicked,
|
||||||
|
[=]()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ui->listID->count(); i++)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = ui->listID->item(i);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
idFilters[Utility::ParseStringToNum(item->text())] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->listID, &QListWidget::itemChanged,
|
||||||
|
[=](QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
bool isChecked = false;
|
||||||
|
int id = Utility::ParseStringToNum(item->text());
|
||||||
|
if (item->checkState() == Qt::Checked) isChecked = true;
|
||||||
|
idFilters[id] = isChecked;
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshFilterList();
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscreteStateWindow::~DiscreteStateWindow()
|
DiscreteStateWindow::~DiscreteStateWindow()
|
||||||
@@ -33,14 +71,45 @@ DiscreteStateWindow::~DiscreteStateWindow()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscreteStateWindow::typeChanged()
|
||||||
|
{
|
||||||
|
if (ui->rbLogged->isChecked())
|
||||||
|
{
|
||||||
|
ui->spinFreq->setEnabled(false);
|
||||||
|
ui->spinIterations->setEnabled(false);
|
||||||
|
ui->lblStatus->setEnabled(false);
|
||||||
|
ui->spinMaxBits->setEnabled(true);
|
||||||
|
ui->spinMinBits->setEnabled(true);
|
||||||
|
ui->listID->setEnabled(true);
|
||||||
|
ui->btnAll->setEnabled(true);
|
||||||
|
ui->btnNone->setEnabled(true);
|
||||||
|
isRealtime = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->spinFreq->setEnabled(true);
|
||||||
|
ui->spinIterations->setEnabled(true);
|
||||||
|
ui->lblStatus->setEnabled(true);
|
||||||
|
ui->spinMaxBits->setEnabled(false);
|
||||||
|
ui->spinMinBits->setEnabled(false);
|
||||||
|
ui->listID->setEnabled(false);
|
||||||
|
ui->btnAll->setEnabled(false);
|
||||||
|
ui->btnNone->setEnabled(false);
|
||||||
|
isRealtime = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DiscreteStateWindow::updatedFrames(int numFrames)
|
void DiscreteStateWindow::updatedFrames(int numFrames)
|
||||||
{
|
{
|
||||||
CANFrame thisFrame;
|
CANFrame thisFrame;
|
||||||
if (numFrames == -1) //all frames deleted. Kill the display
|
if (numFrames == -1) //all frames deleted. Kill the display
|
||||||
{
|
{
|
||||||
|
ui->listID->clear();
|
||||||
|
idFilters.clear();
|
||||||
}
|
}
|
||||||
else if (numFrames == -2) //all new set of frames. Reset
|
else if (numFrames == -2) //all new set of frames. Reset
|
||||||
{
|
{
|
||||||
|
refreshFilterList();
|
||||||
}
|
}
|
||||||
else //just got some new frames. See if they are relevant.
|
else //just got some new frames. See if they are relevant.
|
||||||
{
|
{
|
||||||
@@ -48,12 +117,43 @@ void DiscreteStateWindow::updatedFrames(int numFrames)
|
|||||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
{
|
{
|
||||||
thisFrame = modelFrames->at(i);
|
thisFrame = modelFrames->at(i);
|
||||||
|
|
||||||
|
if (!idFilters.contains(thisFrame.ID))
|
||||||
|
{
|
||||||
|
idFilters.insert(thisFrame.ID, true);
|
||||||
|
QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listID);
|
||||||
|
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
|
||||||
|
listItem->setCheckState(Qt::Checked); //default all filters to be set active
|
||||||
|
}
|
||||||
|
|
||||||
if (operatingState == DWStates::IDLE) stateFrames[0]->append(thisFrame);
|
if (operatingState == DWStates::IDLE) stateFrames[0]->append(thisFrame);
|
||||||
else stateFrames[currToggleState + 1]->append(thisFrame);
|
else stateFrames[currToggleState + 1]->append(thisFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscreteStateWindow::refreshFilterList()
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
|
||||||
|
idFilters.clear();
|
||||||
|
ui->listID->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->listID);
|
||||||
|
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
|
||||||
|
listItem->setCheckState(Qt::Checked); //default all filters to be set active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->listID->sortItems();
|
||||||
|
}
|
||||||
|
|
||||||
void DiscreteStateWindow::showEvent(QShowEvent* event)
|
void DiscreteStateWindow::showEvent(QShowEvent* event)
|
||||||
{
|
{
|
||||||
QDialog::showEvent(event);
|
QDialog::showEvent(event);
|
||||||
@@ -97,7 +197,7 @@ void DiscreteStateWindow::updateStateLabel()
|
|||||||
switch(operatingState)
|
switch(operatingState)
|
||||||
{
|
{
|
||||||
case DWStates::IDLE:
|
case DWStates::IDLE:
|
||||||
ui->lblStatus->setText("WAIT");
|
ui->lblStatus->setText("IDLE");
|
||||||
pal = ui->lblStatus->palette();
|
pal = ui->lblStatus->palette();
|
||||||
pal.setColor(QPalette::WindowText, Qt::red);
|
pal.setColor(QPalette::WindowText, Qt::red);
|
||||||
ui->lblStatus->setPalette(pal);
|
ui->lblStatus->setPalette(pal);
|
||||||
@@ -109,7 +209,7 @@ void DiscreteStateWindow::updateStateLabel()
|
|||||||
ui->lblStatus->setPalette(pal);
|
ui->lblStatus->setPalette(pal);
|
||||||
break;
|
break;
|
||||||
case DWStates::COUNTDOWN_WAITING:
|
case DWStates::COUNTDOWN_WAITING:
|
||||||
ui->lblStatus->setText("Return to resting state");
|
ui->lblStatus->setText("Wait....");
|
||||||
pal = ui->lblStatus->palette();
|
pal = ui->lblStatus->palette();
|
||||||
pal.setColor(QPalette::WindowText, Qt::red);
|
pal.setColor(QPalette::WindowText, Qt::red);
|
||||||
ui->lblStatus->setPalette(pal);
|
ui->lblStatus->setPalette(pal);
|
||||||
@@ -120,32 +220,45 @@ void DiscreteStateWindow::updateStateLabel()
|
|||||||
pal.setColor(QPalette::WindowText, Qt::green);
|
pal.setColor(QPalette::WindowText, Qt::green);
|
||||||
ui->lblStatus->setPalette(pal);
|
ui->lblStatus->setPalette(pal);
|
||||||
break;
|
break;
|
||||||
|
case DWStates::DONE:
|
||||||
|
ui->lblStatus->setText("DONE");
|
||||||
|
pal = ui->lblStatus->palette();
|
||||||
|
pal.setColor(QPalette::WindowText, Qt::green);
|
||||||
|
ui->lblStatus->setPalette(pal);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiscreteStateWindow::handleStartButton()
|
void DiscreteStateWindow::handleStartButton()
|
||||||
{
|
{
|
||||||
operatingState = DWStates::COUNTDOWN_SIGNAL;
|
if (isRealtime)
|
||||||
|
|
||||||
ticksPerStateChange = ticksUntilStateChange = ui->spinFreq->value() * 10;
|
|
||||||
numToggleStates = ui->spinStates->value();
|
|
||||||
numIterations = ui->spinIterations->value();
|
|
||||||
|
|
||||||
currToggleState = 0;
|
|
||||||
currIteration = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < stateFrames.count(); i++)
|
|
||||||
{
|
{
|
||||||
stateFrames[i]->clear();
|
operatingState = DWStates::COUNTDOWN_SIGNAL;
|
||||||
delete(stateFrames[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j <= numToggleStates; j++)
|
ticksPerStateChange = ticksUntilStateChange = ui->spinFreq->value() * 10;
|
||||||
|
numToggleStates = ui->spinStates->value();
|
||||||
|
numIterations = ui->spinIterations->value();
|
||||||
|
|
||||||
|
currToggleState = 0;
|
||||||
|
currIteration = 0;
|
||||||
|
|
||||||
|
for (int i = stateFrames.count() - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
stateFrames[i]->clear();
|
||||||
|
stateFrames.removeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j <= numToggleStates; j++)
|
||||||
|
{
|
||||||
|
stateFrames.append(new QVector<CANFrame>());
|
||||||
|
}
|
||||||
|
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
stateFrames.append(new QVector<CANFrame>());
|
calculateResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
timer->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiscreteStateWindow::handleTick()
|
void DiscreteStateWindow::handleTick()
|
||||||
@@ -168,11 +281,11 @@ void DiscreteStateWindow::handleTick()
|
|||||||
{
|
{
|
||||||
ticksUntilStateChange = ticksPerStateChange;
|
ticksUntilStateChange = ticksPerStateChange;
|
||||||
currIteration++;
|
currIteration++;
|
||||||
if (currIteration == numIterations)
|
if (currIteration > numIterations)
|
||||||
{
|
{
|
||||||
operatingState = DWStates::IDLE;
|
operatingState = DWStates::IDLE;
|
||||||
timer->stop();
|
timer->stop();
|
||||||
//call to calculate our findings here.
|
calculateResults();
|
||||||
}
|
}
|
||||||
else operatingState = DWStates::COUNTDOWN_SIGNAL;
|
else operatingState = DWStates::COUNTDOWN_SIGNAL;
|
||||||
}
|
}
|
||||||
@@ -184,7 +297,7 @@ void DiscreteStateWindow::handleTick()
|
|||||||
ticksUntilStateChange = ticksPerStateChange;
|
ticksUntilStateChange = ticksPerStateChange;
|
||||||
operatingState = DWStates::COUNTDOWN_WAITING;
|
operatingState = DWStates::COUNTDOWN_WAITING;
|
||||||
currToggleState++;
|
currToggleState++;
|
||||||
if (currToggleState == numToggleStates) currToggleState = 0;
|
if (currToggleState > numToggleStates) currToggleState = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -193,5 +306,41 @@ void DiscreteStateWindow::handleTick()
|
|||||||
|
|
||||||
void DiscreteStateWindow::calculateResults()
|
void DiscreteStateWindow::calculateResults()
|
||||||
{
|
{
|
||||||
|
int minBits, maxBits;
|
||||||
|
if (isRealtime)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else //use already loaded frames from main cache
|
||||||
|
{
|
||||||
|
//basic overview: run through all ID filters and see if it is enabled.
|
||||||
|
//If so add it to a giant list of messages by ID where each ID has its own
|
||||||
|
//list of messages
|
||||||
|
//Then, for each ID start a loop that runs from largest bits to smallest bits for scan
|
||||||
|
//For each value run through the algorithm for all messages. At the end list any matches
|
||||||
|
//the simplest approach seems to be to grab that number of bits and then record every
|
||||||
|
//unique value. IF the # of unique values is the same as the number of states then
|
||||||
|
//we've got a match.It should be noted that the # of states must be at least 2 - the idle
|
||||||
|
//state is 1 and then a second state at the minimum. Turn signals might be 3 states then
|
||||||
|
|
||||||
|
minBits = ui->spinMinBits->value();
|
||||||
|
maxBits = ui->spinMaxBits->value();
|
||||||
|
QHash<int, bool>::const_iterator it;
|
||||||
|
QList<CANFrame> frameCache;
|
||||||
|
for (it = idFilters.begin(); it != idFilters.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it.value())
|
||||||
|
{
|
||||||
|
frameCache.clear();
|
||||||
|
for (int i = 0; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
if (modelFrames->at(i).ID == it.key()) frameCache.append(modelFrames->at(i));
|
||||||
|
}
|
||||||
|
for (int bits = maxBits; bits >= minBits; bits--)
|
||||||
|
{
|
||||||
|
QList<int> values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ enum DiscreteWindowState
|
|||||||
IDLE,
|
IDLE,
|
||||||
COUNTDOWN_SIGNAL,
|
COUNTDOWN_SIGNAL,
|
||||||
COUNTDOWN_WAITING,
|
COUNTDOWN_WAITING,
|
||||||
GETTING_SIGNAL
|
GETTING_SIGNAL,
|
||||||
|
DONE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ private slots:
|
|||||||
void updatedFrames(int);
|
void updatedFrames(int);
|
||||||
void handleStartButton();
|
void handleStartButton();
|
||||||
void handleTick();
|
void handleTick();
|
||||||
|
void typeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::DiscreteStateWindow *ui;
|
Ui::DiscreteStateWindow *ui;
|
||||||
@@ -46,7 +48,10 @@ private:
|
|||||||
int currToggleState;
|
int currToggleState;
|
||||||
int numIterations;
|
int numIterations;
|
||||||
int currIteration;
|
int currIteration;
|
||||||
|
bool isRealtime;
|
||||||
|
QHash<int, bool> idFilters;
|
||||||
|
|
||||||
|
void refreshFilterList();
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|||||||
+213
-96
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>749</width>
|
||||||
<height>300</height>
|
<height>795</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -31,63 +31,232 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item row="0" column="1" alignment="Qt::AlignHCenter">
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Number of States:</string>
|
<string>Number of States:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Toggle Frequency (Seconds)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QSpinBox" name="spinFreq">
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>30</number>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QSpinBox" name="spinStates">
|
<widget class="QSpinBox" name="spinStates">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>1</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>20</number>
|
<number>64</number>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2" alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string>Iterations</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QSpinBox" name="spinIterations">
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rbRealtime">
|
||||||
|
<property name="text">
|
||||||
|
<string>Realtime</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rbLogged">
|
||||||
|
<property name="text">
|
||||||
|
<string>From logged data</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="2,2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Toggle Frequency (Seconds)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinFreq">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>30</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Iterations</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinIterations">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</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>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblStatus">
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>120</red>
|
||||||
|
<green>120</green>
|
||||||
|
<blue>120</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Nirmala UI</family>
|
||||||
|
<pointsize>26</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>WAIT</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Min Bits</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinMinBits">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max Bits</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinMaxBits">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>IDs to Scan</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listID"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnNone">
|
||||||
|
<property name="text">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnStart">
|
<widget class="QPushButton" name="btnStart">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -95,58 +264,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="lblStatus">
|
|
||||||
<property name="palette">
|
|
||||||
<palette>
|
|
||||||
<active>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>255</red>
|
|
||||||
<green>0</green>
|
|
||||||
<blue>0</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</active>
|
|
||||||
<inactive>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>255</red>
|
|
||||||
<green>0</green>
|
|
||||||
<blue>0</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</inactive>
|
|
||||||
<disabled>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>120</red>
|
|
||||||
<green>120</green>
|
|
||||||
<blue>120</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</disabled>
|
|
||||||
</palette>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<family>Nirmala UI</family>
|
|
||||||
<pointsize>26</pointsize>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>WAIT</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
+58
-17
@@ -158,9 +158,9 @@ void FlowViewWindow::writeSettings()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Keyboard shortcuts to allow for quick work without needing to move around a mouse.
|
* Keyboard shortcuts to allow for quick work without needing to move around a mouse.
|
||||||
* E = resume or pause playback
|
* R = resume or pause playback
|
||||||
* Q = go back one frame
|
* T = go back one frame
|
||||||
* W = go forward one frame
|
* Y = go forward one frame
|
||||||
*/
|
*/
|
||||||
bool FlowViewWindow::eventFilter(QObject *obj, QEvent *event)
|
bool FlowViewWindow::eventFilter(QObject *obj, QEvent *event)
|
||||||
{
|
{
|
||||||
@@ -371,27 +371,64 @@ void FlowViewWindow::updatedFrames(int numFrames)
|
|||||||
else //just got some new frames. See if they are relevant.
|
else //just got some new frames. See if they are relevant.
|
||||||
{
|
{
|
||||||
if (numFrames > modelFrames->count()) return;
|
if (numFrames > modelFrames->count()) return;
|
||||||
int refID = frameCache[0].ID;
|
int refID;
|
||||||
|
if (frameCache.count() > 0) refID = frameCache[0].ID;
|
||||||
|
else refID = 0;
|
||||||
bool needRefresh = false;
|
bool needRefresh = false;
|
||||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
{
|
{
|
||||||
thisFrame = modelFrames->at(i);
|
thisFrame = modelFrames->at(i);
|
||||||
|
|
||||||
|
if (!foundID.contains(thisFrame.ID))
|
||||||
|
{
|
||||||
|
foundID.append(thisFrame.ID);
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listFrameID);
|
||||||
|
}
|
||||||
|
|
||||||
if (thisFrame.ID == refID)
|
if (thisFrame.ID == refID)
|
||||||
{
|
{
|
||||||
frameCache.append(thisFrame);
|
frameCache.append(thisFrame);
|
||||||
if (ui->cbLiveMode->checkState() == Qt::Checked)
|
|
||||||
|
for (int k = 0; k < 8; k++)
|
||||||
{
|
{
|
||||||
currentPosition = frameCache.count() - 1;
|
if (ui->cbTimeGraph->isChecked())
|
||||||
|
{
|
||||||
|
if (secondsMode){
|
||||||
|
x[k].append((double)(thisFrame.timestamp) / 1000000.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x[k].append(thisFrame.timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x[k].append(x[k].count());
|
||||||
|
}
|
||||||
|
y[k].append(thisFrame.data[k]);
|
||||||
needRefresh = true;
|
needRefresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (ui->cbLiveMode->checkState() == Qt::Checked)
|
||||||
|
{
|
||||||
|
currentPosition = frameCache.count() - 1;
|
||||||
|
memcpy(currBytes, frameCache.at(currentPosition).data, 8);
|
||||||
|
memcpy(refBytes, currBytes, 8);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (needRefresh)
|
if (needRefresh)
|
||||||
{
|
{
|
||||||
updateDataView();
|
for (int k = 0; k < 8; k++)
|
||||||
|
{
|
||||||
|
graphRef[k]->setData(x[k], y[k]);
|
||||||
|
}
|
||||||
|
ui->graphView->replot();
|
||||||
|
updateDataView();
|
||||||
if (ui->cbSync->checkState() == Qt::Checked) emit sendCenterTimeID(frameCache[currentPosition].ID, frameCache[currentPosition].timestamp / 1000000.0);
|
if (ui->cbSync->checkState() == Qt::Checked) emit sendCenterTimeID(frameCache[currentPosition].ID, frameCache[currentPosition].timestamp / 1000000.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateFrameLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowViewWindow::removeAllGraphs()
|
void FlowViewWindow::removeAllGraphs()
|
||||||
@@ -409,7 +446,10 @@ void FlowViewWindow::createGraph(int byteNum)
|
|||||||
|
|
||||||
int numEntries = frameCache.count();
|
int numEntries = frameCache.count();
|
||||||
|
|
||||||
QVector<double> x(numEntries), y(numEntries);
|
x[byteNum].clear();
|
||||||
|
y[byteNum].clear();
|
||||||
|
x[byteNum].resize(numEntries);
|
||||||
|
y[byteNum].resize(numEntries);
|
||||||
|
|
||||||
for (int j = 0; j < numEntries; j++)
|
for (int j = 0; j < numEntries; j++)
|
||||||
{
|
{
|
||||||
@@ -418,26 +458,26 @@ void FlowViewWindow::createGraph(int byteNum)
|
|||||||
if (graphByTime)
|
if (graphByTime)
|
||||||
{
|
{
|
||||||
if (secondsMode){
|
if (secondsMode){
|
||||||
x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
x[byteNum][j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x[j] = frameCache[j].timestamp;
|
x[byteNum][j] = frameCache[j].timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x[j] = j;
|
x[byteNum][j] = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
y[j] = tempVal;
|
y[byteNum][j] = tempVal;
|
||||||
if (y[j] < minval) minval = y[j];
|
if (y[byteNum][j] < minval) minval = y[byteNum][j];
|
||||||
if (y[j] > maxval) maxval = y[j];
|
if (y[byteNum][j] > maxval) maxval = y[byteNum][j];
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->graphView->addGraph();
|
graphRef[byteNum] = ui->graphView->addGraph();
|
||||||
ui->graphView->graph()->setName(QString("Graph %1").arg(ui->graphView->graphCount()-1));
|
ui->graphView->graph()->setName(QString("Graph %1").arg(ui->graphView->graphCount()-1));
|
||||||
ui->graphView->graph()->setData(x,y);
|
ui->graphView->graph()->setData(x[byteNum],y[byteNum]);
|
||||||
ui->graphView->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines
|
ui->graphView->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines
|
||||||
QPen graphPen;
|
QPen graphPen;
|
||||||
graphPen.setColor(graphColors[byteNum]);
|
graphPen.setColor(graphColors[byteNum]);
|
||||||
@@ -656,6 +696,7 @@ void FlowViewWindow::updatePosition(bool forward)
|
|||||||
|
|
||||||
void FlowViewWindow::updateGraphLocation()
|
void FlowViewWindow::updateGraphLocation()
|
||||||
{
|
{
|
||||||
|
if (frameCache.count() == 0) return;
|
||||||
int start = currentPosition - 5;
|
int start = currentPosition - 5;
|
||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
int end = currentPosition + 5;
|
int end = currentPosition + 5;
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ private:
|
|||||||
bool playbackForward;
|
bool playbackForward;
|
||||||
static const QColor graphColors[8];
|
static const QColor graphColors[8];
|
||||||
bool secondsMode;
|
bool secondsMode;
|
||||||
|
QVector<double> x[8], y[8];
|
||||||
|
QCPGraph *graphRef[8];
|
||||||
|
|
||||||
void refreshIDList();
|
void refreshIDList();
|
||||||
void updateFrameLabel();
|
void updateFrameLabel();
|
||||||
|
|||||||
+217
-142
@@ -1,5 +1,6 @@
|
|||||||
#include "framefileio.h"
|
#include "framefileio.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QProgressDialog>
|
#include <QProgressDialog>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -163,7 +164,13 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
|
|||||||
fileName = fileList[fileList.length() - 1];
|
fileName = fileList[fileList.length() - 1];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else
|
||||||
|
{
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setText("File load completed with errors.\r\nPerhaps you selected the wrong file type?");
|
||||||
|
msgBox.exec();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -179,6 +186,7 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
|
|||||||
QByteArray line;
|
QByteArray line;
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
bool pastHeader = false;
|
bool pastHeader = false;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -193,6 +201,8 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
|
|||||||
if (lineCounter == 2) pastHeader = true;
|
if (lineCounter == 2) pastHeader = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inFile->atEnd()) foundErrors = true;
|
||||||
|
|
||||||
while (!inFile->atEnd()) {
|
while (!inFile->atEnd()) {
|
||||||
lineCounter++;
|
lineCounter++;
|
||||||
if (lineCounter > 100)
|
if (lineCounter > 100)
|
||||||
@@ -203,30 +213,33 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
|
|||||||
line = inFile->readLine().simplified().toUpper();
|
line = inFile->readLine().simplified().toUpper();
|
||||||
|
|
||||||
QList<QByteArray> tokens = line.split(',');
|
QList<QByteArray> tokens = line.split(',');
|
||||||
thisFrame.bus = 0;
|
if (tokens.length() > 20)
|
||||||
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.bus = 0;
|
||||||
{
|
thisFrame.timestamp = tokens[1].toDouble() * 1000000.0;
|
||||||
thisFrame.data[i] = tokens[12 + i].toInt(NULL, 16);
|
if (tokens[5].startsWith("T")) thisFrame.isReceived = false;
|
||||||
thisFrame.len++;
|
else thisFrame.isReceived = true;
|
||||||
}
|
thisFrame.ID = tokens[9].toInt(NULL, 16);
|
||||||
else break;
|
if (tokens[11].startsWith("T")) thisFrame.extended = true;
|
||||||
}
|
else thisFrame.extended = false;
|
||||||
|
|
||||||
frames->append(thisFrame);
|
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);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector<CANFrame> *frames)
|
bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector<CANFrame> *frames)
|
||||||
@@ -262,6 +275,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
CANFrame thisFrame;
|
CANFrame thisFrame;
|
||||||
QByteArray line;
|
QByteArray line;
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -283,44 +297,48 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split(' ');
|
QList<QByteArray> tokens = line.split(' ');
|
||||||
int multiplier;
|
int multiplier;
|
||||||
int idxOfDecimal = tokens[0].indexOf('.');
|
if (tokens.length() > 3)
|
||||||
if (idxOfDecimal > -1) {
|
|
||||||
//int decimalPlaces = tokens[0].length() - tokens[0].indexOf('.') - 1;
|
|
||||||
//the result of the above is the # of digits after the decimal.
|
|
||||||
//This program deals in microsecond so turn the value into microseconds
|
|
||||||
multiplier = 1000000; //turn the decimal into full microseconds
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
multiplier = 1; //special case. Assume no decimal means microseconds
|
int idxOfDecimal = tokens[0].indexOf('.');
|
||||||
}
|
if (idxOfDecimal > -1) {
|
||||||
//qDebug() << "decimal places " << decimalPlaces;
|
//int decimalPlaces = tokens[0].length() - tokens[0].indexOf('.') - 1;
|
||||||
thisFrame.timestamp = (int64_t)(tokens[0].toDouble() * multiplier);
|
//the result of the above is the # of digits after the decimal.
|
||||||
char firstChar = tokens[1].left(1)[0];
|
//This program deals in microsecond so turn the value into microseconds
|
||||||
if (firstChar == 'R' || firstChar == 'T')
|
multiplier = 1000000; //turn the decimal into full microseconds
|
||||||
{
|
}
|
||||||
thisFrame.ID = tokens[2].toInt(NULL, 16);
|
else
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
if (tokens[d + 3] != "")
|
multiplier = 1; //special case. Assume no decimal means microseconds
|
||||||
|
}
|
||||||
|
//qDebug() << "decimal places " << decimalPlaces;
|
||||||
|
thisFrame.timestamp = (int64_t)(tokens[0].toDouble() * multiplier);
|
||||||
|
char firstChar = tokens[1].left(1)[0];
|
||||||
|
if (firstChar == 'R' || firstChar == 'T')
|
||||||
|
{
|
||||||
|
thisFrame.ID = tokens[2].toInt(NULL, 16);
|
||||||
|
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++)
|
||||||
{
|
{
|
||||||
thisFrame.data[d] = tokens[d + 3].toInt(NULL, 16);
|
if (tokens[d + 3] != "")
|
||||||
|
{
|
||||||
|
thisFrame.data[d] = tokens[d + 3].toInt(NULL, 16);
|
||||||
|
}
|
||||||
|
else thisFrame.data[d] = 0;
|
||||||
}
|
}
|
||||||
else thisFrame.data[d] = 0;
|
frames->append(thisFrame);
|
||||||
}
|
}
|
||||||
frames->append(thisFrame);
|
|
||||||
}
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveCRTDFile(QString filename, const QVector<CANFrame>* frames)
|
bool FrameFileIO::saveCRTDFile(QString filename, const QVector<CANFrame>* frames)
|
||||||
@@ -384,6 +402,7 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
int fileVersion = 1;
|
int fileVersion = 1;
|
||||||
long long timeStamp = Utility::GetTimeMS();
|
long long timeStamp = Utility::GetTimeMS();
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -406,47 +425,52 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
if (line.length() > 2)
|
if (line.length() > 2)
|
||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split(',');
|
QList<QByteArray> tokens = line.split(',');
|
||||||
if (tokens[0].length() > 3)
|
if (tokens.length() >= 6)
|
||||||
{
|
{
|
||||||
long long temp = tokens[0].right(10).toLongLong();
|
if (tokens[0].length() > 3)
|
||||||
thisFrame.timestamp = temp;
|
{
|
||||||
}
|
long long temp = tokens[0].right(10).toLongLong();
|
||||||
else
|
thisFrame.timestamp = temp;
|
||||||
{
|
}
|
||||||
timeStamp += 5;
|
else
|
||||||
thisFrame.timestamp = timeStamp;
|
{
|
||||||
}
|
timeStamp += 5;
|
||||||
|
thisFrame.timestamp = timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
thisFrame.ID = tokens[1].toInt(NULL, 16);
|
thisFrame.ID = tokens[1].toInt(NULL, 16);
|
||||||
if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1;
|
if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1;
|
||||||
else thisFrame.extended = 0;
|
else thisFrame.extended = 0;
|
||||||
|
|
||||||
if (fileVersion == 1)
|
if (fileVersion == 1)
|
||||||
{
|
{
|
||||||
thisFrame.isReceived = true;
|
thisFrame.isReceived = true;
|
||||||
thisFrame.bus = tokens[3].toInt();
|
thisFrame.bus = tokens[3].toInt();
|
||||||
thisFrame.len = tokens[4].toInt();
|
thisFrame.len = tokens[4].toInt();
|
||||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||||
for (int d = 0; d < thisFrame.len; d++)
|
for (int d = 0; d < thisFrame.len; d++)
|
||||||
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
||||||
}
|
}
|
||||||
else if (fileVersion == 2)
|
else if (fileVersion == 2)
|
||||||
{
|
{
|
||||||
if (tokens[3].at(0) == 'R') thisFrame.isReceived = true;
|
if (tokens[3].at(0) == 'R') thisFrame.isReceived = true;
|
||||||
else thisFrame.isReceived = false;
|
else thisFrame.isReceived = false;
|
||||||
thisFrame.bus = tokens[4].toInt();
|
thisFrame.bus = tokens[4].toInt();
|
||||||
thisFrame.len = tokens[5].toInt();
|
thisFrame.len = tokens[5].toInt();
|
||||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
if (thisFrame.len + 6 > tokens.length()) thisFrame.len = tokens.length() - 6;
|
||||||
for (int d = 0; d < thisFrame.len; d++)
|
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||||
thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16);
|
for (int d = 0; d < thisFrame.len; d++)
|
||||||
}
|
thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
frames->append(thisFrame);
|
frames->append(thisFrame);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector<CANFrame>* frames)
|
bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector<CANFrame>* frames)
|
||||||
@@ -514,6 +538,7 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector<CANFrame>* frames
|
|||||||
QByteArray line;
|
QByteArray line;
|
||||||
long long timeStamp = Utility::GetTimeMS();
|
long long timeStamp = Utility::GetTimeMS();
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -549,10 +574,11 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector<CANFrame>* frames
|
|||||||
|
|
||||||
frames->append(thisFrame);
|
frames->append(thisFrame);
|
||||||
}
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
//4f5,ff 34 23 45 24 e4
|
//4f5,ff 34 23 45 24 e4
|
||||||
@@ -635,6 +661,7 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
QByteArray line;
|
QByteArray line;
|
||||||
uint64_t timeStamp = Utility::GetTimeMS();
|
uint64_t timeStamp = Utility::GetTimeMS();
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -657,24 +684,30 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
if (line.length() > 1)
|
if (line.length() > 1)
|
||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split(' ');
|
QList<QByteArray> tokens = line.split(' ');
|
||||||
QList<QByteArray> timeToks = tokens[0].split(':');
|
if (tokens.length() >= 6)
|
||||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
{
|
||||||
|
QList<QByteArray> timeToks = tokens[0].split(':');
|
||||||
|
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||||
+ (timeToks[2].toInt() * (1000ul * 1000ul)) + (timeToks[3].toInt() * 100ul);
|
+ (timeToks[2].toInt() * (1000ul * 1000ul)) + (timeToks[3].toInt() * 100ul);
|
||||||
thisFrame.timestamp = timeStamp;
|
thisFrame.timestamp = timeStamp;
|
||||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||||
else thisFrame.isReceived = false;
|
else thisFrame.isReceived = false;
|
||||||
thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16);
|
thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16);
|
||||||
if (tokens[4] == "s") thisFrame.extended = false;
|
if (tokens[4] == "s") thisFrame.extended = false;
|
||||||
else thisFrame.extended = true;
|
else thisFrame.extended = true;
|
||||||
thisFrame.bus = tokens[2].toInt() - 1;
|
thisFrame.bus = tokens[2].toInt() - 1;
|
||||||
thisFrame.len = tokens[5].toInt();
|
thisFrame.len = tokens[5].toInt();
|
||||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16);
|
if (thisFrame.len > 8) thisFrame.len = 8;
|
||||||
}
|
if (thisFrame.len < 0) thisFrame.len = 0;
|
||||||
frames->append(thisFrame);
|
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16);
|
||||||
|
frames->append(thisFrame);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveLogFile(QString filename, const QVector<CANFrame>* frames)
|
bool FrameFileIO::saveLogFile(QString filename, const QVector<CANFrame>* frames)
|
||||||
@@ -748,6 +781,7 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
QByteArray line;
|
QByteArray line;
|
||||||
uint64_t timeStamp = Utility::GetTimeMS();
|
uint64_t timeStamp = Utility::GetTimeMS();
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -769,27 +803,48 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
if (line.length() > 1)
|
if (line.length() > 1)
|
||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split(',');
|
QList<QByteArray> tokens = line.split(',');
|
||||||
QString timePortion = unQuote(tokens[0]);
|
if (line.length() >= 5)
|
||||||
QStringList timeToks = timePortion.split(':');
|
{
|
||||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
QString timePortion = unQuote(tokens[0]);
|
||||||
|
QStringList timeToks = timePortion.split(':');
|
||||||
|
if (timeToks.length() >= 3)
|
||||||
|
{
|
||||||
|
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||||
+ (timeToks[2].toDouble() * (1000.0 * 1000.0));
|
+ (timeToks[2].toDouble() * (1000.0 * 1000.0));
|
||||||
thisFrame.timestamp = timeStamp;
|
}
|
||||||
thisFrame.ID = unQuote(tokens[1]).toInt(NULL, 16);
|
else
|
||||||
if (unQuote(tokens[2]).toUpper().at(0) == 'S') thisFrame.extended = false;
|
{
|
||||||
else thisFrame.extended = true;
|
timeStamp = 0;
|
||||||
|
foundErrors = true;
|
||||||
|
}
|
||||||
|
thisFrame.timestamp = timeStamp;
|
||||||
|
thisFrame.ID = unQuote(tokens[1]).toInt(NULL, 16);
|
||||||
|
QString tempStr = unQuote(tokens[2]).toUpper();
|
||||||
|
if (tempStr.length() > 0)
|
||||||
|
{
|
||||||
|
if (tempStr.at(0) == 'S') thisFrame.extended = false;
|
||||||
|
else thisFrame.extended = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thisFrame.extended = false;
|
||||||
|
foundErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
thisFrame.isReceived = true;
|
thisFrame.isReceived = true;
|
||||||
thisFrame.bus = 0;
|
thisFrame.bus = 0;
|
||||||
|
|
||||||
QStringList dataToks = unQuote(tokens[4]).simplified().split(' ');
|
QStringList dataToks = unQuote(tokens[4]).simplified().split(' ');
|
||||||
thisFrame.len = dataToks.length();
|
thisFrame.len = dataToks.length();
|
||||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16);
|
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16);
|
||||||
|
frames->append(thisFrame);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
frames->append(thisFrame);
|
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveIXXATFile(QString filename, const QVector<CANFrame>* frames)
|
bool FrameFileIO::saveIXXATFile(QString filename, const QVector<CANFrame>* frames)
|
||||||
@@ -856,6 +911,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
QByteArray data;
|
QByteArray data;
|
||||||
int timeOffset = 0;
|
int timeOffset = 0;
|
||||||
uint64_t lastTimeStamp = 0;
|
uint64_t lastTimeStamp = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly))
|
if (!inFile->open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
@@ -891,7 +947,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
timeOffset += 60000000ul;
|
timeOffset += 60000000ul;
|
||||||
}
|
}
|
||||||
lastTimeStamp = thisFrame.timestamp;
|
lastTimeStamp = thisFrame.timestamp;
|
||||||
thisFrame.ID = ((unsigned char)data[3] * 256 + (unsigned char)data[2]) & 0x7FF;
|
thisFrame.ID = (((unsigned char)data[3] & 0x0F) * 256 + (unsigned char)data[2]) & 0x7FF;
|
||||||
thisFrame.len = (unsigned char)data[3] >> 4;
|
thisFrame.len = (unsigned char)data[3] >> 4;
|
||||||
|
|
||||||
if (thisFrame.len <= 8 && thisFrame.ID <= 0x7FF)
|
if (thisFrame.len <= 8 && thisFrame.ID <= 0x7FF)
|
||||||
@@ -899,11 +955,12 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d];
|
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)data[4 + d];
|
||||||
frames->append(thisFrame);
|
frames->append(thisFrame);
|
||||||
}
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveCANDOFile(QString filename, const QVector<CANFrame>* frames)
|
bool FrameFileIO::saveCANDOFile(QString filename, const QVector<CANFrame>* frames)
|
||||||
@@ -977,6 +1034,7 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
bool inComment = false;
|
bool inComment = false;
|
||||||
long long timeStamp;
|
long long timeStamp;
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -1006,24 +1064,31 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
if (!inComment)
|
if (!inComment)
|
||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split(';');
|
QList<QByteArray> tokens = line.split(';');
|
||||||
timeStamp = tokens[0].toInt() * 1000;
|
if (tokens.length() >= 4)
|
||||||
thisFrame.timestamp = timeStamp;
|
{
|
||||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
timeStamp = tokens[0].toInt() * 1000;
|
||||||
else thisFrame.isReceived = false;
|
thisFrame.timestamp = timeStamp;
|
||||||
thisFrame.ID = Utility::ParseStringToNum(tokens[2]);
|
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
else thisFrame.isReceived = false;
|
||||||
else thisFrame.extended = true;
|
thisFrame.ID = Utility::ParseStringToNum(tokens[2]);
|
||||||
thisFrame.bus = 0;
|
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||||
thisFrame.len = tokens[3].toInt();
|
else thisFrame.extended = true;
|
||||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]);
|
thisFrame.bus = 0;
|
||||||
frames->append(thisFrame);
|
thisFrame.len = tokens[3].toInt();
|
||||||
|
if (thisFrame.len > 8) thisFrame.len = 8;
|
||||||
|
if (thisFrame.len < 0) thisFrame.len = 0;
|
||||||
|
if (thisFrame.len + 4 > tokens.length()) thisFrame.len = tokens.length() - 4;
|
||||||
|
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]);
|
||||||
|
frames->append(thisFrame);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1126,6 +1191,7 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
QByteArray line;
|
QByteArray line;
|
||||||
long long timeStamp = 0;
|
long long timeStamp = 0;
|
||||||
int lineCounter = 0;
|
int lineCounter = 0;
|
||||||
|
bool foundErrors = false;
|
||||||
|
|
||||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
@@ -1152,31 +1218,36 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
QList<QByteArray> tokens = line.split('\t');
|
QList<QByteArray> tokens = line.split('\t');
|
||||||
|
if (tokens.length() > 3)
|
||||||
|
{
|
||||||
|
QList<QByteArray> timestampToks = tokens[1].split(':');
|
||||||
|
|
||||||
QList<QByteArray> timestampToks = tokens[1].split(':');
|
timeStamp = timestampToks[0].toInt() * 1000000ul * 60 * 60;
|
||||||
|
timeStamp += timestampToks[1].toInt() * 1000000ul * 60;
|
||||||
|
timeStamp += timestampToks[2].toInt() * 1000000ul;
|
||||||
|
timeStamp += timestampToks[3].toInt() * 100;
|
||||||
|
|
||||||
timeStamp = timestampToks[0].toInt() * 1000000ul * 60 * 60;
|
thisFrame.timestamp = timeStamp;
|
||||||
timeStamp += timestampToks[1].toInt() * 1000000ul * 60;
|
|
||||||
timeStamp += timestampToks[2].toInt() * 1000000ul;
|
|
||||||
timeStamp += timestampToks[3].toInt() * 100;
|
|
||||||
|
|
||||||
thisFrame.timestamp = timeStamp;
|
thisFrame.ID = tokens[2].toLong(NULL, 16);
|
||||||
|
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||||
thisFrame.ID = tokens[2].toLong(NULL, 16);
|
else thisFrame.extended = true;
|
||||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
thisFrame.bus = 0;
|
||||||
else thisFrame.extended = true;
|
thisFrame.len = tokens[3].toInt();
|
||||||
thisFrame.bus = 0;
|
if (thisFrame.len < 0) thisFrame.len = 0;
|
||||||
thisFrame.len = tokens[3].toInt();
|
if (thisFrame.len > 8) thisFrame.len = 8;
|
||||||
|
QList<QByteArray> dataToks = tokens[4].split(' ');
|
||||||
QList<QByteArray> dataToks = tokens[4].split(' ');
|
if (thisFrame.len > dataToks.length()) thisFrame.len = dataToks.length();
|
||||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16);
|
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16);
|
||||||
frames->append(thisFrame);
|
frames->append(thisFrame);
|
||||||
|
}
|
||||||
|
else foundErrors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
inFile->close();
|
||||||
delete inFile;
|
delete inFile;
|
||||||
return true;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameFileIO::saveTraceFile(QString filename, const QVector<CANFrame> * frames)
|
bool FrameFileIO::saveTraceFile(QString filename, const QVector<CANFrame> * frames)
|
||||||
@@ -1348,5 +1419,9 @@ bool FrameFileIO::loadCanDumpFile(QString filename, QVector<CANFrame>* frames)
|
|||||||
|
|
||||||
QString FrameFileIO::unQuote(QString inStr)
|
QString FrameFileIO::unQuote(QString inStr)
|
||||||
{
|
{
|
||||||
return inStr.split('\"')[1];
|
QStringList temp;
|
||||||
|
temp = inStr.split('\"');
|
||||||
|
if (temp.length() >= 3)
|
||||||
|
return temp[1];
|
||||||
|
return QString("");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -84,7 +84,9 @@ void FrameInfoWindow::updatedFrames(int numFrames)
|
|||||||
else //just got some new frames. See if they are relevant.
|
else //just got some new frames. See if they are relevant.
|
||||||
{
|
{
|
||||||
if (numFrames > modelFrames->count()) return;
|
if (numFrames > modelFrames->count()) return;
|
||||||
int currID = ui->listFrameID->currentItem()->text().toInt(NULL, 16);
|
int currID = 0;
|
||||||
|
if (ui->listFrameID->currentItem())
|
||||||
|
currID = ui->listFrameID->currentItem()->text().toInt(NULL, 16);
|
||||||
bool foundID = false;
|
bool foundID = false;
|
||||||
for (int x = modelFrames->count() - numFrames; x < modelFrames->count(); x++)
|
for (int x = modelFrames->count() - numFrames; x < modelFrames->count(); x++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -400,10 +400,12 @@ void FramePlaybackWindow::btnLoadLive()
|
|||||||
|
|
||||||
void FramePlaybackWindow::btnBackOneClick()
|
void FramePlaybackWindow::btnBackOneClick()
|
||||||
{
|
{
|
||||||
|
sendingBuffer.clear();
|
||||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||||
playbackActive = false;
|
playbackActive = false;
|
||||||
|
|
||||||
updatePosition(false);
|
updatePosition(false);
|
||||||
|
emit sendFrameBatch(&sendingBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnPauseClick()
|
void FramePlaybackWindow::btnPauseClick()
|
||||||
@@ -450,9 +452,11 @@ void FramePlaybackWindow::btnPlayClick()
|
|||||||
|
|
||||||
void FramePlaybackWindow::btnFwdOneClick()
|
void FramePlaybackWindow::btnFwdOneClick()
|
||||||
{
|
{
|
||||||
|
sendingBuffer.clear();
|
||||||
playbackTimer->stop();
|
playbackTimer->stop();
|
||||||
playbackActive = false;
|
playbackActive = false;
|
||||||
updatePosition(true);
|
updatePosition(true);
|
||||||
|
emit sendFrameBatch(&sendingBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
||||||
|
|||||||
+40
-45
@@ -430,7 +430,7 @@ int FrameSenderWindow::fetchOperand(int idx, ModifierOperand op)
|
|||||||
if (op.notOper) return ~op.databyte;
|
if (op.notOper) return ~op.databyte;
|
||||||
else return op.databyte;
|
else return op.databyte;
|
||||||
}
|
}
|
||||||
else if (op.ID == -2)
|
else if (op.ID == -2) //fetch data from a data byte within the output frame
|
||||||
{
|
{
|
||||||
if (op.notOper) return ~sendingData.at(idx).data[op.databyte];
|
if (op.notOper) return ~sendingData.at(idx).data[op.databyte];
|
||||||
else return sendingData.at(idx).data[op.databyte];
|
else return sendingData.at(idx).data[op.databyte];
|
||||||
@@ -473,6 +473,8 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
QString modString;
|
QString modString;
|
||||||
bool firstOp = true;
|
bool firstOp = true;
|
||||||
bool abort = false;
|
bool abort = false;
|
||||||
|
QString token;
|
||||||
|
ModifierOp thisOp;
|
||||||
|
|
||||||
//Example line:
|
//Example line:
|
||||||
//d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version
|
//d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version
|
||||||
@@ -493,6 +495,7 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
{
|
{
|
||||||
Modifier thisMod;
|
Modifier thisMod;
|
||||||
thisMod.destByte = 0;
|
thisMod.destByte = 0;
|
||||||
|
firstOp = true;
|
||||||
|
|
||||||
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
||||||
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
||||||
@@ -511,58 +514,50 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
abort = false;
|
abort = false;
|
||||||
|
|
||||||
|
token = Utility::grabAlphaNumeric(mods[i]);
|
||||||
|
if (token[0] == '~')
|
||||||
|
{
|
||||||
|
thisOp.first.notOper = true;
|
||||||
|
token = token.remove(0, 1); //remove the ~ character
|
||||||
|
}
|
||||||
|
else thisOp.first.notOper = false;
|
||||||
|
parseOperandString(token.split(":"), thisOp.first);
|
||||||
|
|
||||||
|
if (mods[i].length() < 2) {
|
||||||
|
abort = true;
|
||||||
|
thisOp.operation = ADDITION;
|
||||||
|
thisOp.second.ID = 0;
|
||||||
|
thisOp.second.databyte = 0;
|
||||||
|
thisOp.second.notOper = false;
|
||||||
|
thisMod.operations.append(thisOp);
|
||||||
|
}
|
||||||
|
|
||||||
while (!abort)
|
while (!abort)
|
||||||
{
|
{
|
||||||
QString token = Utility::grabAlphaNumeric(mods[i]);
|
QString operation = Utility::grabOperation(mods[i]);
|
||||||
ModifierOp thisOp;
|
if (operation == "")
|
||||||
|
|
||||||
if (firstOp)
|
|
||||||
{
|
{
|
||||||
if (token[0] == '~')
|
abort = true;
|
||||||
{
|
|
||||||
thisOp.first.notOper = true;
|
|
||||||
token = token.remove(0, 1); //remove the ~ character
|
|
||||||
}
|
|
||||||
else thisOp.first.notOper = false;
|
|
||||||
parseOperandString(token.split(":"), thisOp.first);
|
|
||||||
firstOp = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
thisOp.first.ID = -1; //shadow register
|
thisOp.operation = parseOperation(operation);
|
||||||
}
|
QString secondOp = Utility::grabAlphaNumeric(mods[i]);
|
||||||
if (mods[i].length() == 0) //if this thing had no actual operation or second operand then fake it
|
if (mods[i][0] == '~')
|
||||||
{
|
{
|
||||||
abort = true;
|
thisOp.second.notOper = true;
|
||||||
thisOp.operation = ADDITION;
|
mods[i] = mods[i].remove(0, 1); //remove the ~ character
|
||||||
thisOp.second.ID = 0;
|
}
|
||||||
thisOp.second.databyte = 0;
|
else thisOp.second.notOper = false;
|
||||||
thisOp.second.notOper = false;
|
thisOp.second.bus = sendingData[line].bus;
|
||||||
|
thisOp.second.ID = sendingData[line].ID;
|
||||||
|
parseOperandString(secondOp.split(":"), thisOp.second);
|
||||||
thisMod.operations.append(thisOp);
|
thisMod.operations.append(thisOp);
|
||||||
}
|
}
|
||||||
else //otherwise try to grab them
|
|
||||||
{
|
thisOp.first.ID = -1; //shadow register
|
||||||
QString operation = Utility::grabOperation(mods[i]);
|
if (mods[i].length() < 2) abort = true;
|
||||||
if (operation == "")
|
|
||||||
{
|
|
||||||
abort = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
thisOp.operation = parseOperation(operation);
|
|
||||||
QString secondOp = Utility::grabAlphaNumeric(mods[i]);
|
|
||||||
if (mods[i][0] == '~')
|
|
||||||
{
|
|
||||||
thisOp.second.notOper = true;
|
|
||||||
mods[i] = mods[i].remove(0, 1); //remove the ~ character
|
|
||||||
}
|
|
||||||
else thisOp.second.notOper = false;
|
|
||||||
thisOp.second.bus = sendingData[line].bus;
|
|
||||||
thisOp.second.ID = sendingData[line].ID;
|
|
||||||
parseOperandString(secondOp.split(":"), thisOp.second);
|
|
||||||
thisMod.operations.append(thisOp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendingData[line].modifiers.append(thisMod);
|
sendingData[line].modifiers.append(thisMod);
|
||||||
|
|||||||
+186
-370
@@ -142,6 +142,7 @@ void GraphingWindow::updatedFrames(int numFrames)
|
|||||||
}
|
}
|
||||||
else //just got some new frames. See if they are relevant.
|
else //just got some new frames. See if they are relevant.
|
||||||
{
|
{
|
||||||
|
bool appendedToGraph = false;
|
||||||
if (numFrames > modelFrames->count()) return;
|
if (numFrames > modelFrames->count()) return;
|
||||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
{
|
{
|
||||||
@@ -151,10 +152,17 @@ void GraphingWindow::updatedFrames(int numFrames)
|
|||||||
if (graphParams[j].ID == thisFrame.ID)
|
if (graphParams[j].ID == thisFrame.ID)
|
||||||
{
|
{
|
||||||
appendToGraph(graphParams[j], thisFrame);
|
appendToGraph(graphParams[j], thisFrame);
|
||||||
|
appendedToGraph = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->graphingView->replot();
|
if (appendedToGraph) {
|
||||||
|
for (int j = 0; j < graphParams.count(); j++)
|
||||||
|
{
|
||||||
|
graphParams[j].ref->setData(graphParams[j].x, graphParams[j].y);
|
||||||
|
}
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,33 +693,24 @@ void GraphingWindow::saveDefinitions()
|
|||||||
QList<GraphParams>::iterator iter;
|
QList<GraphParams>::iterator iter;
|
||||||
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
|
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
outFile->write("X,");
|
||||||
outFile->write(QString::number(iter->ID, 16).toUtf8());
|
outFile->write(QString::number(iter->ID, 16).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
if (iter->isDBCSignal)
|
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
||||||
{
|
outFile->putChar(',');
|
||||||
outFile->putChar('S');
|
outFile->write(QString::number(iter->startBit).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
outFile->write(iter->signal.toUtf8());
|
outFile->write(QString::number(iter->numBits).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
}
|
if (iter->isSigned) outFile->putChar('Y');
|
||||||
else
|
else outFile->putChar('N');
|
||||||
{
|
outFile->putChar(',');
|
||||||
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
outFile->write(QString::number(iter->bias).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
outFile->write(QString::number(iter->startByte).toUtf8());
|
outFile->write(QString::number(iter->scale).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
outFile->write(QString::number(iter->endByte).toUtf8());
|
outFile->write(QString::number(iter->stride).toUtf8());
|
||||||
outFile->putChar(',');
|
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->write(QString::number(iter->color.red()).toUtf8());
|
||||||
outFile->putChar(',');
|
outFile->putChar(',');
|
||||||
outFile->write(QString::number(iter->color.green()).toUtf8());
|
outFile->write(QString::number(iter->color.green()).toUtf8());
|
||||||
@@ -729,7 +728,6 @@ void GraphingWindow::loadDefinitions()
|
|||||||
{
|
{
|
||||||
QString filename;
|
QString filename;
|
||||||
QFileDialog dialog;
|
QFileDialog dialog;
|
||||||
bool dbcMissing = false;
|
|
||||||
|
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
filters.append(QString(tr("Graph definition (*.gdf)")));
|
filters.append(QString(tr("Graph definition (*.gdf)")));
|
||||||
@@ -755,66 +753,146 @@ void GraphingWindow::loadDefinitions()
|
|||||||
if (line.length() > 2)
|
if (line.length() > 2)
|
||||||
{
|
{
|
||||||
GraphParams gp;
|
GraphParams gp;
|
||||||
QList<QByteArray> tokens = line.split(',');
|
|
||||||
gp.isDBCSignal = false;
|
|
||||||
|
|
||||||
gp.ID = tokens[0].toInt(NULL, 16);
|
QList<QByteArray> tokens = line.split(',');
|
||||||
if (tokens[1] == "S")
|
|
||||||
|
if (tokens[0] == "X") //newest format based around signals
|
||||||
{
|
{
|
||||||
gp.isDBCSignal = true;
|
gp.ID = tokens[1].toInt(NULL, 16);
|
||||||
//tokens[2] is the signal name. Need to use the message ID and this name to look it up
|
gp.mask = tokens[2].toULongLong(NULL, 16);
|
||||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
|
gp.startBit = tokens[3].toInt();
|
||||||
if (msg != NULL)
|
gp.numBits = tokens[4].toInt();
|
||||||
{
|
if (tokens[5] == "Y") gp.isSigned = true;
|
||||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
|
|
||||||
if (sig == NULL) dbcMissing = true;
|
|
||||||
gp.signal = tokens[2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gp.signal = "";
|
|
||||||
dbcMissing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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;
|
else gp.isSigned = false;
|
||||||
gp.bias = tokens[5].toFloat();
|
gp.bias = tokens[6].toFloat();
|
||||||
gp.scale = tokens[6].toFloat();
|
gp.scale = tokens[7].toFloat();
|
||||||
gp.stride = tokens[7].toInt();
|
gp.stride = tokens[8].toInt();
|
||||||
}
|
|
||||||
if (!gp.isDBCSignal)
|
gp.color.setRed(tokens[9].toInt());
|
||||||
{
|
gp.color.setGreen(tokens[10].toInt());
|
||||||
gp.color.setRed(tokens[8].toInt());
|
gp.color.setBlue(tokens[11].toInt());
|
||||||
gp.color.setGreen(tokens[9].toInt());
|
if (tokens.length() > 12)
|
||||||
gp.color.setBlue(tokens[10].toInt());
|
gp.graphName = tokens[12];
|
||||||
if (tokens.length() > 11)
|
|
||||||
gp.graphName = tokens[11];
|
|
||||||
else
|
else
|
||||||
gp.graphName = QString();
|
gp.graphName = QString();
|
||||||
|
createGraph(gp, true);
|
||||||
}
|
}
|
||||||
else
|
else //one of the two older formats then
|
||||||
{
|
{
|
||||||
gp.color.setRed(tokens[3].toInt());
|
gp.ID = tokens[0].toInt(NULL, 16);
|
||||||
gp.color.setGreen(tokens[4].toInt());
|
if (tokens[1] == "S") //old signal based graph definition
|
||||||
gp.color.setBlue(tokens[5].toInt());
|
{
|
||||||
gp.graphName = tokens[6];
|
//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)
|
||||||
|
{
|
||||||
|
gp.mask = 0xFFFFFFFF;
|
||||||
|
gp.bias = sig->bias;
|
||||||
|
gp.color.setRed(tokens[3].toInt());
|
||||||
|
gp.color.setGreen(tokens[4].toInt());
|
||||||
|
gp.color.setBlue(tokens[5].toInt());
|
||||||
|
gp.graphName = sig->name;
|
||||||
|
gp.intelFormat = sig->intelByteOrder;
|
||||||
|
if (sig->valType == SIGNED_INT) gp.isSigned = true;
|
||||||
|
else gp.isSigned = false;
|
||||||
|
gp.numBits = sig->signalSize;
|
||||||
|
gp.scale = sig->factor;
|
||||||
|
gp.startBit = sig->startBit;
|
||||||
|
gp.stride = 1;
|
||||||
|
createGraph(gp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //old standard graph definition
|
||||||
|
{
|
||||||
|
//hard part - this all changed drastically
|
||||||
|
//the difference between intel and motorola format is whether
|
||||||
|
//start is larger than end byte or not.
|
||||||
|
uint64_t oldMask = tokens[1].toULongLong(NULL, 16);
|
||||||
|
int oldStart = tokens[2].toInt();
|
||||||
|
int oldEnd = tokens[3].toInt();
|
||||||
|
|
||||||
|
if (oldEnd > oldStart) //motorola / big endian - hell...
|
||||||
|
{
|
||||||
|
gp.intelFormat = false;
|
||||||
|
//for now just naively use the entire bytes called for.
|
||||||
|
gp.startBit = 8 * oldStart + 7;
|
||||||
|
gp.numBits = (oldEnd - oldStart + 1) * 8;
|
||||||
|
}
|
||||||
|
else if (oldStart > oldEnd) //intel / little endian - easiest of multi-byte types
|
||||||
|
{
|
||||||
|
//have to find both ends. start bit is somewhere in oldEnd and last bit is somewhere in
|
||||||
|
//oldStart.
|
||||||
|
|
||||||
|
gp.intelFormat = true;
|
||||||
|
|
||||||
|
//start by setting a safe default if nothing else pans out.
|
||||||
|
gp.startBit = 8 * oldEnd;
|
||||||
|
|
||||||
|
int numBytes = oldStart - oldEnd + 1;
|
||||||
|
gp.numBits = numBytes * 8;
|
||||||
|
|
||||||
|
for (int b = 0; b < 8; b++)
|
||||||
|
{
|
||||||
|
if (oldMask & (1 << b))
|
||||||
|
{
|
||||||
|
gp.startBit = (8 * oldEnd) + b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c = 7; c >= 0; c--)
|
||||||
|
{
|
||||||
|
if ( oldMask & (1<<(((numBytes - 1) * 8) + c)) )
|
||||||
|
{
|
||||||
|
gp.numBits -= (7-c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //within a single byte - easier than the above two by a bit - always use intel format for this
|
||||||
|
{
|
||||||
|
gp.intelFormat = true;
|
||||||
|
oldMask = oldMask & 0xFF; //only this part matters
|
||||||
|
//for intel format we give startbit as the lowest bit number in the signal
|
||||||
|
//we can find that by going backward from bit 0 to 7 and picking the first bit that is 1.
|
||||||
|
//that's our start bit (+ 8*oldStart)
|
||||||
|
//set default first in case the rest falls through
|
||||||
|
gp.startBit = 8 * oldStart;
|
||||||
|
gp.numBits = 8;
|
||||||
|
for (int b = 0; b < 8; b++)
|
||||||
|
{
|
||||||
|
if (oldMask & (1 << b))
|
||||||
|
{
|
||||||
|
gp.startBit = 8 * oldStart + b;
|
||||||
|
gp.numBits = 8 - b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//the rest is easy stuff
|
||||||
|
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];
|
||||||
|
else
|
||||||
|
gp.graphName = QString();
|
||||||
|
createGraph(gp, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
createGraph(gp, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inFile->close();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,135 +929,16 @@ void GraphingWindow::addNewGraph()
|
|||||||
void GraphingWindow::appendToGraph(GraphParams ¶ms, CANFrame &frame)
|
void GraphingWindow::appendToGraph(GraphParams ¶ms, CANFrame &frame)
|
||||||
{
|
{
|
||||||
int64_t tempVal; //64 bit temp value.
|
int64_t tempVal; //64 bit temp value.
|
||||||
if (params.isDBCSignal)
|
tempVal = Utility::processIntegerSignal(frame.data, params.startBit, params.numBits, params.intelFormat, params.isSigned); //& params.mask;
|
||||||
|
if (secondsMode)
|
||||||
{
|
{
|
||||||
double tempValue;
|
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||||
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))
|
|
||||||
{
|
|
||||||
//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
|
else
|
||||||
{
|
{
|
||||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
params.x.append(frame.timestamp - params.xbias);
|
||||||
{
|
|
||||||
tempVal = (frame.data[params.startByte] & params.mask);
|
|
||||||
if (params.isSigned && tempVal > 127)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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 = 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.y.append((tempVal * params.scale) + params.bias);
|
||||||
params.ref->setData(params.x,params.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||||
@@ -988,23 +947,15 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
|||||||
float yminval=10000000.0, ymaxval = -1000000.0;
|
float yminval=10000000.0, ymaxval = -1000000.0;
|
||||||
float xminval=10000000000.0, xmaxval = -10000000000.0;
|
float xminval=10000000000.0, xmaxval = -10000000000.0;
|
||||||
GraphParams *refParam = ¶ms;
|
GraphParams *refParam = ¶ms;
|
||||||
DBC_MESSAGE *msg = NULL;
|
int sBit, bits;
|
||||||
DBC_SIGNAL *sig = NULL;
|
bool intelFormat, isSigned;
|
||||||
|
|
||||||
if (params.isDBCSignal)
|
qDebug() << "New Graph ID: " << params.ID;
|
||||||
{
|
qDebug() << "Start bit: " << params.startBit;
|
||||||
msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(params.ID);
|
qDebug() << "Data length: " << params.numBits;
|
||||||
if (msg) sig = msg->sigHandler->findSignalByName(params.signal);
|
qDebug() << "Intel Mode: " << params.intelFormat;
|
||||||
if (sig == NULL) return;
|
qDebug() << "Signed: " << params.isSigned;
|
||||||
qDebug() << "New signal graph: " << params.signal <<" in ID:" << params.ID;
|
qDebug() << "Mask: " << params.mask;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug() << "New Graph ID: " << params.ID;
|
|
||||||
qDebug() << "Start byte: " << params.startByte;
|
|
||||||
qDebug() << "End Byte: " << params.endByte;
|
|
||||||
qDebug() << "Mask: " << params.mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
frameCache.clear();
|
frameCache.clear();
|
||||||
for (int i = 0; i < modelFrames->count(); i++)
|
for (int i = 0; i < modelFrames->count(); i++)
|
||||||
@@ -1020,163 +971,28 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
|||||||
params.x.fill(0, numEntries);
|
params.x.fill(0, numEntries);
|
||||||
params.y.fill(0, numEntries);
|
params.y.fill(0, numEntries);
|
||||||
|
|
||||||
if (params.isDBCSignal)
|
sBit = params.startBit;
|
||||||
|
bits = params.numBits;
|
||||||
|
intelFormat = params.intelFormat;
|
||||||
|
isSigned = params.isSigned;
|
||||||
|
|
||||||
|
for (int j = 0; j < numEntries; j++)
|
||||||
{
|
{
|
||||||
double tempValue;
|
tempVal = Utility::processIntegerSignal(frameCache[j * params.stride].data, sBit, bits, intelFormat, isSigned); //& params.mask;
|
||||||
int l = 0;
|
//qDebug() << tempVal;
|
||||||
for (int j = 0; j < numEntries; j++)
|
if (secondsMode)
|
||||||
{
|
{
|
||||||
//if the given signal was found and successfully processed in this frame then add it to the graph
|
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||||
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);
|
else
|
||||||
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++)
|
params.x[j] = frameCache[j].timestamp;
|
||||||
{
|
|
||||||
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.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.xbias = 0;
|
params.xbias = 0;
|
||||||
@@ -1193,8 +1009,8 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
|||||||
|
|
||||||
if (params.graphName == NULL || params.graphName.length() == 0)
|
if (params.graphName == NULL || params.graphName.length() == 0)
|
||||||
{
|
{
|
||||||
params.graphName = QString("0x") + QString::number(params.ID, 16) + ":" + QString::number(params.startByte);
|
params.graphName = QString("0x") + QString::number(params.ID, 16) + ":" + QString::number(params.startBit);
|
||||||
if ((params.endByte != -1) && (params.endByte != params.startByte)) params.graphName += "-" + QString::number(params.endByte);
|
params.graphName += "-" + QString::number(params.numBits);
|
||||||
}
|
}
|
||||||
ui->graphingView->graph()->setName(params.graphName);
|
ui->graphingView->graph()->setName(params.graphName);
|
||||||
ui->graphingView->graph()->setProperty("id", params.ID);
|
ui->graphingView->graph()->setProperty("id", params.ID);
|
||||||
|
|||||||
+2
-3
@@ -15,7 +15,8 @@ class GraphParams
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t ID;
|
uint32_t ID;
|
||||||
int startByte, endByte;
|
int startBit, numBits;
|
||||||
|
bool intelFormat;
|
||||||
bool isSigned;
|
bool isSigned;
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
float bias;
|
float bias;
|
||||||
@@ -24,8 +25,6 @@ public:
|
|||||||
QColor color;
|
QColor color;
|
||||||
QCPGraph *ref;
|
QCPGraph *ref;
|
||||||
QString graphName;
|
QString graphName;
|
||||||
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
|
//the below stuff is used for internal purposes only - code should be refactored so these can be private
|
||||||
QVector<double> x, y;
|
QVector<double> x, y;
|
||||||
double xbias;
|
double xbias;
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
#include "isotp_handler.h"
|
||||||
|
|
||||||
|
CODE_STRUCT OBDII_FUNCTS[] =
|
||||||
|
{
|
||||||
|
{1, "UDS_OBDII_SHOW_CURRENT", "OBDII - Show current data"},
|
||||||
|
{2, "UDS_OBDII_SHOW_FREEZE", "OBDII - Show freeze data"},
|
||||||
|
{3, "UDS_OBDII_SHOW_STORED_DTC", "OBDII - Show stored DTC codes"},
|
||||||
|
{4, "UDS_OBDII_CLEAR_DTC", "OBDII - Clear current DTC codes"},
|
||||||
|
{5, "UDS_OBDII_TEST_O2", "OBDII - O2 sensor testing"},
|
||||||
|
{6, "UDS_OBDII_TEST_RESULTS", "OBDII - Show emissions testing results"},
|
||||||
|
{7, "UDS_OBDII_SHOW_PENDING_DTC", "OBDII - Show pending DTC codes"},
|
||||||
|
{8, "UDS_OBDII_CONTROL_DEVICES", "OBDII - Control vehicle devices"},
|
||||||
|
{9, "UDS_OBDII_VEH_INFO", "OBDII - Retrieve vehicle information"},
|
||||||
|
{0xA, "UDS_OBDII_PERM_DTC", "OBDII - Show permanent DTC codes"},
|
||||||
|
{0xFF, "UDS_UNKNOWN", "Unknown OBDII code - Likely proprietary"}
|
||||||
|
};
|
||||||
|
|
||||||
|
CODE_STRUCT UDS_FUNCS[] =
|
||||||
|
{
|
||||||
|
{0x10, "UDS_DIAG_CONTROL", "Diagnostic session control"},
|
||||||
|
{0x11, "UDS_ECU_RESET", "Reset ECU"},
|
||||||
|
{0x14, "UDS_CLEAR_DIAG", "Clear diagnostic trouble codes"},
|
||||||
|
{0x19, "UDS_READ_DTC", "Read diagnostic trouble codes"},
|
||||||
|
{0x22, "UDS_READ_BY_ID", "Read data by ID"},
|
||||||
|
{0x23, "UDS_READ_BY_ADDR", "Read data by address"},
|
||||||
|
{0x24, "UDS_READ_SCALING_ID", "Read scaling data by ID"},
|
||||||
|
{0x27, "UDS_SECURITY_ACCESS", "Request security access"},
|
||||||
|
{0x28, "UDS_COMM_CTRL", "Communication control"},
|
||||||
|
{0x2A, "UDS_READ_DATA_ID_PERIODIC", "Read data by ID periodically"},
|
||||||
|
{0x2C, "UDS_DYNAMIC_DATA_DEFINE", "Create dynamic data ID"},
|
||||||
|
{0x2E, "UDS_WRITE_BY_ID", "Write data by ID"},
|
||||||
|
{0x2F, "UDS_IO_CTRL", "Input/Output control (force)"},
|
||||||
|
{0x31, "UDS_ROUTINE_CTRL", "Call a service routine"},
|
||||||
|
{0x34, "UDS_REQUEST_DOWNLOAD", "Request data download (from PC to ECU)"},
|
||||||
|
{0x35, "UDS_REQUEST_UPLOAD", "Request data upload (from ECU to PC)"},
|
||||||
|
{0x36, "UDS_TRANSFER_DATA", "Transfer data"},
|
||||||
|
{0x37, "UDS_REQ_TRANS_EXIT", "Request that data transfer cease"},
|
||||||
|
{0x38, "UDS_REQ_FILE_TRANS", "Request file transfer"},
|
||||||
|
{0x3D, "UDS_WRITE_BY_ADDR", "Write data by address"},
|
||||||
|
{0x3E, "UDS_TESTER_PRESENT", "Tester is present"},
|
||||||
|
{0x83, "UDS_ACCESS_TIMING", "Read or write comm timing parameters"},
|
||||||
|
{0x84, "UDS_SECURED_DATA_TRANS", "Secured data transmission"},
|
||||||
|
{0x85, "UDS_CTRL_DTC_SETTINGS", "Control DTC settings"},
|
||||||
|
{0x86, "UDS_RESPONSE_ON_EVENT", "Request start/stop transmission on event"},
|
||||||
|
{0x87, "UDS_RESPONSE_LINK_CTRL", "Control comm link"},
|
||||||
|
{0xFF, "UDS_UNKNOWN_CODE", "Unknown, likely proprietary UDS function code"}
|
||||||
|
};
|
||||||
|
|
||||||
|
CODE_STRUCT UDS_NEG_RESPONSE[] =
|
||||||
|
{
|
||||||
|
{0x10, "UDS_NEG_GENERAL_REJECT", "General rejection (no other codes matched)"},
|
||||||
|
{0x11, "UDS_NEG_SERVICE_NOTSUPP", "ECU does not support this service code"},
|
||||||
|
{0x12, "UDS_NEG_SUBFUNCT_NOTSUPP", "ECU does not support the requested sub function"},
|
||||||
|
{0x13, "UDS_NEG_INVALID_FORMAT", "Invalid request length or format error"},
|
||||||
|
{0x14, "UDS_NEG_RESPONSE_TOOLONG", "Response would be too long to send"},
|
||||||
|
{0x21, "UDS_NEG_BUSY", "ECU is busy. Try again later"},
|
||||||
|
{0x22, "UDS_NEG_COND_INCORR", "A prereq. condition was not met"},
|
||||||
|
{0x24, "UDS_NEG_REQ_SEQ_ERR", "Invalid sequence of requests"},
|
||||||
|
{0x25, "UDS_NEG_SUBNET_NORESP", "ECU tried to gateway request but response timed out"},
|
||||||
|
{0x26, "UDS_NEG_FAILURE", "A failure (indicated in a DTC) is preventing a reply"},
|
||||||
|
{0x31, "UDS_NEG_REQ_OUTOFRANGE", "A parameter is outside of the valid range"},
|
||||||
|
{0x33, "UDS_NEG_SECURITY_DENIED", "Security access was denied. (invalid seq or ECU not unlocked?)"},
|
||||||
|
{0x35, "UDS_NEG_INVALID_KEY", "Key passed was invalid. Failure counter has been incremented."},
|
||||||
|
{0x36, "UDS_NEG_EXCEED_ATTEMPTS", "Key failed too many times. ECU security access locked out"},
|
||||||
|
{0x37, "UDS_NEG_TIMEDELAY", "Security access too soon after last attempt"},
|
||||||
|
{0x38, "UDS_NEG_EXT_SECUR_1", "Extended security failure code 1"},
|
||||||
|
{0x39, "UDS_NEG_EXT_SECUR_2", "Extended security failure code 2"},
|
||||||
|
{0x3A, "UDS_NEG_EXT_SECUR_3", "Extended security failure code 3"},
|
||||||
|
{0x3B, "UDS_NEG_EXT_SECUR_4", "Extended security failure code 4"},
|
||||||
|
{0x3C, "UDS_NEG_EXT_SECUR_5", "Extended security failure code 5"},
|
||||||
|
{0x3D, "UDS_NEG_EXT_SECUR_6", "Extended security failure code 6"},
|
||||||
|
{0x3E, "UDS_NEG_EXT_SECUR_7", "Extended security failure code 7"},
|
||||||
|
{0x3F, "UDS_NEG_EXT_SECUR_8", "Extended security failure code 8"},
|
||||||
|
{0x40, "UDS_NEG_EXT_SECUR_9", "Extended security failure code 9"},
|
||||||
|
{0x41, "UDS_NEG_EXT_SECUR_10", "Extended security failure code 10"},
|
||||||
|
{0x42, "UDS_NEG_EXT_SECUR_11", "Extended security failure code 11"},
|
||||||
|
{0x43, "UDS_NEG_EXT_SECUR_12", "Extended security failure code 12"},
|
||||||
|
{0x44, "UDS_NEG_EXT_SECUR_13", "Extended security failure code 13"},
|
||||||
|
{0x45, "UDS_NEG_EXT_SECUR_14", "Extended security failure code 14"},
|
||||||
|
{0x46, "UDS_NEG_EXT_SECUR_15", "Extended security failure code 15"},
|
||||||
|
{0x47, "UDS_NEG_EXT_SECUR_16", "Extended security failure code 16"},
|
||||||
|
{0x48, "UDS_NEG_EXT_SECUR_17", "Extended security failure code 17"},
|
||||||
|
{0x49, "UDS_NEG_EXT_SECUR_18", "Extended security failure code 18"},
|
||||||
|
{0x4A, "UDS_NEG_EXT_SECUR_19", "Extended security failure code 19"},
|
||||||
|
{0x4B, "UDS_NEG_EXT_SECUR_20", "Extended security failure code 20"},
|
||||||
|
{0x4C, "UDS_NEG_EXT_SECUR_21", "Extended security failure code 21"},
|
||||||
|
{0x4D, "UDS_NEG_EXT_SECUR_22", "Extended security failure code 22"},
|
||||||
|
{0x4E, "UDS_NEG_EXT_SECUR_23", "Extended security failure code 23"},
|
||||||
|
{0x4F, "UDS_NEG_EXT_SECUR_24", "Extended security failure code 24"},
|
||||||
|
{0x70, "UDS_NEG_UPLOAD_DOWNLOAD", "Fault when attempting to start upload/download"},
|
||||||
|
{0x71, "UDS_NEG_TRX_SUSPENDED", "Transfer aborting due to a fault"},
|
||||||
|
{0x72, "UDS_NEG_GEN_PROGRAMMING", "Fault while attempting to write to ECU memory"},
|
||||||
|
{0x73, "UDS_NEG_WRONG_BLOCK_SEQ", "Invalid sequence value detected during transfer"},
|
||||||
|
{0x78, "UDS_NEG_RESP_PENDING", "Request successful but ECU still busy - Response pending"},
|
||||||
|
{0x7E, "UDS_NEG_SUBFUNCT_CURRSESS", "ECU does not support this subfunction in current session type"},
|
||||||
|
{0x7F, "UDS_NEG_SERVICE_CURRSESS", "ECU does not support this service in current session type"},
|
||||||
|
{0x81, "UDS_NEG_RPM_TOOHIGH", "RPM is too high to execute request"},
|
||||||
|
{0x82, "UDS_NEG_RPM_TOOLOW", "RPM is too low to execute request"},
|
||||||
|
{0x83, "UDS_NEG_ENGINE_RUNNING", "Cannot execute request while engine is running"},
|
||||||
|
{0x84, "UDS_NEG_ENGINE_NOTRUNNING", "Cannot execute request while engine is off"},
|
||||||
|
{0x85, "UDS_NEG_ENG_RUNTIME_LOW", "Cannot execute request until engine has run for longer"},
|
||||||
|
{0x86, "UDS_NEG_TEMPERATURE_HIGH", "Cannot execute request until temperature is lower"},
|
||||||
|
{0x87, "UDS_NEG_TEMPERATURE_LOW", "Cannot execute request until temperature is higher"},
|
||||||
|
{0x88, "UDS_NEG_SPEED_HIGH", "Cannot execute request until vehicle slows down"},
|
||||||
|
{0x89, "UDS_NEG_SPEED_LOW", "Cannot execute request until vehicle is going faster"},
|
||||||
|
{0x8A, "UDS_NEG_PEDAL_HIGH", "Cannot execute request until throttle is lower"},
|
||||||
|
{0x8B, "UDS_NEG_PEDAL_LOW", "Cannot execute request until throttle is higher"},
|
||||||
|
{0x8C, "UDS_NEG_NOT_NEUTRAL", "Cannot execute request until transmission is in neutral"},
|
||||||
|
{0x8D, "UDS_NEG_NOT_INGEAR", "Cannot execute request until vehicle is in gear"},
|
||||||
|
{0x8F, "UDS_NEG_BRAKE_NOTPRESSED", "Cannot execute request until brake pedal is pressed (Hold down)"},
|
||||||
|
{0x90, "UDS_NEG_NOT_PARK", "Cannot execute request until vehicle is in park"},
|
||||||
|
{0x91, "UDS_NEG_CLUTCH_LOCKED", "Cannot execute request while clutch is locked"},
|
||||||
|
{0x92, "UDS_NEG_VOLTAGE_HIGH", "Cannot execute request until voltage is lower"},
|
||||||
|
{0x93, "UDS_NEG_VOLTAGE_LOW", "Cannot execute request until voltage is higher"},
|
||||||
|
};
|
||||||
|
|
||||||
|
ISOTP_HANDLER::ISOTP_HANDLER(const QVector<CANFrame> *frames, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
modelFrames = frames;
|
||||||
|
useExtendedAddressing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::setExtendedAddressing(bool mode)
|
||||||
|
{
|
||||||
|
useExtendedAddressing = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames.
|
||||||
|
void ISOTP_HANDLER::updatedFrames(int numFrames)
|
||||||
|
{
|
||||||
|
if (numFrames == -1) //all frames deleted. Kill the display
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (numFrames == -2) //all new set of frames. Reset
|
||||||
|
{
|
||||||
|
for (int i = 0; i < modelFrames->length(); i++) processFrame(modelFrames->at(i));
|
||||||
|
}
|
||||||
|
else //just got some new frames. See if they are relevant.
|
||||||
|
{
|
||||||
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
processFrame(modelFrames->at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::processFrame(const CANFrame &frame)
|
||||||
|
{
|
||||||
|
uint64_t ID = frame.ID;
|
||||||
|
int frameType;
|
||||||
|
int frameLen;
|
||||||
|
int ln;
|
||||||
|
int offset;
|
||||||
|
ISOTP_MESSAGE msg;
|
||||||
|
ISOTP_MESSAGE *pMsg;
|
||||||
|
|
||||||
|
frameType = 0;
|
||||||
|
frameLen = 0;
|
||||||
|
|
||||||
|
if (useExtendedAddressing)
|
||||||
|
{
|
||||||
|
ID = ID << 8;
|
||||||
|
ID += frame.data[0];
|
||||||
|
frameType = frame.data[1] >> 4;
|
||||||
|
frameLen = frame.data[1] & 0xF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameType = frame.data[0] >> 4;
|
||||||
|
frameLen = frame.data[0] & 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(frameType)
|
||||||
|
{
|
||||||
|
case 0: //single frame message
|
||||||
|
checkNeedFlush(ID);
|
||||||
|
|
||||||
|
if (frameLen == 0) return; //length of zero isn't valid.
|
||||||
|
if (frameLen > 6 && useExtendedAddressing) return; //impossible
|
||||||
|
if (frameLen > 7) return;
|
||||||
|
|
||||||
|
msg.bus = frame.bus;
|
||||||
|
msg.extended = frame.extended;
|
||||||
|
msg.ID = ID;
|
||||||
|
msg.isReceived = frame.isReceived;
|
||||||
|
msg.len = frameLen;
|
||||||
|
msg.data.reserve(frameLen);
|
||||||
|
msg.timestamp = frame.timestamp;
|
||||||
|
if (useExtendedAddressing) for (int j = 0; j < frameLen; j++) msg.data.append(frame.data[j+2]);
|
||||||
|
else for (int j = 0; j < frameLen; j++) msg.data.append(frame.data[j+1]);
|
||||||
|
qDebug() << "Emitting single frame ISOTP message";
|
||||||
|
emit newISOMessage(msg);
|
||||||
|
break;
|
||||||
|
case 1: //first frame of a multi-frame message
|
||||||
|
checkNeedFlush(ID);
|
||||||
|
msg.bus = frame.bus;
|
||||||
|
msg.extended = frame.extended;
|
||||||
|
msg.ID = ID;
|
||||||
|
msg.timestamp = frame.timestamp;
|
||||||
|
msg.isReceived = frame.isReceived;
|
||||||
|
frameLen = frameLen << 8;
|
||||||
|
if (useExtendedAddressing)
|
||||||
|
{
|
||||||
|
frameLen += frame.data[2];
|
||||||
|
frameLen = frameLen & 0xFFF;
|
||||||
|
msg.len = frameLen;
|
||||||
|
msg.data.reserve(frameLen);
|
||||||
|
for (int j = 0; j < 5; j++) msg.data.append(frame.data[3 + j]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameLen += frame.data[1];
|
||||||
|
frameLen = frameLen & 0xFFF;
|
||||||
|
msg.len = frameLen;
|
||||||
|
msg.data.reserve(frameLen);
|
||||||
|
for (int j = 0; j < 6; j++) msg.data.append(frame.data[2 + j]);
|
||||||
|
}
|
||||||
|
messageBuffer.append(msg);
|
||||||
|
break;
|
||||||
|
case 2: //subsequent frames for multi-frame messages
|
||||||
|
pMsg = NULL;
|
||||||
|
for (int i = 0; i < messageBuffer.length(); i++)
|
||||||
|
{
|
||||||
|
if (messageBuffer[i].ID == ID)
|
||||||
|
{
|
||||||
|
pMsg = &messageBuffer[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pMsg) return;
|
||||||
|
ln = pMsg->len - pMsg->data.count();
|
||||||
|
offset = pMsg->data.count();
|
||||||
|
if (useExtendedAddressing)
|
||||||
|
{
|
||||||
|
if (ln > 6) ln = 6;
|
||||||
|
for (int j = 0; j < ln; j++) pMsg->data.append(frame.data[j+2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ln > 7) ln = 7;
|
||||||
|
for (int j = 0; j < ln; j++) pMsg->data.append(frame.data[j+1]);
|
||||||
|
}
|
||||||
|
if (pMsg->len <= pMsg->data.count())
|
||||||
|
{
|
||||||
|
qDebug() << "Emitting multiframe ISOTP message";
|
||||||
|
emit newISOMessage(*pMsg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: //flow control messages -ignored for now
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::checkNeedFlush(uint64_t ID)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < messageBuffer.length(); i++)
|
||||||
|
{
|
||||||
|
if (messageBuffer[i].ID == ID)
|
||||||
|
{
|
||||||
|
//warning... this code will work for direct signals as emit turns into a function call
|
||||||
|
//and thus the other side will have time to do its processing before control returns
|
||||||
|
//and we delete the message on our side. But, if this code were used cross thread the
|
||||||
|
//emit would be a queued message instead and control would immediately return
|
||||||
|
//here and then the message would be deleted before being delivered.
|
||||||
|
//To fix that the message would have to be passed by value instead which I'd like to avoid.
|
||||||
|
//Thus, don't use this across threads unless you like to debug strange issues.
|
||||||
|
qDebug() << "Flushing a partial frame";
|
||||||
|
emit newISOMessage(messageBuffer[i]);
|
||||||
|
messageBuffer.removeAt(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef ISOTP_DECODER_H
|
||||||
|
#define ISOTP_DECODER_H
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "can_structs.h"
|
||||||
|
|
||||||
|
struct CODE_STRUCT
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
QString shortDesc;
|
||||||
|
QString longDesc;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISOTP_HANDLER : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ISOTP_HANDLER(const QVector<CANFrame> *frames, QObject *parent = 0);
|
||||||
|
void setExtendedAddressing(bool mode);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updatedFrames(int);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newISOMessage(ISOTP_MESSAGE &msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<ISOTP_MESSAGE> messageBuffer;
|
||||||
|
const QVector<CANFrame> *modelFrames;
|
||||||
|
bool useExtendedAddressing;
|
||||||
|
|
||||||
|
void processFrame(const CANFrame &frame);
|
||||||
|
void checkNeedFlush(uint64_t ID);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ISOTP_DECODER_H
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#include "isotp_interpreterwindow.h"
|
||||||
|
#include "ui_isotp_interpreterwindow.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::ISOTP_InterpreterWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
modelFrames = frames;
|
||||||
|
|
||||||
|
decoder = new ISOTP_HANDLER(modelFrames);
|
||||||
|
|
||||||
|
connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ISOTP_InterpreterWindow::updatedFrames);
|
||||||
|
connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames);
|
||||||
|
connect(decoder, &ISOTP_HANDLER::newISOMessage, this, &ISOTP_InterpreterWindow::newISOMessage);
|
||||||
|
|
||||||
|
connect(ui->tableIsoFrames, &QTableWidget::itemSelectionChanged, this, &ISOTP_InterpreterWindow::showDetailView);
|
||||||
|
|
||||||
|
QStringList headers;
|
||||||
|
headers << "Timestamp" << "ID" << "Bus" << "Dir" << "Length" << "Data";
|
||||||
|
ui->tableIsoFrames->setColumnCount(6);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(0, 100);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(1, 50);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(2, 50);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(3, 50);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(4, 75);
|
||||||
|
ui->tableIsoFrames->setColumnWidth(5, 200);
|
||||||
|
ui->tableIsoFrames->setHorizontalHeaderLabels(headers);
|
||||||
|
QHeaderView *HorzHdr = ui->tableIsoFrames->horizontalHeader();
|
||||||
|
HorzHdr->setStretchLastSection(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISOTP_InterpreterWindow::~ISOTP_InterpreterWindow()
|
||||||
|
{
|
||||||
|
delete decoder;
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
QDialog::showEvent(event);
|
||||||
|
readSettings();
|
||||||
|
decoder->updatedFrames(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::readSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||||
|
{
|
||||||
|
resize(settings.value("ISODecodeWindow/WindowSize", this->size()).toSize());
|
||||||
|
move(settings.value("ISODecodeWindow/WindowPos", QPoint(50, 50)).toPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::writeSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||||
|
{
|
||||||
|
settings.setValue("ISODecodeWindow/WindowSize", size());
|
||||||
|
settings.setValue("ISODecodeWindow/WindowPos", pos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::updatedFrames(int numFrames)
|
||||||
|
{
|
||||||
|
if (numFrames == -1) //all frames deleted. Kill the display
|
||||||
|
{
|
||||||
|
messages.clear();
|
||||||
|
ui->tableIsoFrames->clear();
|
||||||
|
}
|
||||||
|
else if (numFrames == -2) //all new set of frames. Reset
|
||||||
|
{
|
||||||
|
messages.clear();
|
||||||
|
ui->tableIsoFrames->clear();
|
||||||
|
}
|
||||||
|
else //just got some new frames. See if they are relevant.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::showDetailView()
|
||||||
|
{
|
||||||
|
QString buildString;
|
||||||
|
ISOTP_MESSAGE *msg;
|
||||||
|
int rowNum = ui->tableIsoFrames->currentRow();
|
||||||
|
|
||||||
|
ui->txtFrameDetails->clear();
|
||||||
|
if (rowNum == -1) return;
|
||||||
|
|
||||||
|
msg = &messages[rowNum];
|
||||||
|
|
||||||
|
if (msg->len != msg->data.length())
|
||||||
|
{
|
||||||
|
buildString.append("Message didn't have the correct number of bytes.\rExpected "
|
||||||
|
+ QString::number(msg->len) + " got "
|
||||||
|
+ QString::number(msg->data.length()) + "\r\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
buildString.append(tr("Raw Payload: "));
|
||||||
|
for (int i = 0; i < messages[rowNum].data.count(); i++)
|
||||||
|
{
|
||||||
|
buildString.append(Utility::formatNumber(messages[rowNum].data[i]));
|
||||||
|
buildString.append(" ");
|
||||||
|
}
|
||||||
|
buildString.append("\r\r");
|
||||||
|
|
||||||
|
//if (ui->cb->isChecked())
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
ui->txtFrameDetails->setText(buildString);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE &msg)
|
||||||
|
{
|
||||||
|
int rowNum;
|
||||||
|
QString tempString;
|
||||||
|
|
||||||
|
if ((msg.len != msg.data.count()) && !ui->cbShowIncomplete->isChecked()) return;
|
||||||
|
|
||||||
|
messages.append(msg);
|
||||||
|
|
||||||
|
rowNum = ui->tableIsoFrames->rowCount();
|
||||||
|
ui->tableIsoFrames->insertRow(rowNum);
|
||||||
|
|
||||||
|
ui->tableIsoFrames->setItem(rowNum, 0, new QTableWidgetItem(QString::number(msg.timestamp)));
|
||||||
|
ui->tableIsoFrames->setItem(rowNum, 1, new QTableWidgetItem(QString::number(msg.ID, 16)));
|
||||||
|
ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus)));
|
||||||
|
if (msg.isReceived) ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Rx"));
|
||||||
|
else ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Tx"));
|
||||||
|
ui->tableIsoFrames->setItem(rowNum, 4, new QTableWidgetItem(QString::number(msg.len)));
|
||||||
|
|
||||||
|
for (int i = 0; i < msg.data.count(); i++)
|
||||||
|
{
|
||||||
|
tempString.append(Utility::formatNumber(msg.data[i]));
|
||||||
|
tempString.append(" ");
|
||||||
|
}
|
||||||
|
ui->tableIsoFrames->setItem(rowNum, 5, new QTableWidgetItem(tempString));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef ISOTP_INTERPRETERWINDOW_H
|
||||||
|
#define ISOTP_INTERPRETERWINDOW_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include "can_structs.h"
|
||||||
|
#include "isotp_handler.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ISOTP_InterpreterWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ISOTP_InterpreterWindow : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ISOTP_InterpreterWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
|
||||||
|
~ISOTP_InterpreterWindow();
|
||||||
|
void showEvent(QShowEvent*);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void newISOMessage(ISOTP_MESSAGE &msg);
|
||||||
|
void showDetailView();
|
||||||
|
void updatedFrames(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ISOTP_InterpreterWindow *ui;
|
||||||
|
ISOTP_HANDLER *decoder;
|
||||||
|
|
||||||
|
const QVector<CANFrame> *modelFrames;
|
||||||
|
QVector<ISOTP_MESSAGE> messages;
|
||||||
|
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
|
void readSettings();
|
||||||
|
void writeSettings();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ISOTP_INTERPRETERWINDOW_H
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ISOTP_InterpreterWindow</class>
|
||||||
|
<widget class="QDialog" name="ISOTP_InterpreterWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>792</width>
|
||||||
|
<height>725</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>ISO-TP Decoder</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Interpreted Messages Overview</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="tableIsoFrames"/>
|
||||||
|
</item>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QCheckBox" name="cbShowIncomplete">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show incomplete and/or corrupted messages</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data Details of Selected Message</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Interpret As:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rbRaw">
|
||||||
|
<property name="text">
|
||||||
|
<string>Raw</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rbUDS">
|
||||||
|
<property name="text">
|
||||||
|
<string>UDS</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rbOBDII">
|
||||||
|
<property name="text">
|
||||||
|
<string>OBDII</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="txtFrameDetails"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="lblFilter">
|
||||||
|
<property name="text">
|
||||||
|
<string>IDs to Decode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listFilter"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnNone">
|
||||||
|
<property name="text">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
+55
-7
@@ -69,7 +69,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(&serialWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
|
connect(&serialWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
|
||||||
connect(&serialWorkerThread, &QThread::started, worker, &SerialWorker::run); //setup timers within the proper thread
|
connect(&serialWorkerThread, &QThread::started, worker, &SerialWorker::run); //setup timers within the proper thread
|
||||||
connect(this, &MainWindow::sendSerialPort, worker, &SerialWorker::setSerialPort, Qt::QueuedConnection);
|
connect(this, &MainWindow::sendSerialPort, worker, &SerialWorker::setSerialPort, Qt::QueuedConnection);
|
||||||
connect(worker, &SerialWorker::frameUpdateTick, this, &MainWindow::gotFrames, Qt::QueuedConnection);
|
connect(worker, &SerialWorker::frameUpdateRapid, this, &MainWindow::gotFrames, Qt::QueuedConnection);
|
||||||
connect(this, &MainWindow::updateBaudRates, worker, &SerialWorker::updateBaudRates, Qt::QueuedConnection);
|
connect(this, &MainWindow::updateBaudRates, worker, &SerialWorker::updateBaudRates, Qt::QueuedConnection);
|
||||||
connect(this, &MainWindow::sendCANFrame, worker, &SerialWorker::sendFrame, Qt::QueuedConnection);
|
connect(this, &MainWindow::sendCANFrame, worker, &SerialWorker::sendFrame, Qt::QueuedConnection);
|
||||||
connect(worker, &SerialWorker::connectionSuccess, this, &MainWindow::connectionSucceeded, Qt::QueuedConnection);
|
connect(worker, &SerialWorker::connectionSuccess, this, &MainWindow::connectionSucceeded, Qt::QueuedConnection);
|
||||||
@@ -98,9 +98,12 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
dbcFileWindow = NULL;
|
dbcFileWindow = NULL;
|
||||||
fuzzingWindow = NULL;
|
fuzzingWindow = NULL;
|
||||||
udsScanWindow = NULL;
|
udsScanWindow = NULL;
|
||||||
|
isoWindow = NULL;
|
||||||
dbcHandler = new DBCHandler;
|
dbcHandler = new DBCHandler;
|
||||||
bDirty = false;
|
bDirty = false;
|
||||||
inhibitFilterUpdate = false;
|
inhibitFilterUpdate = false;
|
||||||
|
rxFrames = 0;
|
||||||
|
framesPerSec = 0;
|
||||||
|
|
||||||
model->setDBCHandler(dbcHandler);
|
model->setDBCHandler(dbcHandler);
|
||||||
|
|
||||||
@@ -139,6 +142,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(ui->actionDBC_File_Manager, &QAction::triggered, this, &MainWindow::showDBCFileWindow);
|
connect(ui->actionDBC_File_Manager, &QAction::triggered, this, &MainWindow::showDBCFileWindow);
|
||||||
connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow);
|
connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow);
|
||||||
connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow);
|
connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow);
|
||||||
|
connect(ui->actionISO_TP_Decoder, &QAction::triggered, this, &MainWindow::showISOInterpreterWindow);
|
||||||
|
|
||||||
lbStatusConnected.setText(tr("Not connected"));
|
lbStatusConnected.setText(tr("Not connected"));
|
||||||
updateFileStatus();
|
updateFileStatus();
|
||||||
@@ -150,6 +154,13 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
ui->lbFPS->setText("0");
|
ui->lbFPS->setText("0");
|
||||||
ui->lbNumFrames->setText("0");
|
ui->lbNumFrames->setText("0");
|
||||||
|
|
||||||
|
connect(&updateTimer, &QTimer::timeout, this, &MainWindow::tickGUIUpdate);
|
||||||
|
updateTimer.setInterval(250);
|
||||||
|
updateTimer.start();
|
||||||
|
|
||||||
|
elapsedTime = new QTime;
|
||||||
|
elapsedTime->start();
|
||||||
|
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
allowCapture = true;
|
allowCapture = true;
|
||||||
|
|
||||||
@@ -266,6 +277,14 @@ MainWindow::~MainWindow()
|
|||||||
delete udsScanWindow;
|
delete udsScanWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isoWindow)
|
||||||
|
{
|
||||||
|
isoWindow->close();
|
||||||
|
delete isoWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete elapsedTime;
|
||||||
|
|
||||||
delete ui;
|
delete ui;
|
||||||
delete dbcHandler;
|
delete dbcHandler;
|
||||||
model->clearFrames();
|
model->clearFrames();
|
||||||
@@ -289,6 +308,7 @@ void MainWindow::exitApp()
|
|||||||
if (dbcFileWindow) dbcFileWindow->close();
|
if (dbcFileWindow) dbcFileWindow->close();
|
||||||
if (fuzzingWindow) fuzzingWindow->close();
|
if (fuzzingWindow) fuzzingWindow->close();
|
||||||
if (udsScanWindow) udsScanWindow->close();
|
if (udsScanWindow) udsScanWindow->close();
|
||||||
|
if (isoWindow) isoWindow->close();
|
||||||
this->close();
|
this->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,20 +513,36 @@ void MainWindow::filterClearAll()
|
|||||||
model->setAllFilters(false);
|
model->setAllFilters(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//most of the work is handled elsewhere. Need only to update the # of frames
|
void MainWindow::tickGUIUpdate()
|
||||||
//and maybe auto scroll
|
|
||||||
void MainWindow::gotFrames(int FPS, int framesSinceLastUpdate)
|
|
||||||
{
|
{
|
||||||
|
int elapsed = elapsedTime->elapsed();
|
||||||
|
if(elapsed) {
|
||||||
|
framesPerSec += rxFrames * 1000 / elapsed - (framesPerSec / 4);
|
||||||
|
elapsedTime->restart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
framesPerSec = 0;
|
||||||
|
|
||||||
|
model->sendBulkRefresh(rxFrames);
|
||||||
|
|
||||||
ui->lbNumFrames->setText(QString::number(model->rowCount()));
|
ui->lbNumFrames->setText(QString::number(model->rowCount()));
|
||||||
if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||||
ui->lbFPS->setText(QString::number(FPS));
|
ui->lbFPS->setText(QString::number(framesPerSec / 4));
|
||||||
if (framesSinceLastUpdate > 0)
|
if (rxFrames > 0)
|
||||||
{
|
{
|
||||||
bDirty = true;
|
bDirty = true;
|
||||||
emit framesUpdated(framesSinceLastUpdate); //anyone care that frames were updated?
|
emit framesUpdated(rxFrames); //anyone care that frames were updated?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model->needsFilterRefresh()) updateFilterList();
|
if (model->needsFilterRefresh()) updateFilterList();
|
||||||
|
|
||||||
|
rxFrames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::gotFrames(int framesSinceLastUpdate)
|
||||||
|
{
|
||||||
|
rxFrames += framesSinceLastUpdate;
|
||||||
|
emit frameUpdateRapid(framesSinceLastUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::addFrameToDisplay(CANFrame &frame, bool autoRefresh = false)
|
void MainWindow::addFrameToDisplay(CANFrame &frame, bool autoRefresh = false)
|
||||||
@@ -864,6 +900,18 @@ void MainWindow::showFrameDataAnalysis()
|
|||||||
frameInfoWindow->show();
|
frameInfoWindow->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showISOInterpreterWindow()
|
||||||
|
{
|
||||||
|
if (!isoWindow)
|
||||||
|
{
|
||||||
|
if (!useFiltered)
|
||||||
|
isoWindow = new ISOTP_InterpreterWindow(model->getListReference());
|
||||||
|
else
|
||||||
|
isoWindow = new ISOTP_InterpreterWindow(model->getFilteredListReference());
|
||||||
|
}
|
||||||
|
isoWindow->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::showFrameSenderWindow()
|
void MainWindow::showFrameSenderWindow()
|
||||||
{
|
{
|
||||||
if (!frameSenderWindow)
|
if (!frameSenderWindow)
|
||||||
|
|||||||
+10
-1
@@ -25,6 +25,7 @@
|
|||||||
#include "dbcloadsavewindow.h"
|
#include "dbcloadsavewindow.h"
|
||||||
#include "fuzzingwindow.h"
|
#include "fuzzingwindow.h"
|
||||||
#include "udsscanwindow.h"
|
#include "udsscanwindow.h"
|
||||||
|
#include "isotp_interpreterwindow.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
@@ -65,6 +66,7 @@ private slots:
|
|||||||
void showDBCFileWindow();
|
void showDBCFileWindow();
|
||||||
void showFuzzingWindow();
|
void showFuzzingWindow();
|
||||||
void showUDSScanWindow();
|
void showUDSScanWindow();
|
||||||
|
void showISOInterpreterWindow();
|
||||||
void exitApp();
|
void exitApp();
|
||||||
void handleSaveDecoded();
|
void handleSaveDecoded();
|
||||||
void changeBaudRates();
|
void changeBaudRates();
|
||||||
@@ -75,6 +77,7 @@ private slots:
|
|||||||
void gridDoubleClicked(QModelIndex);
|
void gridDoubleClicked(QModelIndex);
|
||||||
void interpretToggled(bool);
|
void interpretToggled(bool);
|
||||||
void overwriteToggled(bool);
|
void overwriteToggled(bool);
|
||||||
|
void tickGUIUpdate();
|
||||||
void toggleCapture();
|
void toggleCapture();
|
||||||
void normalizeTiming();
|
void normalizeTiming();
|
||||||
void updateFilterList();
|
void updateFilterList();
|
||||||
@@ -83,7 +86,7 @@ private slots:
|
|||||||
void filterClearAll();
|
void filterClearAll();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void gotFrames(int, int);
|
void gotFrames(int);
|
||||||
void updateSettings();
|
void updateSettings();
|
||||||
void gotCenterTimeID(int32_t ID, double timestamp);
|
void gotCenterTimeID(int32_t ID, double timestamp);
|
||||||
void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1);
|
void updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1);
|
||||||
@@ -98,6 +101,7 @@ signals:
|
|||||||
|
|
||||||
//-1 = frames cleared, -2 = a new file has been loaded (so all frames are different), otherwise # of new frames
|
//-1 = frames cleared, -2 = a new file has been loaded (so all frames are different), otherwise # of new frames
|
||||||
void framesUpdated(int numFrames); //something has updated the frame list
|
void framesUpdated(int numFrames); //something has updated the frame list
|
||||||
|
void frameUpdateRapid(int numFrames);
|
||||||
void settingsUpdated();
|
void settingsUpdated();
|
||||||
void sendCenterTimeID(int32_t ID, double timestamp);
|
void sendCenterTimeID(int32_t ID, double timestamp);
|
||||||
|
|
||||||
@@ -111,6 +115,10 @@ private:
|
|||||||
QThread serialWorkerThread;
|
QThread serialWorkerThread;
|
||||||
SerialWorker *worker;
|
SerialWorker *worker;
|
||||||
QByteArray inputBuffer;
|
QByteArray inputBuffer;
|
||||||
|
QTimer updateTimer;
|
||||||
|
QTime *elapsedTime;
|
||||||
|
int framesPerSec;
|
||||||
|
int rxFrames;
|
||||||
bool inhibitFilterUpdate;
|
bool inhibitFilterUpdate;
|
||||||
bool useHex;
|
bool useHex;
|
||||||
bool allowCapture;
|
bool allowCapture;
|
||||||
@@ -135,6 +143,7 @@ private:
|
|||||||
DBCLoadSaveWindow *dbcFileWindow;
|
DBCLoadSaveWindow *dbcFileWindow;
|
||||||
FuzzingWindow *fuzzingWindow;
|
FuzzingWindow *fuzzingWindow;
|
||||||
UDSScanWindow *udsScanWindow;
|
UDSScanWindow *udsScanWindow;
|
||||||
|
ISOTP_InterpreterWindow *isoWindow;
|
||||||
|
|
||||||
//various private storage
|
//various private storage
|
||||||
QLabel lbStatusConnected;
|
QLabel lbStatusConnected;
|
||||||
|
|||||||
@@ -210,6 +210,7 @@
|
|||||||
<addaction name="actionFile_Comparison"/>
|
<addaction name="actionFile_Comparison"/>
|
||||||
<addaction name="actionRange_State_2"/>
|
<addaction name="actionRange_State_2"/>
|
||||||
<addaction name="actionSingle_Multi_State_2"/>
|
<addaction name="actionSingle_Multi_State_2"/>
|
||||||
|
<addaction name="actionISO_TP_Decoder"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuSend_Frames">
|
<widget class="QMenu" name="menuSend_Frames">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -387,6 +388,11 @@
|
|||||||
<string>UDS Scanner</string>
|
<string>UDS Scanner</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionISO_TP_Decoder">
|
||||||
|
<property name="text">
|
||||||
|
<string>ISO-TP Decoder</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
+106
-134
@@ -24,9 +24,13 @@ NewGraphDialog::NewGraphDialog(DBCHandler *handler, QWidget *parent) :
|
|||||||
ui->colorSwatch->setPalette(p);
|
ui->colorSwatch->setPalette(p);
|
||||||
|
|
||||||
connect(ui->cbMessages, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSignals(int)));
|
connect(ui->cbMessages, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSignals(int)));
|
||||||
connect(ui->cbSignals, SIGNAL(currentIndexChanged(int)), this, SLOT(fillFormFromSignal(int)));
|
connect(ui->gridData, SIGNAL(gridClicked(int,int)), this, SLOT(bitfieldClicked(int,int)));
|
||||||
connect(ui->rbSignalGraph, SIGNAL(toggled(bool)), this, SLOT(setSignalActive(bool)));
|
connect(ui->txtDataLen, SIGNAL(textChanged(QString)), this, SLOT(handleDataLenUpdate()));
|
||||||
connect(ui->rbStandardGraph, SIGNAL(toggled(bool)), this, SLOT(setStandardActive(bool)));
|
connect(ui->cbIntel, SIGNAL(toggled(bool)), this, SLOT(drawBitfield()));
|
||||||
|
connect(ui->btnCopySignal, SIGNAL(clicked(bool)), this, SLOT(copySignalToParamsUI()));
|
||||||
|
|
||||||
|
startBit = 0;
|
||||||
|
dataLen = 1;
|
||||||
|
|
||||||
loadMessages();
|
loadMessages();
|
||||||
}
|
}
|
||||||
@@ -36,6 +40,12 @@ NewGraphDialog::~NewGraphDialog()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewGraphDialog::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
QDialog::showEvent(event);
|
||||||
|
loadMessages();
|
||||||
|
}
|
||||||
|
|
||||||
void NewGraphDialog::addButtonClicked()
|
void NewGraphDialog::addButtonClicked()
|
||||||
{
|
{
|
||||||
accept();
|
accept();
|
||||||
@@ -59,91 +69,49 @@ void NewGraphDialog::clearParams()
|
|||||||
ui->txtScale->clear();
|
ui->txtScale->clear();
|
||||||
ui->txtStride->clear();
|
ui->txtStride->clear();
|
||||||
ui->txtName->clear();
|
ui->txtName->clear();
|
||||||
ui->txtData->clear();
|
|
||||||
ui->rbStandardGraph->setChecked(true);
|
|
||||||
setStandardActive(true);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewGraphDialog::setParams(GraphParams ¶ms)
|
void NewGraphDialog::setParams(GraphParams ¶ms)
|
||||||
{
|
{
|
||||||
if (params.isDBCSignal)
|
ui->txtBias->setText(QString::number(params.bias));
|
||||||
{
|
ui->txtMask->setText(Utility::formatNumber(params.mask));
|
||||||
clearParams();
|
ui->txtScale->setText(QString::number(params.scale));
|
||||||
setSignalActive(true);
|
ui->txtStride->setText(QString::number(params.stride));
|
||||||
//loadMessages();
|
ui->cbSigned->setChecked(params.isSigned);
|
||||||
|
ui->cbIntel->setChecked(params.intelFormat);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
startBit = params.startBit;
|
||||||
|
dataLen = params.numBits;
|
||||||
|
ui->txtDataLen->setText(QString::number(dataLen));
|
||||||
ui->txtID->setText(Utility::formatNumber(params.ID));
|
ui->txtID->setText(Utility::formatNumber(params.ID));
|
||||||
ui->txtName->setText(params.graphName);
|
ui->txtName->setText(params.graphName);
|
||||||
QPalette p = ui->colorSwatch->palette();
|
QPalette p = ui->colorSwatch->palette();
|
||||||
p.setColor(QPalette::Button, params.color);
|
p.setColor(QPalette::Button, params.color);
|
||||||
ui->colorSwatch->setPalette(p);
|
ui->colorSwatch->setPalette(p);
|
||||||
|
|
||||||
|
drawBitfield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewGraphDialog::getParams(GraphParams ¶ms)
|
void NewGraphDialog::getParams(GraphParams ¶ms)
|
||||||
{
|
{
|
||||||
params.isDBCSignal = ui->rbSignalGraph->isChecked();
|
|
||||||
params.color = ui->colorSwatch->palette().button().color();
|
params.color = ui->colorSwatch->palette().button().color();
|
||||||
params.graphName = ui->txtName->text();
|
params.graphName = ui->txtName->text();
|
||||||
|
|
||||||
if (params.isDBCSignal)
|
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||||
{
|
params.bias = ui->txtBias->text().toFloat();
|
||||||
params.signal = ui->cbSignals->currentText();
|
params.isSigned = ui->cbSigned->isChecked();
|
||||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
params.intelFormat = ui->cbIntel->isChecked();
|
||||||
params.bias = 0;
|
params.mask = Utility::ParseStringToNum(ui->txtMask->text());
|
||||||
params.isSigned = false;
|
params.scale = ui->txtScale->text().toFloat();
|
||||||
params.mask = 0;
|
params.stride = Utility::ParseStringToNum(ui->txtStride->text());
|
||||||
params.scale = 1;
|
|
||||||
params.bias = 0;
|
|
||||||
params.stride = 1;
|
|
||||||
|
|
||||||
}
|
params.startBit = startBit;
|
||||||
else {
|
params.numBits = dataLen;
|
||||||
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('-');
|
//now catch stupidity and bring it to defaults
|
||||||
params.startByte = -1;
|
if (params.mask == 0) params.mask = 0xFFFFFFFF;
|
||||||
params.endByte = -1;
|
if (fabs(params.scale) < 0.00000001) params.scale = 1.0f;
|
||||||
if (values.count() > 0)
|
if (params.stride < 1) params.stride = 1;
|
||||||
{
|
|
||||||
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()
|
void NewGraphDialog::loadMessages()
|
||||||
@@ -174,73 +142,77 @@ void NewGraphDialog::loadSignals(int idx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewGraphDialog::fillFormFromSignal(int idx)
|
void NewGraphDialog::bitfieldClicked(int x,int y)
|
||||||
|
{
|
||||||
|
int bit = (y * 8 + (7-x));
|
||||||
|
int res;
|
||||||
|
|
||||||
|
qDebug() << "Clicked bit: " << bit;
|
||||||
|
startBit = bit;
|
||||||
|
drawBitfield();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewGraphDialog::drawBitfield()
|
||||||
|
{
|
||||||
|
int64_t bitField = 0;
|
||||||
|
int endBit, sBit;
|
||||||
|
|
||||||
|
bitField |= 1ull << (startBit); //make the start bit a different color to set it apart
|
||||||
|
ui->gridData->setReference((unsigned char *)&bitField, false);
|
||||||
|
|
||||||
|
if (ui->cbIntel->isChecked())
|
||||||
|
{
|
||||||
|
endBit = startBit + dataLen - 1;
|
||||||
|
if (startBit < 0) startBit = 0;
|
||||||
|
if (endBit > 63) endBit = 63;
|
||||||
|
for (int y = startBit; y <= endBit; y++)
|
||||||
|
{
|
||||||
|
bitField |= 1ull << y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //big endian / motorola format
|
||||||
|
{
|
||||||
|
//much more irritating than the intel version...
|
||||||
|
int size = dataLen;
|
||||||
|
sBit = startBit;
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
bitField |= 1ull << sBit;
|
||||||
|
size--;
|
||||||
|
if ((sBit % 8) == 0) sBit += 15;
|
||||||
|
else sBit--;
|
||||||
|
if (sBit > 63) sBit = 63;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->gridData->updateData((unsigned char *)&bitField, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewGraphDialog::handleDataLenUpdate()
|
||||||
|
{
|
||||||
|
dataLen = ui->txtDataLen->text().toInt();
|
||||||
|
if (dataLen < 1) dataLen = 1;
|
||||||
|
if (dataLen > 63) dataLen = 63;
|
||||||
|
drawBitfield();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewGraphDialog::copySignalToParamsUI()
|
||||||
{
|
{
|
||||||
Q_UNUSED(idx);
|
|
||||||
GraphParams params;
|
|
||||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
|
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByName(ui->cbMessages->currentText());
|
||||||
|
if (!msg) return;
|
||||||
if (msg == NULL) return;
|
|
||||||
|
|
||||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
|
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
|
||||||
|
if (!sig) return;
|
||||||
|
|
||||||
if (sig == NULL) return;
|
startBit = sig->startBit;
|
||||||
|
ui->txtBias->setText(QString::number(sig->bias));
|
||||||
params.graphName = sig->name;
|
ui->txtDataLen->setText(QString::number(sig->signalSize));
|
||||||
params.ID = msg->ID;
|
ui->txtID->setText(Utility::formatNumber(msg->ID));
|
||||||
//params.bias = sig->bias;
|
ui->txtMask->setText("0xFFFFFFFF");
|
||||||
//params.scale = sig->factor;
|
ui->txtName->setText(sig->name);
|
||||||
//params.stride = 1;
|
ui->txtScale->setText(QString::number(sig->factor));
|
||||||
//params.mask = (1 << (sig->signalSize)) - 1;
|
ui->txtStride->setText("1");
|
||||||
//if (sig->valType == SIGNED_INT) params.isSigned = true;
|
ui->cbIntel->setChecked(sig->intelByteOrder);
|
||||||
//else params.isSigned = false;
|
if (sig->valType == SIGNED_INT) ui->cbSigned->setChecked(true);
|
||||||
params.color = ui->colorSwatch->palette().color(QPalette::Button);
|
else ui->cbSigned->setChecked(false);
|
||||||
/*
|
drawBitfield();
|
||||||
if (sig->intelByteOrder)
|
|
||||||
{
|
|
||||||
//for this ordering the byte order is reserved and starting byte
|
|
||||||
//will be the higher value
|
|
||||||
params.endByte = sig->startBit / 8;
|
|
||||||
params.startByte = (sig->startBit + sig->signalSize - 1) / 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//for this ordering it goes in normal numerical order
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -16,6 +16,7 @@ class NewGraphDialog : public QDialog
|
|||||||
public:
|
public:
|
||||||
explicit NewGraphDialog(DBCHandler *handler, QWidget *parent = 0);
|
explicit NewGraphDialog(DBCHandler *handler, QWidget *parent = 0);
|
||||||
~NewGraphDialog();
|
~NewGraphDialog();
|
||||||
|
void showEvent(QShowEvent*);
|
||||||
void getParams(GraphParams &);
|
void getParams(GraphParams &);
|
||||||
void setParams(GraphParams &);
|
void setParams(GraphParams &);
|
||||||
void clearParams();
|
void clearParams();
|
||||||
@@ -25,13 +26,15 @@ private slots:
|
|||||||
void colorSwatchClick();
|
void colorSwatchClick();
|
||||||
void loadMessages();
|
void loadMessages();
|
||||||
void loadSignals(int idx);
|
void loadSignals(int idx);
|
||||||
void fillFormFromSignal(int idx);
|
void bitfieldClicked(int,int);
|
||||||
void setSignalActive(bool);
|
void handleDataLenUpdate();
|
||||||
void setStandardActive(bool);
|
void drawBitfield();
|
||||||
|
void copySignalToParamsUI();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::NewGraphDialog *ui;
|
Ui::NewGraphDialog *ui;
|
||||||
DBCHandler *dbcHandler;
|
DBCHandler *dbcHandler;
|
||||||
|
int startBit, dataLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NEWGRAPHDIALOG_H
|
#endif // NEWGRAPHDIALOG_H
|
||||||
|
|||||||
+85
-44
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>492</width>
|
<width>681</width>
|
||||||
<height>340</height>
|
<height>640</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -15,31 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,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>
|
<item>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
@@ -55,28 +31,25 @@
|
|||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Data:</string>
|
<string>Start Bit:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="5" column="0">
|
||||||
<widget class="QLineEdit" name="txtData"/>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Signed:</string>
|
<string>Signed:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QCheckBox" name="cbSigned">
|
<widget class="QCheckBox" name="cbSigned">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="6" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::NoFrame</enum>
|
<enum>QFrame::NoFrame</enum>
|
||||||
@@ -86,47 +59,47 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QLineEdit" name="txtMask"/>
|
<widget class="QLineEdit" name="txtMask"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Bias:</string>
|
<string>Bias:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="7" column="1">
|
||||||
<widget class="QLineEdit" name="txtBias"/>
|
<widget class="QLineEdit" name="txtBias"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="8" column="0">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Scale</string>
|
<string>Scale</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QLineEdit" name="txtScale"/>
|
<widget class="QLineEdit" name="txtScale"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="9" column="0">
|
||||||
<widget class="QLabel" name="label_7">
|
<widget class="QLabel" name="label_7">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stride</string>
|
<string>Stride</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="9" column="1">
|
||||||
<widget class="QLineEdit" name="txtStride"/>
|
<widget class="QLineEdit" name="txtStride"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="10" column="0">
|
||||||
<widget class="QLabel" name="label_8">
|
<widget class="QLabel" name="label_8">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Color</string>
|
<string>Color</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QPushButton" name="colorSwatch">
|
<widget class="QPushButton" name="colorSwatch">
|
||||||
<property name="autoFillBackground">
|
<property name="autoFillBackground">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -139,7 +112,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="11" column="1">
|
||||||
<widget class="QPushButton" name="btnAddGraph">
|
<widget class="QPushButton" name="btnAddGraph">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add this graph</string>
|
<string>Add this graph</string>
|
||||||
@@ -156,6 +129,46 @@
|
|||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLineEdit" name="txtName"/>
|
<widget class="QLineEdit" name="txtName"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="CANDataGrid" name="gridData" native="true">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>290</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>150</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>Intel Format</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QCheckBox" name="cbIntel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data Len:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="txtDataLen"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -214,12 +227,40 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="cbSignals"/>
|
<widget class="QComboBox" name="cbSignals"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnCopySignal">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy Signal Parameters</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</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>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>CANDataGrid</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>candatagrid.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
+44
-24
@@ -12,15 +12,15 @@ SerialWorker::SerialWorker(CANFrameModel *model, QObject *parent) : QObject(pare
|
|||||||
rx_step = 0;
|
rx_step = 0;
|
||||||
buildFrame = new CANFrame;
|
buildFrame = new CANFrame;
|
||||||
canModel = model;
|
canModel = model;
|
||||||
gotFrames = 0;
|
|
||||||
ticker = NULL;
|
ticker = NULL;
|
||||||
elapsedTime = NULL;
|
framesRapid = 0;
|
||||||
framesPerSec = 0;
|
|
||||||
capturing = true;
|
capturing = true;
|
||||||
gotValidated = true;
|
gotValidated = true;
|
||||||
isAutoRestart = false;
|
isAutoRestart = false;
|
||||||
targetID = -1;
|
targetID = -1;
|
||||||
|
|
||||||
|
txTimestampBasis = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
readSettings();
|
readSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,9 +45,6 @@ void SerialWorker::run()
|
|||||||
ticker = new QTimer;
|
ticker = new QTimer;
|
||||||
connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick()));
|
connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||||
|
|
||||||
elapsedTime = new QTime;
|
|
||||||
elapsedTime->start();
|
|
||||||
|
|
||||||
ticker->setInterval(250); //tick four times per second
|
ticker->setInterval(250); //tick four times per second
|
||||||
ticker->setSingleShot(false); //keep ticking
|
ticker->setSingleShot(false); //keep ticking
|
||||||
ticker->start();
|
ticker->start();
|
||||||
@@ -118,6 +115,11 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port)
|
|||||||
output.append((char)0xF1); //yet another command
|
output.append((char)0xF1); //yet another command
|
||||||
output.append((char)0x09); //comm validation command
|
output.append((char)0x09); //comm validation command
|
||||||
|
|
||||||
|
output.append((char)0xF1); //and another command
|
||||||
|
output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try
|
||||||
|
|
||||||
|
continuousTimeSync = true;
|
||||||
|
|
||||||
serial->write(output);
|
serial->write(output);
|
||||||
if (doValidation) connected = false;
|
if (doValidation) connected = false;
|
||||||
else connected = true;
|
else connected = true;
|
||||||
@@ -148,6 +150,11 @@ void SerialWorker::readSerialData()
|
|||||||
c = data.at(i);
|
c = data.at(i);
|
||||||
procRXChar(c);
|
procRXChar(c);
|
||||||
}
|
}
|
||||||
|
if (framesRapid > 0)
|
||||||
|
{
|
||||||
|
emit frameUpdateRapid(framesRapid);
|
||||||
|
framesRapid = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
||||||
@@ -157,12 +164,13 @@ void SerialWorker::sendFrame(const CANFrame *frame, int bus = 0)
|
|||||||
int ID;
|
int ID;
|
||||||
CANFrame tempFrame = *frame;
|
CANFrame tempFrame = *frame;
|
||||||
tempFrame.isReceived = false;
|
tempFrame.isReceived = false;
|
||||||
|
tempFrame.timestamp = ((QDateTime::currentMSecsSinceEpoch() - txTimestampBasis) * 1000);
|
||||||
|
|
||||||
//qDebug() << "Sending out frame with id " << frame->ID;
|
//qDebug() << "Sending out frame with id " << frame->ID;
|
||||||
|
|
||||||
//show our sent frames in the list too. This happens even if we're not connected.
|
//show our sent frames in the list too. This happens even if we're not connected.
|
||||||
canModel->addFrame(tempFrame, false);
|
canModel->addFrame(tempFrame, false);
|
||||||
gotFrames++;
|
framesRapid++;
|
||||||
|
|
||||||
if (serial == NULL) return;
|
if (serial == NULL) return;
|
||||||
if (!serial->isOpen()) return;
|
if (!serial->isOpen()) return;
|
||||||
@@ -233,8 +241,9 @@ void SerialWorker::procRXChar(unsigned char c)
|
|||||||
rx_state = BUILD_CAN_FRAME;
|
rx_state = BUILD_CAN_FRAME;
|
||||||
rx_step = 0;
|
rx_step = 0;
|
||||||
break;
|
break;
|
||||||
case 1: //we don't accept time sync commands from the firmware
|
case 1: //time sync
|
||||||
rx_state = IDLE;
|
rx_state = TIME_SYNC;
|
||||||
|
rx_step = 0;
|
||||||
break;
|
break;
|
||||||
case 2: //process a return reply for digital input states.
|
case 2: //process a return reply for digital input states.
|
||||||
rx_state = GET_DIG_INPUTS;
|
rx_state = GET_DIG_INPUTS;
|
||||||
@@ -316,7 +325,9 @@ void SerialWorker::procRXChar(unsigned char c)
|
|||||||
{
|
{
|
||||||
buildFrame->isReceived = true;
|
buildFrame->isReceived = true;
|
||||||
canModel->addFrame(*buildFrame, false);
|
canModel->addFrame(*buildFrame, false);
|
||||||
gotFrames++;
|
//take the time the frame came in and try to resync the time base.
|
||||||
|
if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame->timestamp / 1000);
|
||||||
|
framesRapid++;
|
||||||
if (buildFrame->ID == targetID) emit gotTargettedFrame(canModel->rowCount() - 1);
|
if (buildFrame->ID == targetID) emit gotTargettedFrame(canModel->rowCount() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,6 +335,29 @@ void SerialWorker::procRXChar(unsigned char c)
|
|||||||
}
|
}
|
||||||
rx_step++;
|
rx_step++;
|
||||||
break;
|
break;
|
||||||
|
case TIME_SYNC: //gives a pretty good base guess for the proper timestamp. Can be refined when traffic starts to flow (if wanted)
|
||||||
|
switch (rx_step)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
buildTimeBasis = c;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
buildTimeBasis += ((uint32_t)c << 8);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
buildTimeBasis += ((uint32_t)c << 16);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
buildTimeBasis += ((uint32_t)c << 24);
|
||||||
|
qDebug() << "GVRET firmware reports timestamp of " << buildTimeBasis;
|
||||||
|
txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - ((uint64_t)buildTimeBasis / (uint64_t)1000ull);
|
||||||
|
continuousTimeSync = false;
|
||||||
|
rx_state = IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rx_step++;
|
||||||
|
break;
|
||||||
|
|
||||||
case GET_ANALOG_INPUTS: //get 9 bytes - 2 per analog input plus checksum
|
case GET_ANALOG_INPUTS: //get 9 bytes - 2 per analog input plus checksum
|
||||||
switch (rx_step)
|
switch (rx_step)
|
||||||
{
|
{
|
||||||
@@ -411,9 +445,6 @@ void SerialWorker::procRXChar(unsigned char c)
|
|||||||
}
|
}
|
||||||
rx_step++;
|
rx_step++;
|
||||||
break;
|
break;
|
||||||
case TIME_SYNC:
|
|
||||||
rx_state = IDLE;
|
|
||||||
break;
|
|
||||||
case SET_DIG_OUTPUTS:
|
case SET_DIG_OUTPUTS:
|
||||||
rx_state = IDLE;
|
rx_state = IDLE;
|
||||||
break;
|
break;
|
||||||
@@ -447,17 +478,6 @@ void SerialWorker::handleTick()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int elapsed = elapsedTime->elapsed();
|
|
||||||
if(elapsed) {
|
|
||||||
framesPerSec += gotFrames * 1000 / elapsed - (framesPerSec / 4);
|
|
||||||
elapsedTime->restart();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
framesPerSec = 0;
|
|
||||||
|
|
||||||
emit frameUpdateTick(framesPerSec / 4, gotFrames); //sends stats to interested parties
|
|
||||||
canModel->sendBulkRefresh(gotFrames);
|
|
||||||
gotFrames = 0;
|
|
||||||
if (doValidation && serial && serial->isOpen()) sendCommValidation();
|
if (doValidation && serial && serial->isOpen()) sendCommValidation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-7
@@ -40,8 +40,8 @@ public:
|
|||||||
void targetFrameID(int);
|
void targetFrameID(int);
|
||||||
|
|
||||||
signals: //we emit signals
|
signals: //we emit signals
|
||||||
void error(const QString &);
|
void error(const QString &);
|
||||||
void frameUpdateTick(int, int); //update interested parties about the # of frames that have come in
|
void frameUpdateRapid(int); //sent *much* more rapidly than the above signal - one param for # of frames
|
||||||
void connectionSuccess(int, int);
|
void connectionSuccess(int, int);
|
||||||
void connectionFailure();
|
void connectionFailure();
|
||||||
void deviceInfo(int, int);
|
void deviceInfo(int, int);
|
||||||
@@ -71,14 +71,13 @@ private:
|
|||||||
bool doValidation;
|
bool doValidation;
|
||||||
bool gotValidated;
|
bool gotValidated;
|
||||||
bool isAutoRestart;
|
bool isAutoRestart;
|
||||||
|
bool continuousTimeSync;
|
||||||
QSerialPort *serial;
|
QSerialPort *serial;
|
||||||
QSerialPortInfo *currentPort;
|
QSerialPortInfo *currentPort;
|
||||||
CANFrameModel *canModel;
|
CANFrameModel *canModel;
|
||||||
QTimer *ticker;
|
QTimer *ticker;
|
||||||
QTime *elapsedTime;
|
QMutex sendBulkMutex;
|
||||||
QMutex sendBulkMutex;
|
int framesRapid;
|
||||||
int framesPerSec;
|
|
||||||
int gotFrames;
|
|
||||||
int targetID;
|
int targetID;
|
||||||
STATE rx_state;
|
STATE rx_state;
|
||||||
int rx_step;
|
int rx_step;
|
||||||
@@ -87,6 +86,8 @@ private:
|
|||||||
bool can0Enabled, can1Enabled;
|
bool can0Enabled, can1Enabled;
|
||||||
int deviceBuildNum;
|
int deviceBuildNum;
|
||||||
int deviceSingleWireMode;
|
int deviceSingleWireMode;
|
||||||
|
uint64_t txTimestampBasis;
|
||||||
|
uint32_t buildTimeBasis;
|
||||||
|
|
||||||
void procRXChar(unsigned char);
|
void procRXChar(unsigned char);
|
||||||
void sendCommValidation();
|
void sendCommValidation();
|
||||||
|
|||||||
+112
-20
@@ -10,10 +10,13 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
|||||||
|
|
||||||
modelFrames = frames;
|
modelFrames = frames;
|
||||||
|
|
||||||
|
currentlyRunning = false;
|
||||||
|
|
||||||
waitTimer = new QTimer;
|
waitTimer = new QTimer;
|
||||||
waitTimer->setInterval(500);
|
waitTimer->setInterval(100);
|
||||||
|
|
||||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
|
connect(MainWindow::getReference(), SIGNAL(frameUpdateRapid(int)), this, SLOT(rapidFrames(int)));
|
||||||
connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS);
|
connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS);
|
||||||
connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
|
connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
|
||||||
|
|
||||||
@@ -32,10 +35,19 @@ UDSScanWindow::~UDSScanWindow()
|
|||||||
|
|
||||||
void UDSScanWindow::scanUDS()
|
void UDSScanWindow::scanUDS()
|
||||||
{
|
{
|
||||||
|
if (currentlyRunning)
|
||||||
|
{
|
||||||
|
waitTimer->stop();
|
||||||
|
sendingFrames.clear();
|
||||||
|
currentlyRunning = false;
|
||||||
|
ui->btnScan->setText("Start Scan");
|
||||||
|
}
|
||||||
|
|
||||||
ui->listResults->clear();
|
ui->listResults->clear();
|
||||||
sendingFrames.clear();
|
sendingFrames.clear();
|
||||||
|
|
||||||
CANFrame frame;
|
CANFrame frame;
|
||||||
|
int typ, id;
|
||||||
int startID, endID;
|
int startID, endID;
|
||||||
startID = Utility::ParseStringToNum(ui->txtStartID->text());
|
startID = Utility::ParseStringToNum(ui->txtStartID->text());
|
||||||
endID = Utility::ParseStringToNum(ui->txtEndID->text());
|
endID = Utility::ParseStringToNum(ui->txtEndID->text());
|
||||||
@@ -43,9 +55,35 @@ void UDSScanWindow::scanUDS()
|
|||||||
int buses = ui->cbBuses->currentIndex();
|
int buses = ui->cbBuses->currentIndex();
|
||||||
buses++;
|
buses++;
|
||||||
if (buses < 1) buses = 1;
|
if (buses < 1) buses = 1;
|
||||||
for (int typ = 1; typ < 5; typ++)
|
|
||||||
|
//start out by sending tester present to every address to see if anyone replies
|
||||||
|
for (id = startID; id <= endID; id++)
|
||||||
{
|
{
|
||||||
for (int id = startID; id < endID; id++)
|
frame.ID = id;
|
||||||
|
frame.len = 8;
|
||||||
|
frame.extended = false;
|
||||||
|
frame.data[0] = 2;
|
||||||
|
frame.data[1] = 0x3E; //tester present
|
||||||
|
frame.data[2] = 0;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//then try asking for the various diagnostic session types
|
||||||
|
for (typ = 1; typ < 5; typ++)
|
||||||
|
{
|
||||||
|
for (id = startID; id <= endID; id++)
|
||||||
{
|
{
|
||||||
frame.ID = id;
|
frame.ID = id;
|
||||||
frame.len = 8;
|
frame.len = 8;
|
||||||
@@ -71,14 +109,14 @@ void UDSScanWindow::scanUDS()
|
|||||||
|
|
||||||
waitTimer->start();
|
waitTimer->start();
|
||||||
currIdx = -1;
|
currIdx = -1;
|
||||||
|
currentlyRunning = true;
|
||||||
|
ui->btnScan->setText("Abort Scan");
|
||||||
sendNextMsg();
|
sendNextMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Updates here are sent about every 1/4 second. That's fine for most windows but not this one.
|
||||||
void UDSScanWindow::updatedFrames(int numFrames)
|
void UDSScanWindow::updatedFrames(int numFrames)
|
||||||
{
|
{
|
||||||
CANFrame thisFrame;
|
|
||||||
QString result;
|
|
||||||
int id;
|
|
||||||
if (numFrames == -1) //all frames deleted. We don't care
|
if (numFrames == -1) //all frames deleted. We don't care
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -87,30 +125,81 @@ void UDSScanWindow::updatedFrames(int numFrames)
|
|||||||
}
|
}
|
||||||
else //just got some new frames. See if they are relevant.
|
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++)
|
}
|
||||||
|
|
||||||
|
//Updates here are nearly once per millisecond if there is heavy traffic. That's more like it!
|
||||||
|
void UDSScanWindow::rapidFrames(int numFrames)
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
QString result;
|
||||||
|
int id;
|
||||||
|
int offset = ui->spinReplyOffset->value();
|
||||||
|
CANFrame sentFrame;
|
||||||
|
bool gotReply = false;
|
||||||
|
|
||||||
|
if (numFrames > modelFrames->count()) return;
|
||||||
|
|
||||||
|
int numSending = sendingFrames.length();
|
||||||
|
if (numSending == 0) return;
|
||||||
|
if (currIdx >= numSending) return;
|
||||||
|
sentFrame = sendingFrames[currIdx];
|
||||||
|
|
||||||
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
if (currIdx >= numSending) return;
|
||||||
|
thisFrame = modelFrames->at(i);
|
||||||
|
id = thisFrame.ID;
|
||||||
|
|
||||||
|
if ((id == (sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked())
|
||||||
{
|
{
|
||||||
thisFrame = modelFrames->at(i);
|
int temp = thisFrame.data[0] >> 4;
|
||||||
id = thisFrame.ID;
|
if (temp == 0) //single frame reply (maybe)
|
||||||
if (id >= 0x7E8 && id <= 0x7EF)
|
|
||||||
{
|
{
|
||||||
id -= 8; //back to original ECU id
|
if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].data[1])
|
||||||
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) + " "
|
result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode "
|
||||||
+ QString::number(thisFrame.data[1], 16) + " " + QString::number(thisFrame.data[2], 16)
|
+ QString::number(sentFrame.data[1], 16)
|
||||||
+ " " + QString::number(thisFrame.data[3], 16);
|
+ " " + QString::number(sentFrame.data[2], 16) + " with affirmation from ID " + QString::number(id, 16)
|
||||||
ui->listResults->addItem(result);
|
+ " on bus " + QString::number(thisFrame.bus) + ".";
|
||||||
sendNextMsg();
|
gotReply = true;
|
||||||
|
}
|
||||||
|
else if ( thisFrame.data[1] == 0x7F)
|
||||||
|
{
|
||||||
|
result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode "
|
||||||
|
+ QString::number(sentFrame.data[1], 16)
|
||||||
|
+ " " + QString::number(sentFrame.data[2], 16) + " with an error from ID " + QString::number(id, 16)
|
||||||
|
+ " on bus " + QString::number(thisFrame.bus) + ".";
|
||||||
|
gotReply = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp == 1) //start of a multiframe reply
|
||||||
|
{
|
||||||
|
if (thisFrame.data[2] == 0x40 + sendingFrames[currIdx].data[1])
|
||||||
|
{
|
||||||
|
result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode "
|
||||||
|
+ QString::number(sentFrame.data[1], 16)
|
||||||
|
+ " " + QString::number(sentFrame.data[2], 16) + " with affirmation from ID " + QString::number(id, 16)
|
||||||
|
+ " on bus " + QString::number(thisFrame.bus) + ".";
|
||||||
|
gotReply = true;
|
||||||
|
}
|
||||||
|
//error replies are never multiframe so the check doesn't have to be done here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (gotReply)
|
||||||
|
{
|
||||||
|
ui->listResults->addItem(result);
|
||||||
|
sendNextMsg();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDSScanWindow::timeOut()
|
void UDSScanWindow::timeOut()
|
||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
result = "ECU at bus " + QString::number(sendingFrames[currIdx].bus) + " ID: " + QString::number(sendingFrames[currIdx].ID, 16) + " did not respond to mode "
|
result = "Request on bus " + QString::number(sendingFrames[currIdx].bus) + " ID: " + QString::number(sendingFrames[currIdx].ID, 16) + " got no response to mode "
|
||||||
+ QString::number(sendingFrames[currIdx].data[2]);
|
+ QString::number(sendingFrames[currIdx].data[1], 16) + " " + QString::number(sendingFrames[currIdx].data[2], 16);
|
||||||
ui->listResults->addItem(result);
|
ui->listResults->addItem(result);
|
||||||
|
|
||||||
sendNextMsg();
|
sendNextMsg();
|
||||||
@@ -122,9 +211,12 @@ void UDSScanWindow::sendNextMsg()
|
|||||||
if (currIdx < sendingFrames.count())
|
if (currIdx < sendingFrames.count())
|
||||||
{
|
{
|
||||||
emit sendCANFrame(&sendingFrames[currIdx], sendingFrames[currIdx].bus);
|
emit sendCANFrame(&sendingFrames[currIdx], sendingFrames[currIdx].bus);
|
||||||
|
waitTimer->start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
waitTimer->stop();
|
waitTimer->stop();
|
||||||
|
ui->btnScan->setText("Start Scan");
|
||||||
|
currentlyRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ signals:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updatedFrames(int numFrames);
|
void updatedFrames(int numFrames);
|
||||||
|
void rapidFrames(int numFrames);
|
||||||
void scanUDS();
|
void scanUDS();
|
||||||
void timeOut();
|
void timeOut();
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ private:
|
|||||||
QTimer *waitTimer;
|
QTimer *waitTimer;
|
||||||
QList<CANFrame> sendingFrames;
|
QList<CANFrame> sendingFrames;
|
||||||
int currIdx = 0;
|
int currIdx = 0;
|
||||||
|
bool currentlyRunning;
|
||||||
|
|
||||||
void sendNextMsg();
|
void sendNextMsg();
|
||||||
};
|
};
|
||||||
|
|||||||
+28
-1
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>UDS Scanner</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@@ -64,6 +64,33 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reply Offset:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinReplyOffset">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-128</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>128</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbAllowAdaptiveOffset">
|
||||||
|
<property name="text">
|
||||||
|
<string>Allow adaptive reply offset</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ public:
|
|||||||
* actual signal. This extends the sign bits out so that the integer result reads as the proper negative
|
* 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.
|
* value. We dont need to do any of this if the sign bit wasn't set.
|
||||||
*/
|
*/
|
||||||
int64_t signedMask = ~((1ULL << sigSize) - 1);
|
uint64_t signedMask = ~((1ULL << sigSize) - 1);
|
||||||
result = (-1LL & signedMask) | result;
|
result = (-1LL & signedMask) | result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user