Use PROTOCOL_TELEMETRY_MULTIMODULE for internal multi when available (#7147)
[opentx.git] / companion / src / flashfirmwaredialog.cpp
blob9a2b688ab8625faeefca5f48811b5f3322d0300e
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 "flashfirmwaredialog.h"
22 #include "ui_flashfirmwaredialog.h"
23 #include "appdata.h"
24 #include "process_flash.h"
25 #include "helpers.h"
26 #include "progressdialog.h"
27 #include "radiointerface.h"
28 #include "progresswidget.h"
29 #include "splashlibrarydialog.h"
30 #include "storage.h"
32 #if defined _MSC_VER || !defined __GNUC__
33 #include <windows.h>
34 #define sleep(x) Sleep(x*1000)
35 #else
36 #include <unistd.h>
37 #endif
39 FlashFirmwareDialog::FlashFirmwareDialog(QWidget *parent) :
40 QDialog(parent),
41 ui(new Ui::FlashFirmwareDialog),
42 fwName(g.profile[g.id()].fwName())
44 ui->setupUi(this);
46 if (!g.profile[g.id()].splashFile().isEmpty()){
47 imageSource = PROFILE;
48 imageFile = g.profile[g.id()].splashFile();
49 ui->useProfileSplash->setChecked(true);
51 else {
52 imageSource = FIRMWARE;
53 imageFile = "";
54 ui->useProfileSplash->setDisabled(true);
57 if (IS_STM32(getCurrentBoard())) {
58 // No backup on Taranis ... could be done if in massstorage
59 ui->backupEEprom->hide();
60 ui->backupEEprom->setCheckState(Qt::Unchecked);
62 else {
63 ui->backupEEprom->setCheckState(g.backupOnFlash() ? Qt::Checked : Qt::Unchecked);
66 QString backupPath = g.profile[g.id()].pBackupDir();
67 if (backupPath.isEmpty()) {
68 backupPath=g.backupDir();
70 if (backupPath.isEmpty() || !QDir(backupPath).exists()) {
71 ui->backupEEprom->setEnabled(false);
74 ui->checkHardwareCompatibility->setChecked(g.checkHardwareCompatibility());
76 updateUI();
78 resize(0, 0); // TODO needed?
81 FlashFirmwareDialog::~FlashFirmwareDialog()
83 delete ui;
86 void FlashFirmwareDialog::updateUI()
88 ui->firmwareFilename->setText(fwName);
89 ui->burnButton->setEnabled(QFile(fwName).exists());
91 FirmwareInterface firmware(fwName);
92 if (firmware.isValid()) {
93 ui->firmwareInfoFrame->show();
94 ui->date->setText(firmware.getDate() + " " + firmware.getTime());
95 ui->version->setText(firmware.getVersion());
96 ui->variant->setText(firmware.getEEpromId());
97 ui->date->setEnabled(true);
98 ui->version->setEnabled(true);
99 ui->variant->setEnabled(true);
100 if (firmware.hasSplash()) {
101 ui->splashFrame->show();
102 ui->splash->setFixedSize(firmware.getSplashWidth(), firmware.getSplashHeight());
104 else {
105 ui->splashFrame->hide();
108 else {
109 imageSource = FIRMWARE;
110 ui->firmwareInfoFrame->hide();
111 ui->splashFrame->hide();
114 QImage image;
115 switch(imageSource) {
116 case FIRMWARE:
117 ui->useFirmwareSplash->setChecked(true);
118 image = firmware.getSplash();
119 break;
120 case PROFILE:
121 ui->useProfileSplash->setChecked(true);
122 image.load(g.profile[g.id()].splashFile());
123 break;
124 case LIBRARY:
125 ui->useLibrarySplash->setChecked(true);
126 image.load(imageFile);
127 break;
128 case EXTERNAL:
129 ui->useExternalSplash->setChecked(true);
130 image.load(imageFile);
131 break;
134 if (!image.isNull()) {
135 ui->splash->setPixmap(makePixMap(image));
139 void FlashFirmwareDialog::on_firmwareLoad_clicked()
141 QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FLASH_FILES_FILTER);
142 if (!fileName.isEmpty()) {
143 fwName = fileName;
144 if (!fwName.isEmpty() && !fwName.endsWith(".dfu") && !FirmwareInterface(fwName).isValid()) {
145 QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("%1 may not be a valid firmware file").arg(fwName));
147 updateUI();
151 void FlashFirmwareDialog::on_useFirmwareSplash_clicked()
153 FirmwareInterface firmware(fwName);
154 if (!firmware.isValid()) {
155 QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "The firmware file is not valid." ));
157 else if (!firmware.hasSplash()) {
158 QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "There is no start screen image in the firmware file." ));
160 else {
161 imageSource = FIRMWARE;
163 updateUI();
166 void FlashFirmwareDialog::on_useProfileSplash_clicked()
168 QString fileName = g.profile[g.id()].splashFile();
169 if (!fileName.isEmpty()) {
170 QImage image(fileName);
171 if (image.isNull()) {
172 QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Profile image %1 is invalid.").arg(fileName));
174 else {
175 imageSource = PROFILE;
178 updateUI();
181 void FlashFirmwareDialog::on_useExternalSplash_clicked()
183 QString supportedImageFormats;
184 for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
185 supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
187 QString fileName = QFileDialog::getOpenFileName(this, tr("Open image file to use as radio start screen"), g.imagesDir(), tr("Images (%1)").arg(supportedImageFormats));
188 if (!fileName.isEmpty()){
189 g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
190 QImage image(fileName);
191 if (image.isNull()) {
192 QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Image could not be loaded from %1").arg(fileName));
194 else{
195 imageSource = EXTERNAL;
196 imageFile = fileName;
199 updateUI();
202 void FlashFirmwareDialog::on_useLibrarySplash_clicked()
204 QString fileName;
205 SplashLibraryDialog *ld = new SplashLibraryDialog(this, &fileName);
206 ld->exec();
207 if (!fileName.isEmpty()) {
208 QImage image(fileName);
209 if (image.isNull()) {
210 QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("The library image could not be loaded"));
212 else {
213 imageSource = LIBRARY;
214 imageFile = fileName;
217 updateUI();
220 void FlashFirmwareDialog::on_burnButton_clicked()
222 g.flashDir(QFileInfo(fwName).dir().absolutePath());
223 g.profile[g.id()].fwName(fwName);
224 g.checkHardwareCompatibility(ui->checkHardwareCompatibility->isChecked());
225 g.backupOnFlash(ui->backupEEprom->isChecked());
227 qDebug() << "FlashFirmwareDialog: flashing" << fwName;
229 if (imageSource != FIRMWARE) {
230 // load the splash image
231 const QPixmap * pixmap = ui->splash->pixmap();
232 QImage image;
233 if (pixmap) {
234 image = pixmap->toImage().scaled(ui->splash->width(), ui->splash->height());
236 if (image.isNull()) {
237 QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Splash image not found"));
238 return;
240 // write the customized firmware
241 QString tempFile;
242 if (getStorageType(fwName) == STORAGE_TYPE_HEX)
243 tempFile = generateProcessUniqueTempFileName("flash.hex");
244 else
245 tempFile = generateProcessUniqueTempFileName("flash.bin");
246 qDebug() << "FlashFirmwareDialog: patching" << fwName << "with custom splash screen and saving to" << tempFile;
247 FirmwareInterface firmware(fwName);
248 firmware.setSplash(image);
249 if (firmware.save(tempFile) <= 0) {
250 QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Cannot save customized firmware"));
251 return;
253 startFlash(tempFile);
255 else {
256 startFlash(fwName);
260 void FlashFirmwareDialog::on_cancelButton_clicked()
262 close();
265 void FlashFirmwareDialog::shrink()
267 resize(0, 0);
270 void FlashFirmwareDialog::startFlash(const QString &filename)
272 bool backup = g.backupOnFlash();
274 close();
276 ProgressDialog progressDialog(this, tr("Write Firmware to Radio"), CompanionIcon("write_flash.png"));
278 // check hardware compatibility if requested
279 if (g.checkHardwareCompatibility()) {
280 QString tempFirmware = generateProcessUniqueTempFileName("flash-check.bin");
281 if (!readFirmware(tempFirmware, progressDialog.progress())) {
282 QMessageBox::warning(this, tr("Firmware check failed"), tr("Could not check firmware from radio"));
283 return;
285 FirmwareInterface previousFirmware(tempFirmware);
286 qunlink(tempFirmware);
287 FirmwareInterface newFirmware(filename);
288 qDebug() << "startFlash: checking firmware compatibility between " << tempFirmware << "and" << filename;
289 if (!newFirmware.isHardwareCompatible(previousFirmware)) {
290 QMessageBox::warning(this, tr("Firmware check failed"), tr("New firmware is not compatible with the one currently installed!"));
291 if (isTempFileName(filename)) {
292 qDebug() << "startFlash: removing temporary file" << filename;
293 qunlink(filename);
295 return;
299 // backup if requested
300 bool result = true;
301 QString backupFilename;
302 QString backupPath;
303 if (backup) {
304 backupPath = g.profile[g.id()].pBackupDir();
305 if (backupPath.isEmpty()) {
306 backupPath=g.backupDir();
308 backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
309 result = readEeprom(backupFilename, progressDialog.progress());
310 sleep(2);
313 // flash
314 result = (result && writeFirmware(filename, progressDialog.progress()));
316 // restore if backup requested
317 if (backup && result) {
318 sleep(2);
319 QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
320 if (!convertEEprom(backupFilename, restoreFilename, filename)) {
321 QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
322 restoreFilename = backupFilename;
324 if (!writeEeprom(restoreFilename, progressDialog.progress())) {
325 QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
329 progressDialog.progress()->setInfo(tr("Flashing done"));
330 progressDialog.exec();
332 if (isTempFileName(filename)) {
333 qDebug() << "startFlash: removing temporary file" << filename;
334 qunlink(filename);