Merge pull request #56 from collin80/WIP

Merge WIP into master
This commit is contained in:
Collin Kidder
2016-06-05 22:20:10 -04:00
42 changed files with 2191 additions and 960 deletions
+18 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
+8
View File
@@ -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();
+1
View File
@@ -43,6 +43,7 @@ public slots:
private slots:
void handleOKButton();
void handleConnTypeChanged();
private:
Ui::ConnectionWindow *ui;
+1
View File
@@ -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
+36
View File
@@ -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();
}
+25
View File
@@ -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
+14
View File
@@ -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;
}
+22
View File
@@ -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
+24
View File
@@ -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
View File
@@ -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;
}
}
}
}
}
+6 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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++)
{
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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 &params, 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 &params, bool createGraphParam)
@@ -988,23 +947,15 @@ void GraphingWindow::createGraph(GraphParams &params, bool createGraphParam)
float yminval=10000000.0, ymaxval = -1000000.0;
float xminval=10000000000.0, xmaxval = -10000000000.0;
GraphParams *refParam = &params;
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 &params, 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 &params, 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
View File
@@ -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;
+274
View File
@@ -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;
}
}
}
+39
View File
@@ -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
+154
View File
@@ -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));
}
+38
View File
@@ -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
+123
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+6
View File
@@ -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
View File
@@ -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 &params)
{
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 &params)
{
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+2
View File
@@ -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
View File
@@ -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">
+1 -1
View File
@@ -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;
}
}