2 ******************************************************************************
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup Uploader Serial and USB Uploader tool
11 * @brief The USB and Serial protocol uploader tool
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <QCoreApplication>
34 #include <QStringList>
39 void showProgress(QString status
);
40 void progressUpdated(int percent
);
41 void usage(QTextStream
*standardOutput
);
45 // Command Line Options
46 #define DOWNLOAD "-dn"
48 #define DOWNDESCRIPTION "-dd"
49 #define PROGRAMFW "-p"
50 #define PROGRAMDESC "-w"
52 #define COMPARECRC "-cc"
53 #define COMPAREALL "-ca"
54 #define STATUSREQUEST "-s"
55 #define LISTDEVICES "-ls"
58 #define USE_SERIAL "-t"
59 #define NO_COUNTDOWN "-i"
61 #define DEBUG "-debug"
62 #define USERMODERESET "-ur"
64 int main(int argc
, char *argv
[])
66 QCoreApplication
a(argc
, argv
);
67 QTextStream
standardOutput(stdout
);
68 int argumentCount
= QCoreApplication::arguments().size();
69 bool use_serial
= false;
72 // bool umodereset = false;
73 DFU::Actions action
= DFU::actionNone
;
78 QStringList args
= QCoreApplication::arguments();
80 if (args
.contains(DEBUG
)) {
83 if (args
.contains(USERMODERESET
)) {
86 standardOutput
<< "Serial firmware uploader tool." << endl
;
87 if (args
.contains(DEVICE
)) {
88 if (args
.indexOf(DEVICE
) + 1 < args
.length()) {
89 device
= (args
[args
.indexOf(DEVICE
) + 1]).toInt();
95 if (argumentCount
== 0 || args
.contains(HELP
) || !args
.contains(USE_SERIAL
)) {
96 usage(&standardOutput
);
98 } else if (args
.contains(PROGRAMFW
)) {
99 if (args
.contains(VERIFY
)) {
104 if (args
.contains(PROGRAMDESC
)) {
105 if (args
.indexOf(PROGRAMDESC
) + 1 < args
.length()) {
106 description
= (args
[args
.indexOf(PROGRAMDESC
) + 1]);
109 if (args
.indexOf(PROGRAMFW
) + 1 < args
.length()) {
110 file
= args
[args
.indexOf(PROGRAMFW
) + 1];
114 action
= DFU::actionProgram
;
115 } else if (args
.contains(COMPARECRC
) || args
.contains(COMPAREALL
)) {
116 if (args
.contains(COMPARECRC
)) {
117 if (args
.indexOf(COMPARECRC
) + 1 < args
.length()) {
118 file
= args
[args
.indexOf(COMPARECRC
) + 1];
122 action
= DFU::actionCompareCrc
;
124 if (args
.indexOf(COMPAREALL
) + 1 < args
.length()) {
125 file
= args
[args
.indexOf(COMPAREALL
) + 1];
129 action
= DFU::actionCompareAll
;
131 } else if (args
.contains(DOWNLOAD
)) {
132 if (args
.indexOf(DOWNLOAD
) + 1 < args
.length()) {
133 file
= args
[args
.indexOf(DOWNLOAD
) + 1];
137 action
= DFU::actionDownload
;
138 } else if (args
.contains(STATUSREQUEST
)) {
139 action
= DFU::actionStatusReq
;
140 } else if (args
.contains(RESET
)) {
141 action
= DFU::actionReset
;
142 } else if (args
.contains(JUMP
)) {
143 action
= DFU::actionJump
;
144 } else if (args
.contains(LISTDEVICES
)) {
145 action
= DFU::actionListDevs
;
147 if ((file
.isEmpty() || device
== -1) && action
!= DFU::actionReset
&& action
!= DFU::actionStatusReq
&& action
!= DFU::actionListDevs
&& action
!= DFU::actionJump
) {
148 usage(&standardOutput
);
151 if (args
.contains(USE_SERIAL
)) {
152 if (args
.indexOf(USE_SERIAL
) + 1 < args
.length()) {
153 serialport
= (args
[args
.indexOf(USE_SERIAL
) + 1]);
158 qDebug() << "Action=" << (int)action
;
159 qDebug() << "File=" << file
;
160 qDebug() << "Device=" << device
;
161 qDebug() << "Action=" << action
;
162 qDebug() << "Description" << description
;
163 qDebug() << "Use Serial port" << use_serial
;
165 qDebug() << "Port Name" << serialport
;
169 if (args
.contains(NO_COUNTDOWN
)) {} else {
170 showProgress("Connect the board");
171 for (int i
= 0; i
< 6; i
++) {
172 progressUpdated(i
* 100 / 5);
173 QThread::msleep(500);
176 standardOutput
<< endl
<< "Connect the board NOW" << endl
;
177 QThread::msleep(1000);
180 ///////////////////////////////////ACTIONS START///////////////////////////////////////////////////
182 DFU::DFUObject
dfu(debug
, use_serial
, serialport
);
184 QObject::connect(&dfu
, &DFU::DFUObject::operationProgress
, showProgress
);
185 QObject::connect(&dfu
, &DFU::DFUObject::progressUpdated
, progressUpdated
);
190 dfu
.AbortOperation();
191 if (!dfu
.enterDFU(0)) {
192 standardOutput
<< "Could not enter DFU mode\n" << endl
;
196 DFU::Status ret
= dfu
.StatusRequest();
197 qDebug() << dfu
.StatusToString(ret
);
199 if (!(action
== DFU::actionStatusReq
|| action
== DFU::actionReset
|| action
== DFU::actionJump
)) {
201 if (action
== DFU::actionListDevs
) {
202 standardOutput
<< "Found " << dfu
.numberOfDevices
<< "\n";
203 for (int x
= 0; x
< dfu
.numberOfDevices
; ++x
) {
204 standardOutput
<< "Device #" << x
<< "\n";
205 standardOutput
<< "Device ID=" << dfu
.devices
[x
].ID
<< "\n";
206 standardOutput
<< "Device Readable=" << dfu
.devices
[x
].Readable
<< "\n";
207 standardOutput
<< "Device Writable=" << dfu
.devices
[x
].Writable
<< "\n";
208 standardOutput
<< "Device SizeOfCode=" << dfu
.devices
[x
].SizeOfCode
<< "\n";
209 standardOutput
<< "BL Version=" << dfu
.devices
[x
].BL_Version
<< "\n";
210 standardOutput
<< "Device SizeOfDesc=" << dfu
.devices
[x
].SizeOfDesc
<< "\n";
211 standardOutput
<< "FW CRC=" << dfu
.devices
[x
].FW_CRC
<< "\n";
213 int size
= ((DFU::device
)dfu
.devices
[x
]).SizeOfDesc
;
215 standardOutput
<< "Description:" << dfu
.DownloadDescription(size
).toLatin1().data() << "\n";
216 standardOutput
<< "\n";
220 if (device
> dfu
.numberOfDevices
- 1) {
221 standardOutput
<< "Error:Invalid Device" << endl
;
224 if (dfu
.numberOfDevices
== 1) {
225 dfu
.use_delay
= false;
227 if (!dfu
.enterDFU(device
)) {
228 standardOutput
<< "Error:Could not enter DFU mode\n" << endl
;
231 if (action
== DFU::actionProgram
) {
232 if (((DFU::device
)dfu
.devices
[device
]).Writable
== false) {
233 standardOutput
<< "ERROR device not Writable\n" << endl
;
236 standardOutput
<< "Uploading..." << endl
;
238 // this call is asynchronous so the only false status it will report
239 // is when it is already running...
240 bool retstatus
= dfu
.UploadFirmware(file
.toLatin1(), verify
, device
);
243 standardOutput
<< "Upload failed with code:" << retstatus
<< endl
;
246 while (!dfu
.isFinished()) {
247 QThread::msleep(500);
249 // TODO check if upload went well...
250 if (file
.endsWith("opfw")) {
252 if (!fwfile
.open(QIODevice::ReadOnly
)) {
253 standardOutput
<< "Cannot open file " << file
<< endl
;
256 QByteArray firmware
= fwfile
.readAll();
257 QByteArray desc
= firmware
.right(100);
258 DFU::Status status
= dfu
.UploadDescription(desc
);
259 if (status
!= DFU::Last_operation_Success
) {
260 standardOutput
<< "Upload failed with code:" << retstatus
<< endl
;
263 } else if (!description
.isEmpty()) {
264 DFU::Status status
= dfu
.UploadDescription(description
);
265 if (status
!= DFU::Last_operation_Success
) {
266 standardOutput
<< "Upload failed with code:" << status
<< endl
;
270 while (!dfu
.isFinished()) {
271 QThread::msleep(500);
273 standardOutput
<< "Uploading Succeeded!\n" << endl
;
274 } else if (action
== DFU::actionDownload
) {
275 if (((DFU::device
)dfu
.devices
[device
]).Readable
== false) {
276 standardOutput
<< "ERROR device not readable\n" << endl
;
280 dfu
.DownloadFirmware(&fw
, 0);
281 while (!dfu
.isFinished()) {
282 QThread::msleep(500);
284 bool ret
= dfu
.SaveByteArrayToFile(file
.toLatin1(), fw
);
286 } else if (action
== DFU::actionCompareCrc
) {
287 dfu
.CompareFirmware(file
.toLatin1(), DFU::crccompare
, device
);
289 } else if (action
== DFU::actionCompareAll
) {
290 if (((DFU::device
)dfu
.devices
[device
]).Readable
== false) {
291 standardOutput
<< "ERROR device not readable\n" << endl
;
294 dfu
.CompareFirmware(file
.toLatin1(), DFU::bytetobytecompare
, device
);
297 } else if (action
== DFU::actionStatusReq
) {
298 standardOutput
<< "Current device status=" << dfu
.StatusToString(dfu
.StatusRequest()).toLatin1().data() << "\n" << endl
;
299 } else if (action
== DFU::actionReset
) {
301 } else if (action
== DFU::actionJump
) {
302 dfu
.JumpToApp(false, false);
309 void showProgress(QString status
)
311 QTextStream
standardOutput(stdout
);
313 standardOutput
<< status
<< endl
;
317 void progressUpdated(int percent
)
321 for (int i
= 0; i
< 50; i
++) {
322 if (i
< (percent
/ 2)) {
323 bar
.replace(i
, 1, "=");
324 } else if (i
== (percent
/ 2)) {
325 bar
.replace(i
, 1, ">");
327 bar
.replace(i
, 1, " ");
330 std::cout
<< "\r" << label
.toLatin1().data() << " [" << bar
<< "] ";
332 std::cout
<< percent
<< "% " << std::flush
;
335 void usage(QTextStream
*standardOutput
)
337 *standardOutput
<< "Options:\n";
338 *standardOutput
<< "-ls : lists available devices\n";
339 *standardOutput
<< "-p <file> : program hw (requires:-d - optionals:-v,-w)\n";
340 *standardOutput
<< "-v : verify (requires:-d)\n";
341 *standardOutput
<< "-dn <file> : download firmware to file\n";
342 // *standardOutput << "-dd <file> : download discription (requires:-d)\n";
343 *standardOutput
<< "-d <Device Number> : target device number (default 0, first device)\n";
344 // *standardOutput << "-w <description> : (requires: -p)\n";
345 *standardOutput
<< "-ca <file> : compares byte by byte current firmware with file\n";
346 *standardOutput
<< "-cc <file> : compares CRC of current firmware with file\n";
347 *standardOutput
<< "-s : requests status of device\n";
348 *standardOutput
<< "-r : resets the device\n";
349 *standardOutput
<< "-j : exits bootloader and jumps to user FW\n";
350 *standardOutput
<< "-debug : prints debug information\n";
351 *standardOutput
<< "-t <port> : uses serial port\n";
352 *standardOutput
<< "-i : immediate, doesn't show the connection countdown\n";
353 *standardOutput
<< "-h : print usage\n";
354 // *standardOutput << "-ur <port> : user mode reset*\n";
355 // *standardOutput << " *requires valid user space firmwares already running\n";
356 *standardOutput
<< "\n";
357 *standardOutput
<< "Program and verify the first device connected to COM1\n";
358 *standardOutput
<< " UploadTool -p c:/gpsp.opfw -v -t COM1\n";
359 *standardOutput
<< "\n";
360 *standardOutput
<< "Perform a quick compare of FW in file with FW on device #1\n";
361 *standardOutput
<< " UploadTool -ca /home/user1/gpsp.opfw -t ttyUSB0\n";
364 void howToUsage(QTextStream
*standardOutput
)
366 *standardOutput
<< "run the tool with -h for more informations" << endl
;