#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(); }