frame.payload() returns a copy (!) of data, so assignig to it has no effect
251 lines
8.1 KiB
C++
251 lines
8.1 KiB
C++
#include "firmwareuploaderwindow.h"
|
|
#include "ui_firmwareuploaderwindow.h"
|
|
#include "mainwindow.h"
|
|
|
|
#include <QFile>
|
|
|
|
//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<CANFrame> *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<const unsigned char *>(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<unsigned char>(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();
|
|
}
|
|
|