[Companion] Fixes
[opentx.git] / companion / src / flasheepromdialog.cpp
blob7f65224c88e64f9232f2a7159366964dbe395534
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 "flasheepromdialog.h"
22 #include "ui_flasheepromdialog.h"
23 #include "eeprominterface.h"
24 #include "helpers.h"
25 #include "storage.h"
26 #include "appdata.h"
27 #include "progressdialog.h"
28 #include "radiointerface.h"
29 #include "splashlibrarydialog.h"
31 FlashEEpromDialog::FlashEEpromDialog(QWidget *parent, const QString &filename):
32 QDialog(parent),
33 ui(new Ui::FlashEEpromDialog),
34 eepromFilename(filename),
35 radioData(new RadioData())
37 ui->setupUi(this);
38 ui->profileLabel->setText(tr("Current profile: %1").arg(g.profile[g.id()].name()));
39 if (!filename.isEmpty()) {
40 ui->eepromFilename->hide();
41 ui->eepromLoad->hide();
43 QString backupPath = g.profile[g.id()].pBackupDir();
44 if (backupPath.isEmpty()) {
45 backupPath=g.backupDir();
46 ui->backupBeforeWrite->setChecked(g.enableBackup() || g.profile[g.id()].penableBackup());
48 if (backupPath.isEmpty() || !QDir(backupPath).exists()) {
49 ui->backupBeforeWrite->setEnabled(false);
51 updateUI();
54 FlashEEpromDialog::~FlashEEpromDialog()
56 delete ui;
59 void FlashEEpromDialog::updateUI()
61 // ui->burnButton->setEnabled(true);
62 ui->eepromFilename->setText(eepromFilename);
63 if (getEEpromVersion(eepromFilename) >= 0) {
64 ui->profileLabel->show();
65 ui->patchCalibration->show();
66 ui->patchHardwareSettings->show();
67 QString name = g.profile[g.id()].name();
68 QString calib = g.profile[g.id()].stickPotCalib();
69 QString trainercalib = g.profile[g.id()].trainerCalib();
70 QString DisplaySet = g.profile[g.id()].display();
71 QString BeeperSet = g.profile[g.id()].beeper();
72 QString HapticSet = g.profile[g.id()].haptic();
73 QString SpeakerSet = g.profile[g.id()].speaker();
74 if (!name.isEmpty()) {
75 ui->profileLabel->show();
76 ui->patchCalibration->show();
77 ui->patchHardwareSettings->show();
78 // TODO I hardcode the number of pots here, should be dependant on the board?
79 if (!((calib.length()==(CPN_MAX_STICKS+3)*12) && (trainercalib.length()==16))) {
80 ui->patchCalibration->setDisabled(true);
82 if (!((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6))) {
83 ui->patchHardwareSettings->setDisabled(true);
86 else {
87 ui->profileLabel->hide();
89 ui->burnButton->setEnabled(true);
91 else {
92 ui->profileLabel->hide();
93 ui->patchCalibration->hide();
94 ui->patchHardwareSettings->hide();
96 QTimer::singleShot(0, this, SLOT(shrink()));
99 void FlashEEpromDialog::on_eepromLoad_clicked()
101 QString filename = QFileDialog::getOpenFileName(this, tr("Choose Radio Backup file"), g.eepromDir(), tr(EXTERNAL_EEPROM_FILES_FILTER));
102 if (!filename.isEmpty()) {
103 eepromFilename = filename;
104 updateUI();
108 int FlashEEpromDialog::getEEpromVersion(const QString & filename)
110 int result = -1;
111 QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
112 Storage storage(filename);
113 if (storage.load(*radioData)) {
114 result = radioData->generalSettings.version;
116 else {
117 QMessageBox::warning(this, tr("Error"), storage.error());
119 return result;
122 bool FlashEEpromDialog::patchCalibration()
124 QString calib = g.profile[g.id()].stickPotCalib();
125 QString trainercalib = g.profile[g.id()].trainerCalib();
126 int potsnum = getCurrentFirmware()->getCapability(Pots);
127 int8_t txVoltageCalibration = (int8_t) g.profile[g.id()].txVoltageCalibration();
128 int8_t txCurrentCalibration = (int8_t) g.profile[g.id()].txCurrentCalibration();
129 int8_t PPM_Multiplier = (int8_t) g.profile[g.id()].ppmMultiplier();
131 if ((calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (trainercalib.length()==16)) {
132 QString Byte;
133 int16_t byte16;
134 bool ok;
135 for (int i=0; i<CPN_MAX_STICKS+potsnum; i++) {
136 Byte=calib.mid(i*12,4);
137 byte16=(int16_t)Byte.toInt(&ok,16);
138 if (ok)
139 radioData->generalSettings.calibMid[i]=byte16;
140 Byte=calib.mid(4+i*12,4);
141 byte16=(int16_t)Byte.toInt(&ok,16);
142 if (ok)
143 radioData->generalSettings.calibSpanNeg[i]=byte16;
144 Byte=calib.mid(8+i*12,4);
145 byte16=(int16_t)Byte.toInt(&ok,16);
146 if (ok)
147 radioData->generalSettings.calibSpanPos[i]=byte16;
149 for (int i=0; i<4; i++) {
150 Byte = trainercalib.mid(i*4,4);
151 byte16 = (int16_t)Byte.toInt(&ok,16);
152 if (ok) {
153 radioData->generalSettings.trainer.calib[i] = byte16;
156 radioData->generalSettings.txCurrentCalibration = txCurrentCalibration;
157 radioData->generalSettings.txVoltageCalibration = txVoltageCalibration;
158 radioData->generalSettings.PPM_Multiplier = PPM_Multiplier;
159 return true;
161 else {
162 QMessageBox::critical(this, tr("Warning"), tr("Wrong radio calibration data in profile, Settings not patched"));
163 return false;
167 bool FlashEEpromDialog::patchHardwareSettings()
169 QString DisplaySet = g.profile[g.id()].display();
170 QString BeeperSet = g.profile[g.id()].beeper();
171 QString HapticSet = g.profile[g.id()].haptic();
172 QString SpeakerSet = g.profile[g.id()].speaker();
173 uint8_t GSStickMode=(uint8_t) g.profile[g.id()].gsStickMode();
174 uint8_t vBatWarn=(uint8_t) g.profile[g.id()].vBatWarn();
176 if ((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6)) {
177 radioData->generalSettings.vBatWarn = vBatWarn;
178 radioData->generalSettings.stickMode = GSStickMode;
179 uint8_t byte8u;
180 int8_t byte8;
181 bool ok;
182 byte8=(int8_t)DisplaySet.mid(0,2).toInt(&ok,16);
183 if (ok) radioData->generalSettings.optrexDisplay=(byte8==1 ? true : false);
184 byte8u=(uint8_t)DisplaySet.mid(2,2).toUInt(&ok,16);
185 if (ok) radioData->generalSettings.contrast=byte8u;
186 byte8u=(uint8_t)DisplaySet.mid(4,2).toUInt(&ok,16);
187 if (ok) radioData->generalSettings.backlightBright=byte8u;
188 byte8u=(uint8_t)BeeperSet.mid(0,2).toUInt(&ok,16);
189 if (ok) radioData->generalSettings.beeperMode=(GeneralSettings::BeeperMode)byte8u;
190 byte8=(int8_t)BeeperSet.mid(2,2).toInt(&ok,16);
191 if (ok) radioData->generalSettings.beeperLength=byte8;
192 byte8u=(uint8_t)HapticSet.mid(0,2).toUInt(&ok,16);
193 if (ok) radioData->generalSettings.hapticMode=(GeneralSettings::BeeperMode)byte8u;
194 byte8u=(uint8_t)HapticSet.mid(2,2).toUInt(&ok,16);
195 if (ok) radioData->generalSettings.hapticStrength=byte8u;
196 byte8=(int8_t)HapticSet.mid(4,2).toInt(&ok,16);
197 if (ok) radioData->generalSettings.hapticLength=byte8;
198 byte8u=(uint8_t)SpeakerSet.mid(0,2).toUInt(&ok,16);
199 if (ok) radioData->generalSettings.speakerMode=byte8u;
200 byte8u=(uint8_t)SpeakerSet.mid(2,2).toUInt(&ok,16);
201 if (ok) radioData->generalSettings.speakerPitch=byte8u;
202 byte8u=(uint8_t)SpeakerSet.mid(4,2).toUInt(&ok,16);
203 if (ok) radioData->generalSettings.speakerVolume=byte8u;
204 return true;
206 else {
207 QMessageBox::critical(this, tr("Warning"), tr("Wrong radio setting data in profile, Settings not patched"));
208 return false;
212 void FlashEEpromDialog::on_burnButton_clicked()
214 // patch the eeprom if needed
215 bool patch = false;
216 if (ui->patchCalibration->isChecked()) {
217 patch |= patchCalibration();
219 if (ui->patchHardwareSettings->isChecked()) {
220 patch |= patchHardwareSettings();
222 QString filename = eepromFilename;
223 if (patch) {
224 QString filename = generateProcessUniqueTempFileName("temp.bin");
225 QFile file(filename);
226 uint8_t *eeprom = (uint8_t*)malloc(getEEpromSize(getCurrentBoard()));
227 int eeprom_size = getCurrentEEpromInterface()->save(eeprom, *radioData, 0, getCurrentFirmware()->getVariantNumber());
228 if (!eeprom_size) {
229 QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
230 return;
232 if (!file.open(QIODevice::WriteOnly)) {
233 QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
234 return;
236 QTextStream outputStream(&file);
237 long result = file.write((char*)eeprom, eeprom_size);
238 if (result != eeprom_size) {
239 QMessageBox::warning(this, tr("Error"), tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
240 return;
244 close();
246 ProgressDialog progressDialog(this, tr("Write Models and Settings to Radio"), CompanionIcon("write_eeprom.png"));
248 // backup previous EEPROM if requested
249 QString backupFilename;
250 QString backupPath;
251 if (ui->backupBeforeWrite->isChecked()) {
252 backupPath = g.profile[g.id()].pBackupDir();
253 if (backupPath.isEmpty()) {
254 backupPath=g.backupDir();
256 backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
258 else if (ui->checkFirmwareCompatibility->isChecked()) {
259 backupFilename = generateProcessUniqueTempFileName("eeprom.bin");
261 if (!backupFilename.isEmpty()) {
262 if (!readEeprom(backupFilename, progressDialog.progress())) {
263 return;
267 // check EEPROM compatibility if requested
268 if (ui->checkFirmwareCompatibility->isChecked()) {
269 int eepromVersion = getEEpromVersion(filename);
270 QString firmwareFilename = generateProcessUniqueTempFileName("flash.bin");
271 if (!readFirmware(firmwareFilename, progressDialog.progress()))
272 return;
273 QString compatEEprom = generateProcessUniqueTempFileName("compat.bin");
274 if (convertEEprom(filename, compatEEprom, firmwareFilename)) {
275 int compatVersion = getEEpromVersion(compatEEprom);
276 if ((compatVersion / 100) != (eepromVersion / 100)) {
277 QMessageBox::warning(this, tr("Warning"), tr("The radio firmware belongs to another product family, check file and preferences!"));
278 return;
280 else if (compatVersion < eepromVersion) {
281 QMessageBox::warning(this, tr("Warning"), tr("The radio firmware is outdated, please upgrade!"));
282 return;
284 filename = compatEEprom;
286 else if (QMessageBox::question(this, "Error", tr("Cannot check Models and Settings compatibility! Continue anyway?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) {
287 return;
289 qunlink(firmwareFilename);
292 // and write...
293 writeEeprom(filename, progressDialog.progress());
295 progressDialog.exec();
298 void FlashEEpromDialog::on_cancelButton_clicked()
300 close();
303 void FlashEEpromDialog::shrink()
305 resize(0, 0);