diff --git a/SavvyCAN.pro b/SavvyCAN.pro index d608800..15ea431 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -56,7 +56,6 @@ SOURCES += main.cpp\ framesenderwindow.cpp \ framefileio.cpp \ mainsettingsdialog.cpp \ - firmwareuploaderwindow.cpp \ scriptingwindow.cpp \ scriptcontainer.cpp \ canfilter.cpp \ @@ -104,6 +103,7 @@ SOURCES += main.cpp\ re/sniffer/SnifferDelegate.cpp \ connections/newconnectiondialog.cpp \ re/temporalgraphwindow.cpp \ + re/udsfirmwareuploaderwindow.cpp \ filterutility.cpp \ pcaplite.cpp @@ -151,7 +151,6 @@ HEADERS += mainwindow.h \ framefileio.h \ config.h \ mainsettingsdialog.h \ - firmwareuploaderwindow.h \ scriptingwindow.h \ scriptcontainer.h \ canfilter.h \ @@ -199,6 +198,7 @@ HEADERS += mainwindow.h \ re/sniffer/SnifferDelegate.h \ connections/newconnectiondialog.h \ re/temporalgraphwindow.h \ + re/udsfirmwareuploaderwindow.h \ filterutility.h \ pcaplite.h @@ -216,7 +216,6 @@ FORMS += ui/candatagrid.ui \ ui/dbcnodeeditor.ui \ ui/discretestatewindow.ui \ ui/filecomparatorwindow.ui \ - ui/firmwareuploaderwindow.ui \ ui/flowviewwindow.ui \ ui/frameinfowindow.ui \ ui/frameplaybackwindow.ui \ @@ -236,7 +235,8 @@ FORMS += ui/candatagrid.ui \ ui/signalviewerwindow.ui \ ui/helpwindow.ui \ ui/newconnectiondialog.ui \ - ui/temporalgraphwindow.ui + ui/temporalgraphwindow.ui \ + ui/udsfirmwareuploaderwindow.ui RESOURCES += \ icons.qrc \ diff --git a/firmwareuploaderwindow.cpp b/firmwareuploaderwindow.cpp deleted file mode 100644 index bc234e2..0000000 --- a/firmwareuploaderwindow.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "firmwareuploaderwindow.h" -#include "ui_firmwareuploaderwindow.h" -#include "mainwindow.h" - -#include - -//You might wonder: Collin, what in the hell is this for? Firmware uploader? For what? I'm interested! Well, it's a custom -//firmware uploader for a motor controller I built. Why would that be in this project. Cuz. It's not really relevant -//to anyone else but might serve as a decent reference for a few things: How to make an uploader interface that runs over CAN, -//how to lay out a screen like this, how to make a comm protocol for firmware updating over CAN. But, most things use UDS -//for firmware updates and wouldn't need this specific code. But, it might be able to be turned into a UDS firmware uploader or downloader. -//Note that this screen is specifically hidden by default because of it's oddball status. You have to re-enable it in mainwindow.cpp to see it. - -FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector *frames, QWidget *parent) : - QDialog(parent), - ui(new Ui::FirmwareUploaderWindow) -{ - ui->setupUi(this); - setWindowFlags(Qt::Window); - - transferInProgress = false; - startedProcess = false; - firmwareSize = 0; - currentSendingPosition = 0; - baseAddress = 0; - bus = 0; - modelFrames = frames; - - ui->lblFilename->setText(""); - ui->spinBus->setValue(0); - ui->spinBus->setMaximum(1); - ui->txtBaseAddr->setText("0x100"); - updateProgress(); - - timer = new QTimer(); - timer->setInterval(100); //100ms without a reply will cause us to attempt a resend - - connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); - connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(handleLoadFile())); - connect(ui->btnStartStop, SIGNAL(clicked(bool)), this, SLOT(handleStartStopTransfer())); - connect(timer, SIGNAL(timeout()), this, SLOT(timerElapsed())); -} - -FirmwareUploaderWindow::~FirmwareUploaderWindow() -{ - timer->stop(); - CANConManager::getInstance()->removeAllTargettedFrames(this); - delete timer; - delete ui; -} - -void FirmwareUploaderWindow::updateProgress() -{ - ui->lblProgress->setText(QString::number(currentSendingPosition * 4) + " of " + QString::number(firmwareSize) + " transferred"); -} - -void FirmwareUploaderWindow::updatedFrames(int numFrames) -{ - //CANFrame thisFrame; - if (numFrames == -1) //all frames deleted. - { - } - else if (numFrames == -2) //all new set of frames. - { - } - else //just got some new frames. See if they are relevant. - { - /* - //run through the supposedly new frames in order - for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++) - { - thisFrame = modelFrames->at(i); - } - */ - } -} - -void FirmwareUploaderWindow::gotTargettedFrame(CANFrame frame) -{ - const unsigned char *data = reinterpret_cast(frame.payload().constData()); - int dataLen = frame.payload().count(); - - qDebug() << "FUW: Got targetted frame with id " << frame.frameId(); - if (frame.frameId() == (uint32_t)(baseAddress + 0x10) && (dataLen == 8) ) { - qDebug() << "Start firmware reply"; - if ((data[0] == 0xAD) && (data[1] == 0xDE)) - { - if ((data[2] == 0xAF) && (data[3] == 0xDE)) - { - qDebug() << "There's dead beef here"; - if ( (data[4] == (token & 0xFF)) && (data[5] == ((token >> 8) & 0xFF) ) ) - { - if ((data[6] == ((token >> 16) & 0xFF)) && (data[7] == ((token >> 24) & 0xFF))) - { - qDebug() << "starting firmware process"; - //MainWindow::getReference()->setTargettedID(baseAddress + 0x20); - transferInProgress = true; - sendFirmwareChunk(); - } - } - } - } - } - - if (frame.frameId() == (uint32_t)(baseAddress + 0x20)) { - qDebug() << "Firmware reception success reply"; - int seq = data[0] + (256 * data[1]); - if (seq == currentSendingPosition) - { - currentSendingPosition++; - if (currentSendingPosition * 4 > firmwareSize || currentSendingPosition > 65535) - { - transferInProgress = false; - timer->stop(); - handleStartStopTransfer(); - ui->progressBar->setValue(100); - sendFirmwareEnding(); - } - else - { - ui->progressBar->setValue((400 * currentSendingPosition) / firmwareSize); - updateProgress(); - sendFirmwareChunk(); - } - } - } -} - -void FirmwareUploaderWindow::timerElapsed() -{ - sendFirmwareChunk(); //resend -} - -void FirmwareUploaderWindow::sendFirmwareChunk() -{ - CANFrame output; - int firmwareLocation = currentSendingPosition * 4; - int xorByte = 0; - output.setExtendedFrameFormat(false); - QByteArray bytes(7,0); - output.bus = bus; - output.setFrameId(baseAddress + 0x16); - bytes[0] = currentSendingPosition & 0xFF; - bytes[1] = (currentSendingPosition >> 8) & 0xFF; - bytes[2] = firmwareData[firmwareLocation++]; - bytes[3] = firmwareData[firmwareLocation++]; - bytes[4] = firmwareData[firmwareLocation++]; - bytes[5] = firmwareData[firmwareLocation++]; - for (int i = 0; i < 6; i++) xorByte ^= static_cast(bytes[i]); - bytes[6] = xorByte; - output.setPayload(bytes); - CANConManager::getInstance()->sendFrame(output); - timer->start(); -} - -void FirmwareUploaderWindow::sendFirmwareEnding() -{ - CANFrame output; - output.setExtendedFrameFormat(false); - output.bus = bus; - QByteArray bytes(4,0); - output.setFrameId(baseAddress + 0x30); - bytes[3] = (char)0xC0; - bytes[2] = (char)0xDE; - bytes[1] = (char)0xFA; - bytes[0] = (char)0xDE; - output.setPayload(bytes); - //sendCANFrame(output, bus); -} - -void FirmwareUploaderWindow::handleStartStopTransfer() -{ - startedProcess = !startedProcess; - - if (startedProcess) //start the process - { - ui->progressBar->setValue(0); - ui->btnStartStop->setText("Stop Upload"); - token = Utility::ParseStringToNum(ui->txtToken->text()); - bus = ui->spinBus->value(); - baseAddress = Utility::ParseStringToNum(ui->txtBaseAddr->text()); - qDebug() << "Base address: " + QString::number(baseAddress); - CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x10, 0x7FF, this); - CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x20, 0x7FF, this); - CANFrame output; - output.setExtendedFrameFormat(false); - QByteArray bytes(8,0); - output.bus = bus; - output.setFrameId(baseAddress); - output.setFrameType(QCanBusFrame::DataFrame); - - bytes[0] = (char)0xEF; - bytes[1] = (char)0xBE; - bytes[2] = (char)0xAD; - bytes[3] = (char)0xDE; - bytes[4] = token & 0xFF; - bytes[5] = (token >> 8) & 0xFF; - bytes[6] = (token >> 16) & 0xFF; - bytes[7] = (token >> 24) & 0xFF; - output.setPayload(bytes); - CANConManager::getInstance()->sendFrame(output); - } - else //stop anything in process - { - ui->btnStartStop->setText("Start Upload"); - CANConManager::getInstance()->removeAllTargettedFrames(this); - } -} - -void FirmwareUploaderWindow::handleLoadFile() -{ - QFileDialog dialog; - - QStringList filters; - filters.append(QString(tr("Raw firmware binary (*.bin)"))); - - dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilters(filters); - dialog.setViewMode(QFileDialog::Detail); - - if (dialog.exec() == QDialog::Accepted) - { - QString filename = dialog.selectedFiles().constFirst(); - - loadBinaryFile(filename); - } -} - -void FirmwareUploaderWindow::loadBinaryFile(QString filename) -{ - - if (transferInProgress) handleStartStopTransfer(); - - QFile inFile(filename); - - if (!inFile.open(QIODevice::ReadOnly)) - { - return; - } - - firmwareData = inFile.readAll(); - - currentSendingPosition = 0; - firmwareSize = firmwareData.length(); - - updateProgress(); - - inFile.close(); -} - diff --git a/firmwareuploaderwindow.h b/firmwareuploaderwindow.h deleted file mode 100644 index 5950735..0000000 --- a/firmwareuploaderwindow.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef FIRMWAREUPLOADERWINDOW_H -#define FIRMWAREUPLOADERWINDOW_H - -#include -#include -#include "can_structs.h" -#include "connections/canconmanager.h" -#include "utility.h" - -namespace Ui { -class FirmwareUploaderWindow; -} - -class FirmwareUploaderWindow : public QDialog -{ - Q_OBJECT - -public: - explicit FirmwareUploaderWindow(const QVector *frames, QWidget *parent = 0); - ~FirmwareUploaderWindow(); - -public slots: - void gotTargettedFrame(CANFrame frame); - -private slots: - void handleLoadFile(); - void handleStartStopTransfer(); - void updatedFrames(int); - void timerElapsed(); - -private: - void updateProgress(); - void loadBinaryFile(QString); - void sendFirmwareChunk(); - void sendFirmwareEnding(); - - Ui::FirmwareUploaderWindow *ui; - bool transferInProgress; - bool startedProcess; - int firmwareSize; - int currentSendingPosition; - int baseAddress; - int bus; - uint32_t token; - QByteArray firmwareData; - const QVector *modelFrames; - QTimer *timer; -}; - -#endif // FIRMWAREUPLOADERWINDOW_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 9e6fea3..b947534 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -80,7 +80,7 @@ MainWindow::MainWindow(QWidget *parent) : dbcMainEditor = nullptr; comparatorWindow = nullptr; settingsDialog = nullptr; - firmwareUploaderWindow = nullptr; + udsFirmwareUploaderWindow = nullptr; discreteStateWindow = nullptr; connectionWindow = nullptr; scriptingWindow = nullptr; @@ -126,7 +126,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionDBC_Comparison, &QAction::triggered, this, &MainWindow::showDBCComparisonWindow); connect(ui->actionScripting_INterface, &QAction::triggered, this, &MainWindow::showScriptingWindow); connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::showSettingsDialog); - connect(ui->actionFirmware_Update, &QAction::triggered, this, &MainWindow::showFirmwareUploaderWindow); + connect(ui->actionUDS_Firmware_Update, &QAction::triggered, this, &MainWindow::showUDSFirmwareUploaderWindow); connect(ui->actionDBC_File_Manager, &QAction::triggered, this, &MainWindow::showDBCFileWindow); connect(ui->actionFuzzing, &QAction::triggered, this, &MainWindow::showFuzzingWindow); connect(ui->actionUDS_Scanner, &QAction::triggered, this, &MainWindow::showUDSScanWindow); @@ -225,7 +225,7 @@ MainWindow::MainWindow(QWidget *parent) : //these either are unfinished/not working or are not for general use. But,they exist //so if you want to enable them and play with them then go for it. - ui->actionFirmware_Update->setVisible(false); + //ui->actionFirmware_Update->setVisible(false); ui->actionMotorControlConfig->setVisible(false); ui->actionSingle_Multi_State_2->setVisible(false); @@ -288,7 +288,7 @@ void MainWindow::killEmAll() killWindow(isoWindow); killWindow(snifferWindow); killWindow(bisectWindow); - killWindow(firmwareUploaderWindow); + killWindow(udsFirmwareUploaderWindow); killWindow(motorctrlConfigWindow); killWindow(signalViewerWindow); killWindow(temporalGraphWindow); @@ -1720,13 +1720,13 @@ void MainWindow::showPlaybackWindow() playbackWindow->show(); } -void MainWindow::showFirmwareUploaderWindow() +void MainWindow::showUDSFirmwareUploaderWindow() { - if (!firmwareUploaderWindow) + if (!udsFirmwareUploaderWindow) { - firmwareUploaderWindow = new FirmwareUploaderWindow(model->getListReference()); + udsFirmwareUploaderWindow = new UDSFirmwareUploaderWindow(model->getListReference()); } - firmwareUploaderWindow->show(); + udsFirmwareUploaderWindow->show(); } void MainWindow::showComparisonWindow() diff --git a/mainwindow.h b/mainwindow.h index 31df02c..faca6bc 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -20,7 +20,6 @@ #include "re/filecomparatorwindow.h" #include "dbc/dbcmaineditor.h" #include "mainsettingsdialog.h" -#include "firmwareuploaderwindow.h" #include "re/discretestatewindow.h" #include "scriptingwindow.h" #include "re/rangestatewindow.h" @@ -33,6 +32,7 @@ #include "signalviewerwindow.h" #include "re/temporalgraphwindow.h" #include "re/dbccomparatorwindow.h" +#include "re/udsfirmwareuploaderwindow.h" #include "canbridgewindow.h" class CANConnection; @@ -89,7 +89,7 @@ private slots: void showFuzzyScopeWindow(); void showComparisonWindow(); void showSettingsDialog(); - void showFirmwareUploaderWindow(); + void showUDSFirmwareUploaderWindow(); void showConnectionSettingsWindow(); void showScriptingWindow(); void showDBCFileWindow(); @@ -184,7 +184,7 @@ private: FileComparatorWindow *comparatorWindow; MainSettingsDialog *settingsDialog; DiscreteStateWindow *discreteStateWindow; - FirmwareUploaderWindow *firmwareUploaderWindow; + UDSFirmwareUploaderWindow *udsFirmwareUploaderWindow; ConnectionWindow *connectionWindow; ScriptingWindow *scriptingWindow; RangeStateWindow *rangeWindow; diff --git a/re/udsfirmwareuploaderwindow.cpp b/re/udsfirmwareuploaderwindow.cpp new file mode 100644 index 0000000..7b41ba1 --- /dev/null +++ b/re/udsfirmwareuploaderwindow.cpp @@ -0,0 +1,467 @@ +#include "udsfirmwareuploaderwindow.h" +#include "ui_udsfirmwareuploaderwindow.h" +#include "mainwindow.h" +#include "connections/canconmanager.h" +#include "utility.h" + +#include +#include +#include + +UDSFirmwareUploaderWindow::UDSFirmwareUploaderWindow(const QVector *frames, QWidget *parent) : + QDialog(parent), + ui(new Ui::UDSFirmwareUploaderWindow) +{ + ui->setupUi(this); + setWindowFlags(Qt::Window); + + modelFrames = frames; + currentState = STATE_IDLE; + firmwareSize = 0; + blockSequenceCounter = 0; + maxBlockLength = 0; + currentDataPos = 0; + busId = 0; + targetId = 0x7E0; + responseId = 0x7E8; + sessionType = 0x02; + securityLevel = 1; + flashAddr = 0x08000000; + useSecurity = true; + + udsHandler = new UDS_HANDLER(); + timeoutTimer = new QTimer(); + timeoutTimer->setInterval(1000); + testerTimer = new QTimer(); + testerTimer->setInterval(2000); + progressTimer = new QElapsedTimer(); + + int numBuses = CANConManager::getInstance()->getNumBuses(); + ui->spinBus->setMaximum(numBuses > 0 ? numBuses - 1 : 0); + + connect(ui->btnLoadFile, &QPushButton::clicked, this, &UDSFirmwareUploaderWindow::handleLoadFile); + connect(ui->btnStartStop, &QPushButton::clicked, this, &UDSFirmwareUploaderWindow::handleStartStop); + connect(ui->btnAbort, &QPushButton::clicked, this, &UDSFirmwareUploaderWindow::handleAbort); + connect(udsHandler, &UDS_HANDLER::newUDSMessage, this, &UDSFirmwareUploaderWindow::gotUDSReply); + connect(timeoutTimer, &QTimer::timeout, this, &UDSFirmwareUploaderWindow::timeoutTriggered); + connect(testerTimer, &QTimer::timeout, this, &UDSFirmwareUploaderWindow::testerPresentTick); +} + +UDSFirmwareUploaderWindow::~UDSFirmwareUploaderWindow() +{ + stopUpload(); + delete testerTimer; + delete timeoutTimer; + delete udsHandler; + delete progressTimer; + delete ui; +} + +void UDSFirmwareUploaderWindow::logMessage(const QString &msg) +{ + QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz"); + ui->txtLog->append("[" + timestamp + "] " + msg); +} + +void UDSFirmwareUploaderWindow::setState(UPLOAD_STATE newState) +{ + currentState = newState; + if (newState == STATE_ERROR || newState == STATE_COMPLETE || newState == STATE_IDLE) + { + timeoutTimer->stop(); + testerTimer->stop(); + ui->btnStartStop->setEnabled(true); + ui->btnAbort->setEnabled(false); + ui->btnLoadFile->setEnabled(true); + } +} + +void UDSFirmwareUploaderWindow::handleLoadFile() +{ + QFileDialog dialog; + QStringList filters; + filters.append("Binary Firmware (*.bin)"); + filters.append("All Files (*)"); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilters(filters); + + if (dialog.exec() == QDialog::Accepted) + { + QString filename = dialog.selectedFiles().constFirst(); + QFile inFile(filename); + if (!inFile.open(QIODevice::ReadOnly)) + { + logMessage("ERROR: Could not open file: " + filename); + return; + } + firmwareData = inFile.readAll(); + firmwareSize = firmwareData.length(); + inFile.close(); + ui->lblFilename->setText(filename + QString(" (%1 bytes)").arg(firmwareSize)); + logMessage("Loaded firmware: " + filename + " (" + QString::number(firmwareSize) + " bytes)"); + } +} + +void UDSFirmwareUploaderWindow::handleStartStop() +{ + if (currentState != STATE_IDLE && currentState != STATE_COMPLETE && currentState != STATE_ERROR) + { + stopUpload(); + return; + } + startUpload(); +} + +void UDSFirmwareUploaderWindow::handleAbort() +{ + stopUpload(); + logMessage("Upload aborted by user"); + setState(STATE_IDLE); +} + +void UDSFirmwareUploaderWindow::startUpload() +{ + if (firmwareData.isEmpty()) + { + logMessage("ERROR: No firmware file loaded"); + return; + } + + busId = ui->spinBus->value(); + targetId = Utility::ParseStringToNum(ui->txtTargetID->text()); + responseId = Utility::ParseStringToNum(ui->txtResponseID->text()); + flashAddr = Utility::ParseStringToNum(ui->txtFlashAddr->text()); + securityLevel = ui->spinSecurityLevel->value(); + useSecurity = ui->ckUseSecurity->isChecked(); + + if (ui->cbSessionType->currentIndex() == 0) sessionType = 0x02; + else sessionType = 0x03; + + blockSequenceCounter = 0; + currentDataPos = 0; + + ui->progressBar->setValue(0); + ui->btnStartStop->setEnabled(false); + ui->btnAbort->setEnabled(true); + ui->btnLoadFile->setEnabled(false); + + udsHandler->setReception(true); + udsHandler->addFilter(busId, responseId, 0x7FF); + + logMessage("Starting UDS firmware upload..."); + logMessage(QString("Target: 0x%1, Response: 0x%2, Bus: %3") + .arg(targetId, 0, 16).arg(responseId, 0, 16).arg(busId)); + logMessage(QString("Flash Address: 0x%1, Size: %2 bytes") + .arg(flashAddr, 0, 16).arg(firmwareSize)); + + sendDiagSession(); +} + +void UDSFirmwareUploaderWindow::stopUpload(bool resetState) +{ + timeoutTimer->stop(); + testerTimer->stop(); + udsHandler->clearAllFilters(); + udsHandler->setReception(false); + + ui->btnStartStop->setEnabled(true); + ui->btnAbort->setEnabled(false); + ui->btnLoadFile->setEnabled(true); + + if (resetState) + { + currentState = STATE_IDLE; + ui->btnStartStop->setText("Start Upload"); + } +} + +void UDSFirmwareUploaderWindow::sendDiagSession() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::DIAG_CONTROL; + msg.subFuncLen = 1; + msg.subFunc = sessionType; + + logMessage("Sending Diagnostic Session Control (0x10) - Sub: 0x" + QString::number(sessionType, 16)); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_DIAG_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendSecuritySeed() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::SECURITY_ACCESS; + msg.subFuncLen = 1; + msg.subFunc = (securityLevel * 2) - 1; + + logMessage("Requesting Security Seed (0x27) - Level: " + QString::number(securityLevel)); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_SEED); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendSecurityKey(const QByteArray &seed) +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::SECURITY_ACCESS; + msg.subFuncLen = 1; + msg.subFunc = securityLevel * 2; + msg.payload() = seed; + + logMessage("Sending Security Key (0x27) - " + seed.toHex(' ')); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_KEY_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendRequestDownload() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::REQUEST_DOWNLOAD; + msg.subFuncLen = 0; + msg.subFunc = 0; + + QByteArray data; + data.append(static_cast(0x00)); + uint32_t addr = flashAddr; + uint32_t size = firmwareSize; + + int addrLen = 4; + int sizeLen = 4; + data[0] = (addrLen << 4) | sizeLen; + + for (int i = addrLen - 1; i >= 0; i--) + data.append((addr >> (i * 8)) & 0xFF); + for (int i = sizeLen - 1; i >= 0; i--) + data.append((size >> (i * 8)) & 0xFF); + + msg.payload() = data; + + logMessage(QString("Sending Request Download (0x34) - Addr: 0x%1, Size: %2") + .arg(addr, 0, 16).arg(size)); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_DOWNLOAD_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendDataBlock() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::TRANSFER_DATA; + msg.subFuncLen = 0; + msg.subFunc = 0; + + QByteArray data; + data.append(blockSequenceCounter & 0xFF); + + int bytesToSend = firmwareSize - currentDataPos; + if (maxBlockLength > 0 && bytesToSend > maxBlockLength) + bytesToSend = maxBlockLength; + + data.append(firmwareData.constData() + currentDataPos, bytesToSend); + msg.payload() = data; + + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_DATA_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendTransferExit() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::REQ_TRANS_EXIT; + msg.subFuncLen = 0; + msg.subFunc = 0; + + logMessage("Sending Request Transfer Exit (0x37)"); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_EXIT_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendECUReset() +{ + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::ECU_RESET; + msg.subFuncLen = 1; + msg.subFunc = 0x01; + + logMessage("Sending ECU Reset (0x11)"); + udsHandler->sendUDSFrame(msg); + setState(STATE_WAIT_RESET_RESP); + timeoutTimer->start(); +} + +void UDSFirmwareUploaderWindow::sendTesterPresent() +{ + if (currentState != STATE_WAIT_DATA_RESP && currentState != STATE_WAIT_DOWNLOAD_RESP) + return; + + UDS_MESSAGE msg; + msg.bus = busId; + msg.setFrameId(targetId); + msg.service = UDS_SERVICES::TESTER_PRESENT; + msg.subFuncLen = 1; + msg.subFunc = 0x80; + + udsHandler->sendUDSFrame(msg); +} + +void UDSFirmwareUploaderWindow::handleNRC(int nrc) +{ + QString desc = udsHandler->getNegativeResponseLong(nrc); + logMessage(QString("NEGATIVE RESPONSE: 0x%1 - %2").arg(nrc, 0, 16).arg(desc)); + setState(STATE_ERROR); + stopUpload(); +} + +void UDSFirmwareUploaderWindow::gotUDSReply(UDS_MESSAGE msg) +{ + if (msg.frameId() != responseId) return; + if (msg.bus != busId) return; + + const unsigned char *data = reinterpret_cast(msg.payload().constData()); + int dataLen = msg.payload().size(); + + if (msg.isErrorReply) + { + qDebug() << "UDS FW Upload: NRC service=" << msg.service << " subfunc=" << msg.subFunc; + handleNRC(msg.subFunc); + return; + } + + timeoutTimer->stop(); + + switch (currentState) + { + case STATE_WAIT_DIAG_RESP: + { + logMessage("Diagnostic Session Control response received"); + if (useSecurity) + { + sendSecuritySeed(); + } + else + { + sendRequestDownload(); + } + break; + } + + case STATE_WAIT_SEED: + { + logMessage("Security seed received (" + QString::number(dataLen) + " bytes)"); + QByteArray seed; + seed.append(reinterpret_cast(data), dataLen); + QByteArray key = seed; + for (int i = 0; i < key.size(); i++) + key[i] = ~key[i]; + sendSecurityKey(key); + break; + } + + case STATE_WAIT_KEY_RESP: + { + logMessage("Security access granted"); + sendRequestDownload(); + break; + } + + case STATE_WAIT_DOWNLOAD_RESP: + { + if (dataLen > 1) + { + int sizeLen = data[0] >> 4; + maxBlockLength = 0; + for (int i = 0; i < sizeLen && (i + 1) < dataLen; i++) + { + maxBlockLength = (maxBlockLength << 8) | data[1 + i]; + } + logMessage(QString("Download accepted. Max block size: %1 bytes").arg(maxBlockLength)); + } + else + { + maxBlockLength = 4096; + logMessage("Download accepted (no block size limit advertised)"); + } + testerTimer->start(); + sendDataBlock(); + break; + } + + case STATE_WAIT_DATA_RESP: + { + progressTimer->start(); + currentDataPos += maxBlockLength > 0 ? + qMin(maxBlockLength, firmwareSize - currentDataPos) : + (firmwareSize - currentDataPos); + blockSequenceCounter++; + + int progress = (currentDataPos * 100) / firmwareSize; + ui->progressBar->setValue(progress); + + if (currentDataPos >= firmwareSize) + { + logMessage("All data blocks transferred"); + testerTimer->stop(); + sendTransferExit(); + } + else + { + sendDataBlock(); + } + break; + } + + case STATE_WAIT_EXIT_RESP: + { + logMessage("Transfer exit confirmed"); + sendECUReset(); + break; + } + + case STATE_WAIT_RESET_RESP: + { + logMessage("ECU reset acknowledged"); + setState(STATE_COMPLETE); + stopUpload(); + logMessage("*** Firmware upload complete! ***"); + ui->progressBar->setValue(100); + break; + } + + default: + break; + } +} + +void UDSFirmwareUploaderWindow::timeoutTriggered() +{ + logMessage("TIMEOUT - No response received"); + handleNRC(0x10); +} + +void UDSFirmwareUploaderWindow::testerPresentTick() +{ + sendTesterPresent(); + logMessage("Tester Present keep-alive sent"); +} + +void UDSFirmwareUploaderWindow::advanceState() +{ +} diff --git a/re/udsfirmwareuploaderwindow.h b/re/udsfirmwareuploaderwindow.h new file mode 100644 index 0000000..e9c8c87 --- /dev/null +++ b/re/udsfirmwareuploaderwindow.h @@ -0,0 +1,89 @@ +#ifndef UDSFIRMWAREUPLOADERWINDOW_H +#define UDSFIRMWAREUPLOADERWINDOW_H + +#include +#include +#include +#include "can_structs.h" +#include "bus_protocols/uds_handler.h" + +namespace Ui { +class UDSFirmwareUploaderWindow; +} + +enum UPLOAD_STATE +{ + STATE_IDLE, + STATE_SEND_DIAG_SESSION, + STATE_WAIT_DIAG_RESP, + STATE_SEND_SECURITY_SEED, + STATE_WAIT_SEED, + STATE_SEND_SECURITY_KEY, + STATE_WAIT_KEY_RESP, + STATE_SEND_REQUEST_DOWNLOAD, + STATE_WAIT_DOWNLOAD_RESP, + STATE_SEND_DATA, + STATE_WAIT_DATA_RESP, + STATE_SEND_TRANSFER_EXIT, + STATE_WAIT_EXIT_RESP, + STATE_SEND_ECU_RESET, + STATE_WAIT_RESET_RESP, + STATE_COMPLETE, + STATE_ERROR +}; + +class UDSFirmwareUploaderWindow : public QDialog +{ + Q_OBJECT + +public: + explicit UDSFirmwareUploaderWindow(const QVector *frames, QWidget *parent = 0); + ~UDSFirmwareUploaderWindow(); + +private slots: + void handleLoadFile(); + void handleStartStop(); + void handleAbort(); + void gotUDSReply(UDS_MESSAGE msg); + void timeoutTriggered(); + void testerPresentTick(); + +private: + void logMessage(const QString &msg); + void setState(UPLOAD_STATE newState); + void startUpload(); + void stopUpload(bool resetState = true); + void sendDiagSession(); + void sendSecuritySeed(); + void sendSecurityKey(const QByteArray &seed); + void sendRequestDownload(); + void sendDataBlock(); + void sendTransferExit(); + void sendECUReset(); + void sendTesterPresent(); + void handleNRC(int nrc); + void advanceState(); + + Ui::UDSFirmwareUploaderWindow *ui; + const QVector *modelFrames; + UDS_HANDLER *udsHandler; + UPLOAD_STATE currentState; + QTimer *timeoutTimer; + QTimer *testerTimer; + QElapsedTimer *progressTimer; + + QByteArray firmwareData; + int firmwareSize; + int busId; + uint32_t targetId; + uint32_t responseId; + int sessionType; + int securityLevel; + uint32_t flashAddr; + int blockSequenceCounter; + int maxBlockLength; + int currentDataPos; + bool useSecurity; +}; + +#endif // UDSFIRMWAREUPLOADERWINDOW_H diff --git a/ui/firmwareuploaderwindow.ui b/ui/firmwareuploaderwindow.ui deleted file mode 100644 index 27a4983..0000000 --- a/ui/firmwareuploaderwindow.ui +++ /dev/null @@ -1,106 +0,0 @@ - - - FirmwareUploaderWindow - - - - 0 - 0 - 327 - 357 - - - - Firmware Updater - - - - - - Loaded File: - - - - - - - - - - - - - - Load File - - - - - - - Device Token: - - - - - - - - - - CAN Bus: - - - - - - - - - - Base Address: - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 0 - - - - - - - X of Y bytes - - - - - - - Start Upload - - - - - - - - diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 72d9cec..fa8430f 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -43,7 +43,7 @@ true - QAbstractItemView::ScrollPerPixel + QAbstractItemView::ScrollMode::ScrollPerPixel false @@ -69,7 +69,7 @@ Remote Connection Active: - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -99,7 +99,7 @@ 8 - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter true @@ -156,11 +156,11 @@ - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - + @@ -173,7 +173,7 @@ - + @@ -186,7 +186,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -263,7 +263,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -294,7 +294,7 @@ Bus Filtering: - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -313,7 +313,7 @@ - QListView::LeftToRight + QListView::Flow::LeftToRight @@ -323,7 +323,7 @@ Frame Filtering: - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -382,7 +382,7 @@ 0 0 1177 - 26 + 20 @@ -411,7 +411,7 @@ - + @@ -641,6 +641,11 @@ CAN Bridge + + + UDS Firmware Update + + diff --git a/ui/udsfirmwareuploaderwindow.ui b/ui/udsfirmwareuploaderwindow.ui new file mode 100644 index 0000000..7a0204c --- /dev/null +++ b/ui/udsfirmwareuploaderwindow.ui @@ -0,0 +1,181 @@ + + + UDSFirmwareUploaderWindow + + + + 0 + 0 + 520 + 520 + + + + UDS Firmware Uploader + + + + + + + + CAN Bus: + + + + + + + + + + Target Request ID: + + + + + + + 0x7E0 + + + + + + + Target Response ID: + + + + + + + 0x7E8 + + + + + + + Session Type: + + + + + + + + Programming (0x02) + + + + + Extended (0x03) + + + + + + + + Security Level: + + + + + + + + + 1 + + + 255 + + + 1 + + + + + + + Enable Security + + + true + + + + + + + + + Flash Address: + + + + + + + 0x08000000 + + + + + + + + + Load Firmware File... + + + + + + + No file loaded + + + + + + + true + + + + + + + 0 + + + + + + + + + Start Upload + + + + + + + Abort + + + false + + + + + + + + + +