From 61b49c9126bc69c73d904bbd0f47e920a59a784a Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Tue, 4 Oct 2022 19:54:55 -0400 Subject: [PATCH] Changed the UDS Scan window quite a bit. Now there are more options for scan types and the ability to create a list of scans to run. --- re/udsscanwindow.cpp | 691 +++++++++++++++++++++++++++++++--------- re/udsscanwindow.h | 61 +++- ui/udsscanwindow.ui | 733 ++++++++++++++++++++++++------------------- 3 files changed, 1010 insertions(+), 475 deletions(-) diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 630ccab..69d6d51 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -6,6 +6,23 @@ #include "utility.h" #include "helpwindow.h" + +static QVector SCANTYPE_NAMES = { + QString("Tester Present"), + QString("Session Control"), + QString("Communication Control"), + QString("ECU Reset"), + QString("Clear DTCs"), + QString("Read DTCs"), + QString("Security Access"), + QString("Read By ID"), + QString("Read By Address"), + QString("Read Scaling Data By ID"), + QString("IO Control"), + QString("Routine Control"), + QString("Custom UDS"), +}; + UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), ui(new Ui::UDSScanWindow) @@ -21,15 +38,23 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : waitTimer->setInterval(100); udsHandler = new UDS_HANDLER; + inhibitUpdates = false; + + for (int i = 0; i < 13; i++) ui->cbScanType->addItem(SCANTYPE_NAMES[i]); + + ui->cbSessType->addItem("No Change"); + ui->cbSessType->addItem("Default"); + ui->cbSessType->addItem("Programming"); + ui->cbSessType->addItem("Extended Diag"); + ui->cbSessType->addItem("Safety Sys Diag"); connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); connect(udsHandler, &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply); - connect(ui->btnScan, &QPushButton::clicked, this, &UDSScanWindow::scanUDS); + connect(ui->btnScanAll, &QPushButton::clicked, this, &UDSScanWindow::scanAll); + connect(ui->btnScanSelected, &QPushButton::clicked, this, &UDSScanWindow::scanSelected); 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->cbScanType, &QComboBox::currentTextChanged, this, &UDSScanWindow::changedScanType); 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())); @@ -38,10 +63,23 @@ UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : 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())); + connect(ui->btnAdd, &QPushButton::clicked, this, &UDSScanWindow::addNewScan); + connect(ui->btnDelete, &QPushButton::clicked, this, &UDSScanWindow::deleteSelectedScan); + connect(ui->btnSave, &QPushButton::clicked, this, &UDSScanWindow::saveScans); + connect(ui->btnLoad, &QPushButton::clicked, this, &UDSScanWindow::loadScans); + connect(ui->listScansToRun, &QListWidget::currentRowChanged, this, &UDSScanWindow::displayScanEntry); + connect(ui->ckShowNoReply, &QCheckBox::toggled, this, &UDSScanWindow::setNoReplyVal); + connect(ui->spinDelay, SIGNAL(valueChanged(int)), this, SLOT(setMaxDelayVal())); + connect(ui->spinIncrement, SIGNAL(valueChanged(int)), this, SLOT(setIncrementVal())); + connect(ui->spinReplyOffset, SIGNAL(valueChanged(int)), this, SLOT(setReplyOffset())); + connect(ui->cbSessType, &QComboBox::currentTextChanged, this, &UDSScanWindow::setSessType); +//not handling show no reply, max reply delay, reply offset, increment int numBuses = CANConManager::getInstance()->getNumBuses(); for (int n = 0; n < numBuses; n++) ui->cbBuses->addItem(QString::number(n)); installEventFilter(this); + + addNewScan(); } UDSScanWindow::~UDSScanWindow() @@ -71,74 +109,368 @@ bool UDSScanWindow::eventFilter(QObject *obj, QEvent *event) return false; } +void UDSScanWindow::displayScanEntry(int idx) +{ + if (inhibitUpdates) return; + if (idx == -1) return; + currEditEntry = &scanEntries.data()[idx]; + ui->spinStartID->setValue(currEditEntry->startID); + ui->spinEndID->setValue(currEditEntry->endID); + ui->spinReplyOffset->setValue(currEditEntry->idOffset); + ui->cbAllowAdaptiveOffset->setChecked(currEditEntry->bAdaptiveOffset); + ui->ckShowNoReply->setChecked(currEditEntry->bShowNoReplies); + ui->cbBuses->setCurrentIndex(currEditEntry->busToScan); + ui->spinDelay->setValue(currEditEntry->maxWaitTime); + ui->cbScanType->setCurrentIndex((int)currEditEntry->scanType); + ui->cbSessType->setCurrentIndex(currEditEntry->sessType); + ui->spinNumBytes->setValue(currEditEntry->subfunctLen); + ui->spinLowerService->setValue(currEditEntry->serviceLower); + ui->spinUpperService->setValue(currEditEntry->serviceUpper); + ui->spinLowerSubfunc->setValue(currEditEntry->subfunctLower); + ui->spinUpperSubfunc->setValue(currEditEntry->subfunctUpper); + ui->spinIncrement->setValue(currEditEntry->subfunctIncrement); +} + +void UDSScanWindow::deleteSelectedScan() +{ + int idx = ui->listScansToRun->currentRow(); + if (idx == -1) return; + scanEntries.removeAt(idx); + + QListWidgetItem *item = ui->listScansToRun->takeItem(idx); + delete item; + int rows = ui->listScansToRun->count(); + ui->listScansToRun->setCurrentRow(rows - 1); + + for (int i = 0; i < rows; i++) + { + QListWidgetItem *item = ui->listScansToRun->item(i); + item->setText(generateListDesc(i)); + } +} + +void UDSScanWindow::addNewScan() +{ + ScanEntry newEntry; + newEntry.busToScan = 0; + newEntry.scanType = SCAN_TYPE::ST_TESTER_PRESENT; + newEntry.sessType = 0; + newEntry.bAdaptiveOffset = false; + newEntry.bShowNoReplies = false; + newEntry.idOffset = 8; + newEntry.startID = 0x7E0; + newEntry.endID = 0x7E7; + newEntry.maxWaitTime = 100; + newEntry.subfunctLen = 1; + newEntry.subfunctIncrement = 1; + newEntry.subfunctLower = 0; + newEntry.subfunctUpper = 0; + newEntry.serviceLower = 1; + newEntry.serviceUpper = 1; + scanEntries.append(newEntry); + displayScanEntry(scanEntries.length() - 1); + ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1)); + ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1); +} + +void UDSScanWindow::loadScans() +{ + QString filename; + QFileDialog dialog(qApp->activeWindow()); + QSettings settings; + bool result = false; + + QStringList filters; + filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)"))); + + dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.setViewMode(QFileDialog::Detail); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + + if (dialog.exec() == QDialog::Accepted) + { + filename = dialog.selectedFiles()[0]; + QFile inFile(filename); + inFile.open(QIODevice::ReadOnly); + QDataStream load(&inFile); + int fileVersion; + load >> fileVersion; + if (fileVersion != 1) + { + QMessageBox::warning(this, "Cannot Load File", "File is not a supported version.\nCannot load it!"); + return; + } + inhibitUpdates = true;; + scanEntries.clear(); + ui->listScansToRun->clear(); + int numEntries; + load >> numEntries; + for (int i = 0; i < numEntries; i++) + { + ScanEntry entry; + load >> entry.startID >> entry.endID; + load >> entry.idOffset >> entry.bAdaptiveOffset >> entry.bShowNoReplies; + load >> entry.busToScan >> entry.maxWaitTime >> entry.scanType; + load >> entry.sessType >> entry.subfunctLen >> entry.subfunctLower; + load >> entry.subfunctUpper >> entry.subfunctIncrement; + load >> entry.serviceLower >> entry.serviceUpper; + scanEntries.append(entry); + ui->listScansToRun->addItem(generateListDesc(scanEntries.length() - 1)); + } + inFile.close(); + inhibitUpdates = false; + ui->listScansToRun->setCurrentRow(ui->listScansToRun->count() - 1); + displayScanEntry(scanEntries.length() - 1); + } +} + +void UDSScanWindow::saveScans() +{ + QString filename; + QFileDialog dialog(qApp->activeWindow()); + QSettings settings; + bool result = false; + + QStringList filters; + filters.append(QString(tr("UDS Test Specification (*.uds *.UDS)"))); + + dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString()); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.setViewMode(QFileDialog::Detail); + dialog.setAcceptMode(QFileDialog::AcceptSave); + + if (dialog.exec() == QDialog::Accepted) + { + filename = dialog.selectedFiles()[0]; + QFile outFile(filename); + outFile.open(QIODevice::WriteOnly); + QDataStream save(&outFile); + save << 1; //file version + save << scanEntries.count(); + for (int i = 0; i < scanEntries.count(); i++) + { + save << scanEntries[i].startID; + save << scanEntries[i].endID; + save << scanEntries[i].idOffset; + save << scanEntries[i].bAdaptiveOffset; + save << scanEntries[i].bShowNoReplies; + save << scanEntries[i].busToScan; + save << scanEntries[i].maxWaitTime; + save << scanEntries[i].scanType; + save << scanEntries[i].sessType; + save << scanEntries[i].subfunctLen; + save << scanEntries[i].subfunctLower; + save << scanEntries[i].subfunctUpper; + save << scanEntries[i].subfunctIncrement; + save << scanEntries[i].serviceLower; + save << scanEntries[i].serviceUpper; + } + outFile.close(); + } +} + +QString UDSScanWindow::generateListDesc(int idx) +{ + QString builder; + ScanEntry entry = scanEntries[idx]; + builder = "(0x" + QString::number(entry.startID, 16) + " - 0x" + QString::number(entry.endID, 16) + ") "; + switch (entry.scanType) + { + case ST_TESTER_PRESENT: + builder += "TP"; + break; + case ST_SESS_CTRL: + builder += "SESS"; + break; + case ST_COMM_CTRL: + builder += "COMM"; + break; + case ST_ECU_RESET: + builder += "ECU"; + break; + case ST_CLEAR_DTC: + builder += "CDTC"; + break; + case ST_READ_DTC: + builder += "RDTC"; + break; + case ST_SEC_ACCESS: + builder += "SECU"; + break; + case ST_READ_ID: + builder += "RID"; + break; + case ST_READ_ADDR: + builder += "RADD"; + break; + case ST_READ_SCALING: + builder += "RSCAL"; + break; + case ST_IO_CTRL: + builder += "IO"; + break; + case ST_ROUTINE_CTRL: + builder += "ROUT"; + break; + case ST_CUSTOM: + builder += "CUST"; + break; + } + return builder; +} + void UDSScanWindow::adaptiveToggled() { + if (inhibitUpdates) return; if (ui->cbAllowAdaptiveOffset->isChecked()) ui->spinReplyOffset->setEnabled(false); else ui->spinReplyOffset->setEnabled(true); + if (currEditEntry) currEditEntry->bAdaptiveOffset = ui->cbAllowAdaptiveOffset->isChecked(); } -void UDSScanWindow::wildcardToggled() +void UDSScanWindow::setSessType() { - 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->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); - ui->spinNumBytes->setEnabled(!state); - ui->spinUpperService->setEnabled(!state); - ui->spinUpperSubfunc->setEnabled(!state); + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->sessType = ui->cbSessType->currentIndex(); } -void UDSScanWindow::readByToggled() +void UDSScanWindow::setNoReplyVal() { - bool state = false; - if (ui->ckReadByAddr->isChecked() || ui->ckReadByID->isChecked()) state = true; - else state = false; + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->bShowNoReplies = ui->ckShowNoReply->isChecked(); +} - ui->spinLowerService->setEnabled(false); - ui->spinLowerSubfunc->setEnabled(state); - ui->spinNumBytes->setEnabled(state); - ui->spinUpperService->setEnabled(false); - ui->spinUpperSubfunc->setEnabled(state); +void UDSScanWindow::setMaxDelayVal() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->maxWaitTime = ui->spinDelay->value(); +} + +void UDSScanWindow::setIncrementVal() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->subfunctIncrement = ui->spinIncrement->value(); +} + +void UDSScanWindow::setReplyOffset() +{ + if (inhibitUpdates) return; + if (currEditEntry) currEditEntry->idOffset = ui->spinReplyOffset->value(); +} + +void UDSScanWindow::changedScanType() +{ + if (inhibitUpdates) return; + int idx = ui->cbScanType->currentIndex(); + if (idx == -1) + { + ui->cbScanType->setCurrentIndex(0); + idx = 0; + } + + if (currEditEntry) currEditEntry->scanType = (SCAN_TYPE)idx; + + QListWidgetItem* item = ui->listScansToRun->currentItem(); + item->setText(generateListDesc(ui->listScansToRun->currentRow())); + + switch (idx) + { + case ST_TESTER_PRESENT: + case ST_SESS_CTRL: + ui->cbSessType->setEnabled(false); + ui->spinLowerService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinUpperSubfunc->setEnabled(false); + ui->spinNumBytes->setEnabled(false); + ui->spinIncrement->setEnabled(false); + ui->cbSessType->setCurrentIndex(0); + break; + case ST_COMM_CTRL: + case ST_ECU_RESET: + case ST_CLEAR_DTC: + case ST_SEC_ACCESS: + case ST_READ_DTC: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(false); + ui->spinUpperSubfunc->setEnabled(false); + ui->spinNumBytes->setEnabled(false); + ui->spinIncrement->setEnabled(false); + break; + case ST_IO_CTRL: + case ST_ROUTINE_CTRL: + case ST_READ_SCALING: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(false); + ui->spinNumBytes->setValue(2); + ui->spinIncrement->setEnabled(true); + break; + case ST_READ_ID: + case ST_READ_ADDR: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(false); + ui->spinUpperService->setEnabled(false); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(true); + ui->spinIncrement->setEnabled(true); + break; + case ST_CUSTOM: + ui->cbSessType->setEnabled(true); + ui->spinLowerService->setEnabled(true); + ui->spinUpperService->setEnabled(true); + ui->spinLowerSubfunc->setEnabled(true); + ui->spinUpperSubfunc->setEnabled(true); + ui->spinNumBytes->setEnabled(true); + ui->spinIncrement->setEnabled(true); + break; + } } void UDSScanWindow::numBytesChanged() { + if (inhibitUpdates) return; uint64_t upperBound = (1ull << (8ull * ui->spinNumBytes->value())) - 1; if (upperBound > 0x7FFFFFFF) upperBound = 0x7FFFFFFF; ui->spinUpperSubfunc->setMaximum(upperBound); + if (currEditEntry) currEditEntry->subfunctLen = ui->spinNumBytes->value(); } void UDSScanWindow::checkIDRange() { + if (inhibitUpdates) return; ui->spinStartID->setMaximum(ui->spinEndID->value()); ui->spinEndID->setMinimum(ui->spinStartID->value()); + if (currEditEntry) currEditEntry->startID = ui->spinStartID->value(); + if (currEditEntry) currEditEntry->endID = ui->spinEndID->value(); + QListWidgetItem* item = ui->listScansToRun->currentItem(); + item->setText(generateListDesc(ui->listScansToRun->currentRow())); } void UDSScanWindow::checkServiceRange() { + if (inhibitUpdates) return; ui->spinLowerService->setMaximum(ui->spinUpperService->value()); ui->spinUpperService->setMinimum(ui->spinLowerService->value()); + if (currEditEntry) currEditEntry->serviceLower = ui->spinLowerService->value(); + if (currEditEntry) currEditEntry->serviceUpper = ui->spinUpperService->value(); } void UDSScanWindow::checkSubFuncRange() { + if (inhibitUpdates) return; ui->spinLowerSubfunc->setMaximum(ui->spinUpperSubfunc->value()); ui->spinUpperSubfunc->setMinimum(ui->spinLowerSubfunc->value()); + if (currEditEntry) currEditEntry->subfunctLower = ui->spinLowerSubfunc->value(); + if (currEditEntry) currEditEntry->subfunctUpper = ui->spinUpperSubfunc->value(); } void UDSScanWindow::saveResults() @@ -196,20 +528,27 @@ void UDSScanWindow::sendOnBuses(UDS_MESSAGE test, int buses) sendingFrames.append(test); } -void UDSScanWindow::scanUDS() +void UDSScanWindow::scanAll() { - if (currentlyRunning) + sendingFrames.clear(); + for (int i = 0; i < scanEntries.count(); i++) { - waitTimer->stop(); - sendingFrames.clear(); - udsHandler->setReception(false); - udsHandler->setProcessAllIDs(false); - udsHandler->setFlowCtrl(false); - currentlyRunning = false; - ui->btnScan->setText("Start Scan"); - return; + setupScan(i); } + startScan(); +} +void UDSScanWindow::scanSelected() +{ + sendingFrames.clear(); + int idx = ui->listScansToRun->currentRow(); + if (idx < 0) return; + setupScan(idx); + startScan(); +} + +void UDSScanWindow::startScan() +{ udsHandler->setReception(true); udsHandler->setProcessAllIDs(true); udsHandler->setFlowCtrl(true); @@ -217,121 +556,173 @@ void UDSScanWindow::scanUDS() waitTimer->setInterval(ui->spinDelay->value()); ui->treeResults->clear(); - sendingFrames.clear(); nodeService = nullptr; nodeID = nullptr; nodeSubFunc = nullptr; - UDS_MESSAGE test; - int typ, id; - int startID, endID; - startID = ui->spinStartID->value(); - endID = ui->spinEndID->value(); - if (endID < startID) { - int temp = startID; - startID = endID; - endID = temp; - } - - int buses = ui->cbBuses->currentIndex(); - - for (id = startID; id <= endID; id++) - { - test.setFrameId( id ); - test.payload().clear(); - - if (ui->ckTester->isChecked()) - { - 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 - { - 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. ;) - { - for (typ = 1; typ < 4; typ++) //try each type of session access - { - test.service = UDS_SERVICES::ECU_RESET; - test.subFunc = typ; - sendOnBuses(test, buses); - } - } - - if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. - { - for (typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work - { - test.service = UDS_SERVICES::SECURITY_ACCESS; - test.subFunc = typ; - 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()) - { - //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); - - 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.subFunc = subTyp; - sendOnBuses(test, buses); - } - } - } - } - waitTimer->start(); currIdx = -1; currentlyRunning = true; - ui->btnScan->setText("Abort Scan"); + //ui->btnScan->setText("Abort Scan"); ui->progressBar->setValue(0); ui->progressBar->setMaximum(sendingFrames.length()); + qDebug() << "Number of operations: " << sendingFrames.length(); sendNextMsg(); } +void UDSScanWindow::stopScan() +{ + waitTimer->stop(); + sendingFrames.clear(); + udsHandler->setReception(false); + udsHandler->setProcessAllIDs(false); + udsHandler->setFlowCtrl(false); + currentlyRunning = false; + //ui->btnScan->setText("Start Scan"); +} + +void UDSScanWindow::setupScan(int idx) +{ + UDS_MESSAGE test; + + qDebug() << "Generating scan id: " << idx; + + for (uint32_t id = scanEntries[idx].startID; id <= scanEntries[idx].endID; id++) + { + test.setFrameId( id ); + + if (scanEntries[idx].sessType > 0) + { + test.payload().clear(); + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFuncLen = 1; + test.subFunc = scanEntries[ idx].sessType; + sendOnBuses(test, scanEntries[idx].busToScan); + } + + test.payload().clear(); + + qDebug() << "Generating scan on ID " << QString::number(id, 16) << " of type " << scanEntries[idx].scanType; + + switch (scanEntries[idx].scanType) + { + case ST_TESTER_PRESENT: + test.service = UDS_SERVICES::TESTER_PRESENT; + test.subFuncLen = 1; + test.subFunc = 0; + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_SESS_CTRL: + for (int typ = 1; typ < 4; typ++) //try each type of session access + { + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_COMM_CTRL: + test.service = UDS_SERVICES::COMM_CTRL; + test.subFuncLen = 2; //need two bytes for this one + test.subFunc = 0x100; //00 01 on the bus = enable Rx/Tx + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_ECU_RESET: + for (int typ = 1; typ < 4; typ++) //try each type of session access + { + test.service = UDS_SERVICES::ECU_RESET; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_CLEAR_DTC: + test.service = UDS_SERVICES::CLEAR_DIAG; + test.subFuncLen = 3; //DTC groups are sent as 3 bytes + test.subFunc = 0xFFFFFF; //clear everything! + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_READ_DTC: + test.service = UDS_SERVICES::READ_DTC; + test.subFuncLen = 2; + test.subFunc = 0x8702; //get DTCs by mask (87 is the mask) + sendOnBuses(test, scanEntries[idx].busToScan); + break; + case ST_SEC_ACCESS: + for (int typ = 1; typ < 0x42; typ = typ + 2) //try each type of session access. In practice only the first 1-3 are likely to work + { + test.service = UDS_SERVICES::SECURITY_ACCESS; + test.subFuncLen = 1; + test.subFunc = typ; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_ID: + test.subFuncLen = scanEntries[idx].subfunctLen; + test.service = UDS_SERVICES::READ_BY_ID; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_ADDR: + test.subFuncLen = scanEntries[idx].subfunctLen; + test.service = UDS_SERVICES::READ_BY_ADDR; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_READ_SCALING: + //sub function should always be a length of 2 though. Should conform to this in the GUI + test.subFuncLen = 2; + test.service = UDS_SERVICES::READ_SCALING_ID; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_IO_CTRL: + test.subFuncLen = 3; + test.service = UDS_SERVICES::IO_CTRL; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subf; //the upper byte will be 0 which is what we want. 0 = Return control to ECU + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_ROUTINE_CTRL: + test.subFuncLen = 3; + test.service = UDS_SERVICES::ROUTINE_CTRL; + for (int subf = scanEntries[idx].subfunctLower; subf <= scanEntries[idx].subfunctUpper; subf += scanEntries[idx].subfunctIncrement) + { + //request results of routine for all the addresses we're testing. This is the safest thing to do. + //starting or stopping arbitrary routines is super dangerous. Don't do that unless you really know + //what the hell you're doing or something really crazy might happen. + test.subFunc = (subf << 8) + 3; + sendOnBuses(test, scanEntries[idx].busToScan); + } + break; + case ST_CUSTOM: + test.subFuncLen = scanEntries[idx].subfunctLen; + + for (uint32_t typ = scanEntries[idx].serviceLower; typ <= scanEntries[idx].serviceUpper; typ++) + { + test.service = typ; + for (int subTyp = scanEntries[idx].subfunctLower; subTyp <= scanEntries[idx].subfunctUpper; subTyp += scanEntries[idx].subfunctIncrement) + { + test.subFunc = subTyp; + sendOnBuses(test, scanEntries[idx].busToScan); + } + } + break; + } + } +} + //Updates here are sent about every 1/4 second. That's fine for most windows but not this one. void UDSScanWindow::updatedFrames(int numFrames) { @@ -491,7 +882,7 @@ void UDSScanWindow::sendNextMsg() udsHandler->setReception(false); udsHandler->setProcessAllIDs(false); udsHandler->setFlowCtrl(false); - ui->btnScan->setText("Start Scan"); + //ui->btnScan->setText("Start Scan"); currentlyRunning = false; } ui->progressBar->setValue(currIdx); diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 9ec8745..ed50e01 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -9,6 +9,44 @@ #include #include + +enum SCAN_TYPE +{ + ST_TESTER_PRESENT, + ST_SESS_CTRL, + ST_COMM_CTRL, + ST_ECU_RESET, + ST_CLEAR_DTC, + ST_READ_DTC, + ST_SEC_ACCESS, + ST_READ_ID, + ST_READ_ADDR, + ST_READ_SCALING, + ST_IO_CTRL, + ST_ROUTINE_CTRL, + ST_CUSTOM, +}; + +//stores the parameters for one scan +class ScanEntry +{ +public: + uint32_t startID, endID; + int32_t idOffset; + bool bAdaptiveOffset; + bool bShowNoReplies; + uint32_t busToScan; + uint32_t maxWaitTime; //in milliseconds + SCAN_TYPE scanType; + uint32_t sessType; + uint32_t subfunctLen; + qint64 subfunctLower; + qint64 subfunctUpper; + uint32_t subfunctIncrement; + uint32_t serviceLower; + uint32_t serviceUpper; +}; + namespace Ui { class UDSScanWindow; } @@ -24,16 +62,25 @@ public: private slots: void updatedFrames(int numFrames); void gotUDSReply(UDS_MESSAGE msg); - void scanUDS(); + void scanAll(); + void scanSelected(); void saveResults(); void timeOut(); void adaptiveToggled(); - void wildcardToggled(); - void readByToggled(); + void changedScanType(); void numBytesChanged(); void checkIDRange(); void checkServiceRange(); void checkSubFuncRange(); + void deleteSelectedScan(); + void addNewScan(); + void loadScans(); + void saveScans(); + void setNoReplyVal(); + void setMaxDelayVal(); + void setIncrementVal(); + void setReplyOffset(); + void setSessType(); private: Ui::UDSScanWindow *ui; @@ -44,9 +91,17 @@ private: QTreeWidgetItem *nodeID; QTreeWidgetItem *nodeService; QTreeWidgetItem *nodeSubFunc; + QVector scanEntries; + ScanEntry *currEditEntry; int currIdx = 0; bool currentlyRunning; + bool inhibitUpdates; + void displayScanEntry(int idx); + QString generateListDesc(int idx); + void setupScan(int idx); + void startScan(); + void stopScan(); void sendNextMsg(); void sendOnBuses(UDS_MESSAGE frame, int buses); void setupNodes(uint32_t replyID); diff --git a/ui/udsscanwindow.ui b/ui/udsscanwindow.ui index cae150e..b9ad262 100644 --- a/ui/udsscanwindow.ui +++ b/ui/udsscanwindow.ui @@ -6,61 +6,346 @@ 0 0 - 742 - 628 + 1053 + 624 UDS Scanner - + - - - Results - - - - - - - false - - - - 1 - - - - - - - - Save Scan Results - - - - - + - + + + Scans To Run + + + + + + + + - + - Starting ID + Add - + + + Delete + + + + + + + + + + + Load + + + + + + + Save + + + + + + + + + + + + + + + + + Starting ID + + + + + + + 0x + + + 536870911 + + + 2016 + + + 16 + + + + + + + + + + + Ending ID + + + + + + + 0x + + + 536870911 + + + 2023 + + + 16 + + + + + + + + + + + Show "No Reply" + + + true + + + + + + + Allow adaptive reply offset + + + true + + + + + + + + + + + + + Bus to scan + + + + + + + + + + Maximum reply delay (ms) + + + + + + + 50 + + + 10000 + + + 10 + + + 100 + + + + + + + Reply Offset: + + + + + + + false + + + -128 + + + 128 + + + 8 + + + + + + + + + + + + 0 + 0 + + + + Scan Type: + + + + + + + + 0 + 0 + + + + + + + + Run test in session type: + + + + + + + false + + + + + + + + + + + + + + Subfunct Len: + + + + + + + false + + + 1 + + + 4 + + + 1 + + + + + + + Lower Bound: + + + + + + + false + 0x - 536870911 + 255 + + + 16 + + + + + + + Upper Bound: + + + + + + + false + + + 0x + + + 255 - 2016 + 255 + + + 16 + + + + + + + Increment + + + + + + + false + + + 0x + + + 1024 + + + 8 16 @@ -70,24 +355,50 @@ - + - + - Ending ID + Lower Service: - + + + false + 0x - 536870911 + 255 + + + 16 + + + + + + + Upper Service: + + + + + + + false + + + 0x + + + 255 - 2023 + 255 16 @@ -97,323 +408,101 @@ - - - Show Tests with no Replies + + + + 0 + 20 + - - true + + QFrame::Plain - - - - - - - - - - Reply Offset: - - - - - - - false - - - -128 - - - 128 - - - 8 - - - - - - - Allow adaptive reply offset - - - true - - - - - - - - - - - Bus to scan - - - - - - - - - - Maximum reply delay (ms) - - - - - - - 50 - - - 10000 - - - 10 - - - 100 - - - - - - - - - - - Scan Types: - - - - - - - Tester Present - - - - - - - Session Ctrl - - - - - - - ECU Reset - - - - - - - Security Access - - - - - - - - - - - Read By ID - - - - - - - Read By Addr - - - - - - - Wildcard - - - - - - - - - - - Lower Service: - - - - - - - false - - - 0x - - - 255 - - - 16 - - - - - - - Upper Service: - - - - - - - false - - - 0x - - - 255 - - - 255 - - - 16 - - - - - - - - - - - Subfunction Bytes: - - - - - - - false - - - 1 - - + 4 - - 1 + + Qt::Horizontal - + - Lower Bound: + Results + + + Qt::AlignCenter - + + + false + + + + 1 + + + + + + false - - 0x + + 0 - - 255 + + true - - 16 - - - - - - - Upper Bound: - - - - - - + false - - 0x - - - 255 - - - 255 - - - 16 + + + + + + + + Run All Scans + + + + + + + Run Selected Scan + + + + + + + + + Save Scan Results - - - - 0 - - - - - - - Start Scan - - - spinStartID spinEndID - ckShowNoReply - spinReplyOffset - cbAllowAdaptiveOffset cbBuses spinDelay - ckTester - ckSession - ckReset - ckSecurity - ckReadByID - ckReadByAddr - ckWildcard spinLowerService spinUpperService spinNumBytes spinLowerSubfunc spinUpperSubfunc - btnScan - treeResults - btnSaveResults