Files
edgetx-gx12/companion/src/burndialog.cpp
T

608 lines
19 KiB
C++

#include "burndialog.h"
#include "ui_burndialog.h"
#include <QtGui>
#include "eeprominterface.h"
#include "helpers.h"
#include "splashlibrary.h"
#include "flashinterface.h"
#include "hexinterface.h"
#include "appdata.h"
// Type 1 = Burn EEPROM, Type 2= Burn Flash
burnDialog::burnDialog(QWidget *parent, int Type, QString * fileName, bool * backupEE, QString DocName):
QDialog(parent),
ui(new Ui::burnDialog),
hexfileName(fileName),
backup(backupEE),
hexType(Type)
{
ui->setupUi(this);
setWindowIcon(CompanionIcon("write_flash.png"));
if (!g.profile[g.id()].splashFile().isEmpty()){
imageSource=PROFILE;
imageFile=g.profile[g.id()].splashFile();
}
else {
ui->useProfileImageCB->setDisabled(true);
imageSource=FIRMWARE;
imageFile="";
}
ui->SplashFrame->hide();
ui->FramFWInfo->hide();
ui->EEbackupCB->hide();
ui->EEbackupCB->setCheckState(*backup ? Qt::Checked : Qt::Unchecked);
if (Type == FLASH_FILE_TYPE ) {
ui->EEpromCB->hide();
ui->profile_label->hide();
ui->patchcalib_CB->hide();
ui->patchhw_CB->hide();
setWindowTitle(tr("Write firmware to Radio"));
if (IS_TARANIS(GetEepromInterface()->getBoard())) {
ui->EEbackupCB->hide();
}
}
else {
ui->FlashLoadButton->setText(tr("Browse for file"));
ui->profile_label->hide();
ui->patchcalib_CB->hide();
ui->patchhw_CB->hide();
ui->EEpromCB->hide();
ui->BurnFlashButton->setDisabled(true);
ui->FWFileName->clear();
ui->DateField->clear();
ui->versionField->clear();
ui->ModField->clear();
ui->FramFWInfo->hide();
ui->SplashFrame->hide();
ui->BurnFlashButton->setDisabled(true);
ui->EEbackupCB->hide();
if (DocName.isEmpty()) {
setWindowTitle(tr("Write Backup to Radio"));
}
else {
setWindowTitle(tr("Write Backup from %1 to Radio").arg(DocName));
}
ui->profile_label->setText(tr("Current profile")+QString(": ")+g.profile[g.id()].name());
}
if (!hexfileName->isEmpty()) {
ui->FWFileName->setText(*hexfileName);
if (Type==FLASH_FILE_TYPE) {
checkFw(*hexfileName);
}
else {
burnraw=false;
if (checkeEprom(*hexfileName)) {
QString Name = g.profile[g.id()].name();
QString calib = g.profile[g.id()].stickPotCalib();
QString trainercalib = g.profile[g.id()].trainerCalib();
QString DisplaySet = g.profile[g.id()].display();
QString BeeperSet = g.profile[g.id()].beeper();
QString HapticSet = g.profile[g.id()].haptic();
QString SpeakerSet = g.profile[g.id()].speaker();
if (!Name.isEmpty()) {
ui->profile_label->show();
ui->patchcalib_CB->show();
ui->patchhw_CB->show();
// TODO I hardcode the number of pots here, should be dependant on the board?
if (!((calib.length()==(NUM_STICKS+3)*12) && (trainercalib.length()==16))) {
ui->patchcalib_CB->setDisabled(true);
}
if (!((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6))) {
ui->patchhw_CB->setDisabled(true);
}
}
else {
ui->profile_label->hide();
}
if (!IS_TARANIS(GetEepromInterface()->getBoard())) {
ui->EEpromCB->show();
}
else {
ui->EEpromCB->setChecked(false);
}
ui->BurnFlashButton->setEnabled(true);
}
}
ui->FWFileName->hide();
ui->FlashLoadButton->hide();
hexfileName->clear();
}
else if (Type==FLASH_FILE_TYPE) {
QString FileName = g.profile[g.id()].fwName();
QFile file(FileName);
if (file.exists()) {
checkFw(FileName);
}
}
updateUI();
resize(0, 0);
}
burnDialog::~burnDialog()
{
delete ui;
}
void burnDialog::on_FlashLoadButton_clicked()
{
QString fileName;
ui->BurnFlashButton->setDisabled(true);
ui->FWFileName->clear();
ui->DateField->clear();
ui->versionField->clear();
ui->ModField->clear();
ui->FramFWInfo->hide();
ui->SplashFrame->hide();
ui->BurnFlashButton->setDisabled(true);
ui->EEbackupCB->hide();
QTimer::singleShot(0, this, SLOT(shrink()));
if (hexType==FLASH_FILE_TYPE) {
fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FLASH_FILES_FILTER);
if(fileName.isEmpty())
return;
checkFw(fileName);
}
else {
QString fileName = QFileDialog::getOpenFileName(this,tr("Choose Radio Backup file"), g.eepromDir(), tr(EXTERNAL_EEPROM_FILES_FILTER));
if (checkeEprom(fileName)) {
if (burnraw==false) {
ui->BurnFlashButton->setEnabled(true);
ui->profile_label->show();
ui->patchcalib_CB->show();
ui->patchhw_CB->show();
if (!IS_TARANIS(GetEepromInterface()->getBoard())) {
ui->EEpromCB->show();
}
else {
ui->EEpromCB->setChecked(false);
}
}
else {
ui->BurnFlashButton->setEnabled(true);
ui->profile_label->hide();
ui->patchcalib_CB->setChecked(false);
ui->patchhw_CB->setChecked(false);
ui->patchhw_CB->hide();
ui->patchcalib_CB->hide();
}
QTimer::singleShot(0, this, SLOT(shrink()));
}
}
updateUI();
}
void burnDialog::checkFw(QString fileName)
{
if (fileName.isEmpty()) {
return;
}
if (!IS_TARANIS(GetEepromInterface()->getBoard())) {
ui->EEbackupCB->show();
}
else {
ui->EEbackupCB->setChecked(false);
*backup=false;
}
ui->FWFileName->setText(fileName);
FlashInterface flash(fileName);
if (flash.isValid()) {
ui->FramFWInfo->show();
ui->DateField->setText(flash.getDate() + " " + flash.getTime());
ui->versionField->setText(flash.getVersion().isEmpty() ? flash.getSvn() : flash.getVersion());
ui->ModField->setText(flash.getEEprom());
ui->SplashFrame->hide();
if (flash.hasSplash()) {
ui->SplashFrame->show();
ui->imageLabel->setFixedSize(flash.getSplashWidth(), flash.getSplashHeight());
}
}
else {
QMessageBox::warning(this, tr("Warning"), tr("%1 may not be a valid firmware file").arg(fileName));
}
ui->BurnFlashButton->setEnabled(true);
QTimer::singleShot(0, this, SLOT(shrink()));
g.flashDir( QFileInfo(fileName).dir().absolutePath() );
}
bool burnDialog::checkeEprom(QString fileName)
{
if (fileName.isEmpty()) {
return false;
}
QFile file(fileName);
if (!file.exists()) {
QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
return false;
}
burnraw=false;
int fileType = getFileType(fileName);
if (fileType==FILE_TYPE_XML) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //reading HEX TEXT file
QMessageBox::critical(this, tr("Error"),tr("Error opening file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
QTextStream inputStream(&file);
XmlInterface(inputStream).load(radioData);
}
else if (fileType==FILE_TYPE_HEX || fileType==FILE_TYPE_EEPE) { //read HEX file
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //reading HEX TEXT file
QMessageBox::critical(this, tr("Error"),tr("Error opening file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
QDomDocument doc(ER9X_EEPROM_FILE_TYPE);
bool xmlOK = doc.setContent(&file);
if(xmlOK) {
if (!LoadEepromXml(radioData, doc)){
return false;
}
}
file.reset();
QTextStream inputStream(&file);
if (fileType==FILE_TYPE_EEPE) { // read EEPE file header
QString hline = inputStream.readLine();
if (hline!=EEPE_EEPROM_FILE_HEADER) {
file.close();
return false;
}
}
uint8_t eeprom[EESIZE_RLC_MAX];
int eeprom_size = HexInterface(inputStream).load(eeprom, EESIZE_RLC_MAX);
if (!eeprom_size) {
int res = QMessageBox::question(this, "Companion",tr("Invalid binary Models and Settings File %1, Proceed anyway ?").arg(fileName),QMessageBox::Yes | QMessageBox::No);
if (res == QMessageBox::No) {
return false;
}
burnraw=true;
ui->FWFileName->setText(fileName);
return true;
}
file.close();
if (!LoadEeprom(radioData, eeprom, eeprom_size)) {
int res = QMessageBox::question(this, "Companion",tr("Invalid binary Models and Settings File %1, Proceed anyway ?").arg(fileName),QMessageBox::Yes | QMessageBox::No);
if (res == QMessageBox::No) {
return false;
}
burnraw=true;
ui->FWFileName->setText(fileName);
return true;
}
}
else if (fileType==FILE_TYPE_BIN) { //read binary
int eeprom_size = file.size();
if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
QMessageBox::critical(this, tr("Error"),tr("Error opening file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
uint8_t *eeprom = (uint8_t *)malloc(eeprom_size);
memset(eeprom, 0, eeprom_size);
long result = file.read((char*)eeprom, eeprom_size);
file.close();
if (result != eeprom_size) {
QMessageBox::critical(this, tr("Error"),tr("Error reading file %1:\n%2.").arg(fileName).arg(file.errorString()));
return false;
}
if (!LoadEeprom(radioData, eeprom, eeprom_size)) {
int res = QMessageBox::question(this, "Companion",tr("Invalid binary Models and Settings File %1, Proceed anyway ?").arg(fileName),QMessageBox::Yes | QMessageBox::No);
if (res == QMessageBox::No) {
return false;
}
burnraw=true;
}
}
ui->FWFileName->setText(fileName);
return true;
}
void burnDialog::displaySplash()
{
QImage image;
if (imageSource == FIRMWARE){
FlashInterface flash(ui->FWFileName->text());
image = flash.getSplash();
}
else {
image.load(imageFile);
}
if (image.isNull()) {
return;
}
ui->imageLabel->setPixmap( makePixMap( image, g.profile[g.id()].fwType()));
}
void burnDialog::updateUI()
{
if (hexType==EEPROM_FILE_TYPE)
return;
ui->useProfileImageCB->setChecked( imageSource == PROFILE );
ui->useFwImageCB->setChecked( imageSource == FIRMWARE );
ui->useLibraryImageCB->setChecked( imageSource == LIBRARY );
ui->useAnotherImageCB->setChecked( imageSource == ANOTHER );
displaySplash();
}
void burnDialog::on_useFwImageCB_clicked()
{
QString fileName = ui->FWFileName->text();
FlashInterface flash(fileName);
if (!flash.isValid()) {
QMessageBox::critical(this, tr("Error"), tr( "The firmware file is not valid." ));
}
else {
if (!flash.hasSplash()) {
QMessageBox::critical(this, tr("Error"), tr( "There is no start screen image in the firmware file." ));
}
else{
imageSource = FIRMWARE;
imageFile = fileName;
}
}
updateUI();
}
void burnDialog::on_useProfileImageCB_clicked()
{
QString fileName = g.profile[g.id()].splashFile();
if (!fileName.isEmpty()){
QImage image(fileName);
if (image.isNull()) {
QMessageBox::critical(this, tr("Error"), tr("Profile image %1 is invalid.").arg(fileName));
}
else {
imageSource = PROFILE;
imageFile = fileName;
}
}
updateUI();
}
void burnDialog::on_useAnotherImageCB_clicked()
{
QString supportedImageFormats;
for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
}
QString fileName = QFileDialog::getOpenFileName(this, tr("Open image file to use as radio start screen"), g.imagesDir(), tr("Images (%1)").arg(supportedImageFormats));
if (!fileName.isEmpty()){
g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
QImage image(fileName);
if (image.isNull()) {
QMessageBox::critical(this, tr("Error"), tr("Image could not be loaded from %1").arg(fileName));
}
else{
imageSource = ANOTHER;
imageFile = fileName;
}
}
updateUI();
}
void burnDialog::on_useLibraryImageCB_clicked()
{
QString fileName;
splashLibrary *ld = new splashLibrary(this,&fileName);
ld->exec();
if (!fileName.isEmpty()) {
QImage image(fileName);
if (image.isNull()) {
QMessageBox::critical(this, tr("Error"), tr("The library image could not be loaded"));
}
else{
imageSource = LIBRARY;
imageFile = fileName;
}
}
updateUI();
}
void burnDialog::on_BurnFlashButton_clicked()
{
if (hexType==FLASH_FILE_TYPE) {
QString fileName=ui->FWFileName->text();
if (!fileName.isEmpty()) {
g.flashDir( QFileInfo(fileName).dir().absolutePath() );
if (!ui->useFwImageCB->isChecked()) {
QImage image = ui->imageLabel->pixmap()->toImage().scaled(ui->imageLabel->width(), ui->imageLabel->height());
if (!image.isNull()) {
QString tempDir = QDir::tempPath();
QString tempFile;
if (getFileType(fileName) == FILE_TYPE_HEX)
tempFile = tempDir + "/flash.hex";
else
tempFile = tempDir + "/flash.bin";
FlashInterface flash(fileName);
flash.setSplash(image);
if (flash.saveFlash(tempFile) > 0) {
hexfileName->clear();
hexfileName->append(tempFile);
} else {
hexfileName->clear();
QMessageBox::critical(this, tr("Warning"), tr("Cannot save customized firmware"));
}
}
else {
hexfileName->clear();
QMessageBox::critical(this, tr("Warning"), tr("Custom image not found"));
}
}
else {
hexfileName->clear();
hexfileName->append(fileName);
}
}
else {
QMessageBox::critical(this, tr("Warning"), tr("No firmware selected"));
hexfileName->clear();
}
}
if (hexType==EEPROM_FILE_TYPE) {
QString calib = g.profile[g.id()].stickPotCalib();
QString trainercalib = g.profile[g.id()].trainerCalib();
int potsnum=GetCurrentFirmware()->getCapability(Pots);
int8_t vBatCalib=(int8_t) g.profile[g.id()].vBatCalib();
int8_t currentCalib=(int8_t) g.profile[g.id()].currentCalib();
int8_t PPM_Multiplier=(int8_t) g.profile[g.id()].ppmMultiplier();
uint8_t GSStickMode=(uint8_t) g.profile[g.id()].gsStickMode();
uint8_t vBatWarn=(uint8_t) g.profile[g.id()].vBatWarn();
QString DisplaySet= g.profile[g.id()].display();
QString BeeperSet= g.profile[g.id()].beeper();
QString HapticSet= g.profile[g.id()].haptic();
QString SpeakerSet= g.profile[g.id()].speaker();
bool patch=false;
if (ui->patchcalib_CB->isChecked()) {
if ((calib.length()==(NUM_STICKS+potsnum)*12) && (trainercalib.length()==16)) {
QString Byte;
int16_t byte16;
bool ok;
for (int i=0; i<(NUM_STICKS+potsnum); i++) {
Byte=calib.mid(i*12,4);
byte16=(int16_t)Byte.toInt(&ok,16);
if (ok)
radioData.generalSettings.calibMid[i]=byte16;
Byte=calib.mid(4+i*12,4);
byte16=(int16_t)Byte.toInt(&ok,16);
if (ok)
radioData.generalSettings.calibSpanNeg[i]=byte16;
Byte=calib.mid(8+i*12,4);
byte16=(int16_t)Byte.toInt(&ok,16);
if (ok)
radioData.generalSettings.calibSpanPos[i]=byte16;
}
for (int i=0; i<4; i++) {
Byte=trainercalib.mid(i*4,4);
byte16=(int16_t)Byte.toInt(&ok,16);
if (ok)
radioData.generalSettings.trainer.calib[i]=byte16;
}
radioData.generalSettings.currentCalib=currentCalib;
radioData.generalSettings.vBatCalib=vBatCalib;
radioData.generalSettings.PPM_Multiplier=PPM_Multiplier;
patch=true;
} else {
QMessageBox::critical(this, tr("Warning"), tr("Wrong radio calibration data in profile, Settings not patched"));
}
}
if (ui->patchhw_CB->isChecked()) {
if ((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6)) {
radioData.generalSettings.vBatWarn=vBatWarn;
radioData.generalSettings.stickMode=GSStickMode;
uint8_t byte8u;
int8_t byte8;
bool ok;
byte8=(int8_t)DisplaySet.mid(0,2).toInt(&ok,16);
if (ok)
radioData.generalSettings.optrexDisplay=(byte8==1 ? true : false);
byte8u=(uint8_t)DisplaySet.mid(2,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.contrast=byte8u;
byte8u=(uint8_t)DisplaySet.mid(4,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.backlightBright=byte8u;
byte8u=(uint8_t)BeeperSet.mid(0,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.beeperMode=(BeeperMode)byte8u;
byte8=(int8_t)BeeperSet.mid(2,2).toInt(&ok,16);
if (ok)
radioData.generalSettings.beeperLength=byte8;
byte8u=(uint8_t)HapticSet.mid(0,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.hapticMode=(BeeperMode)byte8u;
byte8u=(uint8_t)HapticSet.mid(2,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.hapticStrength=byte8u;
byte8=(int8_t)HapticSet.mid(4,2).toInt(&ok,16);
if (ok)
radioData.generalSettings.hapticLength=byte8;
byte8u=(uint8_t)SpeakerSet.mid(0,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.speakerMode=byte8u;
byte8u=(uint8_t)SpeakerSet.mid(2,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.speakerPitch=byte8u;
byte8u=(uint8_t)SpeakerSet.mid(4,2).toUInt(&ok,16);
if (ok)
radioData.generalSettings.speakerVolume=byte8u;
patch=true;
} else {
QMessageBox::critical(this, tr("Warning"), tr("Wrong radio setting data in profile, Settings not patched"));
}
QString fileName;
if (patch) {
QString tempDir = QDir::tempPath();
fileName = tempDir + "/temp.bin";
QFile file(fileName);
uint8_t *eeprom = (uint8_t*)malloc(GetEepromInterface()->getEEpromSize());
int eeprom_size = 0;
eeprom_size = GetEepromInterface()->save(eeprom, radioData, GetCurrentFirmwareVariant());
if (!eeprom_size) {
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
hexfileName->clear();
}
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
hexfileName->clear();
}
QTextStream outputStream(&file);
long result = file.write((char*)eeprom, eeprom_size);
if(result!=eeprom_size) {
QMessageBox::warning(this, tr("Error"),tr("Error writing file %1:\n%2.").arg(fileName).arg(file.errorString()));
hexfileName->clear();
}
hexfileName->clear();
hexfileName->append(fileName);
} else {
hexfileName->clear();
hexfileName->append(ui->FWFileName->text());
}
} else {
hexfileName->clear();
hexfileName->append(ui->FWFileName->text());
}
}
this->close();
}
void burnDialog::on_cancelButton_clicked()
{
hexfileName->clear();
this->close();
}
void burnDialog::on_EEpromCB_toggled(bool checked)
{
*backup = ui->EEpromCB->isChecked();
}
void burnDialog::shrink()
{
resize(0,0);
}
void burnDialog::on_EEbackupCB_clicked()
{
*backup = ui->EEbackupCB->isChecked();
}