Added an ISO-TP decoder. At the moment it tries to decode all frames

and that leads to odd results.
This commit is contained in:
Collin Kidder
2016-03-06 20:44:25 -05:00
parent f6fe53163c
commit 66675e47b3
11 changed files with 412 additions and 5 deletions
+8 -3
View File
@@ -46,7 +46,9 @@ SOURCES += main.cpp\
dbcloadsavewindow.cpp \
fuzzingwindow.cpp \
udsscanwindow.cpp \
can_structs.cpp
can_structs.cpp \
isotp_interpreterwindow.cpp \
isotp_decoder.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -79,7 +81,9 @@ HEADERS += mainwindow.h \
rangestatewindow.h \
dbcloadsavewindow.h \
fuzzingwindow.h \
udsscanwindow.h
udsscanwindow.h \
isotp_interpreterwindow.h \
isotp_decoder.h
FORMS += mainwindow.ui \
graphingwindow.ui \
@@ -100,7 +104,8 @@ FORMS += mainwindow.ui \
rangestatewindow.ui \
dbcloadsavewindow.ui \
fuzzingwindow.ui \
udsscanwindow.ui
udsscanwindow.ui \
isotp_interpreterwindow.ui
DISTFILES +=
+1 -1
View File
@@ -29,7 +29,7 @@ public:
};
//the same as the CANFrame struct but with arbitrary data size.
struct ISOTP_FRAME
struct ISOTP_MESSAGE
{
public:
int ID;
+160
View File
@@ -0,0 +1,160 @@
#include "isotp_decoder.h"
ISOTP_DECODER::ISOTP_DECODER(const QVector<CANFrame> *frames, QObject *parent)
: QObject(parent)
{
modelFrames = frames;
useExtendedAddressing = false;
}
void ISOTP_DECODER::setExtendedAddressing(bool mode)
{
useExtendedAddressing = mode;
}
//remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames.
void ISOTP_DECODER::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_DECODER::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_DECODER::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;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef ISOTP_DECODER_H
#define ISOTP_DECODER_H
#include <QObject>
#include <QDebug>
#include "can_structs.h"
class ISOTP_DECODER : public QObject
{
Q_OBJECT
public:
explicit ISOTP_DECODER(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
+97
View File
@@ -0,0 +1,97 @@
#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_DECODER(modelFrames);
connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_DECODER::updatedFrames);
connect(decoder, &ISOTP_DECODER::newISOMessage, this, &ISOTP_InterpreterWindow::newISOMessage);
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::newISOMessage(ISOTP_MESSAGE &msg)
{
int rowNum;
QString tempString;
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.length(); i++)
{
tempString.append(Utility::formatNumber(msg.data[i]));
tempString.append(" ");
}
ui->tableIsoFrames->setItem(rowNum, 5, new QTableWidgetItem(tempString));
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef ISOTP_INTERPRETERWINDOW_H
#define ISOTP_INTERPRETERWINDOW_H
#include <QDialog>
#include "can_structs.h"
#include "isotp_decoder.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);
private:
Ui::ISOTP_InterpreterWindow *ui;
ISOTP_DECODER *decoder;
const QVector<CANFrame> *modelFrames;
QVector<ISOTP_MESSAGE> messages;
void closeEvent(QCloseEvent *event);
void readSettings();
void writeSettings();
};
#endif // ISOTP_INTERPRETERWINDOW_H
+48
View File
@@ -0,0 +1,48 @@
<?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>571</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="QLabel" name="label_2">
<property name="text">
<string>Data Details of Selected Message</string>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="txtFrameDetails"/>
</item>
<item>
<widget class="QCheckBox" name="cbInterpretUDS">
<property name="text">
<string>Interpret Data as UDS</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+21
View File
@@ -98,6 +98,7 @@ MainWindow::MainWindow(QWidget *parent) :
dbcFileWindow = NULL;
fuzzingWindow = NULL;
udsScanWindow = NULL;
isoWindow = NULL;
dbcHandler = new DBCHandler;
bDirty = false;
inhibitFilterUpdate = false;
@@ -140,6 +141,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();
@@ -274,6 +276,12 @@ MainWindow::~MainWindow()
delete udsScanWindow;
}
if (isoWindow)
{
isoWindow->close();
delete isoWindow;
}
delete elapsedTime;
delete ui;
@@ -299,6 +307,7 @@ void MainWindow::exitApp()
if (dbcFileWindow) dbcFileWindow->close();
if (fuzzingWindow) fuzzingWindow->close();
if (udsScanWindow) udsScanWindow->close();
if (isoWindow) isoWindow->close();
this->close();
}
@@ -884,6 +893,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)
+3
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();
@@ -141,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/>
+1 -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>