Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / experimental / USB_UPLOAD_TOOL / main.cpp
blob980883c29fc55e94ecb654faac80349c7d6101a4
1 /**
2 ******************************************************************************
4 * @file main.cpp
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
8 * @{
9 * @addtogroup Uploader Serial and USB Uploader tool
10 * @{
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
22 * for more details.
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
28 #include "dfu.h"
30 #include <QCoreApplication>
31 #include <QFile>
32 #include <QByteArray>
33 #include <QThread>
34 #include <QStringList>
35 #include <QDebug>
37 #include <iostream>
39 void showProgress(QString status);
40 void progressUpdated(int percent);
41 void usage(QTextStream *standardOutput);
43 QString label;
45 // Command Line Options
46 #define DOWNLOAD "-dn"
47 #define DEVICE "-d"
48 #define DOWNDESCRIPTION "-dd"
49 #define PROGRAMFW "-p"
50 #define PROGRAMDESC "-w"
51 #define VERIFY "-v"
52 #define COMPARECRC "-cc"
53 #define COMPAREALL "-ca"
54 #define STATUSREQUEST "-s"
55 #define LISTDEVICES "-ls"
56 #define RESET "-r"
57 #define JUMP "-j"
58 #define USE_SERIAL "-t"
59 #define NO_COUNTDOWN "-i"
60 #define HELP "-h"
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;
70 bool verify;
71 bool debug = false;
72 // bool umodereset = false;
73 DFU::Actions action = DFU::actionNone;
74 QString file;
75 QString serialport;
76 QString description;
77 int device = -1;
78 QStringList args = QCoreApplication::arguments();
80 if (args.contains(DEBUG)) {
81 debug = true;
83 if (args.contains(USERMODERESET)) {
84 // umodereset = true;
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();
91 } else {
92 device = 0;
95 if (argumentCount == 0 || args.contains(HELP) || !args.contains(USE_SERIAL)) {
96 usage(&standardOutput);
97 return -1;
98 } else if (args.contains(PROGRAMFW)) {
99 if (args.contains(VERIFY)) {
100 verify = true;
101 } else {
102 verify = false;
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];
111 } else {
112 // error
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];
119 } else {
120 // error
122 action = DFU::actionCompareCrc;
123 } else {
124 if (args.indexOf(COMPAREALL) + 1 < args.length()) {
125 file = args[args.indexOf(COMPAREALL) + 1];
126 } else {
127 // error
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];
134 } else {
135 // error
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);
149 return -1;
151 if (args.contains(USE_SERIAL)) {
152 if (args.indexOf(USE_SERIAL) + 1 < args.length()) {
153 serialport = (args[args.indexOf(USE_SERIAL) + 1]);
154 use_serial = true;
157 if (debug) {
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;
164 if (use_serial) {
165 qDebug() << "Port Name" << serialport;
168 if (use_serial) {
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);
187 if (!dfu.ready()) {
188 return -1;
190 dfu.AbortOperation();
191 if (!dfu.enterDFU(0)) {
192 standardOutput << "Could not enter DFU mode\n" << endl;
193 return -1;
195 if (debug) {
196 DFU::Status ret = dfu.StatusRequest();
197 qDebug() << dfu.StatusToString(ret);
199 if (!(action == DFU::actionStatusReq || action == DFU::actionReset || action == DFU::actionJump)) {
200 dfu.findDevices();
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;
214 dfu.enterDFU(x);
215 standardOutput << "Description:" << dfu.DownloadDescription(size).toLatin1().data() << "\n";
216 standardOutput << "\n";
218 return 0;
220 if (device > dfu.numberOfDevices - 1) {
221 standardOutput << "Error:Invalid Device" << endl;
222 return -1;
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;
229 return -1;
231 if (action == DFU::actionProgram) {
232 if (((DFU::device)dfu.devices[device]).Writable == false) {
233 standardOutput << "ERROR device not Writable\n" << endl;
234 return false;
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);
242 if (!retstatus) {
243 standardOutput << "Upload failed with code:" << retstatus << endl;
244 return -1;
246 while (!dfu.isFinished()) {
247 QThread::msleep(500);
249 // TODO check if upload went well...
250 if (file.endsWith("opfw")) {
251 QFile fwfile(file);
252 if (!fwfile.open(QIODevice::ReadOnly)) {
253 standardOutput << "Cannot open file " << file << endl;
254 return -1;
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;
261 return -1;
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;
267 return -1;
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;
277 return false;
279 QByteArray fw;
280 dfu.DownloadFirmware(&fw, 0);
281 while (!dfu.isFinished()) {
282 QThread::msleep(500);
284 bool ret = dfu.SaveByteArrayToFile(file.toLatin1(), fw);
285 return ret;
286 } else if (action == DFU::actionCompareCrc) {
287 dfu.CompareFirmware(file.toLatin1(), DFU::crccompare, device);
288 return 1;
289 } else if (action == DFU::actionCompareAll) {
290 if (((DFU::device)dfu.devices[device]).Readable == false) {
291 standardOutput << "ERROR device not readable\n" << endl;
292 return false;
294 dfu.CompareFirmware(file.toLatin1(), DFU::bytetobytecompare, device);
295 return 1;
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) {
300 dfu.ResetDevice();
301 } else if (action == DFU::actionJump) {
302 dfu.JumpToApp(false, false);
304 return 0;
306 // return a.exec();
309 void showProgress(QString status)
311 QTextStream standardOutput(stdout);
313 standardOutput << status << endl;
314 label = status;
317 void progressUpdated(int percent)
319 std::string bar;
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, ">");
326 } else {
327 bar.replace(i, 1, " ");
330 std::cout << "\r" << label.toLatin1().data() << " [" << bar << "] ";
331 std::cout.width(3);
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;