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"
24 #include "process_flash.h"
26 #include "progressdialog.h"
27 #include "radiointerface.h"
28 #include "progresswidget.h"
29 #include "splashlibrarydialog.h"
32 #if defined _MSC_VER || !defined __GNUC__
34 #define sleep(x) Sleep(x*1000)
39 FlashFirmwareDialog::FlashFirmwareDialog(QWidget
*parent
):
41 ui(new Ui::FlashFirmwareDialog
),
42 fwName(g
.profile
[g
.id()].fwName())
46 if (!g
.profile
[g
.id()].splashFile().isEmpty()){
47 imageSource
= PROFILE
;
48 imageFile
= g
.profile
[g
.id()].splashFile();
49 ui
->useProfileSplash
->setChecked(true);
52 imageSource
= FIRMWARE
;
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
);
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());
78 resize(0, 0); // TODO needed?
81 FlashFirmwareDialog::~FlashFirmwareDialog()
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());
105 ui
->splashFrame
->hide();
109 imageSource
= FIRMWARE
;
110 ui
->firmwareInfoFrame
->hide();
111 ui
->splashFrame
->hide();
115 switch(imageSource
) {
117 ui
->useFirmwareSplash
->setChecked(true);
118 image
= firmware
.getSplash();
121 ui
->useProfileSplash
->setChecked(true);
122 image
.load(g
.profile
[g
.id()].splashFile());
125 ui
->useLibrarySplash
->setChecked(true);
126 image
.load(imageFile
);
129 ui
->useExternalSplash
->setChecked(true);
130 image
.load(imageFile
);
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()) {
144 if (!fwName
.isEmpty() && !fwName
.endsWith(".dfu") && !FirmwareInterface(fwName
).isValid()) {
145 QMessageBox::warning(this, tr("Warning"), tr("%1 may not be a valid firmware file").arg(fwName
));
151 void FlashFirmwareDialog::on_useFirmwareSplash_clicked()
153 FirmwareInterface
firmware(fwName
);
154 if (!firmware
.isValid()) {
155 QMessageBox::warning(this, tr("Error"), tr( "The firmware file is not valid." ));
157 else if (!firmware
.hasSplash()) {
158 QMessageBox::warning(this, tr("Error"), tr( "There is no start screen image in the firmware file." ));
161 imageSource
= FIRMWARE
;
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, tr("Error"), tr("Profile image %1 is invalid.").arg(fileName
));
175 imageSource
= PROFILE
;
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, tr("Error"), tr("Image could not be loaded from %1").arg(fileName
));
195 imageSource
= EXTERNAL
;
196 imageFile
= fileName
;
202 void FlashFirmwareDialog::on_useLibrarySplash_clicked()
205 SplashLibraryDialog
*ld
= new SplashLibraryDialog(this, &fileName
);
207 if (!fileName
.isEmpty()) {
208 QImage
image(fileName
);
209 if (image
.isNull()) {
210 QMessageBox::critical(this, tr("Error"), tr("The library image could not be loaded"));
213 imageSource
= LIBRARY
;
214 imageFile
= fileName
;
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();
234 image
= pixmap
->toImage().scaled(ui
->splash
->width(), ui
->splash
->height());
236 if (image
.isNull()) {
237 QMessageBox::critical(this, tr("Warning"), tr("Splash image not found"));
240 // write the customized firmware
242 if (getStorageType(fwName
) == STORAGE_TYPE_HEX
)
243 tempFile
= generateProcessUniqueTempFileName("flash.hex");
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, tr("Warning"), tr("Cannot save customized firmware"));
253 startFlash(tempFile
);
260 void FlashFirmwareDialog::on_cancelButton_clicked()
265 void FlashFirmwareDialog::shrink()
270 void FlashFirmwareDialog::startFlash(const QString
&filename
)
272 bool backup
= g
.backupOnFlash();
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"));
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
;
299 // backup if requested
301 QString backupFilename
;
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());
314 result
= (result
&& writeFirmware(filename
, progressDialog
.progress()));
316 // restore if backup requested
317 if (backup
&& result
) {
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
;