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"
25 #include <QMessageBox>
30 #if defined _MSC_VER || !defined __GNUC__
34 #define sleep(x) Sleep(x*1000)
39 FlashProcess::FlashProcess(const QString
& cmd
, const QStringList
& args
, ProgressWidget
* progress
):
43 process(new QProcess(this)),
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()
66 bool FlashProcess::run()
68 if (!QFile::exists(cmd
)) {
69 QMessageBox::critical(nullptr, CPN_STR_APP_NAME
, tr("Executable %1 not found").arg(cmd
));
74 if (cmd
.toLower().contains("sam-ba")) {
75 killTimer
= new QTimer(this);
76 connect(killTimer
, SIGNAL(timeout()), this, SLOT(onKillTimerElapsed()));
77 killTimer
->start(2000);
82 connect(this, SIGNAL(finished()), &loop
, SLOT(quit()));
83 process
->start(cmd
, args
);
89 void FlashProcess::onStarted()
92 progress
->addText(cmd
+ " " + args
.join(" "));
93 progress
->addSeparator();
97 bool killProcessByName(const char *szProcessToKill
)
103 hProcessSnap
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0); // Takes a snapshot of all the processes
105 if (hProcessSnap
== INVALID_HANDLE_VALUE
) {
109 pe32
.dwSize
= sizeof(PROCESSENTRY32
);
111 if (!Process32First(hProcessSnap
, &pe32
)) {
112 CloseHandle(hProcessSnap
);
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
129 void FlashProcess::onKillTimerElapsed()
132 // trick to accelerate SAM-BA startup
133 killProcessByName("tasklist.exe");
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 ")) {
167 int start
= text
.indexOf("Complete ");
168 int end
= text
.indexOf("%");
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
) {
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-")) {
191 if (text
.contains("Cannot open device")) {
196 void FlashProcess::analyseStandardError(const QString
&text
)
198 currStderrLine
.append(text
);
199 if (currStderrLine
.contains("#")) {
200 QString avrflashPhase
= currStderrLine
.left(1).toLower();
201 if (avrflashPhase
== "w") {
202 flashPhase
= WRITING
;
203 progress
->setInfo(tr("Writing..."));
204 progress
->setValue(2 * currStderrLine
.count("#"));
206 else if (avrflashPhase
== "r") {
207 if (flashPhase
== READING
) {
208 progress
->setInfo(tr("Reading..."));
211 flashPhase
= VERIFYING
;
212 progress
->setInfo(tr("Verifying..."));
214 progress
->setValue(2 * currStderrLine
.count("#"));
218 if (currStderrLine
.contains("\n")) {
219 int nlPos
= currStderrLine
.lastIndexOf("\n");
220 currStderrLine
= currStderrLine
.mid(nlPos
+1);
223 if ((text
.contains("-E-") && !text
.contains("-E- No receive file name")) ||
224 text
.contains("No DFU capable USB device found")) {
229 void FlashProcess::onReadyReadStandardOutput()
231 QString text
= QString(process
->readAllStandardOutput());
232 progress
->addText(text
);
233 analyseStandardOutput(text
);
236 void FlashProcess::onReadyReadStandardError()
238 QString text
= QString(process
->readAllStandardError());
239 progress
->addText(text
);
240 analyseStandardError(text
);
243 void FlashProcess::errorWizard()
245 QString output
= progress
->getText();
247 if (output
.contains("avrdude: Expected signature for")) { // wrong signature
248 int pos
= output
.indexOf("avrdude: Device signature = ");
249 bool fwexist
= false;
250 QString DeviceStr
= tr("unknown");
254 QString DeviceId
= output
.mid(pos
+28, 8);
255 if (DeviceId
=="0x1e9602") {
256 DeviceStr
= "Atmega 64";
257 FwStr
="\n" + tr("ie: OpenTX for 9X board or OpenTX for 9XR board");
260 else if (DeviceId
=="0x1e9702") {
261 DeviceStr
= "Atmega 128";
262 FwStr
="\n" + tr("ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip");
265 else if (DeviceId
=="0x1e9703") {
266 DeviceStr
= "Atmega 1280";
268 else if (DeviceId
=="0x1e9704") {
269 DeviceStr
= "Atmega 1281";
271 else if (DeviceId
=="0x1e9801") {
272 DeviceStr
= "Atmega 2560";
273 FwStr
="\n" + tr("ie: OpenTX for Gruvin9X board");
276 else if (DeviceId
=="0x1e9802") {
277 DeviceStr
= "Atmega 2561";
280 if (fwexist
==false) {
281 QMessageBox::warning(nullptr, "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
));
284 Firmware
*firmware
= getCurrentFirmware();
285 QMessageBox::warning(nullptr, "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()));
288 else if (output
.contains("No DFU capable USB device found")){
289 QMessageBox::warning(nullptr, "Companion - Tip of the day", tr("Your radio does not seem connected to USB or the driver is not initialized!!!."));
293 void FlashProcess::onFinished(int code
=0)
295 progress
->addSeparator();
296 if (code
==1 && cmd
.toLower().contains("sam-ba")) {
300 progress
->setInfo(tr("Flashing done (exit code = %1)").arg(code
));
301 if (cmd
.toLower().contains("avrdude") || cmd
.toLower().contains("dfu")) {
305 else if (hasErrors
) {
306 progress
->setInfo(tr("Flashing done with errors"));
308 if (lfuse
|| hfuse
|| efuse
) {
311 progress
->setValue(progress
->maximum());
312 progress
->lock(false);
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();