From 03776b6ad750e03ebaefb8fd1ee912255b4e8410 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 12 Oct 2017 20:09:22 -0400 Subject: [PATCH] Some bug fixes, much more work on ISOTP/UDS decoder window. --- bus_protocols/isotp_handler.cpp | 8 ++--- bus_protocols/uds_handler.cpp | 38 +++++++++++--------- canframemodel.cpp | 20 +++++------ re/isotp_interpreterwindow.cpp | 63 +++++++++++++++++++++++++++++---- re/isotp_interpreterwindow.h | 5 +++ ui/isotp_interpreterwindow.ui | 21 ++++++++--- utility.cpp | 4 ++- utility.h | 12 +++++++ 8 files changed, 128 insertions(+), 43 deletions(-) diff --git a/bus_protocols/isotp_handler.cpp b/bus_protocols/isotp_handler.cpp index 38a4caa..a376e1d 100644 --- a/bus_protocols/isotp_handler.cpp +++ b/bus_protocols/isotp_handler.cpp @@ -124,7 +124,7 @@ void ISOTP_HANDLER::rapidFrames(const CANConnection* conn, const QVectorlen <= pMsg->data.count()) { - qDebug() << "Emitting multiframe ISOTP message"; + //qDebug() << "Emitting multiframe ISOTP message"; emit newISOMessage(*pMsg); } break; @@ -298,7 +298,7 @@ void ISOTP_HANDLER::checkNeedFlush(uint64_t ID) if (messageBuffer[i].ID == ID) { //used to pass by reference but now newISOMessage should pass by value which makes it easier to use cross thread - qDebug() << "Flushing a partial frame"; + //qDebug() << "Flushing a partial frame"; emit newISOMessage(messageBuffer[i]); messageBuffer.removeAt(i); return; diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index fd997d1..86f7551 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -320,7 +320,13 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) QString buildString; bool isResponse = true; - if (msg.service < 0x3F || (msg.service > 0x7F && msg.service < 0xAF)) { + if (msg.isErrorReply) + { + isResponse = true; + buildString.append("UDS ERROR Response\n"); + buildString.append("Service: " + getServiceLongDesc(msg.service) + "\n"); + } + else if (msg.service < 0x3F || (msg.service > 0x7F && msg.service < 0xAF)) { isResponse = false; buildString.append("UDS Request\n"); buildString.append("Service: " + getServiceLongDesc(msg.service) + "\n"); @@ -328,7 +334,7 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) else { isResponse = true; - buildString.append("UDS Response\n"); + buildString.append("UDS Positive Response\n"); buildString.append("Service: " + getServiceLongDesc(msg.service - 0x40) + "\n"); } @@ -348,16 +354,16 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) case UDS_SERVICES::DIAG_CONTROL + 0x40: //positive response buildString.append("Session Request: " + getLongDesc(UDS_DIAG_CTRL_SUB, msg.subFunc)); //there should be four extra bytes now - if (msg.data.length() < 4) + if (msg.data.length() < 5) //5 because subfunc codes are left in data so it starts with one subfunc byte { //buildString.append("\nReturned data payload wasn't at least \n4 bytes like it should have been"); } else { - int p2 = msg.data[0] * 256 + msg.data[1]; - buildString.append("\nP2MAX: " + QString::number(p2)); - p2 = msg.data[2] * 256 + msg.data[3]; - buildString.append("\nP2*MAX: " + QString::number(p2)); + int p2 = msg.data[1] * 256 + msg.data[2]; + buildString.append("\nP2MAX: " + QString::number(p2) + "ms"); + p2 = (msg.data[3] * 256 + msg.data[4]) * 10; + buildString.append("\nP2*MAX: " + QString::number(p2) + "ms"); } break; case UDS_SERVICES::ECU_RESET: @@ -367,11 +373,11 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) case UDS_SERVICES::ECU_RESET + 0x40: buildString.append("Reset Type: " + getLongDesc(UDS_ECU_RESET_SUB, msg.subFunc)); //There should be one additional byte which encodes power down time - if (msg.data.length() > 0) + if (msg.data.length() > 1) { - if (msg.data[0] < 0xFF) + if (msg.data[1] < 0xFF) { - buildString.append("\nMinimum powered down time: " + QString::number(msg.data[0])); + buildString.append("\nMinimum powered down time: " + QString::number(msg.data[1])); } else buildString.append("\nPowerdown time not available"); } @@ -385,19 +391,19 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) if ((msg.subFunc % 2) == 1) { buildString.append("Seed request for security level: " + QString::number(msg.subFunc) + "\n"); - if (msg.data.length()> 0) + if (msg.data.length()> 1) { buildString.append("Data payload: "); - for (int j = 0; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); + for (int j = 1; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); } } else { buildString.append("Key sending for security level: " + QString::number(msg.subFunc - 1)); - if (msg.data.length()> 0) //and it sure as hell should be! + if (msg.data.length()> 1) //and it sure as hell should be! { buildString.append("KEY: "); - for (int j = 0; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); + for (int j = 1; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); } } break; @@ -405,10 +411,10 @@ QString UDS_HANDLER::getDetailedMessageAnalysis(const UDS_MESSAGE &msg) if ((msg.subFunc % 2) == 1) { buildString.append("Seed response for security level: " + QString::number(msg.subFunc) + "\n"); - if (msg.data.length()> 0) //be kinda pointless if it weren't + if (msg.data.length()> 1) //be kinda pointless if it weren't { buildString.append("SEED: "); - for (int j = 0; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); + for (int j = 1; j < msg.data.length(); j++) buildString.append(Utility::formatHexNum(msg.data[j]) + " "); } } else diff --git a/canframemodel.cpp b/canframemodel.cpp index f146066..e1a9548 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -85,20 +85,20 @@ void CANFrameModel::setHexMode(bool mode) void CANFrameModel::setSecondsMode(bool mode) { - if (timeSeconds != mode) + if (Utility::secondsMode != mode) { this->beginResetModel(); - timeSeconds = mode; + Utility::secondsMode = mode; this->endResetModel(); } } void CANFrameModel::setSysTimeMode(bool mode) { - if (useSystemTime != mode) + if (Utility::sysTimeMode != mode) { this->beginResetModel(); - useSystemTime = mode; + Utility::sysTimeMode = mode; this->endResetModel(); } } @@ -117,7 +117,7 @@ void CANFrameModel::setInterpetMode(bool mode) void CANFrameModel::setTimeFormat(QString format) { - timeFormat = format; + Utility::timeFormat = format; beginResetModel(); //reset model to show new time format endResetModel(); } @@ -127,6 +127,10 @@ void CANFrameModel::normalizeTiming() mutex.lock(); if (frames.count() == 0) return; timeOffset = frames[0].timestamp; + for (int j = 0; j < frames.count(); j++) + { + if (frames[j].timestamp < timeOffset) timeOffset = frames[j].timestamp; + } for (int i = 0; i < frames.count(); i++) { frames[i].timestamp -= timeOffset; @@ -256,11 +260,7 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const switch (index.column()) { case 0: //timestamp - if (!useSystemTime) { - if (!timeSeconds) return QString::number(thisFrame.timestamp); - else return QString::number((double)thisFrame.timestamp / 1000000.0, 'f', 6); - } - else return QDateTime::fromMSecsSinceEpoch(thisFrame.timestamp / 1000).toString(timeFormat); + return Utility::formatTimestamp(thisFrame.timestamp); break; case 1: //id return Utility::formatNumber(thisFrame.ID); diff --git a/re/isotp_interpreterwindow.cpp b/re/isotp_interpreterwindow.cpp index 70bac8c..4d166f8 100644 --- a/re/isotp_interpreterwindow.cpp +++ b/re/isotp_interpreterwindow.cpp @@ -21,6 +21,10 @@ ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector *frames connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames); connect(decoder, &ISOTP_HANDLER::newISOMessage, this, &ISOTP_InterpreterWindow::newISOMessage); connect(udsDecoder, &UDS_HANDLER::newUDSMessage, this, &ISOTP_InterpreterWindow::newUDSMessage); + connect(ui->listFilter, &QListWidget::itemChanged, this, &ISOTP_InterpreterWindow::listFilterItemChanged); + connect(ui->btnAll, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::filterAll); + connect(ui->btnNone, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::filterNone); + connect(ui->btnCaptured, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::interpretCapturedFrames); connect(ui->tableIsoFrames, &QTableWidget::itemSelectionChanged, this, &ISOTP_InterpreterWindow::showDetailView); connect(ui->btnClearList, &QPushButton::clicked, this, &ISOTP_InterpreterWindow::clearList); @@ -83,24 +87,60 @@ void ISOTP_InterpreterWindow::writeSettings() } } +//erase current list then repopulate as if all the previously captured frames just came in again. +void ISOTP_InterpreterWindow::interpretCapturedFrames() +{ + clearList(); + decoder->rapidFrames(NULL, *modelFrames); +} + +void ISOTP_InterpreterWindow::listFilterItemChanged(QListWidgetItem *item) +{ + if (item) + { + int id = item->text().toInt(NULL, 16); + bool state = item->checkState(); + //qDebug() << id << "*" << state; + idFilters[id] = state; + } +} + +void ISOTP_InterpreterWindow::filterAll() +{ + for (int i = 0 ; i < ui->listFilter->count(); i++) + { + ui->listFilter->item(i)->setCheckState(Qt::Checked); + idFilters[ui->listFilter->item(1)->text().toInt(NULL, 16)] = true; + } +} + +void ISOTP_InterpreterWindow::filterNone() +{ + for (int i = 0 ; i < ui->listFilter->count(); i++) + { + ui->listFilter->item(i)->setCheckState(Qt::Unchecked); + idFilters[ui->listFilter->item(1)->text().toInt(NULL, 16)] = false; + } +} + void ISOTP_InterpreterWindow::clearList() { qDebug() << "Clearing the table"; - while (ui->tableIsoFrames->rowCount() > 0) - ui->tableIsoFrames->removeRow(0); + ui->tableIsoFrames->clearContents(); + ui->tableIsoFrames->model()->removeRows(0, ui->tableIsoFrames->rowCount()); + messages.clear(); + //idFilters.clear(); } void ISOTP_InterpreterWindow::updatedFrames(int numFrames) { if (numFrames == -1) //all frames deleted. Kill the display { - messages.clear(); - ui->tableIsoFrames->clear(); + clearList(); } else if (numFrames == -2) //all new set of frames. Reset { - messages.clear(); - ui->tableIsoFrames->clear(); + clearList(); } else //just got some new frames. See if they are relevant. { @@ -174,12 +214,21 @@ void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE msg) if ((msg.len != msg.data.count()) && !ui->cbShowIncomplete->isChecked()) return; + if (idFilters.find(msg.ID) == idFilters.end()) + { + idFilters.insert(msg.ID, true); + + QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(msg.ID), ui->listFilter); + listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag + listItem->setCheckState(Qt::Checked); + } + if (!idFilters[msg.ID]) return; messages.append(msg); rowNum = ui->tableIsoFrames->rowCount(); ui->tableIsoFrames->insertRow(rowNum); - ui->tableIsoFrames->setItem(rowNum, 0, new QTableWidgetItem(QString::number(msg.timestamp))); + ui->tableIsoFrames->setItem(rowNum, 0, new QTableWidgetItem(Utility::formatTimestamp(msg.timestamp))); ui->tableIsoFrames->setItem(rowNum, 1, new QTableWidgetItem(QString::number(msg.ID, 16))); ui->tableIsoFrames->setItem(rowNum, 2, new QTableWidgetItem(QString::number(msg.bus))); if (msg.isReceived) ui->tableIsoFrames->setItem(rowNum, 3, new QTableWidgetItem("Rx")); diff --git a/re/isotp_interpreterwindow.h b/re/isotp_interpreterwindow.h index b0861fa..3ec1f4c 100644 --- a/re/isotp_interpreterwindow.h +++ b/re/isotp_interpreterwindow.h @@ -26,6 +26,10 @@ private slots: void showDetailView(); void updatedFrames(int); void clearList(); + void listFilterItemChanged(QListWidgetItem *item); + void filterAll(); + void filterNone(); + void interpretCapturedFrames(); private: Ui::ISOTP_InterpreterWindow *ui; @@ -34,6 +38,7 @@ private: const QVector *modelFrames; QVector messages; + QHash idFilters; void closeEvent(QCloseEvent *event); void readSettings(); diff --git a/ui/isotp_interpreterwindow.ui b/ui/isotp_interpreterwindow.ui index d1e955d..cb6e353 100644 --- a/ui/isotp_interpreterwindow.ui +++ b/ui/isotp_interpreterwindow.ui @@ -25,11 +25,22 @@ - - - Clear Messages List - - + + + + + Interpret Previously Captured Frames + + + + + + + Clear Messages List + + + + diff --git a/utility.cpp b/utility.cpp index a11db36..fa1bf06 100644 --- a/utility.cpp +++ b/utility.cpp @@ -1,4 +1,6 @@ #include "utility.h" bool Utility::decimalMode = false; - +bool Utility::secondsMode = true; +bool Utility::sysTimeMode = false; +QString Utility::timeFormat = "MMM-dd HH:mm:ss.zzz"; diff --git a/utility.h b/utility.h index fd81b29..552e6eb 100644 --- a/utility.h +++ b/utility.h @@ -12,6 +12,9 @@ class Utility public: static bool decimalMode; + static bool secondsMode; + static bool sysTimeMode; + static QString timeFormat; static QString unQuote(QString inStr) { @@ -104,6 +107,15 @@ public: return output; } + static QString formatTimestamp(uint64_t timestamp) + { + if (!sysTimeMode) { + if (!secondsMode) return QString::number(timestamp); + else return QString::number((double)timestamp / 1000000.0, 'f', 6); + } + else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000).toString(timeFormat); + } + //parses the input string to grab as much of it as possible while staying alpha numeric static QString grabAlphaNumeric(QString &input) {