From b309cce30be6642296b71e4a678b05755f789b4a Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 24 Apr 2017 21:36:28 -0400 Subject: [PATCH 1/9] Updated version number, added buttons for filter load/save in playback window --- config.h | 2 +- frameplaybackwindow.cpp | 2 ++ ui/frameplaybackwindow.ui | 32 +++++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/config.h b/config.h index 39da5a0..333b4f1 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 165 +#define VERSION 166 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index 4145803..10e8dd4 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -64,6 +64,8 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge connect(ui->btnLoadLive, SIGNAL(clicked(bool)), this, SLOT(btnLoadLive())); connect(ui->tblSequence, SIGNAL(cellPressed(int,int)), this, SLOT(seqTableCellClicked(int,int))); connect(ui->tblSequence, SIGNAL(cellChanged(int,int)), this, SLOT(seqTableCellChanged(int,int))); + connect(ui->btnLoadFilters, SIGNAL(clicked(bool)), this, SLOT(loadFilters())); + connect(ui->btnSaveFilters, SIGNAL(clicked(bool)), this, SLOT(saveFilters())); ui->listID->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint))); diff --git a/ui/frameplaybackwindow.ui b/ui/frameplaybackwindow.ui index cff92d6..4055cfd 100644 --- a/ui/frameplaybackwindow.ui +++ b/ui/frameplaybackwindow.ui @@ -22,7 +22,7 @@ - + :/icons/images/NavBack.png:/icons/images/NavBack.png @@ -33,7 +33,7 @@ - + :/icons/images/PauseHS.png:/icons/images/PauseHS.png @@ -44,7 +44,7 @@ - + :/icons/images/ReverseHS.png:/icons/images/ReverseHS.png @@ -55,7 +55,7 @@ - + :/icons/images/StopHS.png:/icons/images/StopHS.png @@ -66,7 +66,7 @@ - + :/icons/images/PlayHS.png:/icons/images/PlayHS.png @@ -77,7 +77,7 @@ - + :/icons/images/NavForward.png:/icons/images/NavForward.png @@ -328,6 +328,24 @@ + + + + + + Load Filters + + + + + + + Save Filters + + + + + @@ -338,7 +356,7 @@ - + From d38b94120df5df35f1b6c335cd2750c5846b121d Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 11 May 2017 21:42:12 -0400 Subject: [PATCH 2/9] Fixes to allow for rapid frame updating in screens that need it, more implementation of UDS scanner (and fixes to make it work with current code base) --- canframemodel.cpp | 25 ++++--- config.h | 2 +- connections/canconmanager.cpp | 6 +- mainwindow.h | 4 +- re/udsscanwindow.cpp | 104 +++++++++++++------------- re/udsscanwindow.h | 4 +- ui/udsscanwindow.ui | 134 ++++++++++++++++++++++++++-------- 7 files changed, 179 insertions(+), 100 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index 5d24df6..07e2869 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -49,12 +49,12 @@ CANFrameModel::CANFrameModel(QObject *parent) if (QSysInfo::WordSize > 32) { qDebug() << "64 bit OS detected. Requesting a large preallocation"; - preallocSize = 20000000; + preallocSize = 10000000; } else //if compiling for 32 bit you can't ask for gigabytes of preallocation so tone it down. { qDebug() << "32 bit OS detected. Requesting a much restricted prealloc"; - preallocSize = 4000000; + preallocSize = 2000000; } frames.reserve(preallocSize); @@ -106,7 +106,7 @@ void CANFrameModel::setInterpetMode(bool mode) void CANFrameModel::normalizeTiming() { mutex.lock(); - if (frames.count() == 0) return; + if (frames.count() == 0) return; timeOffset = frames[0].timestamp; for (int i = 0; i < frames.count(); i++) { @@ -240,7 +240,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const if (!timeSeconds) return QString::number(thisFrame.timestamp); else return QString::number((double)thisFrame.timestamp / 1000000.0, 'f', 6); break; - case 1: //id + case 1: //id return Utility::formatNumber(thisFrame.ID); break; case 2: //ext @@ -281,7 +281,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const tempString.append(sigString); tempString.append("\n"); } - } + } } } return tempString; @@ -351,7 +351,7 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false) } if (!overwriteDups) - { + { frames.append(tempFrame); if (filters[tempFrame.ID]) { @@ -366,14 +366,14 @@ void CANFrameModel::addFrame(const CANFrame& frame, bool autoRefresh = false) for (int i = 0; i < frames.count(); i++) { if (frames[i].ID == tempFrame.ID) - { + { frames.replace(i, tempFrame); found = true; break; } } if (!found) - { + { frames.append(tempFrame); if (filters[tempFrame.ID]) { @@ -409,9 +409,9 @@ void CANFrameModel::addFrames(const CANConnection*, const QVector& pFr } void CANFrameModel::sendRefresh() -{ +{ qDebug() << "Sending mass refresh"; - QVector tempContainer; + QVector tempContainer; int count = frames.count(); for (int i = 0; i < count; i++) { @@ -423,8 +423,9 @@ void CANFrameModel::sendRefresh() mutex.lock(); beginResetModel(); filteredFrames.clear(); - filteredFrames.append(tempContainer); filteredFrames.reserve(preallocSize); + filteredFrames.append(tempContainer); + lastUpdateNumFrames = filteredFrames.count(); endResetModel(); mutex.unlock(); @@ -479,7 +480,7 @@ void CANFrameModel::clearFrames() * allows for a mass import of frames into the model */ void CANFrameModel::insertFrames(const QVector &newFrames) -{ +{ //not resetting the model here because the serial worker automatically does a bulk refresh every 1/4 second //and that refresh will cause the view to update. If you do both it usually ends up thinking you have //double the number of frames. diff --git a/config.h b/config.h index 333b4f1..d89fe49 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 166 +#define VERSION 167 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index 0403d72..0fe5453 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -17,7 +17,7 @@ CANConManager* CANConManager::getInstance() CANConManager::CANConManager(QObject *parent): QObject(parent) { connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTimer.setInterval(125); /*tick 8 times a second */ + mTimer.setInterval(62); /*tick 16 times a second */ mTimer.setSingleShot(false); mTimer.start(); @@ -39,7 +39,7 @@ CANConManager::~CANConManager() void CANConManager::add(CANConnection* pConn_p) -{ +{ mConns.append(pConn_p); } @@ -196,7 +196,7 @@ bool CANConManager::sendFrames(const QList& pFrames) bool CANConManager::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver) { int tempBusVal; - int busBase = 0; + int busBase = 0; foreach (CANConnection* conn, mConns) { diff --git a/mainwindow.h b/mainwindow.h index 8b90e4b..e9ada2e 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -101,7 +101,7 @@ signals: void suspendCapturing(bool); //-1 = frames cleared, -2 = a new file has been loaded (so all frames are different), otherwise # of new frames - void framesUpdated(int numFrames); //something has updated the frame list + void framesUpdated(int numFrames); //something has updated the frame list (send at gui update frequency) void frameUpdateRapid(int numFrames); void settingsUpdated(); void sendCenterTimeID(int32_t ID, double timestamp); @@ -112,7 +112,7 @@ private: //canbus related data CANFrameModel *model; - DBCHandler *dbcHandler; + DBCHandler *dbcHandler; QByteArray inputBuffer; QTimer updateTimer; QTime *elapsedTime; diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 9f36c36..7d8b3cf 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -17,7 +17,7 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : waitTimer->setInterval(100); connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); - connect(MainWindow::getReference(), SIGNAL(frameUpdateRapid(int)), this, SLOT(rapidFrames(int))); + connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &UDSScanWindow::rapidFrames); connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); @@ -33,6 +33,23 @@ UDSScanWindow::~UDSScanWindow() delete waitTimer; } +void UDSScanWindow::sendOnBuses(CANFrame &frame, int buses) +{ + if (buses < ui->cbBuses->count()- 1) + { + frame.bus = buses; + sendingFrames.append(frame); + } + else + { + for (int c = 0; c < ui->cbBuses->count() - 1; c++) + { + frame.bus = c; + sendingFrames.append(frame); + } + } +} + void UDSScanWindow::scanUDS() { if (currentlyRunning) @@ -43,6 +60,8 @@ void UDSScanWindow::scanUDS() ui->btnScan->setText("Start Scan"); } + waitTimer->setInterval(ui->spinDelay->value()); + ui->listResults->clear(); sendingFrames.clear(); @@ -54,62 +73,51 @@ void UDSScanWindow::scanUDS() int buses = ui->cbBuses->currentIndex(); - //start out by sending tester present to every address to see if anyone replies for (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 < ui->cbBuses->count()- 1) + if (ui->ckTester->isChecked()) { - frame.bus = buses; - sendingFrames.append(frame); - } - else - { - for (int c = 0; c < ui->cbBuses->count() - 1; c++) - { - frame.bus = c; - 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; - frame.extended = false; frame.data[0] = 2; - frame.data[1] = 0x10; - frame.data[2] = typ; + 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 < ui->cbBuses->count()- 1) + sendOnBuses(frame, buses); + } + if (ui->ckSession->isChecked()) + { + for (typ = 1; typ < 4; typ++) //try each type of session access { - frame.bus = buses; - sendingFrames.append(frame); - } - else - { - for (int c = 0; c < ui->cbBuses->count() - 1; c++) - { - frame.bus = c; - sendingFrames.append(frame); - } + frame.data[0] = 2; + frame.data[1] = 0x10; + frame.data[2] = typ; + frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; + frame.data[6] = 0;frame.data[7] = 0; + sendOnBuses(frame, buses); } } + if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;) + { + frame.data[0] = 2; + frame.data[1] = 0x11; //Reset + frame.data[2] = 1; //hard reset. 2 = key off/on 3 = soft reset + frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; + frame.data[6] = 0;frame.data[7] = 0; + sendOnBuses(frame, buses); + } + if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. + { + frame.data[0] = 2; + frame.data[1] = 0x27; //request security mode + frame.data[2] = 1; //request seed from ECU + frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; + frame.data[6] = 0;frame.data[7] = 0; + sendOnBuses(frame, buses); + } } waitTimer->start(); @@ -135,26 +143,24 @@ void UDSScanWindow::updatedFrames(int numFrames) //Updates here are nearly once per millisecond if there is heavy traffic. That's more like it! //TODO: I really doubt this works anymore with the new connection system. This breaks the UDS scanner for now! ;( -void UDSScanWindow::rapidFrames(int numFrames) +void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVector& pFrames) { - CANFrame thisFrame; QString result; uint32_t id; int offset = ui->spinReplyOffset->value(); CANFrame sentFrame; bool gotReply = false; - if (numFrames > modelFrames->count()) return; + if (pFrames.length() <= 0) 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++) + foreach(const CANFrame& thisFrame, pFrames) { if (currIdx >= numSending) return; - thisFrame = modelFrames->at(i); id = thisFrame.ID; if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 4039345..7f232d4 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -2,6 +2,7 @@ #define UDSSCANWINDOW_H #include "can_structs.h" +#include "connections/canconnection.h" #include @@ -19,7 +20,7 @@ public: private slots: void updatedFrames(int numFrames); - void rapidFrames(int numFrames); + void rapidFrames(const CANConnection* conn, const QVector& pFrames); void scanUDS(); void timeOut(); @@ -32,6 +33,7 @@ private: bool currentlyRunning; void sendNextMsg(); + void sendOnBuses(CANFrame &frame, int buses); }; #endif // UDSSCANWINDOW_H diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index 0c157bf..ca477ab 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -7,7 +7,7 @@ 0 0 742 - 527 + 628 @@ -65,41 +65,111 @@ - - - Reply Offset: - - + + + + + Reply Offset: + + + + + + + -128 + + + 128 + + + 8 + + + + + + + Allow adaptive reply offset + + + + - - - -128 - - - 128 - - - 8 - - + + + + + Scan Types: + + + + + + + Tester Present + + + + + + + Session Control + + + + + + + ECU Reset + + + + + + + Security Access + + + + - - - Allow adaptive reply offset - - - - - - - Buses to scan - - - - - + + + + + Buses to scan + + + + + + + + + + Maximum reply delay + + + + + + + 50 + + + 10000 + + + 10 + + + 100 + + + + From 521009ec2b100282c3db3d4809a6b0abc4f6da9b Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 11 May 2017 21:58:55 -0400 Subject: [PATCH 3/9] Added ability to save UDS scan log, fixed bug with aborting a UDS scan --- re/udsscanwindow.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ re/udsscanwindow.h | 1 + ui/udsscanwindow.ui | 7 +++++++ 3 files changed, 48 insertions(+) diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 7d8b3cf..0ff08e1 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -20,6 +20,7 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &UDSScanWindow::rapidFrames); connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); + connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); int numBuses = CANConManager::getInstance()->getNumBuses(); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); @@ -33,6 +34,44 @@ UDSScanWindow::~UDSScanWindow() delete waitTimer; } +void UDSScanWindow::saveResults() +{ + QString filename; + QFileDialog dialog(this); + + QStringList filters; + filters.append(QString(tr("Text File (*.txt)"))); + + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.setViewMode(QFileDialog::Detail); + dialog.setAcceptMode(QFileDialog::AcceptSave); + + if (dialog.exec() == QDialog::Accepted) + { + filename = dialog.selectedFiles()[0]; + if (!filename.contains('.')) filename += ".txt"; + if (dialog.selectedNameFilter() == filters[0]) + { + QFile *outFile = new QFile(filename); + + if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + delete outFile; + return; + } + + for (int i = 0; i < ui->listResults->count(); i++) + { + outFile->write(ui->listResults->item(i)->text().toUtf8()); + outFile->write("\n"); + } + outFile->close(); + delete outFile; + } + } +} + void UDSScanWindow::sendOnBuses(CANFrame &frame, int buses) { if (buses < ui->cbBuses->count()- 1) @@ -58,6 +97,7 @@ void UDSScanWindow::scanUDS() sendingFrames.clear(); currentlyRunning = false; ui->btnScan->setText("Start Scan"); + return; } waitTimer->setInterval(ui->spinDelay->value()); diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 7f232d4..0ffc42e 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -22,6 +22,7 @@ private slots: void updatedFrames(int numFrames); void rapidFrames(const CANConnection* conn, const QVector& pFrames); void scanUDS(); + void saveResults(); void timeOut(); private: diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index ca477ab..ab19fcd 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -24,6 +24,13 @@ + + + + Save Scan Results + + + From d766d442b9dd24f1f7ad314e58ebea4ce15a787d Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 14 May 2017 09:36:32 -0400 Subject: [PATCH 4/9] Move isotp stuff to a new folder where more bus protocols will also be supported --- SavvyCAN.pro | 11 ++++++++--- {re => bus_protocols}/isotp_handler.cpp | 0 {re => bus_protocols}/isotp_handler.h | 0 bus_protocols/j1939_handler.cpp | 2 ++ bus_protocols/j1939_handler.h | 10 ++++++++++ bus_protocols/uds_handler.cpp | 3 +++ bus_protocols/uds_handler.h | 9 +++++++++ 7 files changed, 32 insertions(+), 3 deletions(-) rename {re => bus_protocols}/isotp_handler.cpp (100%) rename {re => bus_protocols}/isotp_handler.h (100%) create mode 100644 bus_protocols/j1939_handler.cpp create mode 100644 bus_protocols/j1939_handler.h create mode 100644 bus_protocols/uds_handler.cpp create mode 100644 bus_protocols/uds_handler.h diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 507299d..481cf8d 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -60,7 +60,10 @@ SOURCES += main.cpp\ re/graphingwindow.cpp \ re/newgraphdialog.cpp \ bisectwindow.cpp \ - signalviewerwindow.cpp + signalviewerwindow.cpp \ + bus_protocols/isotp_handler.cpp \ + bus_protocols/j1939_handler.cpp \ + bus_protocols/uds_handler.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -99,7 +102,6 @@ HEADERS += mainwindow.h \ re/flowviewwindow.h \ re/frameinfowindow.h \ re/fuzzingwindow.h \ - re/isotp_handler.h \ re/isotp_interpreterwindow.h \ re/rangestatewindow.h \ re/udsscanwindow.h \ @@ -109,7 +111,10 @@ HEADERS += mainwindow.h \ re/graphingwindow.h \ re/newgraphdialog.h \ bisectwindow.h \ - signalviewerwindow.h + signalviewerwindow.h \ + bus_protocols/isotp_handler.h \ + bus_protocols/j1939_handler.h \ + bus_protocols/uds_handler.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ diff --git a/re/isotp_handler.cpp b/bus_protocols/isotp_handler.cpp similarity index 100% rename from re/isotp_handler.cpp rename to bus_protocols/isotp_handler.cpp diff --git a/re/isotp_handler.h b/bus_protocols/isotp_handler.h similarity index 100% rename from re/isotp_handler.h rename to bus_protocols/isotp_handler.h diff --git a/bus_protocols/j1939_handler.cpp b/bus_protocols/j1939_handler.cpp new file mode 100644 index 0000000..8b80ca6 --- /dev/null +++ b/bus_protocols/j1939_handler.cpp @@ -0,0 +1,2 @@ +#include "j1939_handler.h" + diff --git a/bus_protocols/j1939_handler.h b/bus_protocols/j1939_handler.h new file mode 100644 index 0000000..504ca14 --- /dev/null +++ b/bus_protocols/j1939_handler.h @@ -0,0 +1,10 @@ +#ifndef J1939_HANDLER_H +#define J1939_HANDLER_H + +#include +#include +#include +#include "can_structs.h" + + +#endif // J1939_HANDLER_H diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp new file mode 100644 index 0000000..c967857 --- /dev/null +++ b/bus_protocols/uds_handler.cpp @@ -0,0 +1,3 @@ +#include "uds_handler.h" + + diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h new file mode 100644 index 0000000..e58eb7d --- /dev/null +++ b/bus_protocols/uds_handler.h @@ -0,0 +1,9 @@ +#ifndef UDS_HANDLER_H +#define UDS_HANDLER_H + +#include +#include +#include +#include "can_structs.h" + +#endif // UDS_HANDLER_H From 1ccb9bac2e2c49cf86da80751d9c6bd763be6652 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 15 May 2017 22:38:59 -0400 Subject: [PATCH 5/9] Major refactoring of ISOTP and UDS code to be more generic and have better functionality. --- SavvyCAN.pro | 1 - bus_protocols/isotp_handler.cpp | 197 +++++++++++++---------------- bus_protocols/isotp_handler.h | 32 +++-- bus_protocols/j1939_handler.h | 11 ++ bus_protocols/uds_handler.cpp | 212 ++++++++++++++++++++++++++++++++ bus_protocols/uds_handler.h | 95 ++++++++++++++ can_structs.h | 26 ---- connections/canconmanager.cpp | 2 +- mainwindow.cpp | 9 +- mainwindow.h | 6 +- re/frameinfowindow.h | 1 + re/isotp_interpreterwindow.cpp | 2 +- re/isotp_interpreterwindow.h | 6 +- re/udsscanwindow.cpp | 88 ++++++------- re/udsscanwindow.h | 12 +- 15 files changed, 494 insertions(+), 206 deletions(-) diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 481cf8d..ac6e484 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -50,7 +50,6 @@ SOURCES += main.cpp\ re/flowviewwindow.cpp \ re/frameinfowindow.cpp \ re/fuzzingwindow.cpp \ - re/isotp_handler.cpp \ re/isotp_interpreterwindow.cpp \ re/rangestatewindow.cpp \ re/udsscanwindow.cpp \ diff --git a/bus_protocols/isotp_handler.cpp b/bus_protocols/isotp_handler.cpp index f679213..dde42ba 100644 --- a/bus_protocols/isotp_handler.cpp +++ b/bus_protocols/isotp_handler.cpp @@ -1,124 +1,23 @@ #include "isotp_handler.h" +#include "connections/canconmanager.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"} -}; +ISOTP_HANDLER* ISOTP_HANDLER::mInstance = NULL; -CODE_STRUCT UDS_FUNCS[] = +ISOTP_HANDLER* ISOTP_HANDLER::getInstance() { - {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"} -}; + if(!mInstance) + { + mInstance = new ISOTP_HANDLER(); + mInstance->modelFrames = MainWindow::getReference()->getCANFrameModel()->getListReference(); + } -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"}, -}; + return mInstance; +} -ISOTP_HANDLER::ISOTP_HANDLER(const QVector *frames, QObject *parent) - : QObject(parent) +ISOTP_HANDLER::ISOTP_HANDLER() { - modelFrames = frames; useExtendedAddressing = false; + isReceiving = false; } void ISOTP_HANDLER::setExtendedAddressing(bool mode) @@ -126,6 +25,64 @@ void ISOTP_HANDLER::setExtendedAddressing(bool mode) useExtendedAddressing = mode; } +void ISOTP_HANDLER::setReception(bool mode) +{ + if (isReceiving == mode) return; + isReceiving = mode; + + if (isReceiving) + { + connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &ISOTP_HANDLER::rapidFrames); + qDebug() << "Enabling reception in ISOTP handler"; + } + else + { + disconnect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &ISOTP_HANDLER::rapidFrames); + qDebug() << "Disabling reception in ISOTP handler"; + } +} + +void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector data) +{ + CANFrame frame; + int currByte = 0; + int index = 0; + if (bus < 0) return; + if (bus >= CANConManager::getInstance()->getNumBuses()) return; + + if (data.length() < 8) + { + frame.bus = bus; + frame.extended = false; + frame.ID = ID; + frame.len = data.length() + 1; + frame.data[0] = frame.len - 1; + for (int i = 0; i < frame.data[0]; i++) frame.data[i + 1] = data[i]; + CANConManager::getInstance()->sendFrame(frame); + } + else //need to send a multi-part ISO_TP message - no flow control possible right now. TODO - Add flow control + { + frame.bus = bus; + frame.ID = ID; + frame.extended = false; + frame.len = 8; + frame.data[0] = 0x10 + (data.length() / 256); + frame.data[1] = data.length() & 0xFF; + for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++]; + CANConManager::getInstance()->sendFrame(frame); + while (currByte < data.length()) + { + frame.data[0] = 0x20 + index; + index = (index + 1) & 0xF; + int bytesToGo = data.length() - currByte; + if (bytesToGo > 7) bytesToGo = 7; + for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++]; + frame.len = 1 + bytesToGo; + CANConManager::getInstance()->sendFrame(frame); + } + } +} + //remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames. void ISOTP_HANDLER::updatedFrames(int numFrames) { @@ -140,11 +97,23 @@ void ISOTP_HANDLER::updatedFrames(int numFrames) { for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++) { - processFrame(modelFrames->at(i)); + //processFrame(modelFrames->at(i)); } } } +void ISOTP_HANDLER::rapidFrames(const CANConnection* conn, const QVector& pFrames) +{ + if (pFrames.length() <= 0) return; + + qDebug() << "received messages in ISOTP handler"; + + foreach(const CANFrame& thisFrame, pFrames) + { + processFrame(thisFrame); + } +} + void ISOTP_HANDLER::processFrame(const CANFrame &frame) { uint64_t ID = frame.ID; diff --git a/bus_protocols/isotp_handler.h b/bus_protocols/isotp_handler.h index 00c2cb8..dc6a1f8 100644 --- a/bus_protocols/isotp_handler.h +++ b/bus_protocols/isotp_handler.h @@ -1,16 +1,25 @@ -#ifndef ISOTP_DECODER_H -#define ISOTP_DECODER_H +#ifndef ISOTP_HANDLER_H +#define ISOTP_HANDLER_H #include #include #include #include "can_structs.h" +#include "mainwindow.h" +#include "canframemodel.h" -struct CODE_STRUCT +//the same as the CANFrame struct but with arbitrary data size. +struct ISOTP_MESSAGE { - int code; - QString shortDesc; - QString longDesc; +public: + uint32_t ID; + int bus; + bool extended; + bool isReceived; + int len; //# of bytes this message should have (as reported) + int actualSize; //# we actually got + QVector data; + uint64_t timestamp; }; class ISOTP_HANDLER : public QObject @@ -18,11 +27,15 @@ class ISOTP_HANDLER : public QObject Q_OBJECT public: - explicit ISOTP_HANDLER(const QVector *frames, QObject *parent = 0); + ISOTP_HANDLER(); void setExtendedAddressing(bool mode); + static ISOTP_HANDLER* getInstance(); + void setReception(bool mode); //set whether to accept and forward frames or not + void sendISOTPFrame(int bus, int ID, QVector data); public slots: void updatedFrames(int); + void rapidFrames(const CANConnection* conn, const QVector& pFrames); signals: void newISOMessage(ISOTP_MESSAGE &msg); @@ -31,9 +44,12 @@ private: QList messageBuffer; const QVector *modelFrames; bool useExtendedAddressing; + bool isReceiving; void processFrame(const CANFrame &frame); void checkNeedFlush(uint64_t ID); + + static ISOTP_HANDLER* mInstance; }; -#endif // ISOTP_DECODER_H +#endif // ISOTP_HANDLER_H diff --git a/bus_protocols/j1939_handler.h b/bus_protocols/j1939_handler.h index 504ca14..53ff315 100644 --- a/bus_protocols/j1939_handler.h +++ b/bus_protocols/j1939_handler.h @@ -6,5 +6,16 @@ #include #include "can_structs.h" +struct J1939ID +{ +public: + int src; + int dest; + int pgn; + int pf; + int ps; + int priority; + bool isBroadcast; +}; #endif // J1939_HANDLER_H diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index c967857..cb5e743 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -1,3 +1,215 @@ #include "uds_handler.h" +#include "connections/canconmanager.h" +#include +QVector UDS_SERVICE_DESC = { + {1, "OBDII_SHOW_CURRENT", "OBDII - Show current data"}, + {2, "OBDII_SHOW_FREEZE", "OBDII - Show freeze data"}, + {3, "OBDII_SHOW_STORED_DTC", "OBDII - Show stored DTC codes"}, + {4, "OBDII_CLEAR_DTC", "OBDII - Clear current DTC codes"}, + {5, "OBDII_TEST_O2", "OBDII - O2 sensor testing"}, + {6, "OBDII_TEST_RESULTS", "OBDII - Show emissions testing results"}, + {7, "OBDII_SHOW_PENDING_DTC", "OBDII - Show pending DTC codes"}, + {8, "OBDII_CONTROL_DEVICES", "OBDII - Control vehicle devices"}, + {9, "OBDII_VEH_INFO", "OBDII - Retrieve vehicle information"}, + {0xA, "OBDII_PERM_DTC", "OBDII - Show permanent DTC codes"}, + {0x10, "DIAG_CONTROL", "Diagnostic session control"}, + {0x11, "ECU_RESET", "Reset ECU"}, + {0x12, "GMLAN_READ_FAILURE_RECORD", "GMLAN - Read Fail"}, + {0x14, "CLEAR_DIAG", "Clear diagnostic trouble codes"}, + {0x19, "READ_DTC", "Read diagnostic trouble codes"}, + {0x1A, "GMLAN_READ_DIAGNOSTIC_ID", "GMLAN - Read diagnostics ID"}, + {0x20, "RETURN_TO_NORMAL", "Return to normal mode"}, + {0x22, "READ_BY_ID", "Read data by ID"}, + {0x23, "READ_BY_ADDR", "Read data by address"}, + {0x24, "READ_SCALING_ID", "Read scaling data by ID"}, + {0x27, "SECURITY_ACCESS", "Request security access"}, + {0x28, "COMM_CTRL", "Communication control"}, + {0x2A, "READ_DATA_ID_PERIODIC", "Read data by ID periodically"}, + {0x2C, "DYNAMIC_DATA_DEFINE", "Create dynamic data ID"}, + {0x2D, "DEFINE_PID_BY_ADDR", "Create a PID for a given memory address"}, + {0x2E, "WRITE_BY_ID", "Write data by ID"}, + {0x2F, "IO_CTRL", "Input/Output control (force)"}, + {0x31, "ROUTINE_CTRL", "Call a service routine"}, + {0x34, "REQUEST_DOWNLOAD", "Request data download (from PC to ECU)"}, + {0x35, "REQUEST_UPLOAD", "Request data upload (from ECU to PC)"}, + {0x36, "TRANSFER_DATA", "Transfer data"}, + {0x37, "REQ_TRANS_EXIT", "Request that data transfer cease"}, + {0x38, "REQ_FILE_TRANS", "Request file transfer"}, + {0x3B, "GMLAN_WRITE_DID", "GMLAN - Write DID"}, + {0x3D, "WRITE_BY_ADDR", "Write data by address"}, + {0x3E, "TESTER_PRESENT", "Tester is present"}, + {0x7F, "NEG_RESPONSE","Negative Response"}, + {0x83, "ACCESS_TIMING", "Read or write comm timing parameters"}, + {0x84, "SECURED_DATA_TRANS", "Secured data transmission"}, + {0x85, "CTRL_DTC_SETTINGS", "Control DTC settings"}, + {0x86, "RESPONSE_ON_EVENT", "Request start/stop transmission on event"}, + {0x87, "RESPONSE_LINK_CTRL", "Control comm link"}, + {0xA2, "GMLAN_REPORT_PROG_STATE", "GMLAN - Report programming state"}, + {0xA5, "GMLAN_ENTER_PROG_MODE", "GMLAN - Enter programming mode"}, + {0xA9, "GMLAN_CHECK_CODES", "GMLAN - Check codes"}, + {0xAA, "GMLAN_READ_DPID", "GMLAN - Read dynamic PID"}, + {0xAE, "GMLAN_DEVICE_CTRL", "GMLAN - Device control"}, + {0xFF, "UNKNOWN_CODE", "Unknown, likely proprietary UDS function code"} +}; + +QVector 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"}, +}; + +UDS_HANDLER* UDS_HANDLER::mInstance = NULL; + +UDS_HANDLER* UDS_HANDLER::getInstance() +{ + if(!mInstance) + { + mInstance = new UDS_HANDLER(); + mInstance->modelFrames = MainWindow::getReference()->getCANFrameModel()->getListReference(); + } + + return mInstance; +} + +UDS_HANDLER::UDS_HANDLER() +{ + isReceiving = false; + useExtendedAddressing = false; +} + +void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg) +{ + qDebug() << "UDS handler got ISOTP frame"; +} + +void UDS_HANDLER::setReception(bool mode) +{ + if (isReceiving == mode) return; + + isReceiving = mode; + + if (isReceiving) + { + connect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&))); + ISOTP_HANDLER::getInstance()->setReception(true); //must enable ISOTP reception too. + qDebug() << "Enabling reception of ISO-TP frames in UDS handler"; + } + else + { + disconnect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&))); + //can't disable ISOTP reception because something else might be using it. + qDebug() << "Disabling reception of ISOTP frames in UDS handler"; + } +} + +void UDS_HANDLER::sendUDSFrame(int bus, int ID, int service, QVector payload) +{ + QVector data; + if (bus < 0) return; + if (bus >= CANConManager::getInstance()->getNumBuses()) return; + if (service < 0 || service > 0xFF) return; + data.append(service); + data.append(payload); + ISOTP_HANDLER::getInstance()->sendISOTPFrame(bus, ID, data); + qDebug() << "Sent UDS service: " << getServiceShortDesc(service) << " on bus " << bus; +} + +QString UDS_HANDLER::getServiceShortDesc(int service) +{ + foreach (CODE_STRUCT code, UDS_SERVICE_DESC) + { + if (code.code == service) return code.shortDesc; + } + return QString(); +} + +QString UDS_HANDLER::getServiceLongDesc(int service) +{ + foreach (CODE_STRUCT code, UDS_SERVICE_DESC) + { + if (code.code == service) return code.longDesc; + } + return QString(); +} + +QString UDS_HANDLER::getNegativeResponseShort(int respCode) +{ + foreach (CODE_STRUCT code, UDS_NEG_RESPONSE) + { + if (code.code == respCode) return code.shortDesc; + } + return QString(); +} + +QString UDS_HANDLER::getNegativeResponseLong(int respCode) +{ + foreach (CODE_STRUCT code, UDS_NEG_RESPONSE) + { + if (code.code == respCode) return code.longDesc; + } + return QString(); +} diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h index e58eb7d..315f722 100644 --- a/bus_protocols/uds_handler.h +++ b/bus_protocols/uds_handler.h @@ -5,5 +5,100 @@ #include #include #include "can_structs.h" +#include "isotp_handler.h" + +namespace UDS_SERVICES +{ + enum + { + OBDII_SHOW_CURRENT = 1, + OBDII_SHOW_FREEZE = 2, + OBDII_SHOW_STORED_DTC = 3, + OBDII_CLEAR_DTC = 4, + OBDII_TEST_O2 = 5, + OBDII_TEST_RESULTS = 6, + OBDII_SHOW_PENDING_DTC = 7, + OBDII_CONTROL_DEVICES = 8, + OBDII_VEH_INFO = 9, + OBDII_PERM_DTC = 0xA, + DIAG_CONTROL = 0x10, + ECU_RESET = 0x11, + GMLAN_READ_FAILURE_RECORD = 0x12, + CLEAR_DIAG = 0x14, + READ_DTC = 0x19, + GMLAN_READ_DIAGNOSTIC_ID = 0x1A, + RETURN_TO_NORMAL = 0x20, + READ_BY_ID = 0x22, + READ_BY_ADDR = 0x23, + READ_SCALING_ID = 0x24, + SECURITY_ACCESS = 0x27, + COMM_CTRL = 0x28, + READ_DATA_ID_PERIODIC = 0x2A, + DYNAMIC_DATA_DEFINE = 0x2C, + DEFINE_PID_BY_ADDR = 0x2D, + WRITE_BY_ID = 0x2E, + IO_CTRL = 0x2F, + ROUTINE_CTRL = 0x31, + REQUEST_DOWNLOAD = 0x34, + REQUEST_UPLOAD = 0x35, + TRANSFER_DATA = 0x36, + REQ_TRANS_EXIT = 0x37, + REQ_FILE_TRANS = 0x38, + GMLAN_WRITE_DID = 0x3B, + WRITE_BY_ADDR = 0x3D, + TESTER_PRESENT = 0x3E, + NEG_RESPONSE = 0x7F, + ACCESS_TIMING = 0x83, + SECURED_DATA_TRANS = 0x84, + CTRL_DTC_SETTINGS = 0x85, + RESPONSE_ON_EVENT = 0x86, + RESPONSE_LINK_CTRL = 0x87, + GMLAN_REPORT_PROG_STATE = 0xA2, + GMLAN_ENTER_PROG_MODE = 0xA5, + GMLAN_CHECK_CODES = 0xA9, + GMLAN_READ_DPID = 0xAA, + GMLAN_DEVICE_CTRL = 0xAE + }; +} + +struct CODE_STRUCT +{ + int code; + QString shortDesc; + QString longDesc; +}; + +class UDS_HANDLER : public QObject +{ + Q_OBJECT + +public: + UDS_HANDLER(); + void setExtendedAddressing(bool mode); + static UDS_HANDLER* getInstance(); + void setReception(bool mode); //set whether to accept and forward frames or not + void sendUDSFrame(int bus, int ID, int service, QVector payload); + QString getServiceShortDesc(int service); + QString getServiceLongDesc(int service); + QString getNegativeResponseShort(int respCode); + QString getNegativeResponseLong(int respCode); + +public slots: + void gotISOTPFrame(ISOTP_MESSAGE &msg); + +signals: + void newUDSMessage(ISOTP_MESSAGE &msg); + +private: + QList messageBuffer; + const QVector *modelFrames; + bool isReceiving; + bool useExtendedAddressing; + + void processFrame(const CANFrame &frame); + + static UDS_HANDLER* mInstance; +}; + #endif // UDS_HANDLER_H diff --git a/can_structs.h b/can_structs.h index 40428b5..ece14b1 100644 --- a/can_structs.h +++ b/can_structs.h @@ -32,31 +32,5 @@ public: } }; -struct J1939ID -{ -public: - int src; - int dest; - int pgn; - int pf; - int ps; - int priority; - bool isBroadcast; -}; - -//the same as the CANFrame struct but with arbitrary data size. -struct ISOTP_MESSAGE -{ -public: - uint32_t ID; - int bus; - bool extended; - bool isReceived; - int len; //# of bytes this message should have (as reported) - int actualSize; //# we actually got - QVector data; - uint64_t timestamp; -}; - #endif // CAN_STRUCTS_H diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index 0fe5453..b83f663 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -17,7 +17,7 @@ CANConManager* CANConManager::getInstance() CANConManager::CANConManager(QObject *parent): QObject(parent) { connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTimer.setInterval(62); /*tick 16 times a second */ + mTimer.setInterval(20); /*Tick 50 times per second to allow for good resolution in reception where needed. GUI updates *MUCH* more slowly*/ mTimer.setSingleShot(false); mTimer.start(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 9af3409..b4b9778 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -168,7 +168,7 @@ MainWindow::MainWindow(QWidget *parent) : //Automatically create the connection window so it can be updated even if we never opened it. connectionWindow = new ConnectionWindow(); - connect(this, SIGNAL(suspendCapturing(bool)), connectionWindow, SLOT(setSuspendAll(bool))); + connect(this, SIGNAL(suspendCapturing(bool)), connectionWindow, SLOT(setSuspendAll(bool))); } @@ -644,7 +644,7 @@ void MainWindow::toggleCapture() } void MainWindow::connectionStatusUpdated(int conns) -{ +{ lbStatusConnected.setText(tr("Connected to ") + QString::number(conns) + tr(" buses")); } @@ -674,6 +674,11 @@ void MainWindow::updateFileStatus() lbStatusFilename.setText(output); } +CANFrameModel* MainWindow::getCANFrameModel() +{ + return model; +} + void MainWindow::showSettingsDialog() { if (!settingsDialog) diff --git a/mainwindow.h b/mainwindow.h index e9ada2e..4a03275 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -8,6 +8,9 @@ #include "canframemodel.h" #include "can_structs.h" #include "framefileio.h" +#include "dbc/dbchandler.h" +#include "bus_protocols/isotp_handler.h" + #include "re/graphingwindow.h" #include "re/frameinfowindow.h" #include "frameplaybackwindow.h" @@ -15,7 +18,6 @@ #include "re/flowviewwindow.h" #include "framesenderwindow.h" #include "re/filecomparatorwindow.h" -#include "dbc/dbchandler.h" #include "dbc/dbcmaineditor.h" #include "mainsettingsdialog.h" #include "firmwareuploaderwindow.h" @@ -32,6 +34,7 @@ #include "signalviewerwindow.h" class ConnectionWindow; +class ISOTP_InterpreterWindow; namespace Ui { class MainWindow; @@ -45,6 +48,7 @@ public: explicit MainWindow(QWidget *parent = 0); static QString loadedFileName; static MainWindow *getReference(); + CANFrameModel * getCANFrameModel(); ~MainWindow(); private slots: diff --git a/re/frameinfowindow.h b/re/frameinfowindow.h index dc3ac57..67bbb44 100644 --- a/re/frameinfowindow.h +++ b/re/frameinfowindow.h @@ -6,6 +6,7 @@ #include #include #include "can_structs.h" +#include "bus_protocols/j1939_handler.h" namespace Ui { class FrameInfoWindow; diff --git a/re/isotp_interpreterwindow.cpp b/re/isotp_interpreterwindow.cpp index 778a2d8..54ccd52 100644 --- a/re/isotp_interpreterwindow.cpp +++ b/re/isotp_interpreterwindow.cpp @@ -9,7 +9,7 @@ ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector *frames ui->setupUi(this); modelFrames = frames; - decoder = new ISOTP_HANDLER(modelFrames); + decoder = ISOTP_HANDLER::getInstance(); connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ISOTP_InterpreterWindow::updatedFrames); connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames); diff --git a/re/isotp_interpreterwindow.h b/re/isotp_interpreterwindow.h index ff099e1..354cef0 100644 --- a/re/isotp_interpreterwindow.h +++ b/re/isotp_interpreterwindow.h @@ -2,8 +2,10 @@ #define ISOTP_INTERPRETERWINDOW_H #include -#include "can_structs.h" -#include "isotp_handler.h" +#include "bus_protocols/isotp_handler.h" + +class ISOTP_MESSAGE; +class ISOTP_HANDLER; namespace Ui { class ISOTP_InterpreterWindow; diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 0ff08e1..ad4e103 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -2,6 +2,7 @@ #include "ui_udsscanwindow.h" #include "mainwindow.h" #include "connections/canconmanager.h" +#include "bus_protocols/uds_handler.h" UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -72,19 +73,20 @@ void UDSScanWindow::saveResults() } } -void UDSScanWindow::sendOnBuses(CANFrame &frame, int buses) +void UDSScanWindow::sendOnBuses(UDS_TESTS test, int buses) { - if (buses < ui->cbBuses->count()- 1) + int busList = buses; + if (busList < ui->cbBuses->count() - 1) { - frame.bus = buses; - sendingFrames.append(frame); + test.bus = buses; + sendingFrames.append(test); } else { for (int c = 0; c < ui->cbBuses->count() - 1; c++) { - frame.bus = c; - sendingFrames.append(frame); + test.bus = c; + sendingFrames.append(test); } } } @@ -105,7 +107,7 @@ void UDSScanWindow::scanUDS() ui->listResults->clear(); sendingFrames.clear(); - CANFrame frame; + UDS_TESTS test; int typ, id; int startID, endID; startID = Utility::ParseStringToNum(ui->txtStartID->text()); @@ -115,48 +117,34 @@ void UDSScanWindow::scanUDS() for (id = startID; id <= endID; id++) { - frame.ID = id; - frame.len = 8; - frame.extended = false; + test.ID = id; if (ui->ckTester->isChecked()) { - 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; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::TESTER_PRESENT; + test.subFunc = 0; + sendOnBuses(test, buses); } if (ui->ckSession->isChecked()) { for (typ = 1; typ < 4; typ++) //try each type of session access { - frame.data[0] = 2; - frame.data[1] = 0x10; - frame.data[2] = typ; - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFunc = typ; + sendOnBuses(test, buses); } } if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;) { - frame.data[0] = 2; - frame.data[1] = 0x11; //Reset - frame.data[2] = 1; //hard reset. 2 = key off/on 3 = soft reset - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::ECU_RESET; + test.subFunc = 1; + sendOnBuses(test, buses); } if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. { - frame.data[0] = 2; - frame.data[1] = 0x27; //request security mode - frame.data[2] = 1; //request seed from ECU - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::SECURITY_ACCESS; + test.subFunc = 1; + sendOnBuses(test, buses); } } @@ -188,7 +176,7 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorspinReplyOffset->value(); - CANFrame sentFrame; + UDS_TESTS sentFrame; bool gotReply = false; if (pFrames.length() <= 0) return; @@ -205,27 +193,27 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorcbAllowAdaptiveOffset->isChecked()) { - int temp = thisFrame.data[0] >> 4; - if (temp == 0) //single frame reply (maybe) - { - if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].data[1]) + //int temp = thisFrame.data[0] >> 4; + //if (temp == 0) //single frame reply (maybe) + //{ + if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].service) { 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) + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 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) + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 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]) @@ -237,7 +225,7 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorlistResults->addItem(result); sendNextMsg(); @@ -259,10 +247,14 @@ void UDSScanWindow::timeOut() void UDSScanWindow::sendNextMsg() { + QVector data; + currIdx++; if (currIdx < sendingFrames.count()) { - CANConManager::getInstance()->sendFrame(sendingFrames[currIdx]); + data.clear(); + data.append(sendingFrames[currIdx].subFunc); + UDS_HANDLER::getInstance()->sendUDSFrame(sendingFrames[currIdx].bus, sendingFrames[currIdx].ID, sendingFrames[currIdx].service, data); waitTimer->start(); } else diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 0ffc42e..55851f7 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -10,6 +10,14 @@ namespace Ui { class UDSScanWindow; } +struct UDS_TESTS +{ + int ID; + int bus; + int service; + int subFunc; +}; + class UDSScanWindow : public QDialog { Q_OBJECT @@ -29,12 +37,12 @@ private: Ui::UDSScanWindow *ui; const QVector *modelFrames; QTimer *waitTimer; - QList sendingFrames; + QList sendingFrames; int currIdx = 0; bool currentlyRunning; void sendNextMsg(); - void sendOnBuses(CANFrame &frame, int buses); + void sendOnBuses(UDS_TESTS frame, int buses); }; #endif // UDSSCANWINDOW_H From 2af1204cdd827f998c6e96708f66abd9d86ca9b4 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 16 May 2017 21:50:54 -0400 Subject: [PATCH 6/9] Additional work on UDS - now UDS scan window can get results from UDS handler instead of trying to do it all itself. --- SavvyCAN.pro | 3 +- bus_protocols/isotp_handler.h | 15 +------- bus_protocols/isotp_message.h | 18 ++++++++++ bus_protocols/uds_handler.cpp | 25 ++++++++++++++ bus_protocols/uds_handler.h | 12 +++++-- config.h | 2 +- re/udsscanwindow.cpp | 65 ++++++++++++++++------------------- re/udsscanwindow.h | 15 +++----- 8 files changed, 91 insertions(+), 64 deletions(-) create mode 100644 bus_protocols/isotp_message.h diff --git a/SavvyCAN.pro b/SavvyCAN.pro index ac6e484..a6492a3 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -113,7 +113,8 @@ HEADERS += mainwindow.h \ signalviewerwindow.h \ bus_protocols/isotp_handler.h \ bus_protocols/j1939_handler.h \ - bus_protocols/uds_handler.h + bus_protocols/uds_handler.h \ + bus_protocols/isotp_message.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ diff --git a/bus_protocols/isotp_handler.h b/bus_protocols/isotp_handler.h index dc6a1f8..5d22c21 100644 --- a/bus_protocols/isotp_handler.h +++ b/bus_protocols/isotp_handler.h @@ -7,20 +7,7 @@ #include "can_structs.h" #include "mainwindow.h" #include "canframemodel.h" - -//the same as the CANFrame struct but with arbitrary data size. -struct ISOTP_MESSAGE -{ -public: - uint32_t ID; - int bus; - bool extended; - bool isReceived; - int len; //# of bytes this message should have (as reported) - int actualSize; //# we actually got - QVector data; - uint64_t timestamp; -}; +#include "isotp_message.h" class ISOTP_HANDLER : public QObject { diff --git a/bus_protocols/isotp_message.h b/bus_protocols/isotp_message.h new file mode 100644 index 0000000..66ed9df --- /dev/null +++ b/bus_protocols/isotp_message.h @@ -0,0 +1,18 @@ +#ifndef ISOTP_MESSAGE_H +#define ISOTP_MESSAGE_H + +//the same as the CANFrame struct but with arbitrary data size. +class ISOTP_MESSAGE +{ +public: + uint32_t ID; + int bus; + bool extended; + bool isReceived; + int len; //# of bytes this message should have (as reported) + int actualSize; //# we actually got + QVector data; + uint64_t timestamp; +}; + +#endif // ISOTP_MESSAGE_H diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index cb5e743..0e30bd7 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -1,5 +1,6 @@ #include "uds_handler.h" #include "connections/canconmanager.h" +#include "mainwindow.h" #include QVector UDS_SERVICE_DESC = { @@ -143,6 +144,18 @@ UDS_HANDLER::UDS_HANDLER() void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg) { qDebug() << "UDS handler got ISOTP frame"; + UDS_MESSAGE udsMsg; + udsMsg.bus = msg.bus; + udsMsg.extended = msg.extended; + udsMsg.ID = msg.ID; + udsMsg.isReceived = msg.isReceived; + udsMsg.timestamp = msg.timestamp; + udsMsg.actualSize = msg.actualSize; + udsMsg.len = msg.len; + udsMsg.service = msg.data.at(0); + udsMsg.subFunc = msg.data.at(1); + udsMsg.data = msg.data.mid(1, -1); //don't copy data[0] which was service number + emit newUDSMessage(udsMsg); } void UDS_HANDLER::setReception(bool mode) @@ -177,6 +190,18 @@ void UDS_HANDLER::sendUDSFrame(int bus, int ID, int service, QVector data; + if (msg.bus < 0) return; + if (msg.bus >= CANConManager::getInstance()->getNumBuses()) return; + if (msg.service < 0 || msg.service > 0xFF) return; + data.append(msg.service); + data.append(msg.data); + ISOTP_HANDLER::getInstance()->sendISOTPFrame(msg.bus, msg.ID, data); + qDebug() << "Sent UDS service: " << getServiceShortDesc(msg.service) << " on bus " << msg.bus; +} + QString UDS_HANDLER::getServiceShortDesc(int service) { foreach (CODE_STRUCT code, UDS_SERVICE_DESC) diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h index 315f722..62b01b7 100644 --- a/bus_protocols/uds_handler.h +++ b/bus_protocols/uds_handler.h @@ -5,7 +5,7 @@ #include #include #include "can_structs.h" -#include "isotp_handler.h" +#include "isotp_message.h" namespace UDS_SERVICES { @@ -68,6 +68,13 @@ struct CODE_STRUCT QString longDesc; }; +class UDS_MESSAGE: public ISOTP_MESSAGE +{ +public: + int service; + int subFunc; +}; + class UDS_HANDLER : public QObject { Q_OBJECT @@ -78,6 +85,7 @@ public: static UDS_HANDLER* getInstance(); void setReception(bool mode); //set whether to accept and forward frames or not void sendUDSFrame(int bus, int ID, int service, QVector payload); + void sendUDSFrame(const UDS_MESSAGE &msg); QString getServiceShortDesc(int service); QString getServiceLongDesc(int service); QString getNegativeResponseShort(int respCode); @@ -87,7 +95,7 @@ public slots: void gotISOTPFrame(ISOTP_MESSAGE &msg); signals: - void newUDSMessage(ISOTP_MESSAGE &msg); + void newUDSMessage(UDS_MESSAGE &msg); private: QList messageBuffer; diff --git a/config.h b/config.h index d89fe49..5d61a24 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 167 +#define VERSION 168 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index ad4e103..ee2f187 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -17,8 +17,10 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : waitTimer = new QTimer; waitTimer->setInterval(100); + UDS_HANDLER::getInstance()->setReception(true); + connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); - connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &UDSScanWindow::rapidFrames); + connect(UDS_HANDLER::getInstance(), &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply); connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); @@ -73,7 +75,7 @@ void UDSScanWindow::saveResults() } } -void UDSScanWindow::sendOnBuses(UDS_TESTS test, int buses) +void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses) { int busList = buses; if (busList < ui->cbBuses->count() - 1) @@ -107,7 +109,7 @@ void UDSScanWindow::scanUDS() ui->listResults->clear(); sendingFrames.clear(); - UDS_TESTS test; + UDS_MESSAGE test; int typ, id; int startID, endID; startID = Utility::ParseStringToNum(ui->txtStartID->text()); @@ -169,49 +171,42 @@ void UDSScanWindow::updatedFrames(int numFrames) } } -//Updates here are nearly once per millisecond if there is heavy traffic. That's more like it! -//TODO: I really doubt this works anymore with the new connection system. This breaks the UDS scanner for now! ;( -void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVector& pFrames) +void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg) { QString result; uint32_t id; int offset = ui->spinReplyOffset->value(); - UDS_TESTS sentFrame; + UDS_MESSAGE sentFrame; bool gotReply = false; - if (pFrames.length() <= 0) return; - int numSending = sendingFrames.length(); if (numSending == 0) return; if (currIdx >= numSending) return; sentFrame = sendingFrames[currIdx]; - foreach(const CANFrame& thisFrame, pFrames) - { - if (currIdx >= numSending) return; - id = thisFrame.ID; + id = msg.ID; - if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) - { - //int temp = thisFrame.data[0] >> 4; - //if (temp == 0) //single frame reply (maybe) - //{ - if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].service) - { - result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " - + QString::number(sentFrame.service, 16) - + " " + QString::number(sentFrame.subFunc, 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.service, 16) - + " " + QString::number(sentFrame.subFunc, 16) + " with an error from ID " + QString::number(id, 16) - + " on bus " + QString::number(thisFrame.bus) + "."; - gotReply = true; - } + if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) + { + //int temp = thisFrame.data[0] >> 4; + //if (temp == 0) //single frame reply (maybe) + //{ + if (msg.service == 0x40 + sendingFrames[currIdx].service) + { + result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 16) + " with affirmation from ID " + QString::number(id, 16) + + " on bus " + QString::number(msg.bus) + "."; + gotReply = true; + } + else if ( msg.service == 0x7F) + { + result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 16) + " with an error from ID " + QString::number(id, 16) + + " on bus " + QString::number(msg.bus) + "."; + gotReply = true; + } //} /* if (temp == 1) //start of a multiframe reply @@ -226,7 +221,7 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVector @@ -10,14 +11,6 @@ namespace Ui { class UDSScanWindow; } -struct UDS_TESTS -{ - int ID; - int bus; - int service; - int subFunc; -}; - class UDSScanWindow : public QDialog { Q_OBJECT @@ -28,7 +21,7 @@ public: private slots: void updatedFrames(int numFrames); - void rapidFrames(const CANConnection* conn, const QVector& pFrames); + void gotUDSReply(UDS_MESSAGE &msg); void scanUDS(); void saveResults(); void timeOut(); @@ -37,12 +30,12 @@ private: Ui::UDSScanWindow *ui; const QVector *modelFrames; QTimer *waitTimer; - QList sendingFrames; + QList sendingFrames; int currIdx = 0; bool currentlyRunning; void sendNextMsg(); - void sendOnBuses(UDS_TESTS frame, int buses); + void sendOnBuses(UDS_MESSAGE frame, int buses); }; #endif // UDSSCANWINDOW_H From 341df5df2dfb784fa19275d0e8b7fba1df5e7b96 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sat, 20 May 2017 21:33:12 -0400 Subject: [PATCH 7/9] More implementation of UDS scanner - now output is colored and in tree format. --- bus_protocols/isotp_handler.cpp | 9 +- bus_protocols/uds_handler.cpp | 156 ++++++++++++---------- bus_protocols/uds_handler.h | 1 + re/udsscanwindow.cpp | 196 +++++++++++++++++++++------- re/udsscanwindow.h | 11 +- ui/udsscanwindow.ui | 220 ++++++++++++++++++++++++++------ 6 files changed, 438 insertions(+), 155 deletions(-) diff --git a/bus_protocols/isotp_handler.cpp b/bus_protocols/isotp_handler.cpp index dde42ba..67a6148 100644 --- a/bus_protocols/isotp_handler.cpp +++ b/bus_protocols/isotp_handler.cpp @@ -55,8 +55,9 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector data) frame.bus = bus; frame.extended = false; frame.ID = ID; - frame.len = data.length() + 1; - frame.data[0] = frame.len - 1; + frame.len = 8; + for (int b = 0; b < 8; b++) frame.data[b] = 0xAA; + frame.data[0] = data.length(); for (int i = 0; i < frame.data[0]; i++) frame.data[i + 1] = data[i]; CANConManager::getInstance()->sendFrame(frame); } @@ -66,18 +67,20 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector data) frame.ID = ID; frame.extended = false; frame.len = 8; + for (int b = 0; b < 8; b++) frame.data[b] = 0xAA; frame.data[0] = 0x10 + (data.length() / 256); frame.data[1] = data.length() & 0xFF; for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++]; CANConManager::getInstance()->sendFrame(frame); while (currByte < data.length()) { + for (int b = 0; b < 8; b++) frame.data[b] = 0xAA; frame.data[0] = 0x20 + index; index = (index + 1) & 0xF; int bytesToGo = data.length() - currByte; if (bytesToGo > 7) bytesToGo = 7; for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++]; - frame.len = 1 + bytesToGo; + frame.len = 8; CANConManager::getInstance()->sendFrame(frame); } } diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index 0e30bd7..438517c 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -56,70 +56,70 @@ QVector UDS_SERVICE_DESC = { QVector 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"}, + {0x10, "GENERAL_REJECT", "General rejection (no other codes matched)"}, + {0x11, "SERVICE_NOTSUPP", "ECU does not support this service code"}, + {0x12, "SUBFUNCT_NOTSUPP", "ECU does not support the requested sub function"}, + {0x13, "INVALID_FORMAT", "Invalid request length or format error"}, + {0x14, "RESPONSE_TOOLONG", "Response would be too long to send"}, + {0x21, "BUSY", "ECU is busy. Try again later"}, + {0x22, "COND_INCORR", "A prereq. condition was not met"}, + {0x24, "REQ_SEQ_ERR", "Invalid sequence of requests"}, + {0x25, "SUBNET_NORESP", "ECU tried to gateway request but response timed out"}, + {0x26, "FAILURE", "A failure (indicated in a DTC) is preventing a reply"}, + {0x31, "REQ_OUTOFRANGE", "A parameter is outside of the valid range"}, + {0x33, "SECURITY_DENIED", "Security access was denied. (invalid seq or ECU not unlocked?)"}, + {0x35, "INVALID_KEY", "Key passed was invalid. Failure counter has been incremented."}, + {0x36, "EXCEED_ATTEMPTS", "Key failed too many times. ECU security access locked out"}, + {0x37, "TIMEDELAY", "Security access too soon after last attempt"}, + {0x38, "EXT_SECUR_1", "Extended security failure code 1"}, + {0x39, "EXT_SECUR_2", "Extended security failure code 2"}, + {0x3A, "EXT_SECUR_3", "Extended security failure code 3"}, + {0x3B, "EXT_SECUR_4", "Extended security failure code 4"}, + {0x3C, "EXT_SECUR_5", "Extended security failure code 5"}, + {0x3D, "EXT_SECUR_6", "Extended security failure code 6"}, + {0x3E, "EXT_SECUR_7", "Extended security failure code 7"}, + {0x3F, "EXT_SECUR_8", "Extended security failure code 8"}, + {0x40, "EXT_SECUR_9", "Extended security failure code 9"}, + {0x41, "EXT_SECUR_10", "Extended security failure code 10"}, + {0x42, "EXT_SECUR_11", "Extended security failure code 11"}, + {0x43, "EXT_SECUR_12", "Extended security failure code 12"}, + {0x44, "EXT_SECUR_13", "Extended security failure code 13"}, + {0x45, "EXT_SECUR_14", "Extended security failure code 14"}, + {0x46, "EXT_SECUR_15", "Extended security failure code 15"}, + {0x47, "EXT_SECUR_16", "Extended security failure code 16"}, + {0x48, "EXT_SECUR_17", "Extended security failure code 17"}, + {0x49, "EXT_SECUR_18", "Extended security failure code 18"}, + {0x4A, "EXT_SECUR_19", "Extended security failure code 19"}, + {0x4B, "EXT_SECUR_20", "Extended security failure code 20"}, + {0x4C, "EXT_SECUR_21", "Extended security failure code 21"}, + {0x4D, "EXT_SECUR_22", "Extended security failure code 22"}, + {0x4E, "EXT_SECUR_23", "Extended security failure code 23"}, + {0x4F, "EXT_SECUR_24", "Extended security failure code 24"}, + {0x70, "UPLOAD_DOWNLOAD", "Fault when attempting to start upload/download"}, + {0x71, "TRX_SUSPENDED", "Transfer aborting due to a fault"}, + {0x72, "GEN_PROGRAMMING", "Fault while attempting to write to ECU memory"}, + {0x73, "WRONG_BLOCK_SEQ", "Invalid sequence value detected during transfer"}, + {0x78, "RESP_PENDING", "Request successful but ECU still busy - Response pending"}, + {0x7E, "SUBFUNCT_CURRSESS", "ECU does not support this subfunction in current session type"}, + {0x7F, "SERVICE_CURRSESS", "ECU does not support this service in current session type"}, + {0x81, "RPM_TOOHIGH", "RPM is too high to execute request"}, + {0x82, "RPM_TOOLOW", "RPM is too low to execute request"}, + {0x83, "ENGINE_RUNNING", "Cannot execute request while engine is running"}, + {0x84, "ENGINE_NOTRUNNING", "Cannot execute request while engine is off"}, + {0x85, "ENG_RUNTIME_LOW", "Cannot execute request until engine has run for longer"}, + {0x86, "TEMPERATURE_HIGH", "Cannot execute request until temperature is lower"}, + {0x87, "TEMPERATURE_LOW", "Cannot execute request until temperature is higher"}, + {0x88, "SPEED_HIGH", "Cannot execute request until vehicle slows down"}, + {0x89, "SPEED_LOW", "Cannot execute request until vehicle is going faster"}, + {0x8A, "PEDAL_HIGH", "Cannot execute request until throttle is lower"}, + {0x8B, "PEDAL_LOW", "Cannot execute request until throttle is higher"}, + {0x8C, "NOT_NEUTRAL", "Cannot execute request until transmission is in neutral"}, + {0x8D, "NOT_INGEAR", "Cannot execute request until vehicle is in gear"}, + {0x8F, "BRAKE_NOTPRESSED", "Cannot execute request until brake pedal is pressed (Hold down)"}, + {0x90, "NOT_PARK", "Cannot execute request until vehicle is in park"}, + {0x91, "CLUTCH_LOCKED", "Cannot execute request while clutch is locked"}, + {0x92, "VOLTAGE_HIGH", "Cannot execute request until voltage is lower"}, + {0x93, "VOLTAGE_LOW", "Cannot execute request until voltage is higher"}, }; UDS_HANDLER* UDS_HANDLER::mInstance = NULL; @@ -152,9 +152,29 @@ void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg) udsMsg.timestamp = msg.timestamp; udsMsg.actualSize = msg.actualSize; udsMsg.len = msg.len; - udsMsg.service = msg.data.at(0); - udsMsg.subFunc = msg.data.at(1); - udsMsg.data = msg.data.mid(1, -1); //don't copy data[0] which was service number + if (msg.data.length() > 0) { + udsMsg.service = msg.data.at(0); + if (udsMsg.service == 0x7F) + { + udsMsg.isErrorReply = true; + if (msg.data.length() > 1) + { + udsMsg.service = msg.data.at(1); + if (msg.data.length() > 2) udsMsg.subFunc = msg.data.at(2); + else return; + } + else return; + udsMsg.data = msg.data.mid(2, -1); //don't copy error byte nor service byte + } + else + { + udsMsg.isErrorReply = false; + if (msg.data.length() > 1) udsMsg.subFunc = msg.data.at(1); + udsMsg.data = msg.data.mid(1, -1); //don't copy service byte + } + } + else return; + emit newUDSMessage(udsMsg); } @@ -207,6 +227,7 @@ QString UDS_HANDLER::getServiceShortDesc(int service) foreach (CODE_STRUCT code, UDS_SERVICE_DESC) { if (code.code == service) return code.shortDesc; + if (code.code == (service + 0x40)) return code.shortDesc; } return QString(); } @@ -216,6 +237,7 @@ QString UDS_HANDLER::getServiceLongDesc(int service) foreach (CODE_STRUCT code, UDS_SERVICE_DESC) { if (code.code == service) return code.longDesc; + if (code.code == (service + 0x40)) return code.longDesc; } return QString(); } diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h index 62b01b7..1d625aa 100644 --- a/bus_protocols/uds_handler.h +++ b/bus_protocols/uds_handler.h @@ -73,6 +73,7 @@ class UDS_MESSAGE: public ISOTP_MESSAGE public: int service; int subFunc; + bool isErrorReply; }; class UDS_HANDLER : public QObject diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index ee2f187..dd70cd6 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -3,6 +3,7 @@ #include "mainwindow.h" #include "connections/canconmanager.h" #include "bus_protocols/uds_handler.h" +#include "utility.h" UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -24,6 +25,9 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); + connect(ui->ckWildcard, &QCheckBox::toggled, this, &UDSScanWindow::wildcardToggled); + connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled); + connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged())); int numBuses = CANConManager::getInstance()->getNumBuses(); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); @@ -37,6 +41,40 @@ UDSScanWindow::~UDSScanWindow() delete waitTimer; } +void UDSScanWindow::adaptiveToggled() +{ + if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false); + else ui->spinReplyOffset->setEnabled(true); +} + +void UDSScanWindow::wildcardToggled() +{ + bool state = false; + if (ui->ckWildcard->isChecked()) state = false; + else state = true; + + ui->ckReset->setEnabled(state); + ui->ckSecurity->setEnabled(state); + ui->ckSession->setEnabled(state); + ui->ckTester->setEnabled(state); + ui->ckReset->setChecked(false); + ui->ckSecurity->setChecked(false); + ui->ckSession->setChecked(false); + ui->ckTester->setChecked(false); + + ui->spinLowerService->setEnabled(!state); + ui->spinLowerSubfunc->setEnabled(!state); + ui->spinNumBytes->setEnabled(!state); + ui->spinUpperService->setEnabled(!state); + ui->spinUpperSubfunc->setEnabled(!state); +} + +void UDSScanWindow::numBytesChanged() +{ + uint64_t upperBound = (1 << (8 * ui->spinNumBytes->value())) - 1; + ui->spinUpperSubfunc->setMaximum(upperBound); +} + void UDSScanWindow::saveResults() { QString filename; @@ -63,18 +101,25 @@ void UDSScanWindow::saveResults() delete outFile; return; } + outFile->write("UDS Scan Log:\n\n"); + dumpNode(ui->treeResults->invisibleRootItem(), outFile, 0); - for (int i = 0; i < ui->listResults->count(); i++) - { - outFile->write(ui->listResults->item(i)->text().toUtf8()); - outFile->write("\n"); - } outFile->close(); delete outFile; } } } +void UDSScanWindow::dumpNode(QTreeWidgetItem* item, QFile *file, int indent) +{ + if (indent > 0) for (int i = 0; i < (indent - 1); i++) file->write("\t"); + file->write(item->text(0).toUtf8()); + file->write("\n"); + for( int i = 0; i < item->childCount(); ++i ) + dumpNode( item->child(i), file, indent + 1 ); + if (indent == 1) file->write("\n"); +} + void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses) { int busList = buses; @@ -106,20 +151,29 @@ void UDSScanWindow::scanUDS() waitTimer->setInterval(ui->spinDelay->value()); - ui->listResults->clear(); + ui->treeResults->clear(); sendingFrames.clear(); + nodeService = NULL; + nodeID = NULL; + nodeSubFunc = NULL; UDS_MESSAGE test; int typ, id; int startID, endID; startID = Utility::ParseStringToNum(ui->txtStartID->text()); endID = Utility::ParseStringToNum(ui->txtEndID->text()); + if (endID < startID) { + int temp = startID; + startID = endID; + endID = temp; + } int buses = ui->cbBuses->currentIndex(); for (id = startID; id <= endID; id++) { test.ID = id; + test.data.clear(); if (ui->ckTester->isChecked()) { @@ -148,6 +202,34 @@ void UDSScanWindow::scanUDS() test.subFunc = 1; sendOnBuses(test, buses); } + if (ui->ckWildcard->isChecked()) + { + int numBytes = ui->spinNumBytes->value(); + + //preallocate the whole buffer so we don't have to keep updating the size and moving as we go. + //TODO: this shows a downside to the current method - it might potentially need to create a huge + //number of frames here. Of course, the rest of the system will do the same so I guess it's a bad idea + //any way you go to generate a 1 billion frame test. + int size = (endID - startID) * (ui->spinUpperService->value() - ui->spinLowerService->value()); + size *= (ui->spinUpperSubfunc->value() - ui->spinLowerSubfunc->value()); + sendingFrames.reserve(size); + + for (typ = ui->spinLowerService->value(); typ <= ui->spinUpperService->value(); typ++) + { + test.service = typ; + for (int subTyp = ui->spinLowerSubfunc->value(); subTyp <= ui->spinUpperSubfunc->value(); subTyp++) + { + test.data.clear(); + //multi-byte data sent big endian (largest value byte first) so plan accordingly. + test.subFunc = subTyp >> (8 * (numBytes - 1)); + for (int by = 1; by < numBytes; by++) + { + test.data.append(subTyp >> (8 * (numBytes - by))); + } + sendOnBuses(test, buses); + } + } + } } waitTimer->start(); @@ -174,6 +256,7 @@ void UDSScanWindow::updatedFrames(int numFrames) void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg) { QString result; + QString serviceShortName; uint32_t id; int offset = ui->spinReplyOffset->value(); UDS_MESSAGE sentFrame; @@ -188,54 +271,78 @@ void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg) if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) { - //int temp = thisFrame.data[0] >> 4; - //if (temp == 0) //single frame reply (maybe) - //{ - if (msg.service == 0x40 + sendingFrames[currIdx].service) - { - result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " - + QString::number(sentFrame.service, 16) - + " " + QString::number(sentFrame.subFunc, 16) + " with affirmation from ID " + QString::number(id, 16) - + " on bus " + QString::number(msg.bus) + "."; - gotReply = true; - } - else if ( msg.service == 0x7F) - { - result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " - + QString::number(sentFrame.service, 16) - + " " + QString::number(sentFrame.subFunc, 16) + " with an error from ID " + QString::number(id, 16) - + " on bus " + QString::number(msg.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. - } */ + serviceShortName = UDS_HANDLER::getInstance()->getServiceShortDesc(sentFrame.service); + if (serviceShortName.length() < 3) serviceShortName = QString::number(sentFrame.service, 16); + if (msg.service == 0x40 + sendingFrames[currIdx].service) + { + setupNodes(); + QTreeWidgetItem *nodePositive = new QTreeWidgetItem(); + QString reply = "POSITIVE "; + for (int i = 0; i < msg.data.length(); i++) + { + reply.append(" "); + reply.append(Utility::formatHexNum(msg.data[i])); + } + nodePositive->setText(0, reply); + nodePositive->setForeground(0, QBrush(Qt::darkGreen)); + nodeSubFunc->addChild(nodePositive); + nodeSubFunc->setForeground(0, QBrush(Qt::darkGreen)); + gotReply = true; + } + else if ( msg.service == 0x7F) + { + setupNodes(); + QTreeWidgetItem *nodeNegative = new QTreeWidgetItem(); + nodeNegative->setText(0, "NEGATIVE - " + UDS_HANDLER::getInstance()->getNegativeResponseShort(msg.data[1])); + nodeNegative->setForeground(0, QBrush(Qt::darkRed)); + nodeSubFunc->addChild(nodeNegative); + nodeSubFunc->setForeground(0, QBrush(Qt::darkRed)); + gotReply = true; + } } if (gotReply) { - ui->listResults->addItem(result); + //ui->listResults->addItem(result); sendNextMsg(); } } +void UDSScanWindow::setupNodes() +{ + QString serviceShortName = UDS_HANDLER::getInstance()->getServiceShortDesc(sendingFrames[currIdx].service); + if (serviceShortName.length() < 3) serviceShortName = QString::number(sendingFrames[currIdx].service, 16); + + if (!nodeID || nodeID->text(0) != Utility::formatHexNum(sendingFrames[currIdx].ID)) + { + nodeID = new QTreeWidgetItem(); + nodeID->setText(0, Utility::formatHexNum(sendingFrames[currIdx].ID)); + ui->treeResults->addTopLevelItem(nodeID); + nodeService = NULL; + } + if (!nodeService || nodeService->text(0) != serviceShortName) + { + nodeService = new QTreeWidgetItem(); + nodeService->setText(0, serviceShortName); + nodeID->addChild(nodeService); + } + + nodeSubFunc = new QTreeWidgetItem(); + nodeSubFunc->setText(0, Utility::formatHexNum(sendingFrames[currIdx].subFunc)); + nodeService->addChild(nodeSubFunc); +} + void UDSScanWindow::timeOut() { - QString result; - 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].service, 16) + " " + QString::number(sendingFrames[currIdx].subFunc, 16); - ui->listResults->addItem(result); + if (ui->ckShowNoReply->isChecked()) + { + setupNodes(); + QTreeWidgetItem *nodeNoReply = new QTreeWidgetItem(); + nodeNoReply->setText(0, "No Reply"); + nodeNoReply->setForeground(0, QBrush(Qt::gray)); + nodeSubFunc->addChild(nodeNoReply); + nodeSubFunc->setForeground(0, QBrush(Qt::gray)); + } sendNextMsg(); } @@ -249,6 +356,7 @@ void UDSScanWindow::sendNextMsg() { data.clear(); data.append(sendingFrames[currIdx].subFunc); + data.append(sendingFrames[currIdx].data); UDS_HANDLER::getInstance()->sendUDSFrame(sendingFrames[currIdx].bus, sendingFrames[currIdx].ID, sendingFrames[currIdx].service, data); waitTimer->start(); } diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index ff412b8..30b0709 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -6,6 +6,8 @@ #include "bus_protocols/uds_handler.h" #include +#include +#include namespace Ui { class UDSScanWindow; @@ -25,17 +27,24 @@ private slots: void scanUDS(); void saveResults(); void timeOut(); + void adaptiveToggled(); + void wildcardToggled(); + void numBytesChanged(); private: Ui::UDSScanWindow *ui; const QVector *modelFrames; QTimer *waitTimer; QList sendingFrames; + QTreeWidgetItem *nodeID; + QTreeWidgetItem *nodeService; + QTreeWidgetItem *nodeSubFunc; int currIdx = 0; bool currentlyRunning; void sendNextMsg(); void sendOnBuses(UDS_MESSAGE frame, int buses); + void setupNodes(); + void dumpNode(QTreeWidgetItem* item, QFile *file, int indent); }; - #endif // UDSSCANWINDOW_H diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index ab19fcd..99ac0bd 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -22,7 +22,16 @@ - + + + false + + + + 1 + + + @@ -69,6 +78,13 @@ + + + + Show Tests with no Replies + + + @@ -102,45 +118,6 @@ - - - - - - Scan Types: - - - - - - - Tester Present - - - - - - - Session Control - - - - - - - ECU Reset - - - - - - - Security Access - - - - - @@ -178,6 +155,169 @@ + + + + + + Scan Types: + + + + + + + Tester Present + + + + + + + Session Control + + + + + + + ECU Reset + + + + + + + Security Access + + + + + + + Wildcard + + + + + + + + + + + Lower Service: + + + + + + + false + + + 255 + + + 16 + + + + + + + Upper Service: + + + + + + + false + + + 255 + + + 255 + + + 16 + + + + + + + + + + + Subfunction Bytes: + + + + + + + false + + + 1 + + + 4 + + + 1 + + + + + + + Lower Bound: + + + + + + + false + + + 255 + + + 16 + + + + + + + Upper Bound: + + + + + + + false + + + 255 + + + 255 + + + 16 + + + + + From 72589c7760dd7ca97e59aedf13e31a2d819f0b64 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 21 May 2017 17:28:20 -0400 Subject: [PATCH 8/9] Preliminaries for new UDS modes, added code to ensure lower and upper bounds are respected on UDS window. --- re/udsscanwindow.cpp | 58 ++++++++++++++++++++++++++++++++++++++------ re/udsscanwindow.h | 4 +++ ui/udsscanwindow.ui | 52 +++++++++++++++++++++++++++++++++------ 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index dd70cd6..4ff3f1d 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -26,12 +26,19 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : connect(waitTimer, &QTimer::timeout, this, &UDSScanWindow::timeOut); connect(ui->btnSaveResults, &QPushButton::clicked, this, &UDSScanWindow::saveResults); connect(ui->ckWildcard, &QCheckBox::toggled, this, &UDSScanWindow::wildcardToggled); + connect(ui->ckReadByAddr, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled); + connect(ui->ckReadByID, &QCheckBox::toggled, this, &UDSScanWindow::readByToggled); connect(ui->cbAllowAdaptiveOffset, &QCheckBox::toggled, this, &UDSScanWindow::adaptiveToggled); connect(ui->spinNumBytes, SIGNAL(valueChanged(int)), this, SLOT(numBytesChanged())); + connect(ui->spinLowerService, SIGNAL(valueChanged(int)), this, SLOT(checkServiceRange())); + connect(ui->spinUpperService, SIGNAL(valueChanged(int)), this, SLOT(checkServiceRange())); + connect(ui->spinLowerSubfunc, SIGNAL(valueChanged(int)), this, SLOT(checkSubFuncRange())); + connect(ui->spinUpperSubfunc, SIGNAL(valueChanged(int)), this, SLOT(checkSubFuncRange())); + connect(ui->spinStartID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange())); + connect(ui->spinEndID, SIGNAL(valueChanged(int)), this, SLOT(checkIDRange())); int numBuses = CANConManager::getInstance()->getNumBuses(); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); - ui->cbBuses->addItem(tr("All")); } UDSScanWindow::~UDSScanWindow() @@ -57,10 +64,14 @@ void UDSScanWindow::wildcardToggled() ui->ckSecurity->setEnabled(state); ui->ckSession->setEnabled(state); ui->ckTester->setEnabled(state); + ui->ckReadByAddr->setEnabled(state); + ui->ckReadByID->setEnabled(state); ui->ckReset->setChecked(false); ui->ckSecurity->setChecked(false); ui->ckSession->setChecked(false); ui->ckTester->setChecked(false); + ui->ckReadByAddr->setChecked(false); + ui->ckReadByID->setChecked(false); ui->spinLowerService->setEnabled(!state); ui->spinLowerSubfunc->setEnabled(!state); @@ -69,12 +80,43 @@ void UDSScanWindow::wildcardToggled() ui->spinUpperSubfunc->setEnabled(!state); } +void UDSScanWindow::readByToggled() +{ + bool state = false; + if (ui->ckReadByAddr->isChecked() || ui->ckReadByID->isChecked()) state = true; + else state = false; + + ui->spinLowerService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(state); + ui->spinNumBytes->setEnabled(state); + ui->spinUpperService->setEnabled(false); + ui->spinUpperSubfunc->setEnabled(state); +} + void UDSScanWindow::numBytesChanged() { uint64_t upperBound = (1 << (8 * ui->spinNumBytes->value())) - 1; ui->spinUpperSubfunc->setMaximum(upperBound); } +void UDSScanWindow::checkIDRange() +{ + ui->spinStartID->setMaximum(ui->spinEndID->value()); + ui->spinEndID->setMinimum(ui->spinStartID->value()); +} + +void UDSScanWindow::checkServiceRange() +{ + ui->spinLowerService->setMaximum(ui->spinUpperService->value()); + ui->spinUpperService->setMinimum(ui->spinLowerService->value()); +} + +void UDSScanWindow::checkSubFuncRange() +{ + ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value()); + ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value()); +} + void UDSScanWindow::saveResults() { QString filename; @@ -123,19 +165,19 @@ void UDSScanWindow::dumpNode(QTreeWidgetItem* item, QFile *file, int indent) void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses) { int busList = buses; - if (busList < ui->cbBuses->count() - 1) - { + //if (busList < ui->cbBuses->count() - 1) + //{ test.bus = buses; sendingFrames.append(test); - } - else + //} + /*else { for (int c = 0; c < ui->cbBuses->count() - 1; c++) { test.bus = c; sendingFrames.append(test); } - } + }*/ } void UDSScanWindow::scanUDS() @@ -160,8 +202,8 @@ void UDSScanWindow::scanUDS() UDS_MESSAGE test; int typ, id; int startID, endID; - startID = Utility::ParseStringToNum(ui->txtStartID->text()); - endID = Utility::ParseStringToNum(ui->txtEndID->text()); + startID = ui->spinStartID->value(); + endID = ui->spinEndID->value(); if (endID < startID) { int temp = startID; startID = endID; diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 30b0709..33bea56 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -29,7 +29,11 @@ private slots: void timeOut(); void adaptiveToggled(); void wildcardToggled(); + void readByToggled(); void numBytesChanged(); + void checkIDRange(); + void checkServiceRange(); + void checkSubFuncRange(); private: Ui::UDSScanWindow *ui; diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index 99ac0bd..4f51117 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -52,9 +52,18 @@ - - - 0x7E0 + + + 0x + + + 536870911 + + + 2016 + + + 16 @@ -70,9 +79,18 @@ - - - 0x7E7 + + + 0x + + + 536870911 + + + 2024 + + + 16 @@ -123,7 +141,7 @@ - Buses to scan + Bus to scan @@ -174,7 +192,7 @@ - Session Control + Session Ctrl @@ -192,6 +210,24 @@ + + + + + + + + Read By ID + + + + + + + Read By Addr + + + From e3bb44f61b1dd19a594ed7e2d76584698131be84 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 21 May 2017 19:44:26 -0400 Subject: [PATCH 9/9] More implementation of UDS code, bug fixes to UDS, addition of progress bar for UDS --- bus_protocols/uds_handler.cpp | 28 ++++++++------ bus_protocols/uds_handler.h | 4 +- connections/canconnection.cpp | 2 +- re/udsscanwindow.cpp | 70 +++++++++++++++++++++++------------ ui/udsscanwindow.ui | 18 ++++++++- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index 438517c..112eb06 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -122,6 +122,15 @@ QVector UDS_NEG_RESPONSE = {0x93, "VOLTAGE_LOW", "Cannot execute request until voltage is higher"}, }; +UDS_MESSAGE::UDS_MESSAGE() +{ + subFunc = 0; + service = 0; + subFuncLen = 1; + extended = false; + isErrorReply = false; +} + UDS_HANDLER* UDS_HANDLER::mInstance = NULL; UDS_HANDLER* UDS_HANDLER::getInstance() @@ -198,27 +207,22 @@ void UDS_HANDLER::setReception(bool mode) } } -void UDS_HANDLER::sendUDSFrame(int bus, int ID, int service, QVector payload) -{ - QVector data; - if (bus < 0) return; - if (bus >= CANConManager::getInstance()->getNumBuses()) return; - if (service < 0 || service > 0xFF) return; - data.append(service); - data.append(payload); - ISOTP_HANDLER::getInstance()->sendISOTPFrame(bus, ID, data); - qDebug() << "Sent UDS service: " << getServiceShortDesc(service) << " on bus " << bus; -} - void UDS_HANDLER::sendUDSFrame(const UDS_MESSAGE &msg) { QVector data; if (msg.bus < 0) return; if (msg.bus >= CANConManager::getInstance()->getNumBuses()) return; if (msg.service < 0 || msg.service > 0xFF) return; + data.append(msg.service); + for (int b = msg.subFuncLen - 1; b >= 0; b--) + { + data.append((msg.subFunc >> (8 * b)) & 0xFF); + } + data.append(msg.data); ISOTP_HANDLER::getInstance()->sendISOTPFrame(msg.bus, msg.ID, data); + qDebug() << "Sent UDS service: " << getServiceShortDesc(msg.service) << " on bus " << msg.bus; } diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h index 1d625aa..8e745a3 100644 --- a/bus_protocols/uds_handler.h +++ b/bus_protocols/uds_handler.h @@ -73,7 +73,10 @@ class UDS_MESSAGE: public ISOTP_MESSAGE public: int service; int subFunc; + int subFuncLen; bool isErrorReply; + + UDS_MESSAGE(); }; class UDS_HANDLER : public QObject @@ -85,7 +88,6 @@ public: void setExtendedAddressing(bool mode); static UDS_HANDLER* getInstance(); void setReception(bool mode); //set whether to accept and forward frames or not - void sendUDSFrame(int bus, int ID, int service, QVector payload); void sendUDSFrame(const UDS_MESSAGE &msg); QString getServiceShortDesc(int service); QString getServiceLongDesc(int service); diff --git a/connections/canconnection.cpp b/connections/canconnection.cpp index cdfb748..4f8905e 100644 --- a/connections/canconnection.cpp +++ b/connections/canconnection.cpp @@ -343,7 +343,7 @@ bool CANConnection::removeAllTargettedFrames(QObject *receiver) void CANConnection::checkTargettedFrame(CANFrame &frame) { unsigned int maskedID; - qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus; + //qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus; foreach (const CANFlt filt, mBusData_p[frame.bus].mTargettedFrames) { qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask; diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 4ff3f1d..8d241fa 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -223,6 +223,7 @@ void UDSScanWindow::scanUDS() test.subFunc = 0; sendOnBuses(test, buses); } + if (ui->ckSession->isChecked()) { for (typ = 1; typ < 4; typ++) //try each type of session access @@ -232,22 +233,45 @@ void UDSScanWindow::scanUDS() sendOnBuses(test, buses); } } + if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;) { test.service = UDS_SERVICES::ECU_RESET; test.subFunc = 1; sendOnBuses(test, buses); } + if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. { test.service = UDS_SERVICES::SECURITY_ACCESS; test.subFunc = 1; sendOnBuses(test, buses); } + + if (ui->ckReadByAddr->isChecked()) + { + test.subFuncLen = ui->spinNumBytes->value(); + test.service = UDS_SERVICES::READ_BY_ADDR; + for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++) + { + test.subFunc = subf; + sendOnBuses(test, buses); + } + } + + if (ui->ckReadByID->isChecked()) + { + test.subFuncLen = ui->spinNumBytes->value(); + test.service = UDS_SERVICES::READ_BY_ID; + for (int subf = ui->spinLowerSubfunc->value(); subf <= ui->spinUpperSubfunc->value(); subf++) + { + test.subFunc = subf; + sendOnBuses(test, buses); + } + } + if (ui->ckWildcard->isChecked()) { - int numBytes = ui->spinNumBytes->value(); - //preallocate the whole buffer so we don't have to keep updating the size and moving as we go. //TODO: this shows a downside to the current method - it might potentially need to create a huge //number of frames here. Of course, the rest of the system will do the same so I guess it's a bad idea @@ -256,18 +280,14 @@ void UDSScanWindow::scanUDS() size *= (ui->spinUpperSubfunc->value() - ui->spinLowerSubfunc->value()); sendingFrames.reserve(size); + test.subFuncLen = ui->spinNumBytes->value(); + for (typ = ui->spinLowerService->value(); typ <= ui->spinUpperService->value(); typ++) { test.service = typ; for (int subTyp = ui->spinLowerSubfunc->value(); subTyp <= ui->spinUpperSubfunc->value(); subTyp++) { - test.data.clear(); - //multi-byte data sent big endian (largest value byte first) so plan accordingly. - test.subFunc = subTyp >> (8 * (numBytes - 1)); - for (int by = 1; by < numBytes; by++) - { - test.data.append(subTyp >> (8 * (numBytes - by))); - } + test.subFunc = subTyp; sendOnBuses(test, buses); } } @@ -278,6 +298,8 @@ void UDSScanWindow::scanUDS() currIdx = -1; currentlyRunning = true; ui->btnScan->setText("Abort Scan"); + ui->progressBar->setValue(0); + ui->progressBar->setMaximum(sendingFrames.length()); sendNextMsg(); } @@ -311,6 +333,8 @@ void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg) id = msg.ID; + qDebug() << "UDS message ID " << msg.ID << " service: " << msg.service << " subfunc: " << msg.subFunc; + if ((id == (uint32_t)(sentFrame.ID + offset)) || ui->cbAllowAdaptiveOffset->isChecked()) { serviceShortName = UDS_HANDLER::getInstance()->getServiceShortDesc(sentFrame.service); @@ -332,15 +356,19 @@ void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg) nodeSubFunc->setForeground(0, QBrush(Qt::darkGreen)); gotReply = true; } - else if ( msg.service == 0x7F) + else if ( msg.isErrorReply && msg.service == sendingFrames[currIdx].service) { - setupNodes(); - QTreeWidgetItem *nodeNegative = new QTreeWidgetItem(); - nodeNegative->setText(0, "NEGATIVE - " + UDS_HANDLER::getInstance()->getNegativeResponseShort(msg.data[1])); - nodeNegative->setForeground(0, QBrush(Qt::darkRed)); - nodeSubFunc->addChild(nodeNegative); - nodeSubFunc->setForeground(0, QBrush(Qt::darkRed)); - gotReply = true; + if (msg.data.length()) + { + setupNodes(); + QTreeWidgetItem *nodeNegative = new QTreeWidgetItem(); + qDebug() << ui->spinNumBytes->value(); + nodeNegative->setText(0, "NEGATIVE - " + UDS_HANDLER::getInstance()->getNegativeResponseShort(msg.data[0])); + nodeNegative->setForeground(0, QBrush(Qt::darkRed)); + nodeSubFunc->addChild(nodeNegative); + nodeSubFunc->setForeground(0, QBrush(Qt::darkRed)); + gotReply = true; + } } } if (gotReply) @@ -391,15 +419,10 @@ void UDSScanWindow::timeOut() void UDSScanWindow::sendNextMsg() { - QVector data; - currIdx++; if (currIdx < sendingFrames.count()) { - data.clear(); - data.append(sendingFrames[currIdx].subFunc); - data.append(sendingFrames[currIdx].data); - UDS_HANDLER::getInstance()->sendUDSFrame(sendingFrames[currIdx].bus, sendingFrames[currIdx].ID, sendingFrames[currIdx].service, data); + UDS_HANDLER::getInstance()->sendUDSFrame(sendingFrames[currIdx]); waitTimer->start(); } else @@ -408,4 +431,5 @@ void UDSScanWindow::sendNextMsg() ui->btnScan->setText("Start Scan"); currentlyRunning = false; } + ui->progressBar->setValue(currIdx); } diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index 4f51117..c305706 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -87,7 +87,7 @@ 536870911 - 2024 + 2023 16 @@ -101,6 +101,9 @@ Show Tests with no Replies + + true + @@ -116,6 +119,9 @@ + + false + -128 @@ -132,6 +138,9 @@ Allow adaptive reply offset + + true + @@ -354,6 +363,13 @@ + + + + 0 + + +