Make TX volatge for simu more flexible (#7124)
[opentx.git] / companion / src / flasheepromdialog.cpp
blob6c210f9402ee6c338d91d3eb505e5e3bfb09bf2a
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)
36 ui->setupUi(this);
37 ui->profileLabel->setText(tr("Current profile: %1").arg(g.profile[g.id()].name()));
38 if (!filename.isEmpty()) {
39 ui->eepromFilename->hide();
40 ui->eepromLoad->hide();
42 QString backupPath = g.profile[g.id()].pBackupDir();
43 if (backupPath.isEmpty()) {
44 backupPath = g.backupDir();
45 ui->backupBeforeWrite->setChecked(g.enableBackup() || g.profile[g.id()].penableBackup());
47 if (backupPath.isEmpty() || !QDir(backupPath).exists()) {
48 ui->backupBeforeWrite->setEnabled(false);
52 FlashEEpromDialog::~FlashEEpromDialog()
54 delete ui;
57 void FlashEEpromDialog::showEvent(QShowEvent *)
59 updateUI();
62 void FlashEEpromDialog::updateUI()
64 // ui->burnButton->setEnabled(true);
65 ui->eepromFilename->setText(eepromFilename);
66 if (!eepromFilename.isEmpty() && getEEpromVersion(eepromFilename) >= 0) {
67 ui->profileLabel->show();
68 ui->patchCalibration->show();
69 ui->patchHardwareSettings->show();
70 QString name = g.profile[g.id()].name();
71 QString calib = g.profile[g.id()].stickPotCalib();
72 QString trainercalib = g.profile[g.id()].trainerCalib();
73 QString DisplaySet = g.profile[g.id()].display();
74 QString BeeperSet = g.profile[g.id()].beeper();
75 QString HapticSet = g.profile[g.id()].haptic();
76 QString SpeakerSet = g.profile[g.id()].speaker();
77 if (!name.isEmpty()) {
78 ui->profileLabel->show();
79 ui->patchCalibration->show();
80 ui->patchHardwareSettings->show();
81 // TODO I hardcode the number of pots here, should be dependant on the board?
82 if (!((calib.length()==(CPN_MAX_STICKS+3)*12) && (trainercalib.length()==16))) {
83 ui->patchCalibration->setDisabled(true);
85 if (!((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6))) {
86 ui->patchHardwareSettings->setDisabled(true);
89 else {
90 ui->profileLabel->hide();
92 ui->burnButton->setEnabled(true);
94 else {
95 ui->profileLabel->hide();
96 ui->patchCalibration->hide();
97 ui->patchHardwareSettings->hide();
99 QTimer::singleShot(0, this, SLOT(shrink()));
102 void FlashEEpromDialog::on_eepromLoad_clicked()
104 QString filename = QFileDialog::getOpenFileName(this, tr("Choose Radio Backup file"), g.eepromDir(), EXTERNAL_EEPROM_FILES_FILTER);
105 if (!filename.isEmpty()) {
106 eepromFilename = filename;
107 updateUI();
111 int FlashEEpromDialog::getEEpromVersion(const QString & filename)
113 int result = -1;
114 QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
115 Storage storage(filename);
116 if (storage.load(*radioData)) {
117 result = radioData->generalSettings.version;
119 else {
120 QMessageBox::warning(this, CPN_STR_TTL_ERROR, storage.error());
122 return result;
125 bool FlashEEpromDialog::patchCalibration(RadioData * radioData)
127 QString calib = g.profile[g.id()].stickPotCalib();
128 QString trainercalib = g.profile[g.id()].trainerCalib();
129 int potsnum = getBoardCapability(getCurrentBoard(), Board::Pots);
130 int8_t txVoltageCalibration = (int8_t) g.profile[g.id()].txVoltageCalibration();
131 int8_t txCurrentCalibration = (int8_t) g.profile[g.id()].txCurrentCalibration();
132 int8_t PPM_Multiplier = (int8_t) g.profile[g.id()].ppmMultiplier();
134 if ((calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (trainercalib.length()==16)) {
135 QString Byte;
136 int16_t byte16;
137 bool ok;
138 for (int i=0; i<CPN_MAX_STICKS+potsnum; i++) {
139 Byte=calib.mid(i*12,4);
140 byte16=(int16_t)Byte.toInt(&ok,16);
141 if (ok)
142 radioData->generalSettings.calibMid[i]=byte16;
143 Byte=calib.mid(4+i*12,4);
144 byte16=(int16_t)Byte.toInt(&ok,16);
145 if (ok)
146 radioData->generalSettings.calibSpanNeg[i]=byte16;
147 Byte=calib.mid(8+i*12,4);
148 byte16=(int16_t)Byte.toInt(&ok,16);
149 if (ok)
150 radioData->generalSettings.calibSpanPos[i]=byte16;
152 for (int i=0; i<4; i++) {
153 Byte = trainercalib.mid(i*4,4);
154 byte16 = (int16_t)Byte.toInt(&ok,16);
155 if (ok) {
156 radioData->generalSettings.trainer.calib[i] = byte16;
159 radioData->generalSettings.txCurrentCalibration = txCurrentCalibration;
160 radioData->generalSettings.txVoltageCalibration = txVoltageCalibration;
161 radioData->generalSettings.PPM_Multiplier = PPM_Multiplier;
162 return true;
164 else {
165 QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio calibration data in profile, Settings not patched"));
166 return false;
170 bool FlashEEpromDialog::patchHardwareSettings(RadioData * radioData)
172 QString DisplaySet = g.profile[g.id()].display();
173 QString BeeperSet = g.profile[g.id()].beeper();
174 QString HapticSet = g.profile[g.id()].haptic();
175 QString SpeakerSet = g.profile[g.id()].speaker();
176 uint8_t GSStickMode=(uint8_t) g.profile[g.id()].gsStickMode();
177 uint8_t vBatWarn=(uint8_t) g.profile[g.id()].vBatWarn();
179 if ((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6)) {
180 radioData->generalSettings.vBatWarn = vBatWarn;
181 radioData->generalSettings.stickMode = GSStickMode;
182 uint8_t byte8u;
183 int8_t byte8;
184 bool ok;
185 byte8=(int8_t)DisplaySet.mid(0,2).toInt(&ok,16);
186 if (ok) radioData->generalSettings.optrexDisplay=(byte8==1 ? true : false);
187 byte8u=(uint8_t)DisplaySet.mid(2,2).toUInt(&ok,16);
188 if (ok) radioData->generalSettings.contrast=byte8u;
189 byte8u=(uint8_t)DisplaySet.mid(4,2).toUInt(&ok,16);
190 if (ok) radioData->generalSettings.backlightBright=byte8u;
191 byte8u=(uint8_t)BeeperSet.mid(0,2).toUInt(&ok,16);
192 if (ok) radioData->generalSettings.beeperMode=(GeneralSettings::BeeperMode)byte8u;
193 byte8=(int8_t)BeeperSet.mid(2,2).toInt(&ok,16);
194 if (ok) radioData->generalSettings.beeperLength=byte8;
195 byte8u=(uint8_t)HapticSet.mid(0,2).toUInt(&ok,16);
196 if (ok) radioData->generalSettings.hapticMode=(GeneralSettings::BeeperMode)byte8u;
197 byte8u=(uint8_t)HapticSet.mid(2,2).toUInt(&ok,16);
198 if (ok) radioData->generalSettings.hapticStrength=byte8u;
199 byte8=(int8_t)HapticSet.mid(4,2).toInt(&ok,16);
200 if (ok) radioData->generalSettings.hapticLength=byte8;
201 byte8u=(uint8_t)SpeakerSet.mid(0,2).toUInt(&ok,16);
202 if (ok) radioData->generalSettings.speakerMode=byte8u;
203 byte8u=(uint8_t)SpeakerSet.mid(2,2).toUInt(&ok,16);
204 if (ok) radioData->generalSettings.speakerPitch=byte8u;
205 byte8u=(uint8_t)SpeakerSet.mid(4,2).toUInt(&ok,16);
206 if (ok) radioData->generalSettings.speakerVolume=byte8u;
207 return true;
209 else {
210 QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio setting data in profile, Settings not patched"));
211 return false;
215 void FlashEEpromDialog::on_burnButton_clicked()
217 QString filename = eepromFilename;
218 bool patch = false;
220 if (ui->patchCalibration->isChecked() || ui->patchHardwareSettings->isChecked()) {
221 QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
222 Storage storage(eepromFilename);
223 if (storage.load(*radioData)) {
224 if (ui->patchCalibration->isChecked())
225 patch |= patchCalibration(radioData.data());
226 if (ui->patchHardwareSettings->isChecked())
227 patch |= patchHardwareSettings(radioData.data());
230 if (patch) {
231 filename = generateProcessUniqueTempFileName("patched.bin");
232 QFile file(filename);
233 uint8_t *eeprom = (uint8_t*)malloc(Boards::getEEpromSize(getCurrentBoard()));
234 int eeprom_size = getCurrentEEpromInterface()->save(eeprom, *radioData, 0, getCurrentFirmware()->getVariantNumber());
235 if (eeprom_size == 0) {
236 return;
238 if (!file.open(QIODevice::WriteOnly)) {
239 QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
240 return;
242 QTextStream outputStream(&file);
243 long result = file.write((char*)eeprom, eeprom_size);
244 if (result != eeprom_size) {
245 QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
246 return;
251 close();
253 ProgressDialog progressDialog(this, tr("Write Models and Settings to Radio"), CompanionIcon("write_eeprom.png"));
255 // backup previous EEPROM if requested
256 QString backupFilename;
257 QString backupPath;
258 if (ui->backupBeforeWrite->isChecked()) {
259 backupPath = g.profile[g.id()].pBackupDir();
260 if (backupPath.isEmpty()) {
261 backupPath=g.backupDir();
263 backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
265 else if (ui->checkFirmwareCompatibility->isChecked()) {
266 backupFilename = generateProcessUniqueTempFileName("eeprom.bin");
268 if (!backupFilename.isEmpty()) {
269 if (!readEeprom(backupFilename, progressDialog.progress())) {
270 return;
274 // check EEPROM compatibility if requested
275 if (ui->checkFirmwareCompatibility->isChecked()) {
276 int eepromVersion = getEEpromVersion(filename);
277 QString firmwareFilename = generateProcessUniqueTempFileName("flash.bin");
278 if (!readFirmware(firmwareFilename, progressDialog.progress()))
279 return;
280 QString compatEEprom = generateProcessUniqueTempFileName("compat.bin");
281 if (convertEEprom(filename, compatEEprom, firmwareFilename)) {
282 int compatVersion = getEEpromVersion(compatEEprom);
283 if ((compatVersion / 100) != (eepromVersion / 100)) {
284 QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware belongs to another product family, check file and preferences!"));
285 return;
287 else if (compatVersion < eepromVersion) {
288 QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware is outdated, please upgrade!"));
289 return;
291 filename = compatEEprom;
293 else if (QMessageBox::question(this, CPN_STR_TTL_ERROR, tr("Cannot check Models and Settings compatibility! Continue anyway?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) {
294 return;
296 qunlink(firmwareFilename);
299 // and write...
300 bool result = writeEeprom(filename, progressDialog.progress());
301 if (!result && !progressDialog.isEmpty()) {
302 progressDialog.exec();
306 void FlashEEpromDialog::on_cancelButton_clicked()
308 close();
311 void FlashEEpromDialog::shrink()
313 resize(0, 0);