[companion] Adjust GVAR not possible in global functions (fix #5425)
[opentx.git] / companion / src / process_flash.cpp
blob85b6abb9cbfb15f1cdf4a524b434bf5df2d638fc
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "process_flash.h"
22 #include "progresswidget.h"
23 #include "eeprominterface.h"
24 #include <QFile>
25 #include <QMessageBox>
26 #include <QProcess>
27 #include <QTimer>
28 #include <QEventLoop>
30 #if defined _MSC_VER || !defined __GNUC__
31 #include <Windows.h>
32 #include <WinBase.h>
33 #include <tlhelp32.h>
34 #define sleep(x) Sleep(x*1000)
35 #else
36 #include <unistd.h>
37 #endif
39 FlashProcess::FlashProcess(const QString &cmd, const QStringList &args, ProgressWidget *progress):
40 progress(progress),
41 cmd(cmd),
42 args(args),
43 process(new QProcess(this)),
44 hasErrors(false),
45 lfuse(0),
46 hfuse(0),
47 efuse(0),
48 flashPhase(READING)
49 #if !__GNUC__
50 , killTimer(NULL)
51 #endif
53 connect(process, SIGNAL(started()),this, SLOT(onStarted()));
54 connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput()));
55 connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError()));
56 connect(process, SIGNAL(finished(int)), this, SLOT(onFinished(int)));
59 FlashProcess::~FlashProcess()
61 #if !__GNUC__
62 delete killTimer;
63 #endif
66 bool FlashProcess::run()
68 if (!QFile::exists(cmd)) {
69 QMessageBox::critical(NULL, "Companion", tr("Executable %1 not found").arg(cmd));
70 return false;
73 #if !__GNUC__
74 if (cmd.toLower().contains("sam-ba")) {
75 killTimer = new QTimer(this);
76 connect(killTimer, SIGNAL(timeout()), this, SLOT(onKillTimerElapsed()));
77 killTimer->start(2000);
79 #endif
81 QEventLoop loop;
82 connect(this, SIGNAL(finished()), &loop, SLOT(quit()));
83 process->start(cmd, args);
84 loop.exec();
86 return true;
89 void FlashProcess::onStarted()
91 progress->lock(true);
92 progress->addText(cmd + " " + args.join(" "));
93 progress->addSeparator();
96 #if !__GNUC__
97 bool killProcessByName(const char *szProcessToKill)
99 HANDLE hProcessSnap;
100 HANDLE hProcess;
101 PROCESSENTRY32 pe32;
103 hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // Takes a snapshot of all the processes
105 if (hProcessSnap == INVALID_HANDLE_VALUE) {
106 return false;
109 pe32.dwSize = sizeof(PROCESSENTRY32);
111 if (!Process32First(hProcessSnap, &pe32)) {
112 CloseHandle(hProcessSnap);
113 return false;
116 do {
117 if (!strcmp(pe32.szExeFile,szProcessToKill)) { // checks if process at current position has the name of to be killed app
118 hProcess = OpenProcess(PROCESS_TERMINATE,0, pe32.th32ProcessID); // gets handle to process
119 TerminateProcess(hProcess, 0); // Terminate process by handle
120 CloseHandle(hProcess); // close the handle
122 } while (Process32Next(hProcessSnap, &pe32)); // gets next member of snapshot
124 CloseHandle(hProcessSnap); // closes the snapshot handle
125 return true;
127 #endif
129 void FlashProcess::onKillTimerElapsed()
131 #if !__GNUC__
132 // trick to accelerate SAM-BA startup
133 killProcessByName("tasklist.exe");
134 #endif
137 void FlashProcess::analyseStandardOutput(const QString &text)
139 currStdoutLine.append(text);
140 if (currStdoutLine.contains("size = ")) {
141 int pos = currStdoutLine.lastIndexOf("size = ");
142 QString temp = currStdoutLine.mid(pos+7);
143 pos = temp.lastIndexOf("\n");
144 int size = temp.left(pos).toInt();
145 progress->setMaximum(size/2048);
147 if (currStdoutLine.contains("\n")) {
148 int nlPos = currStdoutLine.lastIndexOf("\n");
149 currStdoutLine = currStdoutLine.mid(nlPos+1);
151 if (!currStdoutLine.isEmpty()) {
152 if (currStdoutLine.at(0) == QChar('.')) {
153 int pos = currStdoutLine.lastIndexOf(".");
154 progress->setValue(pos);
156 else if (currStdoutLine.startsWith("Starting upload: [")) {
157 int pos = (currStdoutLine.lastIndexOf("#")-19)*100/256;
158 progress->setValue(pos);
162 if (text.contains("Complete ")) {
163 #if !__GNUC__
164 delete killTimer;
165 killTimer = NULL;
166 #endif
167 int start = text.indexOf("Complete ");
168 int end = text.indexOf("%");
169 if (start > 0) {
170 start += 9;
171 int value = text.mid(start, end-start).toInt();
172 progress->setValue(value);
176 if (text.contains(":010000")) {
177 // contains fuse info
178 QStringList stl = text.split(":01000000");
179 foreach (QString t, stl) {
180 bool ok = false;
181 if (!lfuse) lfuse = t.left(2).toInt(&ok, 16);
182 if (!hfuse && !ok) hfuse = t.left(2).toInt(&ok, 16);
183 if (!efuse && !ok) efuse = t.left(2).toInt(&ok, 16);
187 if (text.contains("-E-")) {
188 hasErrors = true;
192 void FlashProcess::analyseStandardError(const QString &text)
194 currStderrLine.append(text);
195 if (currStderrLine.contains("#")) {
196 QString avrflashPhase = currStderrLine.left(1).toLower();
197 if (avrflashPhase == "w") {
198 flashPhase = WRITING;
199 progress->setInfo(tr("Writing..."));
200 progress->setValue(2 * currStderrLine.count("#"));
202 else if (avrflashPhase == "r") {
203 if (flashPhase == READING) {
204 progress->setInfo(tr("Reading..."));
206 else {
207 flashPhase = VERIFYING;
208 progress->setInfo(tr("Verifying..."));
210 progress->setValue(2 * currStderrLine.count("#"));
214 if (currStderrLine.contains("\n")) {
215 int nlPos = currStderrLine.lastIndexOf("\n");
216 currStderrLine = currStderrLine.mid(nlPos+1);
219 if ((text.contains("-E-") && !text.contains("-E- No receive file name")) ||
220 text.contains("No DFU capable USB device found")) {
221 hasErrors = true;
225 void FlashProcess::onReadyReadStandardOutput()
227 QString text = QString(process->readAllStandardOutput());
228 progress->addText(text);
229 analyseStandardOutput(text);
232 void FlashProcess::onReadyReadStandardError()
234 QString text = QString(process->readAllStandardError());
235 progress->addText(text);
236 analyseStandardError(text);
239 void FlashProcess::errorWizard()
241 QString output = progress->getText();
243 if (output.contains("avrdude: Expected signature for")) { // wrong signature
244 int pos = output.indexOf("avrdude: Device signature = ");
245 bool fwexist = false;
246 QString DeviceStr = tr("unknown");
247 QString FwStr = "";
249 if (pos > 0) {
250 QString DeviceId = output.mid(pos+28, 8);
251 if (DeviceId=="0x1e9602") {
252 DeviceStr = "Atmega 64";
253 FwStr="\n" + tr("ie: OpenTX for 9X board or OpenTX for 9XR board");
254 fwexist = true;
256 else if (DeviceId=="0x1e9702") {
257 DeviceStr = "Atmega 128";
258 FwStr="\n" + tr("ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip");
259 fwexist = true;
261 else if (DeviceId=="0x1e9703") {
262 DeviceStr = "Atmega 1280";
264 else if (DeviceId=="0x1e9704") {
265 DeviceStr = "Atmega 1281";
267 else if (DeviceId=="0x1e9801") {
268 DeviceStr = "Atmega 2560";
269 FwStr="\n" + tr("ie: OpenTX for Gruvin9X board");
270 fwexist = true;
272 else if (DeviceId=="0x1e9802") {
273 DeviceStr = "Atmega 2561";
276 if (fwexist==false) {
277 QMessageBox::warning(NULL, "Companion - Tip of the day", tr("Your radio uses a %1 CPU!!!\n\nPlease check advanced burn options to set the correct cpu type.").arg(DeviceStr));
279 else {
280 Firmware *firmware = getCurrentFirmware();
281 QMessageBox::warning(NULL, "Companion - Tip of the day", tr("Your radio uses a %1 CPU!!!\n\nPlease select an appropriate firmware type to program it.").arg(DeviceStr)+FwStr+tr("\nYou are currently using:\n %1").arg(firmware->getName()));
284 else if (output.contains("No DFU capable USB device found")){
285 #if defined WIN32 || !defined __GNUC__
286 QMessageBox::warning(NULL, "Companion - Tip of the day", tr("Your radio does not seem connected to USB or the driver is not installed!!!\n\nPlease use ZADIG to properly install the driver."));
287 #else
288 QMessageBox::warning(NULL, "Companion - Tip of the day", tr("Your radio does not seem connected to USB or the driver is not initialized!!!."));
289 #endif
293 void FlashProcess::onFinished(int code=0)
295 progress->addSeparator();
296 if (code==1 && cmd.toLower().contains("sam-ba")) {
297 code = 0;
299 if (code) {
300 progress->setInfo(tr("Flashing done (exit code = %1)").arg(code));
301 if (cmd.toLower().contains("avrdude") || cmd.toLower().contains("dfu")) {
302 errorWizard();
305 else if (hasErrors) {
306 progress->setInfo(tr("Flashing done with errors"));
308 if (lfuse || hfuse || efuse) {
309 addReadFuses();
311 progress->setValue(progress->maximum());
312 progress->lock(false);
313 emit finished();
316 void FlashProcess::addReadFuses()
318 progress->addSeparator();
319 progress->addText(tr("FUSES: Low=%1 High=%2 Ext=%3").arg(lfuse, 2, 16, QChar('0')).arg(hfuse, 2, 16, QChar('0')).arg(efuse, 2, 16, QChar('0')));
320 progress->addSeparator();