@@ -1,6 +1,6 @@
|
||||
# SavvyCAN
|
||||
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.
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
The CANDue board must be running the GVRET firmware which can also be found
|
||||
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
|
||||
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)
|
||||
|
||||
6. Vector Trace files
|
||||
|
||||
7. IXXAT Minilog files
|
||||
|
||||
8. CAN-DO Logs
|
||||
|
||||
9. Vehicle Spy log files
|
||||
|
||||
Requires QScintilla library available at:
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
sudo apt-get install qt5-default qtdeclarative5-dev libqt5serialport5-dev libudev-dev
|
||||
|
||||
+13
-3
@@ -46,7 +46,11 @@ SOURCES += main.cpp\
|
||||
dbcloadsavewindow.cpp \
|
||||
fuzzingwindow.cpp \
|
||||
udsscanwindow.cpp \
|
||||
can_structs.cpp
|
||||
can_structs.cpp \
|
||||
isotp_interpreterwindow.cpp \
|
||||
isotp_handler.cpp \
|
||||
deltawindow.cpp \
|
||||
deltamodel.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
can_structs.h \
|
||||
@@ -79,7 +83,11 @@ HEADERS += mainwindow.h \
|
||||
rangestatewindow.h \
|
||||
dbcloadsavewindow.h \
|
||||
fuzzingwindow.h \
|
||||
udsscanwindow.h
|
||||
udsscanwindow.h \
|
||||
isotp_interpreterwindow.h \
|
||||
isotp_handler.h \
|
||||
deltawindow.h \
|
||||
deltamodel.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
graphingwindow.ui \
|
||||
@@ -100,7 +108,9 @@ FORMS += mainwindow.ui \
|
||||
rangestatewindow.ui \
|
||||
dbcloadsavewindow.ui \
|
||||
fuzzingwindow.ui \
|
||||
udsscanwindow.ui
|
||||
udsscanwindow.ui \
|
||||
isotp_interpreterwindow.ui \
|
||||
deltawindow.ui
|
||||
|
||||
DISTFILES +=
|
||||
|
||||
|
||||
+3
-2
@@ -29,14 +29,15 @@ public:
|
||||
};
|
||||
|
||||
//the same as the CANFrame struct but with arbitrary data size.
|
||||
struct ISOTP_FRAME
|
||||
struct ISOTP_MESSAGE
|
||||
{
|
||||
public:
|
||||
int ID;
|
||||
int bus;
|
||||
bool extended;
|
||||
bool isReceived;
|
||||
int len;
|
||||
int len; //# of bytes this message should have (as reported)
|
||||
int actualSize; //# we actually got
|
||||
QVector<unsigned char> data;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
+31
-12
@@ -6,12 +6,23 @@
|
||||
int CANFrameModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
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()
|
||||
{
|
||||
return frames.count();
|
||||
int count;
|
||||
count = frames.count();
|
||||
return count;
|
||||
}
|
||||
|
||||
int CANFrameModel::columnCount(const QModelIndex &index) const
|
||||
@@ -23,8 +34,8 @@ int CANFrameModel::columnCount(const QModelIndex &index) const
|
||||
CANFrameModel::CANFrameModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
frames.reserve(10000000); //yes, I'm preallocating 10 million entries in this list. I don't think anyone will exceed this.
|
||||
filteredFrames.reserve(10000000);
|
||||
frames.reserve(50000000); //yes, preallocating a huge number of frames.
|
||||
filteredFrames.reserve(50000000); //the goal is to prevent a reallocation from ever happening
|
||||
dbcHandler = NULL;
|
||||
interpretFrames = false;
|
||||
overwriteDups = false;
|
||||
@@ -75,6 +86,7 @@ void CANFrameModel::setInterpetMode(bool mode)
|
||||
|
||||
void CANFrameModel::normalizeTiming()
|
||||
{
|
||||
mutex.lock();
|
||||
if (frames.count() == 0) return;
|
||||
timeOffset = frames[0].timestamp;
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
@@ -87,11 +99,14 @@ void CANFrameModel::normalizeTiming()
|
||||
filteredFrames[i].timestamp -= timeOffset;
|
||||
}
|
||||
this->endResetModel();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void CANFrameModel::setOverwriteMode(bool mode)
|
||||
{
|
||||
beginResetModel();
|
||||
overwriteDups = mode;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CANFrameModel::setFilterState(int ID, bool state)
|
||||
@@ -120,6 +135,7 @@ void CANFrameModel::recalcOverwrite()
|
||||
int lastUnique = 0;
|
||||
bool found;
|
||||
|
||||
mutex.lock();
|
||||
beginResetModel();
|
||||
for (int i = 1; i < frames.count(); i++)
|
||||
{
|
||||
@@ -143,6 +159,7 @@ void CANFrameModel::recalcOverwrite()
|
||||
while (frames.count() > lastUnique) frames.removeLast();
|
||||
|
||||
filteredFrames.clear();
|
||||
filteredFrames.reserve(50000000);
|
||||
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
@@ -153,6 +170,7 @@ void CANFrameModel::recalcOverwrite()
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
mutex.lock();
|
||||
{
|
||||
qDebug() << "Sending mass refresh";
|
||||
QVector<CANFrame> tempContainer;
|
||||
beginResetModel();
|
||||
QVector<CANFrame> tempContainer;
|
||||
int count = frames.count();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -340,8 +356,11 @@ void CANFrameModel::sendRefresh()
|
||||
tempContainer.append(frames[i]);
|
||||
}
|
||||
}
|
||||
mutex.lock();
|
||||
beginResetModel();
|
||||
filteredFrames.clear();
|
||||
filteredFrames = tempContainer;
|
||||
filteredFrames.append(tempContainer);
|
||||
filteredFrames.reserve(50000000);
|
||||
lastUpdateNumFrames = filteredFrames.count();
|
||||
endResetModel();
|
||||
mutex.unlock();
|
||||
@@ -376,14 +395,12 @@ void CANFrameModel::sendBulkRefresh(int num)
|
||||
|
||||
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);
|
||||
//beginInsertRows(QModelIndex(), filteredFrames.count() - num, filteredFrames.count() - 1);
|
||||
//endInsertRows();
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
mutex.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -399,6 +416,8 @@ void CANFrameModel::clearFrames()
|
||||
frames.clear();
|
||||
filteredFrames.clear();
|
||||
filters.clear();
|
||||
frames.reserve(50000000);
|
||||
filteredFrames.reserve(50000000);
|
||||
this->endResetModel();
|
||||
lastUpdateNumFrames = 0;
|
||||
mutex.unlock();
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
int columnCount(const QModelIndex &) const;
|
||||
int totalFrameCount();
|
||||
int totalFrameCount();
|
||||
|
||||
void addFrame(const CANFrame &, bool);
|
||||
void sendRefresh();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CONFIG
|
||||
#define CONFIG
|
||||
|
||||
#define VERSION 151
|
||||
#define VERSION 156
|
||||
|
||||
//try to keep this in sync.
|
||||
//SavvyCAN will complain if you connect a GVRET board with a revision
|
||||
|
||||
@@ -48,6 +48,9 @@ ConnectionWindow::ConnectionWindow(QWidget *parent) :
|
||||
#endif
|
||||
|
||||
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()
|
||||
@@ -60,6 +63,11 @@ void ConnectionWindow::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
qDebug() << "Show connectionwindow";
|
||||
handleConnTypeChanged();
|
||||
}
|
||||
|
||||
void ConnectionWindow::handleConnTypeChanged()
|
||||
{
|
||||
if (ui->rbGVRET->isChecked()) getSerialPorts();
|
||||
if (ui->rbKvaser->isChecked()) getKvaserPorts();
|
||||
if (ui->rbSocketCAN->isChecked()) getSocketcanPorts();
|
||||
|
||||
@@ -43,6 +43,7 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void handleOKButton();
|
||||
void handleConnTypeChanged();
|
||||
|
||||
private:
|
||||
Ui::ConnectionWindow *ui;
|
||||
|
||||
@@ -180,6 +180,7 @@ bool DBC_SIGNAL::processAsDouble(const CANFrame &frame, double &outValue)
|
||||
endResult = ((double)result * factor) + bias;
|
||||
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)
|
||||
{
|
||||
//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->setInterval(100);
|
||||
|
||||
isRealtime = ui->rbRealtime->isChecked();
|
||||
typeChanged();
|
||||
|
||||
connect(ui->btnStart, SIGNAL(clicked(bool)), this, SLOT(handleStartButton()));
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
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()
|
||||
@@ -33,14 +71,45 @@ DiscreteStateWindow::~DiscreteStateWindow()
|
||||
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)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
if (numFrames == -1) //all frames deleted. Kill the display
|
||||
{
|
||||
ui->listID->clear();
|
||||
idFilters.clear();
|
||||
}
|
||||
else if (numFrames == -2) //all new set of frames. Reset
|
||||
{
|
||||
refreshFilterList();
|
||||
}
|
||||
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++)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
@@ -97,7 +197,7 @@ void DiscreteStateWindow::updateStateLabel()
|
||||
switch(operatingState)
|
||||
{
|
||||
case DWStates::IDLE:
|
||||
ui->lblStatus->setText("WAIT");
|
||||
ui->lblStatus->setText("IDLE");
|
||||
pal = ui->lblStatus->palette();
|
||||
pal.setColor(QPalette::WindowText, Qt::red);
|
||||
ui->lblStatus->setPalette(pal);
|
||||
@@ -109,7 +209,7 @@ void DiscreteStateWindow::updateStateLabel()
|
||||
ui->lblStatus->setPalette(pal);
|
||||
break;
|
||||
case DWStates::COUNTDOWN_WAITING:
|
||||
ui->lblStatus->setText("Return to resting state");
|
||||
ui->lblStatus->setText("Wait....");
|
||||
pal = ui->lblStatus->palette();
|
||||
pal.setColor(QPalette::WindowText, Qt::red);
|
||||
ui->lblStatus->setPalette(pal);
|
||||
@@ -120,32 +220,45 @@ void DiscreteStateWindow::updateStateLabel()
|
||||
pal.setColor(QPalette::WindowText, Qt::green);
|
||||
ui->lblStatus->setPalette(pal);
|
||||
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()
|
||||
{
|
||||
operatingState = DWStates::COUNTDOWN_SIGNAL;
|
||||
|
||||
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++)
|
||||
if (isRealtime)
|
||||
{
|
||||
stateFrames[i]->clear();
|
||||
delete(stateFrames[i]);
|
||||
}
|
||||
operatingState = DWStates::COUNTDOWN_SIGNAL;
|
||||
|
||||
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()
|
||||
@@ -168,11 +281,11 @@ void DiscreteStateWindow::handleTick()
|
||||
{
|
||||
ticksUntilStateChange = ticksPerStateChange;
|
||||
currIteration++;
|
||||
if (currIteration == numIterations)
|
||||
if (currIteration > numIterations)
|
||||
{
|
||||
operatingState = DWStates::IDLE;
|
||||
timer->stop();
|
||||
//call to calculate our findings here.
|
||||
calculateResults();
|
||||
}
|
||||
else operatingState = DWStates::COUNTDOWN_SIGNAL;
|
||||
}
|
||||
@@ -184,7 +297,7 @@ void DiscreteStateWindow::handleTick()
|
||||
ticksUntilStateChange = ticksPerStateChange;
|
||||
operatingState = DWStates::COUNTDOWN_WAITING;
|
||||
currToggleState++;
|
||||
if (currToggleState == numToggleStates) currToggleState = 0;
|
||||
if (currToggleState > numToggleStates) currToggleState = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -193,5 +306,41 @@ void DiscreteStateWindow::handleTick()
|
||||
|
||||
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,
|
||||
COUNTDOWN_SIGNAL,
|
||||
COUNTDOWN_WAITING,
|
||||
GETTING_SIGNAL
|
||||
GETTING_SIGNAL,
|
||||
DONE
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,6 +34,7 @@ private slots:
|
||||
void updatedFrames(int);
|
||||
void handleStartButton();
|
||||
void handleTick();
|
||||
void typeChanged();
|
||||
|
||||
private:
|
||||
Ui::DiscreteStateWindow *ui;
|
||||
@@ -46,7 +48,10 @@ private:
|
||||
int currToggleState;
|
||||
int numIterations;
|
||||
int currIteration;
|
||||
bool isRealtime;
|
||||
QHash<int, bool> idFilters;
|
||||
|
||||
void refreshFilterList();
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
+213
-96
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>749</width>
|
||||
<height>795</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -31,63 +31,232 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1" alignment="Qt::AlignHCenter">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Number of States:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||
<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">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinStates">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>20</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>
|
||||
<number>64</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<widget class="QPushButton" name="btnStart">
|
||||
<property name="text">
|
||||
@@ -95,58 +264,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
+58
-17
@@ -158,9 +158,9 @@ void FlowViewWindow::writeSettings()
|
||||
|
||||
/*
|
||||
* Keyboard shortcuts to allow for quick work without needing to move around a mouse.
|
||||
* E = resume or pause playback
|
||||
* Q = go back one frame
|
||||
* W = go forward one frame
|
||||
* R = resume or pause playback
|
||||
* T = go back one frame
|
||||
* Y = go forward one frame
|
||||
*/
|
||||
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.
|
||||
{
|
||||
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;
|
||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ui->cbLiveMode->checkState() == Qt::Checked)
|
||||
{
|
||||
currentPosition = frameCache.count() - 1;
|
||||
memcpy(currBytes, frameCache.at(currentPosition).data, 8);
|
||||
memcpy(refBytes, currBytes, 8);
|
||||
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
updateFrameLabel();
|
||||
}
|
||||
|
||||
void FlowViewWindow::removeAllGraphs()
|
||||
@@ -409,7 +446,10 @@ void FlowViewWindow::createGraph(int byteNum)
|
||||
|
||||
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++)
|
||||
{
|
||||
@@ -418,26 +458,26 @@ void FlowViewWindow::createGraph(int byteNum)
|
||||
if (graphByTime)
|
||||
{
|
||||
if (secondsMode){
|
||||
x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
x[byteNum][j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
x[j] = frameCache[j].timestamp;
|
||||
x[byteNum][j] = frameCache[j].timestamp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x[j] = j;
|
||||
x[byteNum][j] = j;
|
||||
}
|
||||
|
||||
y[j] = tempVal;
|
||||
if (y[j] < minval) minval = y[j];
|
||||
if (y[j] > maxval) maxval = y[j];
|
||||
y[byteNum][j] = tempVal;
|
||||
if (y[byteNum][j] < minval) minval = y[byteNum][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()->setData(x,y);
|
||||
ui->graphView->graph()->setData(x[byteNum],y[byteNum]);
|
||||
ui->graphView->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines
|
||||
QPen graphPen;
|
||||
graphPen.setColor(graphColors[byteNum]);
|
||||
@@ -656,6 +696,7 @@ void FlowViewWindow::updatePosition(bool forward)
|
||||
|
||||
void FlowViewWindow::updateGraphLocation()
|
||||
{
|
||||
if (frameCache.count() == 0) return;
|
||||
int start = currentPosition - 5;
|
||||
if (start < 0) start = 0;
|
||||
int end = currentPosition + 5;
|
||||
|
||||
@@ -55,6 +55,8 @@ private:
|
||||
bool playbackForward;
|
||||
static const QColor graphColors[8];
|
||||
bool secondsMode;
|
||||
QVector<double> x[8], y[8];
|
||||
QCPGraph *graphRef[8];
|
||||
|
||||
void refreshIDList();
|
||||
void updateFrameLabel();
|
||||
|
||||
+217
-142
@@ -1,5 +1,6 @@
|
||||
#include "framefileio.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include <iostream>
|
||||
@@ -163,7 +164,13 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
|
||||
fileName = fileList[fileList.length() - 1];
|
||||
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;
|
||||
}
|
||||
@@ -179,6 +186,7 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
|
||||
QByteArray line;
|
||||
int lineCounter = 0;
|
||||
bool pastHeader = false;
|
||||
bool foundErrors = false;
|
||||
|
||||
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 (inFile->atEnd()) foundErrors = true;
|
||||
|
||||
while (!inFile->atEnd()) {
|
||||
lineCounter++;
|
||||
if (lineCounter > 100)
|
||||
@@ -203,30 +213,33 @@ bool FrameFileIO::loadVehicleSpyFile(QString filename, QVector<CANFrame> *frames
|
||||
line = inFile->readLine().simplified().toUpper();
|
||||
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.timestamp = tokens[1].toDouble() * 1000000.0;
|
||||
if (tokens[5].startsWith("T")) thisFrame.isReceived = false;
|
||||
else thisFrame.isReceived = true;
|
||||
thisFrame.ID = tokens[9].toInt(NULL, 16);
|
||||
if (tokens[11].startsWith("T")) thisFrame.extended = true;
|
||||
else thisFrame.extended = false;
|
||||
|
||||
thisFrame.len = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (tokens.length() > 20)
|
||||
{
|
||||
if (tokens[12 + i].length() > 0)
|
||||
{
|
||||
thisFrame.data[i] = tokens[12 + i].toInt(NULL, 16);
|
||||
thisFrame.len++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.timestamp = tokens[1].toDouble() * 1000000.0;
|
||||
if (tokens[5].startsWith("T")) thisFrame.isReceived = false;
|
||||
else thisFrame.isReceived = true;
|
||||
thisFrame.ID = tokens[9].toInt(NULL, 16);
|
||||
if (tokens[11].startsWith("T")) thisFrame.extended = true;
|
||||
else thisFrame.extended = false;
|
||||
|
||||
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();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveVehicleSpyFile(QString filename, const QVector<CANFrame> *frames)
|
||||
@@ -262,6 +275,7 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
||||
CANFrame thisFrame;
|
||||
QByteArray line;
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -283,44 +297,48 @@ bool FrameFileIO::loadCRTDFile(QString filename, QVector<CANFrame>* frames)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(' ');
|
||||
int multiplier;
|
||||
int idxOfDecimal = tokens[0].indexOf('.');
|
||||
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
|
||||
if (tokens.length() > 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++)
|
||||
int idxOfDecimal = tokens[0].indexOf('.');
|
||||
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
|
||||
{
|
||||
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();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveCRTDFile(QString filename, const QVector<CANFrame>* frames)
|
||||
@@ -384,6 +402,7 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||
int fileVersion = 1;
|
||||
long long timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -406,47 +425,52 @@ bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||
if (line.length() > 2)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
if (tokens[0].length() > 3)
|
||||
if (tokens.length() >= 6)
|
||||
{
|
||||
long long temp = tokens[0].right(10).toLongLong();
|
||||
thisFrame.timestamp = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeStamp += 5;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
}
|
||||
if (tokens[0].length() > 3)
|
||||
{
|
||||
long long temp = tokens[0].right(10).toLongLong();
|
||||
thisFrame.timestamp = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeStamp += 5;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
}
|
||||
|
||||
thisFrame.ID = tokens[1].toInt(NULL, 16);
|
||||
if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1;
|
||||
else thisFrame.extended = 0;
|
||||
thisFrame.ID = tokens[1].toInt(NULL, 16);
|
||||
if (tokens[2].toUpper().contains("TRUE")) thisFrame.extended = 1;
|
||||
else thisFrame.extended = 0;
|
||||
|
||||
if (fileVersion == 1)
|
||||
{
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = tokens[3].toInt();
|
||||
thisFrame.len = tokens[4].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
||||
}
|
||||
else if (fileVersion == 2)
|
||||
{
|
||||
if (tokens[3].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.bus = tokens[4].toInt();
|
||||
thisFrame.len = tokens[5].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16);
|
||||
}
|
||||
if (fileVersion == 1)
|
||||
{
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = tokens[3].toInt();
|
||||
thisFrame.len = tokens[4].toInt();
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[5 + d].toInt(NULL, 16);
|
||||
}
|
||||
else if (fileVersion == 2)
|
||||
{
|
||||
if (tokens[3].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.bus = tokens[4].toInt();
|
||||
thisFrame.len = tokens[5].toInt();
|
||||
if (thisFrame.len + 6 > tokens.length()) thisFrame.len = tokens.length() - 6;
|
||||
for (int c = 0; c < 8; c++) thisFrame.data[c] = 0;
|
||||
for (int d = 0; d < thisFrame.len; d++)
|
||||
thisFrame.data[d] = tokens[6 + d].toInt(NULL, 16);
|
||||
}
|
||||
|
||||
frames->append(thisFrame);
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
else foundErrors = true;
|
||||
}
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveNativeCSVFile(QString filename, const QVector<CANFrame>* frames)
|
||||
@@ -514,6 +538,7 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector<CANFrame>* frames
|
||||
QByteArray line;
|
||||
long long timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -549,10 +574,11 @@ bool FrameFileIO::loadGenericCSVFile(QString filename, QVector<CANFrame>* frames
|
||||
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
else foundErrors = true;
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
//4f5,ff 34 23 45 24 e4
|
||||
@@ -635,6 +661,7 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
||||
QByteArray line;
|
||||
uint64_t timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -657,24 +684,30 @@ bool FrameFileIO::loadLogFile(QString filename, QVector<CANFrame>* frames)
|
||||
if (line.length() > 1)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(' ');
|
||||
QList<QByteArray> timeToks = tokens[0].split(':');
|
||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||
if (tokens.length() >= 6)
|
||||
{
|
||||
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);
|
||||
thisFrame.timestamp = timeStamp;
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16);
|
||||
if (tokens[4] == "s") thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = tokens[2].toInt() - 1;
|
||||
thisFrame.len = tokens[5].toInt();
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = tokens[d + 6].toInt(NULL, 16);
|
||||
}
|
||||
frames->append(thisFrame);
|
||||
thisFrame.timestamp = timeStamp;
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = tokens[3].right(tokens[3].length() - 2).toInt(NULL, 16);
|
||||
if (tokens[4] == "s") thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = tokens[2].toInt() - 1;
|
||||
thisFrame.len = tokens[5].toInt();
|
||||
if (thisFrame.len > 8) thisFrame.len = 8;
|
||||
if (thisFrame.len < 0) thisFrame.len = 0;
|
||||
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();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveLogFile(QString filename, const QVector<CANFrame>* frames)
|
||||
@@ -748,6 +781,7 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector<CANFrame>* frames)
|
||||
QByteArray line;
|
||||
uint64_t timeStamp = Utility::GetTimeMS();
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -769,27 +803,48 @@ bool FrameFileIO::loadIXXATFile(QString filename, QVector<CANFrame>* frames)
|
||||
if (line.length() > 1)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
QString timePortion = unQuote(tokens[0]);
|
||||
QStringList timeToks = timePortion.split(':');
|
||||
timeStamp = (timeToks[0].toInt() * (1000ul * 1000ul * 60ul * 60ul)) + (timeToks[1].toInt() * (1000ul * 1000ul * 60ul))
|
||||
if (line.length() >= 5)
|
||||
{
|
||||
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));
|
||||
thisFrame.timestamp = timeStamp;
|
||||
thisFrame.ID = unQuote(tokens[1]).toInt(NULL, 16);
|
||||
if (unQuote(tokens[2]).toUpper().at(0) == 'S') thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.bus = 0;
|
||||
thisFrame.isReceived = true;
|
||||
thisFrame.bus = 0;
|
||||
|
||||
QStringList dataToks = unQuote(tokens[4]).simplified().split(' ');
|
||||
thisFrame.len = dataToks.length();
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16);
|
||||
QStringList dataToks = unQuote(tokens[4]).simplified().split(' ');
|
||||
thisFrame.len = dataToks.length();
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = dataToks[d].toInt(NULL, 16);
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
else foundErrors = true;
|
||||
}
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveIXXATFile(QString filename, const QVector<CANFrame>* frames)
|
||||
@@ -856,6 +911,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
||||
QByteArray data;
|
||||
int timeOffset = 0;
|
||||
uint64_t lastTimeStamp = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly))
|
||||
{
|
||||
@@ -891,7 +947,7 @@ bool FrameFileIO::loadCANDOFile(QString filename, QVector<CANFrame>* frames)
|
||||
timeOffset += 60000000ul;
|
||||
}
|
||||
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;
|
||||
|
||||
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];
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
else foundErrors = true;
|
||||
}
|
||||
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
bool FrameFileIO::saveCANDOFile(QString filename, const QVector<CANFrame>* frames)
|
||||
@@ -977,6 +1034,7 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
||||
bool inComment = false;
|
||||
long long timeStamp;
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -1006,24 +1064,31 @@ bool FrameFileIO::loadMicrochipFile(QString filename, QVector<CANFrame>* frames)
|
||||
if (!inComment)
|
||||
{
|
||||
QList<QByteArray> tokens = line.split(';');
|
||||
timeStamp = tokens[0].toInt() * 1000;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = Utility::ParseStringToNum(tokens[2]);
|
||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.len = tokens[3].toInt();
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)Utility::ParseStringToNum(tokens[4 + d]);
|
||||
frames->append(thisFrame);
|
||||
if (tokens.length() >= 4)
|
||||
{
|
||||
timeStamp = tokens[0].toInt() * 1000;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
if (tokens[1].at(0) == 'R') thisFrame.isReceived = true;
|
||||
else thisFrame.isReceived = false;
|
||||
thisFrame.ID = Utility::ParseStringToNum(tokens[2]);
|
||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = 0;
|
||||
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();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1126,6 +1191,7 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector<CANFrame>* frames)
|
||||
QByteArray line;
|
||||
long long timeStamp = 0;
|
||||
int lineCounter = 0;
|
||||
bool foundErrors = false;
|
||||
|
||||
if (!inFile->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
@@ -1152,31 +1218,36 @@ bool FrameFileIO::loadTraceFile(QString filename, QVector<CANFrame>* frames)
|
||||
else
|
||||
{
|
||||
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;
|
||||
timeStamp += timestampToks[1].toInt() * 1000000ul * 60;
|
||||
timeStamp += timestampToks[2].toInt() * 1000000ul;
|
||||
timeStamp += timestampToks[3].toInt() * 100;
|
||||
thisFrame.timestamp = timeStamp;
|
||||
|
||||
thisFrame.timestamp = timeStamp;
|
||||
|
||||
thisFrame.ID = tokens[2].toLong(NULL, 16);
|
||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.len = tokens[3].toInt();
|
||||
|
||||
QList<QByteArray> dataToks = tokens[4].split(' ');
|
||||
for (int d = 0; d < thisFrame.len; d++) thisFrame.data[d] = (unsigned char)dataToks[d].toInt(NULL, 16);
|
||||
frames->append(thisFrame);
|
||||
thisFrame.ID = tokens[2].toLong(NULL, 16);
|
||||
if (thisFrame.ID <= 0x7FF) thisFrame.extended = false;
|
||||
else thisFrame.extended = true;
|
||||
thisFrame.bus = 0;
|
||||
thisFrame.len = tokens[3].toInt();
|
||||
if (thisFrame.len < 0) thisFrame.len = 0;
|
||||
if (thisFrame.len > 8) thisFrame.len = 8;
|
||||
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);
|
||||
frames->append(thisFrame);
|
||||
}
|
||||
else foundErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
inFile->close();
|
||||
delete inFile;
|
||||
return true;
|
||||
return !foundErrors;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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.
|
||||
{
|
||||
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;
|
||||
for (int x = modelFrames->count() - numFrames; x < modelFrames->count(); x++)
|
||||
{
|
||||
|
||||
@@ -400,10 +400,12 @@ void FramePlaybackWindow::btnLoadLive()
|
||||
|
||||
void FramePlaybackWindow::btnBackOneClick()
|
||||
{
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
||||
playbackActive = false;
|
||||
|
||||
updatePosition(false);
|
||||
emit sendFrameBatch(&sendingBuffer);
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::btnPauseClick()
|
||||
@@ -450,9 +452,11 @@ void FramePlaybackWindow::btnPlayClick()
|
||||
|
||||
void FramePlaybackWindow::btnFwdOneClick()
|
||||
{
|
||||
sendingBuffer.clear();
|
||||
playbackTimer->stop();
|
||||
playbackActive = false;
|
||||
updatePosition(true);
|
||||
emit sendFrameBatch(&sendingBuffer);
|
||||
}
|
||||
|
||||
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
||||
|
||||
+40
-45
@@ -430,7 +430,7 @@ int FrameSenderWindow::fetchOperand(int idx, ModifierOperand op)
|
||||
if (op.notOper) 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];
|
||||
else return sendingData.at(idx).data[op.databyte];
|
||||
@@ -473,6 +473,8 @@ void FrameSenderWindow::processModifierText(int line)
|
||||
QString modString;
|
||||
bool firstOp = true;
|
||||
bool abort = false;
|
||||
QString token;
|
||||
ModifierOp thisOp;
|
||||
|
||||
//Example line:
|
||||
//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;
|
||||
thisMod.destByte = 0;
|
||||
firstOp = true;
|
||||
|
||||
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
||||
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
||||
@@ -511,58 +514,50 @@ void FrameSenderWindow::processModifierText(int line)
|
||||
continue;
|
||||
}
|
||||
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)
|
||||
{
|
||||
QString token = Utility::grabAlphaNumeric(mods[i]);
|
||||
ModifierOp thisOp;
|
||||
|
||||
if (firstOp)
|
||||
QString operation = Utility::grabOperation(mods[i]);
|
||||
if (operation == "")
|
||||
{
|
||||
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);
|
||||
firstOp = false;
|
||||
abort = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
thisOp.first.ID = -1; //shadow register
|
||||
}
|
||||
if (mods[i].length() == 0) //if this thing had no actual operation or second operand then fake it
|
||||
{
|
||||
abort = true;
|
||||
thisOp.operation = ADDITION;
|
||||
thisOp.second.ID = 0;
|
||||
thisOp.second.databyte = 0;
|
||||
thisOp.second.notOper = false;
|
||||
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);
|
||||
}
|
||||
else //otherwise try to grab them
|
||||
{
|
||||
QString operation = Utility::grabOperation(mods[i]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
thisOp.first.ID = -1; //shadow register
|
||||
if (mods[i].length() < 2) abort = true;
|
||||
}
|
||||
|
||||
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.
|
||||
{
|
||||
bool appendedToGraph = false;
|
||||
if (numFrames > modelFrames->count()) return;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
for (iter = graphParams.begin(); iter != graphParams.end(); ++iter)
|
||||
{
|
||||
outFile->write("X,");
|
||||
outFile->write(QString::number(iter->ID, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isDBCSignal)
|
||||
{
|
||||
outFile->putChar('S');
|
||||
outFile->putChar(',');
|
||||
outFile->write(iter->signal.toUtf8());
|
||||
outFile->putChar(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->startByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->endByte).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isSigned) outFile->putChar('Y');
|
||||
else outFile->putChar('N');
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->bias).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->scale).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->stride).toUtf8());
|
||||
outFile->putChar(',');
|
||||
}
|
||||
outFile->write(QString::number(iter->mask, 16).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->startBit).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->numBits).toUtf8());
|
||||
outFile->putChar(',');
|
||||
if (iter->isSigned) outFile->putChar('Y');
|
||||
else outFile->putChar('N');
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->bias).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->scale).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->stride).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->color.red()).toUtf8());
|
||||
outFile->putChar(',');
|
||||
outFile->write(QString::number(iter->color.green()).toUtf8());
|
||||
@@ -729,7 +728,6 @@ void GraphingWindow::loadDefinitions()
|
||||
{
|
||||
QString filename;
|
||||
QFileDialog dialog;
|
||||
bool dbcMissing = false;
|
||||
|
||||
QStringList filters;
|
||||
filters.append(QString(tr("Graph definition (*.gdf)")));
|
||||
@@ -755,66 +753,146 @@ void GraphingWindow::loadDefinitions()
|
||||
if (line.length() > 2)
|
||||
{
|
||||
GraphParams gp;
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
gp.isDBCSignal = false;
|
||||
|
||||
gp.ID = tokens[0].toInt(NULL, 16);
|
||||
if (tokens[1] == "S")
|
||||
QList<QByteArray> tokens = line.split(',');
|
||||
|
||||
if (tokens[0] == "X") //newest format based around signals
|
||||
{
|
||||
gp.isDBCSignal = true;
|
||||
//tokens[2] is the signal name. Need to use the message ID and this name to look it up
|
||||
DBC_MESSAGE *msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(gp.ID);
|
||||
if (msg != NULL)
|
||||
{
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(tokens[2]);
|
||||
if (sig == NULL) dbcMissing = true;
|
||||
gp.signal = tokens[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
gp.signal = "";
|
||||
dbcMissing = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gp.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;
|
||||
gp.ID = tokens[1].toInt(NULL, 16);
|
||||
gp.mask = tokens[2].toULongLong(NULL, 16);
|
||||
gp.startBit = tokens[3].toInt();
|
||||
gp.numBits = tokens[4].toInt();
|
||||
if (tokens[5] == "Y") gp.isSigned = true;
|
||||
else gp.isSigned = false;
|
||||
gp.bias = tokens[5].toFloat();
|
||||
gp.scale = tokens[6].toFloat();
|
||||
gp.stride = tokens[7].toInt();
|
||||
}
|
||||
if (!gp.isDBCSignal)
|
||||
{
|
||||
gp.color.setRed(tokens[8].toInt());
|
||||
gp.color.setGreen(tokens[9].toInt());
|
||||
gp.color.setBlue(tokens[10].toInt());
|
||||
if (tokens.length() > 11)
|
||||
gp.graphName = tokens[11];
|
||||
gp.bias = tokens[6].toFloat();
|
||||
gp.scale = tokens[7].toFloat();
|
||||
gp.stride = tokens[8].toInt();
|
||||
|
||||
gp.color.setRed(tokens[9].toInt());
|
||||
gp.color.setGreen(tokens[10].toInt());
|
||||
gp.color.setBlue(tokens[11].toInt());
|
||||
if (tokens.length() > 12)
|
||||
gp.graphName = tokens[12];
|
||||
else
|
||||
gp.graphName = QString();
|
||||
createGraph(gp, true);
|
||||
}
|
||||
else
|
||||
else //one of the two older formats then
|
||||
{
|
||||
gp.color.setRed(tokens[3].toInt());
|
||||
gp.color.setGreen(tokens[4].toInt());
|
||||
gp.color.setBlue(tokens[5].toInt());
|
||||
gp.graphName = tokens[6];
|
||||
gp.ID = tokens[0].toInt(NULL, 16);
|
||||
if (tokens[1] == "S") //old signal based graph definition
|
||||
{
|
||||
//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();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
{
|
||||
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.x.append(frame.timestamp - params.xbias);
|
||||
}
|
||||
|
||||
params.ref->setData(params.x,params.y);
|
||||
params.y.append((tempVal * params.scale) + params.bias);
|
||||
}
|
||||
|
||||
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 xminval=10000000000.0, xmaxval = -10000000000.0;
|
||||
GraphParams *refParam = ¶ms;
|
||||
DBC_MESSAGE *msg = NULL;
|
||||
DBC_SIGNAL *sig = NULL;
|
||||
int sBit, bits;
|
||||
bool intelFormat, isSigned;
|
||||
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
msg = dbcHandler->getFileByIdx(0)->messageHandler->findMsgByID(params.ID);
|
||||
if (msg) sig = msg->sigHandler->findSignalByName(params.signal);
|
||||
if (sig == NULL) return;
|
||||
qDebug() << "New signal graph: " << params.signal <<" in ID:" << params.ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "New Graph ID: " << params.ID;
|
||||
qDebug() << "Start byte: " << params.startByte;
|
||||
qDebug() << "End Byte: " << params.endByte;
|
||||
qDebug() << "Mask: " << params.mask;
|
||||
}
|
||||
qDebug() << "New Graph ID: " << params.ID;
|
||||
qDebug() << "Start bit: " << params.startBit;
|
||||
qDebug() << "Data length: " << params.numBits;
|
||||
qDebug() << "Intel Mode: " << params.intelFormat;
|
||||
qDebug() << "Signed: " << params.isSigned;
|
||||
qDebug() << "Mask: " << params.mask;
|
||||
|
||||
frameCache.clear();
|
||||
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.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;
|
||||
int l = 0;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
tempVal = Utility::processIntegerSignal(frameCache[j * params.stride].data, sBit, bits, intelFormat, isSigned); //& params.mask;
|
||||
//qDebug() << tempVal;
|
||||
if (secondsMode)
|
||||
{
|
||||
//if the given signal was found and successfully processed in this frame then add it to the graph
|
||||
if (sig->processAsDouble(frameCache[j], tempValue))
|
||||
{
|
||||
//qDebug() << "tempValue: " << tempValue;
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[l] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[l] = frameCache[j].timestamp;
|
||||
}
|
||||
params.y[l] = tempValue;
|
||||
if (params.y[l] < yminval) yminval = params.y[l];
|
||||
if (params.y[l] > ymaxval) ymaxval = params.y[l];
|
||||
if (params.x[l] < xminval) xminval = params.x[l];
|
||||
if (params.x[l] > xmaxval) xmaxval = params.x[l];
|
||||
l++;
|
||||
}
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
params.x.resize(l);
|
||||
params.y.resize(l);
|
||||
params.x.squeeze();
|
||||
params.y.squeeze();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (params.endByte == -1 || params.startByte == params.endByte)
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempVal = (frameCache[j * params.stride].data[params.startByte] & params.mask);
|
||||
if (params.isSigned && tempVal > 127)
|
||||
{
|
||||
tempVal = tempVal - 256;
|
||||
}
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
params.y[j] = (tempVal * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
}
|
||||
else if (params.endByte > params.startByte) //big endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.endByte - params.startByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte - c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += (tempByte * expon);
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
}
|
||||
else //little endian
|
||||
{
|
||||
float tempValue;
|
||||
int64_t tempValInt;
|
||||
int numBytes = (params.startByte - params.endByte) + 1;
|
||||
int64_t shiftRef = (uint64_t)1 << (numBytes * 8);
|
||||
uint64_t maskShifter;
|
||||
uint8_t tempByte;
|
||||
for (int j = 0; j < numEntries; j++)
|
||||
{
|
||||
tempValInt = 0;
|
||||
int64_t expon = 1;
|
||||
maskShifter = params.mask;
|
||||
for (int c = 0; c < numBytes; c++)
|
||||
{
|
||||
tempByte = frameCache[j * params.stride].data[params.endByte + c];
|
||||
tempByte &= maskShifter;
|
||||
tempValInt += tempByte * expon;
|
||||
expon *= 256;
|
||||
maskShifter = maskShifter >> 8;
|
||||
}
|
||||
tempValInt &= params.mask;
|
||||
|
||||
int64_t twocompPoint = params.mask;
|
||||
if (shiftRef < twocompPoint || twocompPoint == -1) twocompPoint = shiftRef;
|
||||
//qDebug() << "two comp point: " << twocompPoint;
|
||||
if (params.isSigned && tempValInt > ((twocompPoint / 2)))
|
||||
{
|
||||
tempValInt = tempValInt - twocompPoint;
|
||||
}
|
||||
|
||||
tempValue = (float)tempValInt;
|
||||
|
||||
if (secondsMode)
|
||||
{
|
||||
params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.x[j] = frameCache[j].timestamp;
|
||||
}
|
||||
|
||||
params.y[j] = (tempValue * params.scale) + params.bias;
|
||||
if (params.y[j] < yminval) yminval = params.y[j];
|
||||
if (params.y[j] > ymaxval) ymaxval = params.y[j];
|
||||
if (params.x[j] < xminval) xminval = params.x[j];
|
||||
if (params.x[j] > xmaxval) xmaxval = params.x[j];
|
||||
}
|
||||
params.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];
|
||||
}
|
||||
|
||||
params.xbias = 0;
|
||||
@@ -1193,8 +1009,8 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam)
|
||||
|
||||
if (params.graphName == NULL || params.graphName.length() == 0)
|
||||
{
|
||||
params.graphName = QString("0x") + QString::number(params.ID, 16) + ":" + QString::number(params.startByte);
|
||||
if ((params.endByte != -1) && (params.endByte != params.startByte)) params.graphName += "-" + QString::number(params.endByte);
|
||||
params.graphName = QString("0x") + QString::number(params.ID, 16) + ":" + QString::number(params.startBit);
|
||||
params.graphName += "-" + QString::number(params.numBits);
|
||||
}
|
||||
ui->graphingView->graph()->setName(params.graphName);
|
||||
ui->graphingView->graph()->setProperty("id", params.ID);
|
||||
|
||||
+2
-3
@@ -15,7 +15,8 @@ class GraphParams
|
||||
{
|
||||
public:
|
||||
uint32_t ID;
|
||||
int startByte, endByte;
|
||||
int startBit, numBits;
|
||||
bool intelFormat;
|
||||
bool isSigned;
|
||||
uint64_t mask;
|
||||
float bias;
|
||||
@@ -24,8 +25,6 @@ public:
|
||||
QColor color;
|
||||
QCPGraph *ref;
|
||||
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
|
||||
QVector<double> x, y;
|
||||
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::started, worker, &SerialWorker::run); //setup timers within the proper thread
|
||||
connect(this, &MainWindow::sendSerialPort, worker, &SerialWorker::setSerialPort, Qt::QueuedConnection);
|
||||
connect(worker, &SerialWorker::frameUpdateTick, this, &MainWindow::gotFrames, Qt::QueuedConnection);
|
||||
connect(worker, &SerialWorker::frameUpdateRapid, this, &MainWindow::gotFrames, Qt::QueuedConnection);
|
||||
connect(this, &MainWindow::updateBaudRates, worker, &SerialWorker::updateBaudRates, Qt::QueuedConnection);
|
||||
connect(this, &MainWindow::sendCANFrame, worker, &SerialWorker::sendFrame, Qt::QueuedConnection);
|
||||
connect(worker, &SerialWorker::connectionSuccess, this, &MainWindow::connectionSucceeded, Qt::QueuedConnection);
|
||||
@@ -98,9 +98,12 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
dbcFileWindow = NULL;
|
||||
fuzzingWindow = NULL;
|
||||
udsScanWindow = NULL;
|
||||
isoWindow = NULL;
|
||||
dbcHandler = new DBCHandler;
|
||||
bDirty = false;
|
||||
inhibitFilterUpdate = false;
|
||||
rxFrames = 0;
|
||||
framesPerSec = 0;
|
||||
|
||||
model->setDBCHandler(dbcHandler);
|
||||
|
||||
@@ -139,6 +142,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(ui->actionDBC_File_Manager, &QAction::triggered, this, &MainWindow::showDBCFileWindow);
|
||||
connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow);
|
||||
connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow);
|
||||
connect(ui->actionISO_TP_Decoder, &QAction::triggered, this, &MainWindow::showISOInterpreterWindow);
|
||||
|
||||
lbStatusConnected.setText(tr("Not connected"));
|
||||
updateFileStatus();
|
||||
@@ -150,6 +154,13 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
ui->lbFPS->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;
|
||||
allowCapture = true;
|
||||
|
||||
@@ -266,6 +277,14 @@ MainWindow::~MainWindow()
|
||||
delete udsScanWindow;
|
||||
}
|
||||
|
||||
if (isoWindow)
|
||||
{
|
||||
isoWindow->close();
|
||||
delete isoWindow;
|
||||
}
|
||||
|
||||
delete elapsedTime;
|
||||
|
||||
delete ui;
|
||||
delete dbcHandler;
|
||||
model->clearFrames();
|
||||
@@ -289,6 +308,7 @@ void MainWindow::exitApp()
|
||||
if (dbcFileWindow) dbcFileWindow->close();
|
||||
if (fuzzingWindow) fuzzingWindow->close();
|
||||
if (udsScanWindow) udsScanWindow->close();
|
||||
if (isoWindow) isoWindow->close();
|
||||
this->close();
|
||||
}
|
||||
|
||||
@@ -493,20 +513,36 @@ void MainWindow::filterClearAll()
|
||||
model->setAllFilters(false);
|
||||
}
|
||||
|
||||
//most of the work is handled elsewhere. Need only to update the # of frames
|
||||
//and maybe auto scroll
|
||||
void MainWindow::gotFrames(int FPS, int framesSinceLastUpdate)
|
||||
void MainWindow::tickGUIUpdate()
|
||||
{
|
||||
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()));
|
||||
if (ui->cbAutoScroll->isChecked()) ui->canFramesView->scrollToBottom();
|
||||
ui->lbFPS->setText(QString::number(FPS));
|
||||
if (framesSinceLastUpdate > 0)
|
||||
ui->lbFPS->setText(QString::number(framesPerSec / 4));
|
||||
if (rxFrames > 0)
|
||||
{
|
||||
bDirty = true;
|
||||
emit framesUpdated(framesSinceLastUpdate); //anyone care that frames were updated?
|
||||
emit framesUpdated(rxFrames); //anyone care that frames were updated?
|
||||
}
|
||||
|
||||
if (model->needsFilterRefresh()) updateFilterList();
|
||||
|
||||
rxFrames = 0;
|
||||
}
|
||||
|
||||
void MainWindow::gotFrames(int framesSinceLastUpdate)
|
||||
{
|
||||
rxFrames += framesSinceLastUpdate;
|
||||
emit frameUpdateRapid(framesSinceLastUpdate);
|
||||
}
|
||||
|
||||
void MainWindow::addFrameToDisplay(CANFrame &frame, bool autoRefresh = false)
|
||||
@@ -864,6 +900,18 @@ void MainWindow::showFrameDataAnalysis()
|
||||
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()
|
||||
{
|
||||
if (!frameSenderWindow)
|
||||
|
||||
+10
-1
@@ -25,6 +25,7 @@
|
||||
#include "dbcloadsavewindow.h"
|
||||
#include "fuzzingwindow.h"
|
||||
#include "udsscanwindow.h"
|
||||
#include "isotp_interpreterwindow.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
@@ -65,6 +66,7 @@ private slots:
|
||||
void showDBCFileWindow();
|
||||
void showFuzzingWindow();
|
||||
void showUDSScanWindow();
|
||||
void showISOInterpreterWindow();
|
||||
void exitApp();
|
||||
void handleSaveDecoded();
|
||||
void changeBaudRates();
|
||||
@@ -75,6 +77,7 @@ private slots:
|
||||
void gridDoubleClicked(QModelIndex);
|
||||
void interpretToggled(bool);
|
||||
void overwriteToggled(bool);
|
||||
void tickGUIUpdate();
|
||||
void toggleCapture();
|
||||
void normalizeTiming();
|
||||
void updateFilterList();
|
||||
@@ -83,7 +86,7 @@ private slots:
|
||||
void filterClearAll();
|
||||
|
||||
public slots:
|
||||
void gotFrames(int, int);
|
||||
void gotFrames(int);
|
||||
void updateSettings();
|
||||
void gotCenterTimeID(int32_t ID, double timestamp);
|
||||
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
|
||||
void framesUpdated(int numFrames); //something has updated the frame list
|
||||
void frameUpdateRapid(int numFrames);
|
||||
void settingsUpdated();
|
||||
void sendCenterTimeID(int32_t ID, double timestamp);
|
||||
|
||||
@@ -111,6 +115,10 @@ private:
|
||||
QThread serialWorkerThread;
|
||||
SerialWorker *worker;
|
||||
QByteArray inputBuffer;
|
||||
QTimer updateTimer;
|
||||
QTime *elapsedTime;
|
||||
int framesPerSec;
|
||||
int rxFrames;
|
||||
bool inhibitFilterUpdate;
|
||||
bool useHex;
|
||||
bool allowCapture;
|
||||
@@ -135,6 +143,7 @@ private:
|
||||
DBCLoadSaveWindow *dbcFileWindow;
|
||||
FuzzingWindow *fuzzingWindow;
|
||||
UDSScanWindow *udsScanWindow;
|
||||
ISOTP_InterpreterWindow *isoWindow;
|
||||
|
||||
//various private storage
|
||||
QLabel lbStatusConnected;
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
<addaction name="actionFile_Comparison"/>
|
||||
<addaction name="actionRange_State_2"/>
|
||||
<addaction name="actionSingle_Multi_State_2"/>
|
||||
<addaction name="actionISO_TP_Decoder"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSend_Frames">
|
||||
<property name="title">
|
||||
@@ -387,6 +388,11 @@
|
||||
<string>UDS Scanner</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionISO_TP_Decoder">
|
||||
<property name="text">
|
||||
<string>ISO-TP Decoder</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
+106
-134
@@ -24,9 +24,13 @@ NewGraphDialog::NewGraphDialog(DBCHandler *handler, QWidget *parent) :
|
||||
ui->colorSwatch->setPalette(p);
|
||||
|
||||
connect(ui->cbMessages, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSignals(int)));
|
||||
connect(ui->cbSignals, SIGNAL(currentIndexChanged(int)), this, SLOT(fillFormFromSignal(int)));
|
||||
connect(ui->rbSignalGraph, SIGNAL(toggled(bool)), this, SLOT(setSignalActive(bool)));
|
||||
connect(ui->rbStandardGraph, SIGNAL(toggled(bool)), this, SLOT(setStandardActive(bool)));
|
||||
connect(ui->gridData, SIGNAL(gridClicked(int,int)), this, SLOT(bitfieldClicked(int,int)));
|
||||
connect(ui->txtDataLen, SIGNAL(textChanged(QString)), this, SLOT(handleDataLenUpdate()));
|
||||
connect(ui->cbIntel, SIGNAL(toggled(bool)), this, SLOT(drawBitfield()));
|
||||
connect(ui->btnCopySignal, SIGNAL(clicked(bool)), this, SLOT(copySignalToParamsUI()));
|
||||
|
||||
startBit = 0;
|
||||
dataLen = 1;
|
||||
|
||||
loadMessages();
|
||||
}
|
||||
@@ -36,6 +40,12 @@ NewGraphDialog::~NewGraphDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewGraphDialog::showEvent(QShowEvent* event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
loadMessages();
|
||||
}
|
||||
|
||||
void NewGraphDialog::addButtonClicked()
|
||||
{
|
||||
accept();
|
||||
@@ -59,91 +69,49 @@ void NewGraphDialog::clearParams()
|
||||
ui->txtScale->clear();
|
||||
ui->txtStride->clear();
|
||||
ui->txtName->clear();
|
||||
ui->txtData->clear();
|
||||
ui->rbStandardGraph->setChecked(true);
|
||||
setStandardActive(true);
|
||||
|
||||
}
|
||||
|
||||
void NewGraphDialog::setParams(GraphParams ¶ms)
|
||||
{
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
clearParams();
|
||||
setSignalActive(true);
|
||||
//loadMessages();
|
||||
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
ui->txtBias->setText(QString::number(params.bias));
|
||||
ui->txtMask->setText(Utility::formatNumber(params.mask));
|
||||
ui->txtScale->setText(QString::number(params.scale));
|
||||
ui->txtStride->setText(QString::number(params.stride));
|
||||
ui->cbSigned->setChecked(params.isSigned);
|
||||
ui->cbIntel->setChecked(params.intelFormat);
|
||||
|
||||
startBit = params.startBit;
|
||||
dataLen = params.numBits;
|
||||
ui->txtDataLen->setText(QString::number(dataLen));
|
||||
ui->txtID->setText(Utility::formatNumber(params.ID));
|
||||
ui->txtName->setText(params.graphName);
|
||||
QPalette p = ui->colorSwatch->palette();
|
||||
p.setColor(QPalette::Button, params.color);
|
||||
ui->colorSwatch->setPalette(p);
|
||||
|
||||
drawBitfield();
|
||||
}
|
||||
|
||||
void NewGraphDialog::getParams(GraphParams ¶ms)
|
||||
{
|
||||
params.isDBCSignal = ui->rbSignalGraph->isChecked();
|
||||
params.color = ui->colorSwatch->palette().button().color();
|
||||
params.graphName = ui->txtName->text();
|
||||
|
||||
if (params.isDBCSignal)
|
||||
{
|
||||
params.signal = ui->cbSignals->currentText();
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = 0;
|
||||
params.isSigned = false;
|
||||
params.mask = 0;
|
||||
params.scale = 1;
|
||||
params.bias = 0;
|
||||
params.stride = 1;
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = ui->txtBias->text().toFloat();
|
||||
params.isSigned = ui->cbSigned->isChecked();
|
||||
params.intelFormat = ui->cbIntel->isChecked();
|
||||
params.mask = Utility::ParseStringToNum(ui->txtMask->text());
|
||||
params.scale = ui->txtScale->text().toFloat();
|
||||
params.stride = Utility::ParseStringToNum(ui->txtStride->text());
|
||||
|
||||
}
|
||||
else {
|
||||
params.ID = Utility::ParseStringToNum(ui->txtID->text());
|
||||
params.bias = ui->txtBias->text().toFloat();
|
||||
params.isSigned = ui->cbSigned->isChecked();
|
||||
params.mask = Utility::ParseStringToNum(ui->txtMask->text());
|
||||
params.scale = ui->txtScale->text().toFloat();
|
||||
params.stride = Utility::ParseStringToNum(ui->txtStride->text());
|
||||
params.signal = "";
|
||||
params.startBit = startBit;
|
||||
params.numBits = dataLen;
|
||||
|
||||
QStringList values = ui->txtData->text().split('-');
|
||||
params.startByte = -1;
|
||||
params.endByte = -1;
|
||||
if (values.count() > 0)
|
||||
{
|
||||
params.startByte = values[0].toInt();
|
||||
if (values.count() > 1)
|
||||
{
|
||||
params.endByte = values[1].toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//now catch stupidity and bring it to defaults
|
||||
if (params.mask == 0) params.mask = 0xFFFFFFFF;
|
||||
if (fabs(params.scale) < 0.00000001) params.scale = 1.0f;
|
||||
if (params.stride < 1) params.stride = 1;
|
||||
}
|
||||
//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()
|
||||
@@ -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());
|
||||
|
||||
if (msg == NULL) return;
|
||||
|
||||
if (!msg) return;
|
||||
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(ui->cbSignals->currentText());
|
||||
if (!sig) return;
|
||||
|
||||
if (sig == NULL) return;
|
||||
|
||||
params.graphName = sig->name;
|
||||
params.ID = msg->ID;
|
||||
//params.bias = sig->bias;
|
||||
//params.scale = sig->factor;
|
||||
//params.stride = 1;
|
||||
//params.mask = (1 << (sig->signalSize)) - 1;
|
||||
//if (sig->valType == SIGNED_INT) params.isSigned = true;
|
||||
//else params.isSigned = false;
|
||||
params.color = ui->colorSwatch->palette().color(QPalette::Button);
|
||||
/*
|
||||
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);
|
||||
startBit = sig->startBit;
|
||||
ui->txtBias->setText(QString::number(sig->bias));
|
||||
ui->txtDataLen->setText(QString::number(sig->signalSize));
|
||||
ui->txtID->setText(Utility::formatNumber(msg->ID));
|
||||
ui->txtMask->setText("0xFFFFFFFF");
|
||||
ui->txtName->setText(sig->name);
|
||||
ui->txtScale->setText(QString::number(sig->factor));
|
||||
ui->txtStride->setText("1");
|
||||
ui->cbIntel->setChecked(sig->intelByteOrder);
|
||||
if (sig->valType == SIGNED_INT) ui->cbSigned->setChecked(true);
|
||||
else ui->cbSigned->setChecked(false);
|
||||
drawBitfield();
|
||||
}
|
||||
|
||||
+6
-3
@@ -16,6 +16,7 @@ class NewGraphDialog : public QDialog
|
||||
public:
|
||||
explicit NewGraphDialog(DBCHandler *handler, QWidget *parent = 0);
|
||||
~NewGraphDialog();
|
||||
void showEvent(QShowEvent*);
|
||||
void getParams(GraphParams &);
|
||||
void setParams(GraphParams &);
|
||||
void clearParams();
|
||||
@@ -25,13 +26,15 @@ private slots:
|
||||
void colorSwatchClick();
|
||||
void loadMessages();
|
||||
void loadSignals(int idx);
|
||||
void fillFormFromSignal(int idx);
|
||||
void setSignalActive(bool);
|
||||
void setStandardActive(bool);
|
||||
void bitfieldClicked(int,int);
|
||||
void handleDataLenUpdate();
|
||||
void drawBitfield();
|
||||
void copySignalToParamsUI();
|
||||
|
||||
private:
|
||||
Ui::NewGraphDialog *ui;
|
||||
DBCHandler *dbcHandler;
|
||||
int startBit, dataLen;
|
||||
};
|
||||
|
||||
#endif // NEWGRAPHDIALOG_H
|
||||
|
||||
+85
-44
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>492</width>
|
||||
<height>340</height>
|
||||
<width>681</width>
|
||||
<height>640</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -15,31 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbStandardGraph">
|
||||
<property name="text">
|
||||
<string>Standard Graph</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbSignalGraph">
|
||||
<property name="text">
|
||||
<string>DBC Signal Graph</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="1" column="0">
|
||||
@@ -55,28 +31,25 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Data:</string>
|
||||
<string>Start Bit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="txtData"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Signed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="cbSigned">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
@@ -86,47 +59,47 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="txtMask"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Bias:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="txtBias"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Scale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="txtScale"/>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Stride</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="txtStride"/>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QPushButton" name="colorSwatch">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
@@ -139,7 +112,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QPushButton" name="btnAddGraph">
|
||||
<property name="text">
|
||||
<string>Add this graph</string>
|
||||
@@ -156,6 +129,46 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtName"/>
|
||||
</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>
|
||||
</item>
|
||||
<item>
|
||||
@@ -214,12 +227,40 @@
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbSignals"/>
|
||||
</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>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CANDataGrid</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>candatagrid.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
+44
-24
@@ -12,15 +12,15 @@ SerialWorker::SerialWorker(CANFrameModel *model, QObject *parent) : QObject(pare
|
||||
rx_step = 0;
|
||||
buildFrame = new CANFrame;
|
||||
canModel = model;
|
||||
gotFrames = 0;
|
||||
ticker = NULL;
|
||||
elapsedTime = NULL;
|
||||
framesPerSec = 0;
|
||||
framesRapid = 0;
|
||||
capturing = true;
|
||||
gotValidated = true;
|
||||
isAutoRestart = false;
|
||||
targetID = -1;
|
||||
|
||||
txTimestampBasis = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
readSettings();
|
||||
}
|
||||
|
||||
@@ -45,9 +45,6 @@ void SerialWorker::run()
|
||||
ticker = new QTimer;
|
||||
connect(ticker, SIGNAL(timeout()), this, SLOT(handleTick()));
|
||||
|
||||
elapsedTime = new QTime;
|
||||
elapsedTime->start();
|
||||
|
||||
ticker->setInterval(250); //tick four times per second
|
||||
ticker->setSingleShot(false); //keep ticking
|
||||
ticker->start();
|
||||
@@ -118,6 +115,11 @@ void SerialWorker::setSerialPort(QSerialPortInfo *port)
|
||||
output.append((char)0xF1); //yet another 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);
|
||||
if (doValidation) connected = false;
|
||||
else connected = true;
|
||||
@@ -148,6 +150,11 @@ void SerialWorker::readSerialData()
|
||||
c = data.at(i);
|
||||
procRXChar(c);
|
||||
}
|
||||
if (framesRapid > 0)
|
||||
{
|
||||
emit frameUpdateRapid(framesRapid);
|
||||
framesRapid = 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;
|
||||
CANFrame tempFrame = *frame;
|
||||
tempFrame.isReceived = false;
|
||||
tempFrame.timestamp = ((QDateTime::currentMSecsSinceEpoch() - txTimestampBasis) * 1000);
|
||||
|
||||
//qDebug() << "Sending out frame with id " << frame->ID;
|
||||
|
||||
//show our sent frames in the list too. This happens even if we're not connected.
|
||||
canModel->addFrame(tempFrame, false);
|
||||
gotFrames++;
|
||||
framesRapid++;
|
||||
|
||||
if (serial == NULL) return;
|
||||
if (!serial->isOpen()) return;
|
||||
@@ -233,8 +241,9 @@ void SerialWorker::procRXChar(unsigned char c)
|
||||
rx_state = BUILD_CAN_FRAME;
|
||||
rx_step = 0;
|
||||
break;
|
||||
case 1: //we don't accept time sync commands from the firmware
|
||||
rx_state = IDLE;
|
||||
case 1: //time sync
|
||||
rx_state = TIME_SYNC;
|
||||
rx_step = 0;
|
||||
break;
|
||||
case 2: //process a return reply for digital input states.
|
||||
rx_state = GET_DIG_INPUTS;
|
||||
@@ -316,7 +325,9 @@ void SerialWorker::procRXChar(unsigned char c)
|
||||
{
|
||||
buildFrame->isReceived = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -324,6 +335,29 @@ void SerialWorker::procRXChar(unsigned char c)
|
||||
}
|
||||
rx_step++;
|
||||
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
|
||||
switch (rx_step)
|
||||
{
|
||||
@@ -411,9 +445,6 @@ void SerialWorker::procRXChar(unsigned char c)
|
||||
}
|
||||
rx_step++;
|
||||
break;
|
||||
case TIME_SYNC:
|
||||
rx_state = IDLE;
|
||||
break;
|
||||
case SET_DIG_OUTPUTS:
|
||||
rx_state = IDLE;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -40,8 +40,8 @@ public:
|
||||
void targetFrameID(int);
|
||||
|
||||
signals: //we emit signals
|
||||
void error(const QString &);
|
||||
void frameUpdateTick(int, int); //update interested parties about the # of frames that have come in
|
||||
void error(const QString &);
|
||||
void frameUpdateRapid(int); //sent *much* more rapidly than the above signal - one param for # of frames
|
||||
void connectionSuccess(int, int);
|
||||
void connectionFailure();
|
||||
void deviceInfo(int, int);
|
||||
@@ -71,14 +71,13 @@ private:
|
||||
bool doValidation;
|
||||
bool gotValidated;
|
||||
bool isAutoRestart;
|
||||
bool continuousTimeSync;
|
||||
QSerialPort *serial;
|
||||
QSerialPortInfo *currentPort;
|
||||
CANFrameModel *canModel;
|
||||
QTimer *ticker;
|
||||
QTime *elapsedTime;
|
||||
QMutex sendBulkMutex;
|
||||
int framesPerSec;
|
||||
int gotFrames;
|
||||
QTimer *ticker;
|
||||
QMutex sendBulkMutex;
|
||||
int framesRapid;
|
||||
int targetID;
|
||||
STATE rx_state;
|
||||
int rx_step;
|
||||
@@ -87,6 +86,8 @@ private:
|
||||
bool can0Enabled, can1Enabled;
|
||||
int deviceBuildNum;
|
||||
int deviceSingleWireMode;
|
||||
uint64_t txTimestampBasis;
|
||||
uint32_t buildTimeBasis;
|
||||
|
||||
void procRXChar(unsigned char);
|
||||
void sendCommValidation();
|
||||
|
||||
+112
-20
@@ -10,10 +10,13 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||
|
||||
modelFrames = frames;
|
||||
|
||||
currentlyRunning = false;
|
||||
|
||||
waitTimer = new QTimer;
|
||||
waitTimer->setInterval(500);
|
||||
waitTimer->setInterval(100);
|
||||
|
||||
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(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut);
|
||||
|
||||
@@ -32,10 +35,19 @@ UDSScanWindow::~UDSScanWindow()
|
||||
|
||||
void UDSScanWindow::scanUDS()
|
||||
{
|
||||
if (currentlyRunning)
|
||||
{
|
||||
waitTimer->stop();
|
||||
sendingFrames.clear();
|
||||
currentlyRunning = false;
|
||||
ui->btnScan->setText("Start Scan");
|
||||
}
|
||||
|
||||
ui->listResults->clear();
|
||||
sendingFrames.clear();
|
||||
|
||||
CANFrame frame;
|
||||
int typ, id;
|
||||
int startID, endID;
|
||||
startID = Utility::ParseStringToNum(ui->txtStartID->text());
|
||||
endID = Utility::ParseStringToNum(ui->txtEndID->text());
|
||||
@@ -43,9 +55,35 @@ void UDSScanWindow::scanUDS()
|
||||
int buses = ui->cbBuses->currentIndex();
|
||||
buses++;
|
||||
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.len = 8;
|
||||
@@ -71,14 +109,14 @@ void UDSScanWindow::scanUDS()
|
||||
|
||||
waitTimer->start();
|
||||
currIdx = -1;
|
||||
currentlyRunning = true;
|
||||
ui->btnScan->setText("Abort Scan");
|
||||
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)
|
||||
{
|
||||
CANFrame thisFrame;
|
||||
QString result;
|
||||
int id;
|
||||
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.
|
||||
{
|
||||
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);
|
||||
id = thisFrame.ID;
|
||||
if (id >= 0x7E8 && id <= 0x7EF)
|
||||
int temp = thisFrame.data[0] >> 4;
|
||||
if (temp == 0) //single frame reply (maybe)
|
||||
{
|
||||
id -= 8; //back to original ECU id
|
||||
result = "ECU at bus " + QString::number(thisFrame.bus) + " ID: " + QString::number(id, 16) + " responds to mode "
|
||||
+ QString::number(sendingFrames[currIdx].data[2]) + " with: " + QString::number(thisFrame.data[0], 16) + " "
|
||||
+ QString::number(thisFrame.data[1], 16) + " " + QString::number(thisFrame.data[2], 16)
|
||||
+ " " + QString::number(thisFrame.data[3], 16);
|
||||
ui->listResults->addItem(result);
|
||||
sendNextMsg();
|
||||
if (thisFrame.data[1] == 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;
|
||||
}
|
||||
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()
|
||||
{
|
||||
QString result;
|
||||
result = "ECU at bus " + QString::number(sendingFrames[currIdx].bus) + " ID: " + QString::number(sendingFrames[currIdx].ID, 16) + " did not respond to mode "
|
||||
+ QString::number(sendingFrames[currIdx].data[2]);
|
||||
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[1], 16) + " " + QString::number(sendingFrames[currIdx].data[2], 16);
|
||||
ui->listResults->addItem(result);
|
||||
|
||||
sendNextMsg();
|
||||
@@ -122,9 +211,12 @@ void UDSScanWindow::sendNextMsg()
|
||||
if (currIdx < sendingFrames.count())
|
||||
{
|
||||
emit sendCANFrame(&sendingFrames[currIdx], sendingFrames[currIdx].bus);
|
||||
waitTimer->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
waitTimer->stop();
|
||||
ui->btnScan->setText("Start Scan");
|
||||
currentlyRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void updatedFrames(int numFrames);
|
||||
void rapidFrames(int numFrames);
|
||||
void scanUDS();
|
||||
void timeOut();
|
||||
|
||||
@@ -31,6 +32,7 @@ private:
|
||||
QTimer *waitTimer;
|
||||
QList<CANFrame> sendingFrames;
|
||||
int currIdx = 0;
|
||||
bool currentlyRunning;
|
||||
|
||||
void sendNextMsg();
|
||||
};
|
||||
|
||||
+28
-1
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>UDS Scanner</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -64,6 +64,33 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<widget class="QLabel" name="label">
|
||||
<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
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user