1 #include "firmwareuploaderwindow.h"
2 #include "ui_firmwareuploaderwindow.h"
3 #include "mainwindow.h"
4 
5 #include <QFile>
6 
7 //You might wonder: Collin, what in the hell is this for? Firmware uploader? For what? I'm interested! Well, it's a custom
8 //firmware uploader for a motor controller I built. Why would that be in this project. Cuz. It's not really relevant
9 //to anyone else but might serve as a decent reference for a few things: How to make an uploader interface that runs over CAN,
10 //how to lay out a screen like this, how to make a comm protocol for firmware updating over CAN. But, most things use UDS
11 //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.
12 //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.
13 
FirmwareUploaderWindow(const QVector<CANFrame> * frames,QWidget * parent)14 FirmwareUploaderWindow::FirmwareUploaderWindow(const QVector<CANFrame> *frames, QWidget *parent) :
15     QDialog(parent),
16     ui(new Ui::FirmwareUploaderWindow)
17 {
18     ui->setupUi(this);
19     setWindowFlags(Qt::Window);
20 
21     transferInProgress = false;
22     startedProcess = false;
23     firmwareSize = 0;
24     currentSendingPosition = 0;
25     baseAddress = 0;
26     bus = 0;
27     modelFrames = frames;
28 
29     ui->lblFilename->setText("");
30     ui->spinBus->setValue(0);
31     ui->spinBus->setMaximum(1);
32     ui->txtBaseAddr->setText("0x100");
33     updateProgress();
34 
35     timer = new QTimer();
36     timer->setInterval(100); //100ms without a reply will cause us to attempt a resend
37 
38     connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
39     connect(ui->btnLoadFile, SIGNAL(clicked(bool)), this, SLOT(handleLoadFile()));
40     connect(ui->btnStartStop, SIGNAL(clicked(bool)), this, SLOT(handleStartStopTransfer()));
41     connect(timer, SIGNAL(timeout()), this, SLOT(timerElapsed()));
42 }
43 
~FirmwareUploaderWindow()44 FirmwareUploaderWindow::~FirmwareUploaderWindow()
45 {
46     timer->stop();
47     CANConManager::getInstance()->removeAllTargettedFrames(this);
48     delete timer;
49     delete ui;
50 }
51 
updateProgress()52 void FirmwareUploaderWindow::updateProgress()
53 {
54     ui->lblProgress->setText(QString::number(currentSendingPosition * 4) + " of " + QString::number(firmwareSize) + " transferred");
55 }
56 
updatedFrames(int numFrames)57 void FirmwareUploaderWindow::updatedFrames(int numFrames)
58 {
59     //CANFrame thisFrame;
60     if (numFrames == -1) //all frames deleted.
61     {
62     }
63     else if (numFrames == -2) //all new set of frames.
64     {
65     }
66     else //just got some new frames. See if they are relevant.
67     {
68         /*
69         //run through the supposedly new frames in order
70         for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
71         {
72             thisFrame = modelFrames->at(i);
73         }
74         */
75     }
76 }
77 
gotTargettedFrame(CANFrame frame)78 void FirmwareUploaderWindow::gotTargettedFrame(CANFrame frame)
79 {
80     const unsigned char *data = reinterpret_cast<const unsigned char *>(frame.payload().constData());
81     int dataLen = frame.payload().count();
82 
83     qDebug() << "FUW: Got targetted frame with id " << frame.frameId();
84     if (frame.frameId() == (uint32_t)(baseAddress + 0x10) && (dataLen == 8) ) {
85         qDebug() << "Start firmware reply";
86         if ((data[0] == 0xAD) && (data[1] == 0xDE))
87         {
88             if ((data[2] == 0xAF) && (data[3] == 0xDE))
89             {
90                 qDebug() << "There's dead beef here";
91                 if ( (data[4] == (token & 0xFF)) && (data[5] == ((token >> 8) & 0xFF) ) )
92                 {
93                     if ((data[6] == ((token >> 16) & 0xFF)) && (data[7] == ((token >> 24) & 0xFF)))
94                     {
95                         qDebug() << "starting firmware process";
96                         //MainWindow::getReference()->setTargettedID(baseAddress + 0x20);
97                         transferInProgress = true;
98                         sendFirmwareChunk();
99                     }
100                 }
101             }
102         }
103     }
104 
105     if (frame.frameId() == (uint32_t)(baseAddress + 0x20)) {
106         qDebug() << "Firmware reception success reply";
107         int seq = data[0] + (256 * data[1]);
108         if (seq == currentSendingPosition)
109         {
110             currentSendingPosition++;
111             if (currentSendingPosition * 4 > firmwareSize || currentSendingPosition > 65535)
112             {
113                 transferInProgress = false;
114                 timer->stop();
115                 handleStartStopTransfer();
116                 ui->progressBar->setValue(100);
117                 sendFirmwareEnding();
118             }
119             else
120             {
121                 ui->progressBar->setValue((400 * currentSendingPosition) / firmwareSize);
122                 updateProgress();
123                 sendFirmwareChunk();
124             }
125         }
126     }
127 }
128 
timerElapsed()129 void FirmwareUploaderWindow::timerElapsed()
130 {
131     sendFirmwareChunk(); //resend
132 }
133 
sendFirmwareChunk()134 void FirmwareUploaderWindow::sendFirmwareChunk()
135 {
136     CANFrame *output = new CANFrame;
137     int firmwareLocation = currentSendingPosition * 4;
138     int xorByte = 0;
139     output->setExtendedFrameFormat(false);
140     QByteArray bytes(7,0);
141     output->bus = bus;
142     output->setFrameId(baseAddress + 0x16);
143     output->payload()[0] = currentSendingPosition & 0xFF;
144     output->payload()[1] = (currentSendingPosition >> 8) & 0xFF;
145     output->payload()[2] = firmwareData[firmwareLocation++];
146     output->payload()[3] = firmwareData[firmwareLocation++];
147     output->payload()[4] = firmwareData[firmwareLocation++];
148     output->payload()[5] = firmwareData[firmwareLocation++];
149     for (int i = 0; i < 6; i++) xorByte = xorByte ^ static_cast<unsigned char>(output->payload()[i]);
150     output->payload()[6] = xorByte;
151     output->setPayload(bytes);
152     CANConManager::getInstance()->sendFrame(*output);
153     timer->start();
154 }
155 
sendFirmwareEnding()156 void FirmwareUploaderWindow::sendFirmwareEnding()
157 {
158     CANFrame *output = new CANFrame;
159     output->setExtendedFrameFormat(false);
160     output->bus = bus;
161     QByteArray bytes(4,0);
162     output->setFrameId(baseAddress + 0x30);
163     output->payload()[3] = 0xC0;
164     output->payload()[2] = 0xDE;
165     output->payload()[1] = 0xFA;
166     output->payload()[0] = 0xDE;
167     output->setPayload(bytes);
168     //sendCANFrame(output, bus);
169 }
170 
handleStartStopTransfer()171 void FirmwareUploaderWindow::handleStartStopTransfer()
172 {
173     startedProcess = !startedProcess;
174 
175     if (startedProcess) //start the process
176     {
177         ui->progressBar->setValue(0);
178         ui->btnStartStop->setText("Stop Upload");
179         token = Utility::ParseStringToNum(ui->txtToken->text());
180         bus = ui->spinBus->value();
181         baseAddress = Utility::ParseStringToNum(ui->txtBaseAddr->text());
182         qDebug() << "Base address: " + QString::number(baseAddress);
183         CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x10, 0x7FF, this);
184         CANConManager::getInstance()->addTargettedFrame(bus, baseAddress + 0x20, 0x7FF, this);
185         CANFrame *output = new CANFrame;
186         output->setExtendedFrameFormat(false);
187         QByteArray bytes(8,0);
188         output->bus = bus;
189         output->setFrameId(baseAddress);
190         output->setFrameType(QCanBusFrame::DataFrame);
191 
192         bytes[0] = 0xEF;
193         bytes[1] = 0xBE;
194         bytes[2] = 0xAD;
195         bytes[3] = 0xDE;
196         bytes[4] = token & 0xFF;
197         bytes[5] = (token >> 8) & 0xFF;
198         bytes[6] = (token >> 16) & 0xFF;
199         bytes[7] = (token >> 24) & 0xFF;
200         output->setPayload(bytes);
201         CANConManager::getInstance()->sendFrame(*output);
202     }
203     else //stop anything in process
204     {
205         ui->btnStartStop->setText("Start Upload");
206         CANConManager::getInstance()->removeAllTargettedFrames(this);
207     }
208 }
209 
handleLoadFile()210 void FirmwareUploaderWindow::handleLoadFile()
211 {
212     QString filename;
213     QFileDialog dialog;
214 
215     QStringList filters;
216     filters.append(QString(tr("Raw firmware binary (*.bin)")));
217 
218     dialog.setFileMode(QFileDialog::ExistingFile);
219     dialog.setNameFilters(filters);
220     dialog.setViewMode(QFileDialog::Detail);
221 
222     if (dialog.exec() == QDialog::Accepted)
223     {
224         filename = dialog.selectedFiles()[0];
225 
226         loadBinaryFile(filename);
227     }
228 }
229 
loadBinaryFile(QString filename)230 void FirmwareUploaderWindow::loadBinaryFile(QString filename)
231 {
232 
233     if (transferInProgress) handleStartStopTransfer();
234 
235     QFile *inFile = new QFile(filename);
236 
237     if (!inFile->open(QIODevice::ReadOnly))
238     {
239         delete inFile;
240         return;
241     }
242 
243     firmwareData = inFile->readAll();
244 
245     currentSendingPosition = 0;
246     firmwareSize = firmwareData.length();
247 
248     updateProgress();
249 
250     inFile->close();
251     delete inFile;
252 }
253 
254