1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-14 20:10:08 +03:00

[Companion] Work in progress - QTreeView in MdiChild (#4197)

[Companion] QTreeView in MdiChild, Horus and X7 support added, fixes for #4224
This commit is contained in:
Bertrand Songis 2017-01-15 17:45:57 +01:00 committed by GitHub
parent d6b84371a9
commit a65aa3d6c7
60 changed files with 3539 additions and 3153 deletions

View file

@ -185,7 +185,6 @@ set(companion_MOC_HDRS
flashfirmwaredialog.h flashfirmwaredialog.h
flasheepromdialog.h flasheepromdialog.h
downloaddialog.h downloaddialog.h
modelslist.h
mdichild.h mdichild.h
mainwindow.h mainwindow.h
radionotfound.h radionotfound.h

View file

@ -20,21 +20,16 @@
#include <QApplication> #include <QApplication>
#include <QTranslator> #include <QTranslator>
#include <QLocale>
#include <QString>
#include <QDir> #include <QDir>
#include <QFileInfo>
#include <QSplashScreen> #include <QSplashScreen>
#include <QThread>
#include <iostream>
#if defined(JOYSTICKS) || defined(SIMU_AUDIO) #if defined(JOYSTICKS) || defined(SIMU_AUDIO)
#include <SDL.h> #include <SDL.h>
#undef main #undef main
#endif #endif
#include "mainwindow.h" #include "mainwindow.h"
#include "version.h" #include "version.h"
#include "eeprominterface.h"
#include "appdata.h" #include "appdata.h"
#include "storage.h"
#if defined _MSC_VER || !defined __GNUC__ #if defined _MSC_VER || !defined __GNUC__
#include <windows.h> #include <windows.h>
@ -107,6 +102,7 @@ int main(int argc, char *argv[])
} }
#endif #endif
registerStorageFactories();
registerEEpromInterfaces(); registerEEpromInterfaces();
registerOpenTxFirmwares(); registerOpenTxFirmwares();
registerSimulators(); registerSimulators();

View file

@ -21,6 +21,7 @@
#include "contributorsdialog.h" #include "contributorsdialog.h"
#include "ui_htmldialog.h" #include "ui_htmldialog.h"
#include "helpers.h" #include "helpers.h"
#include <QFile>
ContributorsDialog::ContributorsDialog(QWidget * parent): ContributorsDialog::ContributorsDialog(QWidget * parent):
QDialog(parent), QDialog(parent),

View file

@ -22,6 +22,7 @@
#define _EEPROMIMPORTEXPORT_H_ #define _EEPROMIMPORTEXPORT_H_
#include "customdebug.h" #include "customdebug.h"
#include <QBitArray>
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0])) #define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))

View file

@ -18,11 +18,6 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <stdio.h>
#include <list>
#include <float.h>
#include <QtWidgets>
#include <stdlib.h>
#include "eeprominterface.h" #include "eeprominterface.h"
#include "firmwares/er9x/er9xinterface.h" #include "firmwares/er9x/er9xinterface.h"
#include "firmwares/ersky9x/ersky9xinterface.h" #include "firmwares/ersky9x/ersky9xinterface.h"
@ -32,9 +27,41 @@
#include "helpers.h" #include "helpers.h"
#include "wizarddata.h" #include "wizarddata.h"
#include "firmwareinterface.h" #include "firmwareinterface.h"
#include <stdio.h>
#include <list>
#include <float.h>
#include <QtWidgets>
#include <stdlib.h>
#include <bitset>
std::list<QString> EEPROMWarnings; std::list<QString> EEPROMWarnings;
int getEEpromSize(BoardEnum board)
{
switch (board) {
case BOARD_STOCK:
return EESIZE_STOCK;
case BOARD_M128:
return EESIZE_M128;
case BOARD_MEGA2560:
case BOARD_GRUVIN9X:
return EESIZE_GRUVIN9X;
case BOARD_SKY9X:
return EESIZE_SKY9X;
case BOARD_9XRPRO:
case BOARD_AR9X:
return EESIZE_9XRPRO;
case BOARD_TARANIS_X7:
case BOARD_TARANIS_X9D:
case BOARD_TARANIS_X9DP:
case BOARD_TARANIS_X9E:
case BOARD_FLAMENCO:
return EESIZE_TARANIS;
default:
return 0; // unlimited
}
}
const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out
1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2, 1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1, 2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1,
@ -631,7 +658,7 @@ QString RawSwitch::toString() const
BoardEnum board = GetEepromInterface()->getBoard(); BoardEnum board = GetEepromInterface()->getBoard();
switch(type) { switch(type) {
case SWITCH_TYPE_SWITCH: case SWITCH_TYPE_SWITCH:
if (IS_HORUS(board) || IS_TARANIS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
div_t qr = div(index-1, 3); div_t qr = div(index-1, 3);
Firmware::Switch sw = GetCurrentFirmware()->getSwitch(qr.quot); Firmware::Switch sw = GetCurrentFirmware()->getSwitch(qr.quot);
const char * positions[] = { ARROW_UP, "-", ARROW_DOWN }; const char * positions[] = { ARROW_UP, "-", ARROW_DOWN };
@ -1402,6 +1429,11 @@ void ModelData::clearMixes()
mixData[i].clear(); mixData[i].clear();
} }
RadioData::RadioData()
{
models.resize(GetCurrentFirmware()->getCapability(Models));
}
void ModelData::clear() void ModelData::clear()
{ {
memset(this, 0, sizeof(ModelData)); memset(this, 0, sizeof(ModelData));
@ -1412,7 +1444,7 @@ void ModelData::clear()
moduleData[1].ppm.delay = 300; moduleData[1].ppm.delay = 300;
moduleData[2].ppm.delay = 300; moduleData[2].ppm.delay = 300;
int board = GetEepromInterface()->getBoard(); int board = GetEepromInterface()->getBoard();
if (IS_TARANIS(board) || IS_HORUS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
moduleData[0].protocol = PULSES_PXX_XJT_X16; moduleData[0].protocol = PULSES_PXX_XJT_X16;
moduleData[1].protocol = PULSES_OFF; moduleData[1].protocol = PULSES_OFF;
} }
@ -1627,16 +1659,10 @@ int ModelData::getChannelsMax(bool forceExtendedLimits) const
} }
QList<EEPROMInterface *> eepromInterfaces; QList<EEPROMInterface *> eepromInterfaces;
void registerEEpromInterfaces() void registerEEpromInterfaces()
{ {
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_STOCK)); registerOpenTxEEpromInterfaces();
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_M128));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_GRUVIN9X));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_SKY9X));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_9XRPRO));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9D));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9DP));
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9E));
// eepromInterfaces.push_back(new Ersky9xInterface()); // eepromInterfaces.push_back(new Ersky9xInterface());
// eepromInterfaces.push_back(new Er9xInterface()); // eepromInterfaces.push_back(new Er9xInterface());
} }
@ -1764,7 +1790,7 @@ const int Firmware::getFlashSize()
} }
} }
Firmware * GetFirmware(QString id) Firmware * GetFirmware(const QString & id)
{ {
foreach(Firmware * firmware, firmwares) { foreach(Firmware * firmware, firmwares) {
Firmware * result = firmware->getFirmwareVariant(id); Firmware * result = firmware->getFirmwareVariant(id);

File diff suppressed because it is too large Load diff

View file

@ -92,11 +92,6 @@ Er9xGeneral::operator GeneralSettings ()
result.vBatWarn = vBatWarn; result.vBatWarn = vBatWarn;
result.txVoltageCalibration = txVoltageCalibration; result.txVoltageCalibration = txVoltageCalibration;
result.trainer = trainer; result.trainer = trainer;
result.blightinv=blightinv;
result.stickScroll=stickScroll;
result.crosstrim=crosstrim;
result.hideNameOnSplash=hideNameOnSplash;
result.enablePpmsim=enablePpmsim;
result.view = std::min((uint8_t)4, view); result.view = std::min((uint8_t)4, view);
result.disableThrottleWarning = disableThrottleWarning; result.disableThrottleWarning = disableThrottleWarning;
@ -123,9 +118,6 @@ Er9xGeneral::operator GeneralSettings ()
result.preBeep = preBeep; result.preBeep = preBeep;
result.flashBeep = flashBeep; result.flashBeep = flashBeep;
result.splashMode = disableSplashScreen; result.splashMode = disableSplashScreen;
result.disablePotScroll=(disablePotScroll==1);
result.disableBG=(disableBG==1);
result.frskyinternalalarm = frskyinternalalarm;
result.backlightMode = 0; result.backlightMode = 0;
if (lightSw == 22) { if (lightSw == 22) {

View file

@ -18,11 +18,12 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <iostream>
#include "er9xinterface.h" #include "er9xinterface.h"
#include "er9xeeprom.h" #include "er9xeeprom.h"
#include "rlefile.h" #include "rlefile.h"
#include "appdata.h" // #include "appdata.h"
// #include <iostream>
#include <bitset>
#define FILE_TYP_GENERAL 1 #define FILE_TYP_GENERAL 1
#define FILE_TYP_MODEL 2 #define FILE_TYP_MODEL 2
@ -46,20 +47,6 @@ const char * Er9xInterface::getName()
return "Er9x"; return "Er9x";
} }
const int Er9xInterface::getEEpromSize()
{
QString avrMCU = g.mcu();
if (avrMCU==QString("m128")) {
return 2*EESIZE_STOCK;
}
return EESIZE_STOCK;
}
const int Er9xInterface::getMaxModels()
{
return 16;
}
inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode) inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode)
{ {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
@ -92,6 +79,7 @@ inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode)
model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode); model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
} }
#if 0
unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
{ {
std::cout << "trying er9x xml import... "; std::cout << "trying er9x xml import... ";
@ -108,7 +96,7 @@ unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
radioData.generalSettings=er9xGeneral; radioData.generalSettings=er9xGeneral;
std::cout << "version " << (unsigned int)er9xGeneral.myVers << " "; std::cout << "version " << (unsigned int)er9xGeneral.myVers << " ";
} }
for (int i=0; i<getMaxModels(); i++) { for (int i=0; i<getCapability(Models); i++) {
Er9xModelData er9xModel; Er9xModelData er9xModel;
memset(&er9xModel,0,sizeof(er9xModel)); memset(&er9xModel,0,sizeof(er9xModel));
if(loadModelDataXML(&doc, &er9xModel, i)) { if(loadModelDataXML(&doc, &er9xModel, i)) {
@ -120,6 +108,7 @@ unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
errors.set(ALL_OK); errors.set(ALL_OK);
return errors.to_ulong(); return errors.to_ulong();
} }
#endif
unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size) unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
{ {
@ -127,7 +116,7 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i
std::bitset<NUM_ERRORS> errors; std::bitset<NUM_ERRORS> errors;
if (size != getEEpromSize()) { if (size != getEEpromSize(BOARD_STOCK)) {
std::cout << "wrong size\n"; std::cout << "wrong size\n";
errors.set(WRONG_SIZE); errors.set(WRONG_SIZE);
return errors.to_ulong(); return errors.to_ulong();
@ -176,7 +165,7 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i
} }
radioData.generalSettings = er9xGeneral; radioData.generalSettings = er9xGeneral;
for (int i=0; i<getMaxModels(); i++) { for (int i=0; i<getCapability(Models); i++) {
Er9xModelData er9xModel; Er9xModelData er9xModel;
efile->openRd(FILE_MODEL(i)); efile->openRd(FILE_MODEL(i));
if (!efile->readRlc1((uint8_t*)&er9xModel, sizeof(Er9xModelData))) { if (!efile->readRlc1((uint8_t*)&er9xModel, sizeof(Er9xModelData))) {
@ -331,3 +320,13 @@ bool Er9xInterface::loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod,
// check version? // check version?
return true; return true;
} }
int Er9xInterface::getCapability(Capability capability)
{
switch (capability) {
case Models:
return 16;
default:
return 0;
}
}

View file

@ -37,10 +37,6 @@ class Er9xInterface : public EEPROMInterface
virtual const char * getName(); virtual const char * getName();
virtual const int getEEpromSize();
virtual const int getMaxModels();
virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size); virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size);
virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index); virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index);
@ -58,6 +54,8 @@ class Er9xInterface : public EEPROMInterface
virtual int isAvailable(PulsesProtocol proto, int port=0); virtual int isAvailable(PulsesProtocol proto, int port=0);
virtual int getCapability(Capability capability);
protected: protected:
RleFile * efile; RleFile * efile;

View file

@ -143,8 +143,6 @@ Ersky9xGeneral::operator GeneralSettings ()
result.preBeep = preBeep; result.preBeep = preBeep;
result.flashBeep = flashBeep; result.flashBeep = flashBeep;
result.splashMode = disableSplashScreen; result.splashMode = disableSplashScreen;
result.disablePotScroll=(disablePotScroll==1);
result.disableBG=(disableBG==1);
result.templateSetup = templateSetup; result.templateSetup = templateSetup;
result.PPM_Multiplier = PPM_Multiplier; result.PPM_Multiplier = PPM_Multiplier;
getEEPROMString(result.ownerName, ownerName, sizeof(ownerName)); getEEPROMString(result.ownerName, ownerName, sizeof(ownerName));

View file

@ -18,10 +18,11 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <iostream>
#include "ersky9xinterface.h" #include "ersky9xinterface.h"
#include "ersky9xeeprom.h" #include "ersky9xeeprom.h"
#include "rlefile.h" #include "rlefile.h"
#include <iostream>
#include <bitset>
#define FILE_TYP_GENERAL 1 #define FILE_TYP_GENERAL 1
#define FILE_TYP_MODEL 2 #define FILE_TYP_MODEL 2
@ -48,16 +49,6 @@ const char * Ersky9xInterface::getName()
return "Ersky9x"; return "Ersky9x";
} }
const int Ersky9xInterface::getEEpromSize()
{
return EESIZE_SKY9X;
}
const int Ersky9xInterface::getMaxModels()
{
return 20;
}
inline void applyStickModeToModel(Ersky9xModelData_v10 & model, unsigned int mode) inline void applyStickModeToModel(Ersky9xModelData_v10 & model, unsigned int mode)
{ {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
@ -122,6 +113,7 @@ inline void applyStickModeToModel(Ersky9xModelData_v11 & model, unsigned int mod
model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode); model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
} }
#if 0
unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc) unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
{ {
std::cout << "trying ersky9x xml import... "; std::cout << "trying ersky9x xml import... ";
@ -138,7 +130,7 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
radioData.generalSettings=ersky9xGeneral; radioData.generalSettings=ersky9xGeneral;
std::cout << "version " << (unsigned int)ersky9xGeneral.myVers << " "; std::cout << "version " << (unsigned int)ersky9xGeneral.myVers << " ";
} }
for(int i=0; i<getMaxModels(); i++) { for(int i=0; i<getCapability(Models); i++) {
if (ersky9xGeneral.myVers == 10) { if (ersky9xGeneral.myVers == 10) {
if (!loadModelDataXML<Ersky9xModelData_v10>(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) { if (!loadModelDataXML<Ersky9xModelData_v10>(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) {
std::cout << "ko\n"; std::cout << "ko\n";
@ -158,6 +150,7 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
errors.set(ALL_OK); errors.set(ALL_OK);
return errors.to_ulong(); return errors.to_ulong();
} }
#endif
unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size) unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
{ {
@ -206,7 +199,7 @@ unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom
} }
radioData.generalSettings = ersky9xGeneral; radioData.generalSettings = ersky9xGeneral;
for (int i=0; i<getMaxModels(); i++) { for (int i=0; i<getCapability(Models); i++) {
uint8_t buffer[4096]; uint8_t buffer[4096];
uint size; uint size;
memset(buffer,0,sizeof(buffer)); memset(buffer,0,sizeof(buffer));
@ -380,3 +373,13 @@ bool Ersky9xInterface::loadModelDataXML(QDomDocument * qdoc, ModelData *model, i
*model = ersky9xModel; *model = ersky9xModel;
return true; return true;
} }
int Ersky9xInterface::getCapability(Capability capability)
{
switch (capability) {
case Models:
return 20;
default:
return 0;
}
}

View file

@ -37,16 +37,11 @@ class Ersky9xInterface : public EEPROMInterface
virtual const char * getName(); virtual const char * getName();
virtual const int getEEpromSize();
virtual const int getMaxModels();
virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size); virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size);
virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index); virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index);
virtual unsigned long loadxml(RadioData &radioData, QDomDocument &doc);
virtual int save(uint8_t * eeprom, RadioData & radioData, uint8_t version=0, uint32_t variant=0) virtual int save(uint8_t * eeprom, RadioData & radioData, uint8_t version=0, uint32_t variant=0)
{ {
return 0; return 0;
@ -58,6 +53,8 @@ class Ersky9xInterface : public EEPROMInterface
virtual int isAvailable(PulsesProtocol proto, int port=0); virtual int isAvailable(PulsesProtocol proto, int port=0);
virtual int getCapability(Capability capability);
protected: protected:
RleFile * efile; RleFile * efile;

View file

@ -35,13 +35,14 @@
#define MAX_SLIDERS(board) (IS_HORUS(board) ? 4 : (board == BOARD_TARANIS_X7 ? 0 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : 2) : 0))) #define MAX_SLIDERS(board) (IS_HORUS(board) ? 4 : (board == BOARD_TARANIS_X7 ? 0 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : 2) : 0)))
#define MAX_MOUSE_ANALOGS(board) (IS_HORUS(board) ? 2 : 0) #define MAX_MOUSE_ANALOGS(board) (IS_HORUS(board) ? 2 : 0)
#define MAX_SWITCHES(board, version) (IS_HORUS(board) ? 8 : (board == BOARD_TARANIS_X7 ? 6 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 18 : 8) : 7))) #define MAX_SWITCHES(board, version) (IS_HORUS(board) ? 8 : (board == BOARD_TARANIS_X7 ? 6 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 18 : 8) : 7)))
#define MAX_SWITCHES_POSITION(board, version) (IS_HORUS(board) ? 24 : (board == BOARD_TARANIS_X7 ? 6*3 : (IS_TARANIS_X9E(board) ? 18*3 : (IS_TARANIS(board) ? 8*3 : 9)))) #define MAX_SWITCHES_POSITION(board, version) (IS_TARANIS_X7(board) ? 6*3 : (IS_TARANIS_X9E(board) ? 18*3 : (IS_HORUS_OR_TARANIS(board) ? 8*3 : 9)))
#define MAX_ROTARY_ENCODERS(board) (IS_2560(board) ? 2 : (IS_SKY9X(board) ? 1 : 0)) #define MAX_ROTARY_ENCODERS(board) (IS_2560(board) ? 2 : (IS_SKY9X(board) ? 1 : 0))
#define MAX_FLIGHT_MODES(board, version) (IS_ARM(board) ? 9 : (IS_DBLRAM(board, version) ? 6 : 5)) #define MAX_FLIGHT_MODES(board, version) (IS_ARM(board) ? 9 : (IS_DBLRAM(board, version) ? 6 : 5))
#define MAX_TIMERS(board, version) ((IS_ARM(board) && version >= 217) ? 3 : 2) #define MAX_TIMERS(board, version) ((IS_ARM(board) && version >= 217) ? 3 : 2)
#define MAX_MIXERS(board, version) (IS_ARM(board) ? 64 : 32) #define MAX_MIXERS(board, version) (IS_ARM(board) ? 64 : 32)
#define MAX_CHANNELS(board, version) (IS_ARM(board) ? 32 : 16) #define MAX_CHANNELS(board, version) (IS_ARM(board) ? 32 : 16)
#define MAX_EXPOS(board, version) (IS_ARM(board) ? ((IS_TARANIS(board) && version >= 216) ? 64 : 32) : (IS_DBLRAM(board, version) ? 16 : 14)) #define MAX_TRIMS(board) (IS_HORUS(board) ? 6 : 4)
#define MAX_EXPOS(board, version) (IS_ARM(board) ? ((IS_HORUS_OR_TARANIS(board) && version >= 216) ? 64 : 32) : (IS_DBLRAM(board, version) ? 16 : 14))
#define MAX_LOGICAL_SWITCHES(board, version) (IS_ARM(board) ? (version >= 218 ? 64 : 32) : ((IS_DBLEEPROM(board, version) && version<217) ? 15 : 12)) #define MAX_LOGICAL_SWITCHES(board, version) (IS_ARM(board) ? (version >= 218 ? 64 : 32) : ((IS_DBLEEPROM(board, version) && version<217) ? 15 : 12))
#define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? (version >= 216 ? 64 : 32) : (IS_DBLEEPROM(board, version) ? 24 : 16)) #define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? (version >= 216 ? 64 : 32) : (IS_DBLEEPROM(board, version) ? 24 : 16))
#define MAX_CURVES(board, version) (IS_ARM(board) ? ((HAS_LARGE_LCD(board) && version >= 216) ? 32 : 16) : 8) #define MAX_CURVES(board, version) (IS_ARM(board) ? ((HAS_LARGE_LCD(board) && version >= 216) ? 32 : 16) : 8)
@ -58,7 +59,7 @@
inline int switchIndex(int i, BoardEnum board, unsigned int version) inline int switchIndex(int i, BoardEnum board, unsigned int version)
{ {
bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version); bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
if (!IS_TARANIS(board) && afterrelease21March2013) if (!IS_HORUS_OR_TARANIS(board) && afterrelease21March2013)
return (i<=3 ? i+3 : (i<=6 ? i-3 : i)); return (i<=3 ? i+3 : (i<=6 ? i-3 : i));
else else
return i; return i;
@ -102,7 +103,7 @@ class SwitchesConversionTable: public ConversionTable {
val++; val++;
} }
if (IS_TARANIS(board) && version >= 216) { if (IS_HORUS_OR_TARANIS(board) && version >= 216) {
for (int i=1; i<=MAX_POTS(board, version)*6; i++) { for (int i=1; i<=MAX_POTS(board, version)*6; i++) {
addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, -i), -val+offset); addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, -i), -val+offset);
addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, i), val++); addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, i), val++);
@ -110,7 +111,7 @@ class SwitchesConversionTable: public ConversionTable {
} }
if (version >= 216) { if (version >= 216) {
for (int i=1; i<=8; i++) { for (int i=1; i<=2*MAX_TRIMS(board); i++) {
addConversion(RawSwitch(SWITCH_TYPE_TRIM, -i), -val+offset); addConversion(RawSwitch(SWITCH_TYPE_TRIM, -i), -val+offset);
addConversion(RawSwitch(SWITCH_TYPE_TRIM, i), val++); addConversion(RawSwitch(SWITCH_TYPE_TRIM, i), val++);
} }
@ -245,7 +246,7 @@ class SourcesConversionTable: public ConversionTable {
} }
} }
for (int i=0; i<CPN_MAX_STICKS+MAX_POTS(board, version)+MAX_SLIDERS(board); i++) { for (int i=0; i<CPN_MAX_STICKS+MAX_POTS(board, version)+MAX_SLIDERS(board)+MAX_MOUSE_ANALOGS(board); i++) {
addConversion(RawSource(SOURCE_TYPE_STICK, i), val++); addConversion(RawSource(SOURCE_TYPE_STICK, i), val++);
} }
@ -267,7 +268,7 @@ class SourcesConversionTable: public ConversionTable {
} }
if (afterrelease21March2013) { if (afterrelease21March2013) {
for (int i=0; i<CPN_MAX_STICKS; i++) for (int i=0; i<MAX_TRIMS(board); i++)
addConversion(RawSource(SOURCE_TYPE_TRIM, i), val++); addConversion(RawSource(SOURCE_TYPE_TRIM, i), val++);
} }

View file

@ -18,13 +18,14 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <iostream>
#include <QMessageBox>
#include "opentxinterface.h" #include "opentxinterface.h"
#include "opentxeeprom.h" #include "opentxeeprom.h"
#include "rlefile.h" #include "rlefile.h"
#include "appdata.h" #include "appdata.h"
#include "storage_sdcard.h" #include <bitset>
#include <QMessageBox>
#include <QTime>
#include <QUrl>
#define OPENTX_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/firmware" #define OPENTX_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/firmware"
#define OPENTX_NIGHT_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/nightly/firmware" #define OPENTX_NIGHT_FIRMWARE_DOWNLOADS "http://downloads-22.open-tx.org/nightly/firmware"
@ -89,44 +90,27 @@ const char * OpenTxEepromInterface::getName()
} }
} }
const int OpenTxEepromInterface::getEEpromSize() uint32_t OpenTxEepromInterface::getFourCC()
{ {
switch (board) { switch (board) {
case BOARD_STOCK: case BOARD_HORUS:
return EESIZE_STOCK; return 0x3478746F;
case BOARD_M128:
return EESIZE_M128;
case BOARD_MEGA2560:
case BOARD_GRUVIN9X:
return EESIZE_GRUVIN9X;
case BOARD_SKY9X:
return EESIZE_SKY9X;
case BOARD_9XRPRO:
case BOARD_AR9X:
return EESIZE_9XRPRO;
case BOARD_TARANIS_X7: case BOARD_TARANIS_X7:
case BOARD_TARANIS_X9D: case BOARD_TARANIS_X9D:
case BOARD_TARANIS_X9DP: case BOARD_TARANIS_X9DP:
case BOARD_TARANIS_X9E: case BOARD_TARANIS_X9E:
case BOARD_FLAMENCO: return 0x3378746F;
return EESIZE_TARANIS; case BOARD_SKY9X:
case BOARD_AR9X:
return 0x3278746F;
case BOARD_MEGA2560:
case BOARD_GRUVIN9X:
return 0x3178746F;
default: default:
return 0; // unlimited return 0;
} }
} }
const int OpenTxEepromInterface::getMaxModels()
{
if (IS_ARM(board))
return 60;
else if (board == BOARD_M128)
return 30;
else if (IS_2560(board))
return 30;
else
return 16;
}
bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version) bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version)
{ {
QByteArray data(sizeof(settings), 0); // GeneralSettings should be always bigger than the EEPROM struct QByteArray data(sizeof(settings), 0); // GeneralSettings should be always bigger than the EEPROM struct
@ -162,12 +146,15 @@ bool OpenTxEepromInterface::loadModelFromRLE(ModelData & model, RleFile * rleFil
template <class T, class M> template <class T, class M>
bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version) bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version)
{ {
if (version == 0) {
version = getLastDataVersion(getBoard());
}
QByteArray raw; QByteArray raw;
M manager((T&)src, board, version, 0); M manager((T&)src, board, version, 0);
manager.Dump(); // manager.Dump();
manager.Export(raw); manager.Export(raw);
data.resize(8); data.resize(8);
*((uint32_t*)&data.data()[0]) = 0x3178396F; *((uint32_t*)&data.data()[0]) = getFourCC();
data[4] = version; data[4] = version;
data[5] = 'M'; data[5] = 'M';
*((uint16_t*)&data.data()[6]) = raw.size(); *((uint16_t*)&data.data()[6]) = raw.size();
@ -180,13 +167,19 @@ bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data,
{ {
M manager(dest, board, version, variant); M manager(dest, board, version, variant);
manager.Import(data); manager.Import(data);
manager.Dump(); // Dumps the structure so that it's easy to check with firmware datastructs.h // manager.Dump(); // Dumps the structure so that it's easy to check with firmware datastructs.h
return true; return true;
} }
template <class T, class M> template <class T, class M>
bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data) bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data)
{ {
uint32_t fourcc = *((uint32_t*)&data.data()[0]);
if (getFourCC() != fourcc) {
qDebug() << QString().sprintf("%s: Wrong fourcc %x vs %x", getName(), fourcc, getFourCC());
return false;
}
qDebug() << QString().sprintf("%s: OK", getName());
uint8_t version = data[4]; uint8_t version = data[4];
QByteArray raw = data.right(data.size() - 8); QByteArray raw = data.right(data.size() - 8);
return loadFromByteArray<T, M>(dest, raw, version); return loadFromByteArray<T, M>(dest, raw, version);
@ -215,84 +208,26 @@ bool OpenTxEepromInterface::saveModel(unsigned int index, ModelData &model, uint
return (sz == eeprom.size()); return (sz == eeprom.size());
} }
unsigned long OpenTxEepromInterface::loadxml(RadioData &radioData, QDomDocument &doc) QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
void registerOpenTxEEpromInterface(BoardEnum board)
{ {
std::bitset<NUM_ERRORS> errors; OpenTxEepromInterface * interface = new OpenTxEepromInterface(board);
errors.set(UNKNOWN_ERROR); opentxEEpromInterfaces.push_back(interface);
return errors.to_ulong(); eepromInterfaces.push_back(interface);
} }
int OpenTxEepromInterface::loadFile(RadioData & radioData, const QString & filename) void registerOpenTxEEpromInterfaces()
{ {
StorageSdcard storage; registerOpenTxEEpromInterface(BOARD_STOCK);
registerOpenTxEEpromInterface(BOARD_M128);
storage.read(filename); registerOpenTxEEpromInterface(BOARD_GRUVIN9X);
registerOpenTxEEpromInterface(BOARD_SKY9X);
// Radio settings registerOpenTxEEpromInterface(BOARD_9XRPRO);
qDebug() << "Radio settings:" << storage.radio.size(); registerOpenTxEEpromInterface(BOARD_TARANIS_X9D);
loadFromByteArray<GeneralSettings, OpenTxGeneralData>(radioData.generalSettings, storage.radio); registerOpenTxEEpromInterface(BOARD_TARANIS_X9DP);
registerOpenTxEEpromInterface(BOARD_TARANIS_X9E);
// Models registerOpenTxEEpromInterface(BOARD_TARANIS_X7);
int modelIndex = 0; registerOpenTxEEpromInterface(BOARD_HORUS);
QString modelList = QString(storage.modelList);
QList<QByteArray> lines = storage.modelList.split('\n');
QString category = QObject::tr("Unknown");
foreach (const QByteArray & line, lines) {
if (!line.isEmpty()) {
if (line.startsWith('[') && line.endsWith(']')) {
category = line.mid(1, line.size() - 2);
}
else {
qDebug() << "Loading" << line;
foreach (const ModelFile &model, storage.models) {
if (line == model.filename) {
loadFromByteArray<ModelData, OpenTxModelData>(radioData.models[modelIndex], model.data);
strncpy(radioData.models[modelIndex].filename, line.data(), sizeof(radioData.models[modelIndex].filename));
strncpy(radioData.models[modelIndex].category, category.toStdString().c_str(), sizeof(radioData.models[modelIndex].category));
radioData.models[modelIndex].used = true;
modelIndex++;
}
}
}
}
}
return 0;
}
int OpenTxEepromInterface::saveFile(const RadioData & radioData, const QString & filename)
{
StorageSdcard storage;
uint8_t version = getLastDataVersion(board);
// models.txt
storage.modelList = QByteArray();
QString currentCategory = "";
// radio.bin
saveToByteArray<GeneralSettings, OpenTxGeneralData>(radioData.generalSettings, storage.radio, version);
// all models
for (int i=0; i<CPN_MAX_MODELS; i++) {
const ModelData & model = radioData.models[i];
if (!model.isEmpty()) {
QString modelFilename = model.filename;
QByteArray modelData;
saveToByteArray<ModelData, OpenTxModelData>(model, modelData, version);
ModelFile modelFile = { modelFilename, modelData };
storage.models.append(modelFile);
QString modelCategory = model.category;
if (currentCategory != modelCategory) {
storage.modelList.append(QString().sprintf("[%s]\n", model.category));
currentCategory = modelCategory;
}
storage.modelList.append(modelFilename + "\n");
}
}
storage.write(filename);
return 0;
} }
unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size) unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size)
@ -301,7 +236,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
std::bitset<NUM_ERRORS> errors; std::bitset<NUM_ERRORS> errors;
if (size != getEEpromSize()) { if (size != getEEpromSize(board)) {
if (size == 4096) { if (size == 4096) {
int notnull = false; int notnull = false;
for (int i = 2048; i < 4096; i++) { for (int i = 2048; i < 4096; i++) {
@ -321,7 +256,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
} }
} }
else { else {
std::cout << " wrong size (" << size << "/" << getEEpromSize() << ")\n"; std::cout << " wrong size (" << size << "/" << getEEpromSize(board) << ")\n";
errors.set(WRONG_SIZE); errors.set(WRONG_SIZE);
return errors.to_ulong(); return errors.to_ulong();
} }
@ -362,7 +297,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
} }
std::cout << " variant " << radioData.generalSettings.variant; std::cout << " variant " << radioData.generalSettings.variant;
for (int i = 0; i < getMaxModels(); i++) { for (int i = 0; i < GetCurrentFirmware()->getCapability(Models); i++) {
if (!loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) { if (!loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) {
std::cout << " ko\n"; std::cout << " ko\n";
errors.set(UNKNOWN_ERROR); errors.set(UNKNOWN_ERROR);
@ -389,7 +324,7 @@ uint8_t OpenTxEepromInterface::getLastDataVersion(BoardEnum board)
} }
} }
int OpenTxEepromInterface::save(uint8_t * eeprom, RadioData & radioData, uint8_t version, uint32_t variant) int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, uint8_t version, uint32_t variant)
{ {
EEPROMWarnings.clear(); EEPROMWarnings.clear();
@ -397,7 +332,7 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, RadioData & radioData, uint8_t
version = getLastDataVersion(board); version = getLastDataVersion(board);
} }
int size = getEEpromSize(); int size = getEEpromSize(board);
efile->EeFsCreate(eeprom, size, board, version); efile->EeFsCreate(eeprom, size, board, version);
@ -408,14 +343,14 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, RadioData & radioData, uint8_t
variant |= TARANIS_X9E_VARIANT; variant |= TARANIS_X9E_VARIANT;
} }
int result = saveRadioSettings<OpenTxGeneralData>(radioData.generalSettings, board, version, variant); int result = saveRadioSettings<OpenTxGeneralData>((GeneralSettings &)radioData.generalSettings, board, version, variant);
if (!result) { if (!result) {
return 0; return 0;
} }
for (int i = 0; i < getMaxModels(); i++) { for (int i = 0; i < GetCurrentFirmware()->getCapability(Models); i++) {
if (!radioData.models[i].isEmpty()) { if (!radioData.models[i].isEmpty()) {
result = saveModel<OpenTxModelData>(i, radioData.models[i], version, variant); result = saveModel<OpenTxModelData>(i, (ModelData &)radioData.models[i], version, variant);
if (!result) { if (!result) {
return 0; return 0;
} }
@ -501,6 +436,15 @@ Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
int OpenTxFirmware::getCapability(Capability capability) int OpenTxFirmware::getCapability(Capability capability)
{ {
switch (capability) { switch (capability) {
case Models:
if (IS_ARM(board))
return 60;
else if (board == BOARD_M128)
return 30;
else if (IS_2560(board))
return 30;
else
return 16;
case Imperial: case Imperial:
if (IS_ARM(board)) if (IS_ARM(board))
return 0; return 0;
@ -533,12 +477,12 @@ int OpenTxFirmware::getCapability(Capability capability)
case FlightModesHaveFades: case FlightModesHaveFades:
return 1; return 1;
case Heli: case Heli:
if (IS_TARANIS(board) || IS_HORUS(board)) if (IS_HORUS_OR_TARANIS(board))
return id.contains("noheli") ? 0 : 1; return id.contains("noheli") ? 0 : 1;
else else
return id.contains("heli") ? 1 : 0; return id.contains("heli") ? 1 : 0;
case Gvars: case Gvars:
if (IS_TARANIS(board) || IS_HORUS(board)) if (IS_HORUS_OR_TARANIS(board))
return id.contains("nogvars") ? 0 : 9; return id.contains("nogvars") ? 0 : 9;
else if (id.contains("gvars")) else if (id.contains("gvars"))
return IS_ARM(board) ? 9 : 5; return IS_ARM(board) ? 9 : 5;
@ -547,7 +491,7 @@ int OpenTxFirmware::getCapability(Capability capability)
case ModelName: case ModelName:
return (IS_HORUS(board) ? 15 : (HAS_LARGE_LCD(board) ? 12 : 10)); return (IS_HORUS(board) ? 15 : (HAS_LARGE_LCD(board) ? 12 : 10));
case FlightModesName: case FlightModesName:
return ((IS_TARANIS(board) || IS_HORUS(board)) ? 10 : 6); return (IS_HORUS_OR_TARANIS(board) ? 10 : 6);
case GvarsName: case GvarsName:
return (IS_9X(board) ? 0 : 6); return (IS_9X(board) ? 0 : 6);
case GvarsInCS: case GvarsInCS:
@ -598,14 +542,14 @@ int OpenTxFirmware::getCapability(Capability capability)
return 18; return 18;
else if (board == BOARD_TARANIS_X7) else if (board == BOARD_TARANIS_X7)
return 6; return 6;
else if (IS_TARANIS(board) || board == BOARD_HORUS) else if (IS_HORUS_OR_TARANIS(board))
return 8; return 8;
else else
return 7; return 7;
case SwitchesPositions: case SwitchesPositions:
if (IS_TARANIS_X9E(board)) if (IS_TARANIS_X9E(board))
return 18 * 3; return 18 * 3;
else if (IS_TARANIS(board)) else if (IS_HORUS_OR_TARANIS(board))
return 8 * 3; return 8 * 3;
else else
return 9; return 9;
@ -652,7 +596,7 @@ int OpenTxFirmware::getCapability(Capability capability)
case Haptic: case Haptic:
return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || id.contains("haptic")); return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || id.contains("haptic"));
case ModelTrainerEnable: case ModelTrainerEnable:
if (IS_TARANIS(board)) if (IS_HORUS_OR_TARANIS(board))
return 1; return 1;
else else
return 0; return 0;
@ -669,15 +613,15 @@ int OpenTxFirmware::getCapability(Capability capability)
case NumCurves: case NumCurves:
return (HAS_LARGE_LCD(board) ? 32 : (IS_ARM(board) ? 16 : 8)); return (HAS_LARGE_LCD(board) ? 32 : (IS_ARM(board) ? 16 : 8));
case HasMixerNames: case HasMixerNames:
return (IS_ARM(board) ? (IS_TARANIS(board) ? 8 : 6) : false); return (IS_ARM(board) ? (IS_HORUS_OR_TARANIS(board) ? 8 : 6) : false);
case HasExpoNames: case HasExpoNames:
return (IS_ARM(board) ? (IS_TARANIS(board) ? 8 : 6) : false); return (IS_ARM(board) ? (IS_HORUS_OR_TARANIS(board) ? 8 : 6) : false);
case HasNoExpo: case HasNoExpo:
return (IS_TARANIS(board) ? false : true); return (IS_HORUS_OR_TARANIS(board) ? false : true);
case ChannelsName: case ChannelsName:
return (IS_ARM(board) ? (HAS_LARGE_LCD(board) ? 6 : 4) : 0); return (IS_ARM(board) ? (HAS_LARGE_LCD(board) ? 6 : 4) : 0);
case HasCvNames: case HasCvNames:
return (IS_TARANIS(board) ? 1 : 0); return (IS_HORUS_OR_TARANIS(board) ? 1 : 0);
case Telemetry: case Telemetry:
if (IS_2560(board) || IS_ARM(board) || id.contains("frsky") || id.contains("telemetrez")) if (IS_2560(board) || IS_ARM(board) || id.contains("frsky") || id.contains("telemetrez"))
return TM_HASTELEMETRY | TM_HASOFFSET | TM_HASWSHH; return TM_HASTELEMETRY | TM_HASOFFSET | TM_HASWSHH;
@ -686,6 +630,9 @@ int OpenTxFirmware::getCapability(Capability capability)
case TelemetryBars: case TelemetryBars:
return 1; return 1;
case TelemetryCustomScreens: case TelemetryCustomScreens:
if (IS_HORUS(board))
return 0;
else
return IS_ARM(board) ? 4 : 2; return IS_ARM(board) ? 4 : 2;
case TelemetryCustomScreensFieldsPerLine: case TelemetryCustomScreensFieldsPerLine:
return HAS_LARGE_LCD(board) ? 3 : 2; return HAS_LARGE_LCD(board) ? 3 : 2;
@ -732,6 +679,8 @@ int OpenTxFirmware::getCapability(Capability capability)
case LcdWidth: case LcdWidth:
if (IS_HORUS(board)) if (IS_HORUS(board))
return 480; return 480;
else if (IS_TARANIS_X7(board))
return 128;
else if (IS_TARANIS(board)) else if (IS_TARANIS(board))
return 212; return 212;
else else
@ -744,6 +693,8 @@ int OpenTxFirmware::getCapability(Capability capability)
case LcdDepth: case LcdDepth:
if (IS_HORUS(board)) if (IS_HORUS(board))
return 16; return 16;
else if (IS_TARANIS_X7(board))
return 1;
else if (IS_TARANIS(board)) else if (IS_TARANIS(board))
return 4; return 4;
else else
@ -869,7 +820,7 @@ Firmware::Switch OpenTxFirmware::getSwitch(unsigned int index)
{SWITCH_TOGGLE, "SH"}}; {SWITCH_TOGGLE, "SH"}};
return switches[index]; return switches[index];
} }
else if (IS_TARANIS(board) || board == BOARD_HORUS) { else if (IS_HORUS_OR_TARANIS(board)) {
const Switch switches[] = {{SWITCH_3POS, "SA"}, const Switch switches[] = {{SWITCH_3POS, "SA"},
{SWITCH_3POS, "SB"}, {SWITCH_3POS, "SB"},
{SWITCH_3POS, "SC"}, {SWITCH_3POS, "SC"},
@ -904,7 +855,7 @@ Firmware::Switch OpenTxFirmware::getSwitch(unsigned int index)
QTime OpenTxFirmware::getMaxTimerStart() QTime OpenTxFirmware::getMaxTimerStart()
{ {
if (IS_TARANIS(board) || IS_HORUS(board)) if (IS_HORUS_OR_TARANIS(board))
return QTime(23, 59, 59); return QTime(23, 59, 59);
else if (IS_ARM(board)) else if (IS_ARM(board))
return QTime(8, 59, 59); return QTime(8, 59, 59);
@ -925,7 +876,7 @@ bool OpenTxFirmware::isTelemetrySourceAvailable(int source)
int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port) int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
{ {
if (IS_TARANIS(board) || IS_HORUS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
switch (port) { switch (port) {
case 0: case 0:
switch (proto) { switch (proto) {
@ -1604,3 +1555,46 @@ void unregisterOpenTxFirmwares()
delete f; delete f;
} }
} }
template <class T, class M>
bool loadFromByteArray(T & dest, const QByteArray & data)
{
foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
if (eepromInterface->loadFromByteArray<T, M>(dest, data)) {
return true;
}
}
return false;
}
template <class T, class M>
bool saveToByteArray(const T & dest, QByteArray & data)
{
BoardEnum board = GetCurrentFirmware()->getBoard();
foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
if (eepromInterface->getBoard() == board) {
return eepromInterface->saveToByteArray<T, M>(dest, data);
}
}
return false;
}
bool loadModelFromByteArray(ModelData & model, const QByteArray & data)
{
return loadFromByteArray<ModelData, OpenTxModelData>(model, data);
}
bool loadRadioSettingsFromByteArray(GeneralSettings & settings, const QByteArray & data)
{
return loadFromByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);
}
bool writeModelToByteArray(const ModelData & model, QByteArray & data)
{
return saveToByteArray<ModelData, OpenTxModelData>(model, data);
}
bool writeRadioSettingsToByteArray(const GeneralSettings & settings, QByteArray & data)
{
return saveToByteArray<GeneralSettings, OpenTxGeneralData>(settings, data);
}

View file

@ -33,28 +33,18 @@ class OpenTxEepromInterface : public EEPROMInterface
virtual ~OpenTxEepromInterface(); virtual ~OpenTxEepromInterface();
virtual const int getEEpromSize();
virtual const int getMaxModels();
virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size); virtual unsigned long load(RadioData &, const uint8_t * eeprom, int size);
bool loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant); bool loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant);
virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index); virtual unsigned long loadBackup(RadioData &, const uint8_t * eeprom, int esize, int index);
virtual unsigned long loadxml(RadioData & radioData, QDomDocument & doc); virtual int save(uint8_t * eeprom, const RadioData & radioData, uint8_t version=0, uint32_t variant=0);
virtual int save(uint8_t * eeprom, RadioData & radioData, uint8_t version=0, uint32_t variant=0);
virtual int getSize(const ModelData &); virtual int getSize(const ModelData &);
virtual int getSize(const GeneralSettings &); virtual int getSize(const GeneralSettings &);
virtual int loadFile(RadioData & radioData, const QString & filename);
virtual int saveFile(const RadioData & radioData, const QString & filename);
protected: protected:
const char * getName(); const char * getName();
@ -66,11 +56,12 @@ class OpenTxEepromInterface : public EEPROMInterface
template <class T, class M> template <class T, class M>
bool loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant=0); bool loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant=0);
public:
template <class T, class M> template <class T, class M>
bool loadFromByteArray(T & dest, const QByteArray & data); bool loadFromByteArray(T & dest, const QByteArray & data);
template <class T, class M> template <class T, class M>
bool saveToByteArray(const T & src, QByteArray & data, uint8_t version); bool saveToByteArray(const T & src, QByteArray & data, uint8_t version=0);
bool loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version); bool loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version);
@ -84,6 +75,8 @@ class OpenTxEepromInterface : public EEPROMInterface
uint8_t getLastDataVersion(BoardEnum board); uint8_t getLastDataVersion(BoardEnum board);
uint32_t getFourCC();
RleFile * efile; RleFile * efile;
}; };
@ -152,5 +145,14 @@ class OpenTxFirmware: public Firmware
void registerOpenTxFirmwares(); void registerOpenTxFirmwares();
void unregisterOpenTxFirmwares(); void unregisterOpenTxFirmwares();
void registerOpenTxEEpromInterfaces();
extern QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
bool loadModelFromByteArray(ModelData & model, const QByteArray & data);
bool loadRadioSettingsFromByteArray(GeneralSettings & settings, const QByteArray & data);
bool writeModelToByteArray(const ModelData & model, QByteArray & data);
bool writeRadioSettingsToByteArray(const GeneralSettings & settings, QByteArray & data);
#endif // _OPENTXINTERFACE_H_ #endif // _OPENTXINTERFACE_H_

View file

@ -22,12 +22,10 @@
#include "ui_flasheepromdialog.h" #include "ui_flasheepromdialog.h"
#include "eeprominterface.h" #include "eeprominterface.h"
#include "helpers.h" #include "helpers.h"
#include "firmwareinterface.h" #include "storage.h"
#include "hexinterface.h"
#include "appdata.h" #include "appdata.h"
#include "progressdialog.h" #include "progressdialog.h"
#include "radiointerface.h" #include "radiointerface.h"
#include "storage_eeprom.h"
#include "splashlibrarydialog.h" #include "splashlibrarydialog.h"
FlashEEpromDialog::FlashEEpromDialog(QWidget *parent, const QString &filename): FlashEEpromDialog::FlashEEpromDialog(QWidget *parent, const QString &filename):
@ -110,85 +108,14 @@ void FlashEEpromDialog::on_eepromLoad_clicked()
int FlashEEpromDialog::getEEpromVersion(const QString & filename) int FlashEEpromDialog::getEEpromVersion(const QString & filename)
{ {
int result = -1; int result = -1;
int eeprom_size = 0; QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
Storage storage(filename);
if (filename.isEmpty()) { if (storage.load(*radioData)) {
return -1;
}
QFile file(filename);
if (!file.exists()) {
QMessageBox::warning(this, tr("Error"), tr("Unable to find file %1!").arg(filename));
return -1;
}
QByteArray eeprom(EESIZE_MAX, 0);
int fileType = getFileType(filename);
#if 0
if (fileType==FILE_TYPE_XML) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(this, tr("Error"),tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString()));
return -1;
}
QTextStream inputStream(&file);
XmlInterface(inputStream).load(testData);
}
else
#endif
if (fileType==FILE_TYPE_HEX || fileType==FILE_TYPE_EEPE) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::warning(this, tr("Error"),tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString()));
return -1;
}
QDomDocument doc(ER9X_EEPROM_FILE_TYPE);
bool xmlOK = doc.setContent(&file);
if (xmlOK) {
RadioData * radioData = new RadioData();
std::bitset<NUM_ERRORS> errors((unsigned long long)LoadEepromXml(*radioData, doc));
if (!errors.test(ALL_OK)) {
QMessageBox::warning(this, tr("Error"), tr("Invalid Models and Settings File %1").arg(filename));
}
else {
result = radioData->generalSettings.version; result = radioData->generalSettings.version;
} }
delete radioData;
return result;
}
file.reset();
QTextStream inputStream(&file);
if (fileType==FILE_TYPE_EEPE) { // read EEPE file header
QString hline = inputStream.readLine();
if (hline!=EEPE_EEPROM_FILE_HEADER) {
QMessageBox::warning(this, tr("Error"), tr("Invalid Models and Settings File %1").arg(filename));
return -1;
}
}
eeprom_size = HexInterface(inputStream).load((uint8_t *)eeprom.data(), EESIZE_MAX);
}
else if (fileType==FILE_TYPE_BIN) { //read binary
eeprom_size = file.size();
if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
QMessageBox::warning(this, tr("Error"), tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString()));
return -1;
}
int len = file.read(eeprom.data(), eeprom_size);
if (len != eeprom_size) {
QMessageBox::warning(this, tr("Error"), tr("Error reading file %1:\n%2.").arg(filename).arg(file.errorString()));
return -1;
}
}
RadioData * radioData = new RadioData();
std::bitset<NUM_ERRORS> errors((unsigned long long)LoadEeprom(*radioData, (const uint8_t *)eeprom.data(), eeprom_size));
if (eeprom_size == 0 || !errors.test(ALL_OK)) {
QMessageBox::warning(this, tr("Error"), tr("Invalid Models and Settings file %1").arg(filename));
}
else { else {
result = radioData->generalSettings.version; QMessageBox::warning(this, tr("Error"), storage.error());
} }
delete radioData;
return result; return result;
} }
@ -205,7 +132,7 @@ bool FlashEEpromDialog::patchCalibration()
QString Byte; QString Byte;
int16_t byte16; int16_t byte16;
bool ok; bool ok;
for (int i=0; i<(CPN_MAX_STICKS+potsnum); i++) { for (int i=0; i<CPN_MAX_STICKS+potsnum; i++) {
Byte=calib.mid(i*12,4); Byte=calib.mid(i*12,4);
byte16=(int16_t)Byte.toInt(&ok,16); byte16=(int16_t)Byte.toInt(&ok,16);
if (ok) if (ok)
@ -296,7 +223,7 @@ void FlashEEpromDialog::on_burnButton_clicked()
if (patch) { if (patch) {
QString filename = generateProcessUniqueTempFileName("temp.bin"); QString filename = generateProcessUniqueTempFileName("temp.bin");
QFile file(filename); QFile file(filename);
uint8_t *eeprom = (uint8_t*)malloc(GetEepromInterface()->getEEpromSize()); uint8_t *eeprom = (uint8_t*)malloc(getEEpromSize(GetCurrentFirmware()->getBoard()));
int eeprom_size = GetEepromInterface()->save(eeprom, *radioData, 0, GetCurrentFirmware()->getVariantNumber()); int eeprom_size = GetEepromInterface()->save(eeprom, *radioData, 0, GetCurrentFirmware()->getVariantNumber());
if (!eeprom_size) { if (!eeprom_size) {
QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString())); QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));

View file

@ -21,16 +21,13 @@
#include "flashfirmwaredialog.h" #include "flashfirmwaredialog.h"
#include "ui_flashfirmwaredialog.h" #include "ui_flashfirmwaredialog.h"
#include "appdata.h" #include "appdata.h"
#include "storage_eeprom.h"
#include "eeprominterface.h"
#include "firmwareinterface.h"
#include "process_flash.h" #include "process_flash.h"
#include "helpers.h" #include "helpers.h"
#include "hexinterface.h"
#include "progressdialog.h" #include "progressdialog.h"
#include "radiointerface.h" #include "radiointerface.h"
#include "progresswidget.h" #include "progresswidget.h"
#include "splashlibrarydialog.h" #include "splashlibrarydialog.h"
#include "storage.h"
#if defined _MSC_VER || !defined __GNUC__ #if defined _MSC_VER || !defined __GNUC__
#include <windows.h> #include <windows.h>
@ -242,7 +239,7 @@ void FlashFirmwareDialog::on_burnButton_clicked()
} }
// write the customized firmware // write the customized firmware
QString tempFile; QString tempFile;
if (getFileType(fwName) == FILE_TYPE_HEX) if (getStorageType(fwName) == STORAGE_TYPE_HEX)
tempFile = generateProcessUniqueTempFileName("flash.hex"); tempFile = generateProcessUniqueTempFileName("flash.hex");
else else
tempFile = generateProcessUniqueTempFileName("flash.bin"); tempFile = generateProcessUniqueTempFileName("flash.bin");

View file

@ -23,22 +23,12 @@
void HardwarePanel::setupSwitchConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type, bool threePos = true) void HardwarePanel::setupSwitchConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type, bool threePos = true)
{ {
bool enabled = false; if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Switches)) {
if (IS_TARANIS(firmware->getBoard())) {
if (IS_TARANIS_X9E(firmware->getBoard())) {
enabled = true;
type->addItem(tr("None"), Firmware::SWITCH_NONE); type->addItem(tr("None"), Firmware::SWITCH_NONE);
}
else if (index < 8) {
enabled = true;
}
}
if (enabled) {
type->addItem(tr("2 Positions Toggle"), Firmware::SWITCH_TOGGLE); type->addItem(tr("2 Positions Toggle"), Firmware::SWITCH_TOGGLE);
type->addItem(tr("2 Positions"), Firmware::SWITCH_2POS); type->addItem(tr("2 Positions"), Firmware::SWITCH_2POS);
if (threePos) type->addItem(tr("3 Positions"), Firmware::SWITCH_3POS); if (threePos)
type->addItem(tr("3 Positions"), Firmware::SWITCH_3POS);
name->setField(generalSettings.switchName[index], 3, this); name->setField(generalSettings.switchName[index], 3, this);
type->setField(generalSettings.switchConfig[index], this); type->setField(generalSettings.switchConfig[index], this);
} }
@ -51,20 +41,8 @@ void HardwarePanel::setupSwitchConfig(int index, QLabel *label, AutoLineEdit *na
void HardwarePanel::setupPotConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type) void HardwarePanel::setupPotConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type)
{ {
bool enabled = false; if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Pots)) {
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+index).toString());
if (IS_TARANIS_X9E(firmware->getBoard()) && index < 4) {
label->setText(RawSource(SOURCE_TYPE_STICK, index+CPN_MAX_STICKS).toString());
enabled = true;
}
else if (IS_TARANIS_PLUS(firmware->getBoard()) && index < 3) {
enabled = true;
}
else if (IS_TARANIS(firmware->getBoard()) && index < 2) {
enabled = true;
}
if (enabled) {
type->addItem(tr("None"), GeneralSettings::POT_NONE); type->addItem(tr("None"), GeneralSettings::POT_NONE);
type->addItem(tr("Pot with detent"), GeneralSettings::POT_WITH_DETENT); type->addItem(tr("Pot with detent"), GeneralSettings::POT_WITH_DETENT);
type->addItem(tr("Multipos switch"), GeneralSettings::POT_MULTIPOS_SWITCH); type->addItem(tr("Multipos switch"), GeneralSettings::POT_MULTIPOS_SWITCH);
@ -81,21 +59,8 @@ void HardwarePanel::setupPotConfig(int index, QLabel *label, AutoLineEdit *name,
void HardwarePanel::setupSliderConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type) void HardwarePanel::setupSliderConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type)
{ {
bool enabled = false; if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Sliders)) {
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+firmware->getCapability(Pots)+index).toString());
if (IS_TARANIS(firmware->getBoard()) && index < 2) {
type->setEnabled(false);
enabled = true;
}
else if (IS_TARANIS_X9E(firmware->getBoard()) && index < 4) {
enabled = true;
}
if (IS_TARANIS_X9E(firmware->getBoard())) {
label->setText(RawSource(SOURCE_TYPE_STICK, index+CPN_MAX_STICKS+4).toString());
}
if (enabled) {
type->addItem(tr("None"), GeneralSettings::SLIDER_NONE); type->addItem(tr("None"), GeneralSettings::SLIDER_NONE);
type->addItem(tr("Slider with detent"), GeneralSettings::SLIDER_WITH_DETENT); type->addItem(tr("Slider with detent"), GeneralSettings::SLIDER_WITH_DETENT);
name->setField(generalSettings.sliderName[index], 3, this); name->setField(generalSettings.sliderName[index], 3, this);
@ -114,7 +79,7 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
{ {
ui->setupUi(this); ui->setupUi(this);
if (IS_TARANIS(firmware->getBoard())) { if (IS_STM32(firmware->getBoard())) {
ui->rudName->setField(generalSettings.stickName[0], 3, this); ui->rudName->setField(generalSettings.stickName[0], 3, this);
ui->eleName->setField(generalSettings.stickName[1], 3, this); ui->eleName->setField(generalSettings.stickName[1], 3, this);
ui->thrName->setField(generalSettings.stickName[2], 3, this); ui->thrName->setField(generalSettings.stickName[2], 3, this);

View file

@ -31,10 +31,9 @@
#include "appdata.h" #include "appdata.h"
#include "helpers.h" #include "helpers.h"
#include "modeledit/modeledit.h"
#include "simulatordialog.h" #include "simulatordialog.h"
#include "simulatorinterface.h" #include "storage/sdcard.h"
#include "firmwareinterface.h"
#include "storage/storage_sdcard.h"
Stopwatch gStopwatch("global"); Stopwatch gStopwatch("global");
@ -377,13 +376,14 @@ void populateGvarUseCB(QComboBox *b, unsigned int phase)
void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettings & generalSettings, SwitchContext context) void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettings & generalSettings, SwitchContext context)
{ {
BoardEnum board = GetCurrentFirmware()->getBoard();
RawSwitch item; RawSwitch item;
b->clear(); b->clear();
if (context != MixesContext && context != GlobalFunctionsContext) { if (context != MixesContext && context != GlobalFunctionsContext) {
// !FMx // !FMx
if (IS_ARM(GetCurrentFirmware()->getBoard())) { if (IS_ARM(board)) {
for (int i=-GetCurrentFirmware()->getCapability(FlightModes); i<0; i++) { for (int i=-GetCurrentFirmware()->getCapability(FlightModes); i<0; i++) {
item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i); item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i);
b->addItem(item.toString(), item.toValue()); b->addItem(item.toString(), item.toValue());
@ -424,7 +424,7 @@ void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettin
for (int i=-GetCurrentFirmware()->getCapability(SwitchesPositions); i<0; i++) { for (int i=-GetCurrentFirmware()->getCapability(SwitchesPositions); i<0; i++) {
item = RawSwitch(SWITCH_TYPE_SWITCH, i); item = RawSwitch(SWITCH_TYPE_SWITCH, i);
if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings.switchPositionAllowedTaranis(i)){ if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchPositionAllowedTaranis(i)) {
continue; continue;
} }
b->addItem(item.toString(), item.toValue()); b->addItem(item.toString(), item.toValue());
@ -446,7 +446,7 @@ void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettin
for (int i=1; i<=GetCurrentFirmware()->getCapability(SwitchesPositions); i++) { for (int i=1; i<=GetCurrentFirmware()->getCapability(SwitchesPositions); i++) {
item = RawSwitch(SWITCH_TYPE_SWITCH, i); item = RawSwitch(SWITCH_TYPE_SWITCH, i);
if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings.switchPositionAllowedTaranis(i)){ if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchPositionAllowedTaranis(i)) {
continue; continue;
} }
b->addItem(item.toString(), item.toValue()); b->addItem(item.toString(), item.toValue());
@ -496,7 +496,7 @@ void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettin
// FMx // FMx
if (context != MixesContext && context != GlobalFunctionsContext) { if (context != MixesContext && context != GlobalFunctionsContext) {
if (IS_ARM(GetCurrentFirmware()->getBoard())) { if (IS_ARM(board)) {
for (int i=1; i<=GetCurrentFirmware()->getCapability(FlightModes); i++) { for (int i=1; i<=GetCurrentFirmware()->getCapability(FlightModes); i++) {
item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i); item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i);
b->addItem(item.toString(), item.toValue()); b->addItem(item.toString(), item.toValue());
@ -612,7 +612,7 @@ void populateSourceCB(QComboBox *b, const RawSource & source, const GeneralSetti
for (int i=0; i<GetCurrentFirmware()->getCapability(Switches); i++) { for (int i=0; i<GetCurrentFirmware()->getCapability(Switches); i++) {
item = RawSource(SOURCE_TYPE_SWITCH, i); item = RawSource(SOURCE_TYPE_SWITCH, i);
b->addItem(item.toString(model), item.toValue()); b->addItem(item.toString(model), item.toValue());
if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings.switchSourceAllowedTaranis(i)) { if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchSourceAllowedTaranis(i)) {
QModelIndex index = b->model()->index(b->count()-1, 0); QModelIndex index = b->model()->index(b->count()-1, 0);
QVariant v(0); QVariant v(0);
b->model()->setData(index, v, Qt::UserRole - 1); b->model()->setData(index, v, Qt::UserRole - 1);
@ -837,12 +837,13 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
if (board == BOARD_HORUS && HORUS_READY_FOR_RELEASE()) { if (board == BOARD_HORUS && HORUS_READY_FOR_RELEASE()) {
dialog = new SimulatorDialogHorus(parent, simulator, flags); dialog = new SimulatorDialogHorus(parent, simulator, flags);
GetEepromInterface()->saveFile(*simuData, g.profile[g.id()].sdPath()); SdcardFormat sdcard(g.profile[g.id()].sdPath());
sdcard.write(*simuData);
dialog->start(NULL); dialog->start(NULL);
} }
else if (board == BOARD_FLAMENCO) { else if (board == BOARD_FLAMENCO) {
dialog = new SimulatorDialogFlamenco(parent, simulator, flags); dialog = new SimulatorDialogFlamenco(parent, simulator, flags);
QByteArray eeprom(GetEepromInterface()->getEEpromSize(), 0); QByteArray eeprom(getEEpromSize(board), 0);
firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData); firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData);
dialog->start(eeprom); dialog->start(eeprom);
} }
@ -856,13 +857,13 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
} }
} }
dialog = new SimulatorDialogTaranis(parent, simulator, flags); dialog = new SimulatorDialogTaranis(parent, simulator, flags);
QByteArray eeprom(GetEepromInterface()->getEEpromSize(), 0); QByteArray eeprom(getEEpromSize(board), 0);
firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData); firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData);
dialog->start(eeprom); dialog->start(eeprom);
} }
else { else {
dialog = new SimulatorDialog9X(parent, simulator, flags); dialog = new SimulatorDialog9X(parent, simulator, flags);
QByteArray eeprom(GetEepromInterface()->getEEpromSize(), 0); QByteArray eeprom(getEEpromSize(board), 0);
firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData, 0, firmware->getCapability(SimulatorVariant)); firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData, 0, firmware->getCapability(SimulatorVariant));
dialog->start(eeprom); dialog->start(eeprom);
} }

View file

@ -21,13 +21,15 @@
#ifndef _HELPERS_H_ #ifndef _HELPERS_H_
#define _HELPERS_H_ #define _HELPERS_H_
#include "eeprominterface.h"
#include "modeledit/modeledit.h"
#include <QCheckBox> #include <QCheckBox>
#include <QSpinBox> #include <QSpinBox>
#include <QTableWidget> #include <QTableWidget>
#include <QGridLayout> #include <QGridLayout>
#include <QDebug> #include <QDebug>
#include "eeprominterface.h" #include <QTime>
#include "modeledit/modeledit.h" #include <QElapsedTimer>
extern const QColor colors[CPN_MAX_CURVES]; extern const QColor colors[CPN_MAX_CURVES];

View file

@ -18,10 +18,6 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <QtGui>
#include <QNetworkProxyFactory>
#include <QFileInfo>
#include <QDesktopServices>
#include "mainwindow.h" #include "mainwindow.h"
#include "mdichild.h" #include "mdichild.h"
#include "burnconfigdialog.h" #include "burnconfigdialog.h"
@ -48,7 +44,11 @@
#include "process_sync.h" #include "process_sync.h"
#include "radiointerface.h" #include "radiointerface.h"
#include "progressdialog.h" #include "progressdialog.h"
#include "storage_sdcard.h" #include "storage.h"
#include <QtGui>
#include <QNetworkProxyFactory>
#include <QFileInfo>
#include <QDesktopServices>
#define OPENTX_COMPANION_DOWNLOADS "http://downloads-22.open-tx.org/companion" #define OPENTX_COMPANION_DOWNLOADS "http://downloads-22.open-tx.org/companion"
#define DONATE_STR "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QUZ48K4SEXDP2" #define DONATE_STR "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QUZ48K4SEXDP2"
@ -128,16 +128,16 @@ MainWindow::MainWindow():
} }
if (strl.count()>1) str = strl[1]; if (strl.count()>1) str = strl[1];
if (!str.isEmpty()) { if (!str.isEmpty()) {
int fileType = getFileType(str); int fileType = getStorageType(str);
if (fileType==FILE_TYPE_HEX) { if (fileType==STORAGE_TYPE_HEX) {
writeFlash(str); writeFlash(str);
} }
if (fileType==FILE_TYPE_EEPE || fileType==FILE_TYPE_EEPM || fileType==FILE_TYPE_BIN) { if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN) {
MdiChild * child = createMdiChild(); MdiChild * child = createMdiChild();
if (child->loadFile(str)) { if (child->loadFile(str)) {
if (!(printing && (model >=0 && model<GetEepromInterface()->getMaxModels()) && !printfilename.isEmpty() )) { if (!(printing && model >= 0 && model<GetCurrentFirmware()->getCapability(Models) && !printfilename.isEmpty())) {
statusBar()->showMessage(tr("File loaded"), 2000); statusBar()->showMessage(tr("File loaded"), 2000);
child->show(); child->show();
} }
@ -735,8 +735,9 @@ void MainWindow::writeEeprom()
void MainWindow::simulate() void MainWindow::simulate()
{ {
if (activeMdiChild()) if (activeMdiChild()) {
activeMdiChild()->simulate(); activeMdiChild()->radioSimulate();
}
} }
@ -755,43 +756,7 @@ void MainWindow::loadBackup()
void MainWindow::readEeprom() void MainWindow::readEeprom()
{ {
if (GetCurrentFirmware()->getBoard()== BOARD_HORUS && HORUS_READY_FOR_RELEASE()) { if (GetCurrentFirmware()->getBoard()== BOARD_HORUS && HORUS_READY_FOR_RELEASE()) {
// just an example // TODO
QString path = findMassstoragePath("RADIO");
if (path.isEmpty()) {
qDebug() << "Horus card not found";
return;
}
QString realPath = path.remove(path.size()- 5, 5);
qDebug() << "Reading files from" << realPath;
StorageSdcard storage;
storage.read(realPath);
// display models.txt
QString modelList = QString(storage.modelList);
qDebug() << "Models: size" << modelList.size() << "contents" << modelList;
// info about radio.bin
qDebug() << "Radio settings:" << storage.radio.size();
// info about all models
QList<QString> models = storage.getModelsFileNames();
qDebug() << "We have" << models.size() << "models:";
foreach(QString filename, models) {
QList<ModelFile>::const_iterator i = storage.getModelIterator(filename);
if (i != storage.models.end()) {
qDebug() << "\tModel:" << i->filename << "size" << i->data.size();
}
}
for (QList<ModelFile>::iterator i = storage.models.begin(); i != storage.models.end(); ++i) {
}
// for test immediately save to current dir
storage.write("./");
} }
else { else {
QString tempFile; QString tempFile;
@ -861,16 +826,6 @@ void MainWindow::writeBackup()
cd->exec(); cd->exec();
} }
int MainWindow::getFileType(const QString & fullFileName)
{
if(QFileInfo(fullFileName).suffix().toUpper()=="HEX") return FILE_TYPE_HEX;
if(QFileInfo(fullFileName).suffix().toUpper()=="BIN") return FILE_TYPE_BIN;
if(QFileInfo(fullFileName).suffix().toUpper()=="EEPM") return FILE_TYPE_EEPM;
if(QFileInfo(fullFileName).suffix().toUpper()=="EEPE") return FILE_TYPE_EEPE;
if(QFileInfo(fullFileName).suffix().toUpper()=="XML") return FILE_TYPE_XML;
return 0;
}
void MainWindow::writeFlash(QString fileToFlash) void MainWindow::writeFlash(QString fileToFlash)
{ {
FlashFirmwareDialog *cd = new FlashFirmwareDialog(this); FlashFirmwareDialog *cd = new FlashFirmwareDialog(this);

View file

@ -164,7 +164,6 @@ class MainWindow : public QMainWindow
void updateLanguageActions(); void updateLanguageActions();
void updateIconThemeActions(); void updateIconThemeActions();
int getFileType(const QString & fullFileName);
QString Theme; QString Theme;
QString ISize; QString ISize;
QString strippedName(const QString & fullFileName); QString strippedName(const QString & fullFileName);

View file

@ -32,7 +32,7 @@
#include "appdata.h" #include "appdata.h"
#include "wizarddialog.h" #include "wizarddialog.h"
#include "flashfirmwaredialog.h" #include "flashfirmwaredialog.h"
#include "storage_eeprom.h" #include "storage.h"
#if defined _MSC_VER || !defined __GNUC__ #if defined _MSC_VER || !defined __GNUC__
#include <windows.h> #include <windows.h>
@ -48,13 +48,38 @@ MdiChild::MdiChild():
isUntitled(true), isUntitled(true),
fileChanged(false) fileChanged(false)
{ {
BoardEnum board = GetCurrentFirmware()->getBoard();
ui->setupUi(this); ui->setupUi(this);
setWindowIcon(CompanionIcon("open.png")); setWindowIcon(CompanionIcon("open.png"));
modelsListModel = new TreeModel(&radioData, this);
ui->modelsList->setModel(modelsListModel);
ui->simulateButton->setIcon(CompanionIcon("simulate.png")); ui->simulateButton->setIcon(CompanionIcon("simulate.png"));
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
eepromInterfaceChanged(); eepromInterfaceChanged();
connect(ui->modelsList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(openModelEditWindow()));
connect(ui->modelsList, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showModelsListContextMenu(const QPoint &)));
// connect(ui->modelsList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
ui->modelsList->setContextMenuPolicy(Qt::CustomContextMenu);
ui->modelsList->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->modelsList->setSelectionMode(QAbstractItemView::ExtendedSelection);
// ui->modelsList->setDragEnabled(true);
// ui->modelsList->setAcceptDrops(true);
// ui->modelsList->setDragDropOverwriteMode(true);
// ui->modelsList->setDropIndicatorShown(true);
if (IS_HORUS(board)) {
ui->modelsList->header()->hide();
}
else {
ui->modelsList->setIndentation(0);
}
if (!(isMaximized() || isMinimized())) { if (!(isMaximized() || isMinimized())) {
adjustSize(); adjustSize();
} }
@ -65,9 +90,12 @@ MdiChild::~MdiChild()
delete ui; delete ui;
} }
void MdiChild::eepromInterfaceChanged() void MdiChild::refresh(bool expand)
{ {
ui->modelsList->refreshList(); modelsListModel->refresh();
if (1 || expand) {
ui->modelsList->expandAll();
}
if (GetCurrentFirmware()->getBoard() == BOARD_HORUS && !HORUS_READY_FOR_RELEASE()) { if (GetCurrentFirmware()->getBoard() == BOARD_HORUS && !HORUS_READY_FOR_RELEASE()) {
ui->simulateButton->setEnabled(false); ui->simulateButton->setEnabled(false);
} }
@ -77,57 +105,223 @@ void MdiChild::eepromInterfaceChanged()
updateTitle(); updateTitle();
} }
void MdiChild::confirmDelete()
{
if (QMessageBox::warning(this, "Companion", tr("Delete selected models?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
deleteSelectedModels();
}
}
void MdiChild::deleteSelectedModels()
{
foreach (QModelIndex index, ui->modelsList->selectionModel()->selectedIndexes()) {
if (index.column() == 0) {
unsigned int modelIndex = modelsListModel->getModelIndex(index);
if (radioData.generalSettings.currModelIndex != modelIndex) {
qDebug() << "delete" << modelIndex;
radioData.models[modelIndex].clear();
setModified();
}
else {
QMessageBox::warning(this, "Companion", tr("Cannot delete default model."), QMessageBox::Ok);
}
}
}
}
void MdiChild::showModelsListContextMenu(const QPoint & pos)
{
int modelIndex = getCurrentRow();
QPoint globalPos = ui->modelsList->mapToGlobal(pos);
QMenu contextMenu;
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat("application/x-companion");
if (modelIndex >= 0) {
contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(modelEdit()));
contextMenu.addAction(CompanionIcon("open.png"), tr("&Restore from backup"), this, SLOT(loadBackup()));
contextMenu.addAction(CompanionIcon("wizard.png"), tr("&Model Wizard"), this, SLOT(wizardEdit()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"), this, SLOT(confirmDelete()), tr("Delete"));
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"), this, SLOT(copy()), tr("Ctrl+C"));
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"), this, SLOT(cut()), tr("Ctrl+X"));
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"), this, SLOT(paste()), tr("Ctrl+V"))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("duplicate.png"), tr("D&uplicate"), this, SLOT(duplicate()), tr("Ctrl+U"));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("currentmodel.png"), tr("&Use as default"), this, SLOT(setDefault()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("print.png"), tr("P&rint model"), this, SLOT(print()), QKeySequence(tr("Ctrl+P")));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("simulate.png"), tr("&Simulate model"), this, SLOT(modelSimulate()), tr("Alt+S"));
}
// TODO context menu for radio settings
// contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(EditModel()));
contextMenu.exec(globalPos);
}
void MdiChild::eepromInterfaceChanged()
{
refresh();
}
void MdiChild::cut() void MdiChild::cut()
{ {
ui->modelsList->cut(); copy();
deleteSelectedModels();
} }
void MdiChild::copy() void MdiChild::copy()
{ {
ui->modelsList->copy(); QByteArray gmData;
doCopy(&gmData);
QMimeData * mimeData = new QMimeData;
mimeData->setData("application/x-companion", gmData);
QClipboard * clipboard = QApplication::clipboard();
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
}
void MdiChild::doCopy(QByteArray * gmData)
{
foreach(QModelIndex index, ui->modelsList->selectionModel()->selectedIndexes()) {
if (index.column() == 0) {
unsigned int modelIndex = modelsListModel->getModelIndex(index);
if (modelIndex >= 0) {
gmData->append('M');
gmData->append((char *) &radioData.models[modelIndex], sizeof(ModelData));
}
}
}
// TODO to copy radio settings
// gmData->append('G');
// gmData->append((char *) &radioData.generalSettings, sizeof(GeneralSettings));
}
void MdiChild::doPaste(QByteArray * gmData, int index)
{
char * gData = gmData->data();
bool modified = false;
int size = 0;
while (size < gmData->size()) {
char c = *gData++;
size++;
if (c == 'G') {
// General settings
int ret = QMessageBox::question(this, "Companion", tr("Do you want to overwrite radio general settings?"),
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
radioData.generalSettings = *((GeneralSettings *)gData);
modified = 1;
}
gData += sizeof(GeneralSettings);
size += sizeof(GeneralSettings);
}
else if (c == 'M') {
if (index < GetCurrentFirmware()->getCapability(Models)) {
// Model data
int ret = QMessageBox::Yes;
if (!radioData.models[index].isEmpty()) {
ret = QMessageBox::question(this, "Companion", tr("You are pasting on an not empty model, are you sure?"),
QMessageBox::Yes | QMessageBox::No);
}
if (ret == QMessageBox::Yes) {
radioData.models[index] = *((ModelData *)gData);
strcpy(radioData.models[index].filename, radioData.getNextModelFilename().toStdString().c_str());
modified = 1;
}
gData += sizeof(ModelData);
size += sizeof(ModelData);
index++;
}
}
else {
qWarning() << "paste error";
break;
}
}
if (modified) {
setModified();
}
} }
void MdiChild::paste() void MdiChild::paste()
{ {
ui->modelsList->paste(); if (hasPasteData()) {
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
QByteArray gmData = mimeData->data("application/x-companion");
doPaste(&gmData, getCurrentRow());
}
} }
bool MdiChild::hasPasteData() bool MdiChild::hasPasteData() const
{ {
return ui->modelsList->hasPasteData(); const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
return mimeData->hasFormat("application/x-companion");
} }
bool MdiChild::hasSelection() bool MdiChild::hasSelection() const
{ {
return ui->modelsList->hasSelection(); return ui->modelsList->selectionModel()->hasSelection();
} }
void MdiChild::updateTitle() void MdiChild::updateTitle()
{ {
QString title = userFriendlyCurrentFile() + "[*]" + " (" + GetCurrentFirmware()->getName() + QString(")"); QString title = userFriendlyCurrentFile() + "[*]" + " (" + GetCurrentFirmware()->getName() + QString(")");
if (!IS_SKY9X(GetCurrentFirmware()->getBoard())) int availableEEpromSize = modelsListModel->getAvailableEEpromSize();
title += QString(" - %1 ").arg(EEPromAvail) + tr("free bytes"); if (availableEEpromSize >= 0) {
title += QString(" - %1 ").arg(availableEEpromSize) + tr("free bytes");
}
setWindowTitle(title); setWindowTitle(title);
} }
void MdiChild::setModified() void MdiChild::setModified()
{ {
ui->modelsList->refreshList(); refresh();
fileChanged = true; fileChanged = true;
updateTitle();
documentWasModified(); documentWasModified();
} }
void MdiChild::keyPressEvent(QKeyEvent * event)
{
if (event->matches(QKeySequence::Delete)) {
deleteSelectedModels();
}
else if (event->matches(QKeySequence::Cut)) {
cut();
}
else if (event->matches(QKeySequence::Copy)) {
copy();
}
else if (event->matches(QKeySequence::Paste)) {
paste();
}
else if (event->matches(QKeySequence::Underline)) {
// TODO duplicate();
}
else {
QWidget::keyPressEvent(event); // run the standard event in case we didn't catch an action
}
}
void MdiChild::on_simulateButton_clicked() void MdiChild::on_simulateButton_clicked()
{ {
startSimulation(this, radioData, -1); radioSimulate();
} }
void MdiChild::checkAndInitModel(int row) void MdiChild::checkAndInitModel(int row)
{ {
ModelData &model = radioData.models[row - 1]; ModelData & model = radioData.models[row];
if (model.isEmpty()) { if (model.isEmpty()) {
model.setDefaultValues(row - 1, radioData.generalSettings); model.setDefaultValues(row, radioData.generalSettings);
setModified(); setModified();
} }
} }
@ -142,49 +336,47 @@ void MdiChild::generalEdit()
void MdiChild::modelEdit() void MdiChild::modelEdit()
{ {
int row = getCurrentRow(); int row = getCurrentRow();
if (row == 0) {
generalEdit();
}
else {
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
checkAndInitModel(row); checkAndInitModel(row);
ModelData & model = radioData.models[row - 1]; ModelData & model = radioData.models[row];
gStopwatch.restart(); gStopwatch.restart();
gStopwatch.report("ModelEdit creation"); gStopwatch.report("ModelEdit creation");
ModelEdit *t = new ModelEdit(this, radioData, (row - 1), GetCurrentFirmware()/*firmware*/); ModelEdit * t = new ModelEdit(this, radioData, (row), GetCurrentFirmware()/*firmware*/);
gStopwatch.report("ModelEdit created"); gStopwatch.report("ModelEdit created");
t->setWindowTitle(tr("Editing model %1: ").arg(row) + model.name); t->setWindowTitle(tr("Editing model %1: ").arg(row+1) + model.name);
connect(t, SIGNAL(modified()), this, SLOT(setModified())); connect(t, SIGNAL(modified()), this, SLOT(setModified()));
gStopwatch.report("STARTING MODEL EDIT"); gStopwatch.report("STARTING MODEL EDIT");
t->show(); t->show();
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
gStopwatch.report("ModelEdit shown"); gStopwatch.report("ModelEdit shown");
} }
void MdiChild::setDefault()
{
int row = getCurrentRow();
if (!radioData.models[row].isEmpty() && radioData.generalSettings.currModelIndex != (unsigned)row) {
radioData.setCurrentModel(row);
setModified();
}
} }
void MdiChild::wizardEdit() void MdiChild::wizardEdit()
{ {
int row = getCurrentRow(); int row = getCurrentRow();
if (row > 0) {
checkAndInitModel(row); checkAndInitModel(row);
WizardDialog * wizard = new WizardDialog(radioData.generalSettings, row, this); WizardDialog * wizard = new WizardDialog(radioData.generalSettings, row+1, this);
wizard->exec(); wizard->exec();
if (wizard->mix.complete /*TODO rather test the exec() result?*/) { if (wizard->mix.complete /*TODO rather test the exec() result?*/) {
radioData.models[row - 1] = wizard->mix; radioData.models[row] = wizard->mix;
setModified(); setModified();
} }
} }
}
void MdiChild::openEditWindow() void MdiChild::openModelEditWindow()
{ {
int row = getCurrentRow(); int row = getCurrentRow();
if (row == 0){ if (row >= 0) {
generalEdit(); ModelData & model = radioData.models[row];
}
else{
ModelData & model = radioData.models[row - 1];
if (model.isEmpty() && g.useWizard()) { if (model.isEmpty() && g.useWizard()) {
wizardEdit(); wizardEdit();
} }
@ -197,152 +389,30 @@ void MdiChild::openEditWindow()
void MdiChild::newFile() void MdiChild::newFile()
{ {
static int sequenceNumber = 1; static int sequenceNumber = 1;
isUntitled = true; isUntitled = true;
curFile = QString("document%1.eepe").arg(sequenceNumber++); curFile = QString("document%1.eepe").arg(sequenceNumber++);
updateTitle(); updateTitle();
} }
bool MdiChild::loadFile(const QString & fileName, bool resetCurrentFile) bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile)
{ {
QFile file(fileName); Storage storage(filename);
if (!storage.load(radioData)) {
if (!file.exists()) { QMessageBox::critical(this, tr("Error"), storage.error());
QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
return false; return false;
} }
int fileType = getFileType(fileName); QString warning = storage.warning();
if (!warning.isEmpty()) {
#if 0 // TODO ShowEepromWarnings(this, tr("Warning"), warning);
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
#endif
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); refresh(true);
bool xmlOK = doc.setContent(&file);
if (xmlOK) {
std::bitset<NUM_ERRORS> errors((unsigned long long)LoadEepromXml(radioData, doc));
if (errors.test(ALL_OK)) {
ui->modelsList->refreshList();
if(resetCurrentFile) setCurrentFile(fileName);
return true;
}
}
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;
}
}
QByteArray eeprom(EESIZE_MAX, 0);
int eeprom_size = HexInterface(inputStream).load((uint8_t *)eeprom.data(), EESIZE_MAX);
if (!eeprom_size) {
QMessageBox::critical(this, tr("Error"),
tr("Invalid EEPROM File %1")
.arg(fileName));
file.close();
return false;
}
file.close();
std::bitset<NUM_ERRORS> errors((unsigned long long)LoadEeprom(radioData, (uint8_t *)eeprom.data(), eeprom_size));
if (!errors.test(ALL_OK)) {
ShowEepromErrors(this, tr("Error"), tr("Invalid EEPROM File %1").arg(fileName), errors.to_ulong());
return false;
}
if (errors.test(HAS_WARNINGS)) {
ShowEepromWarnings(this, tr("Warning"), errors.to_ulong());
}
ui->modelsList->refreshList();
if (resetCurrentFile) setCurrentFile(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()));
free(eeprom);
return false;
}
std::bitset<NUM_ERRORS> errorsEeprom((unsigned long long)LoadEeprom(radioData, eeprom, eeprom_size));
if (!errorsEeprom.test(ALL_OK)) {
std::bitset<NUM_ERRORS> errorsBackup((unsigned long long)LoadBackup(radioData, eeprom, eeprom_size, 0));
if (!errorsBackup.test(ALL_OK)) {
ShowEepromErrors(this, tr("Error"), tr("Invalid binary EEPROM File %1").arg(fileName), (errorsEeprom | errorsBackup).to_ulong());
free(eeprom);
return false;
}
if (errorsBackup.test(HAS_WARNINGS)) {
ShowEepromWarnings(this, tr("Warning"), errorsBackup.to_ulong());
}
}
else if (errorsEeprom.test(HAS_WARNINGS)) {
ShowEepromWarnings(this, tr("Warning"), errorsEeprom.to_ulong());
}
ui->modelsList->refreshList();
if (resetCurrentFile) if (resetCurrentFile)
setCurrentFile(fileName); setCurrentFile(filename);
free(eeprom);
return true; return true;
} }
else if (fileType == FILE_TYPE_OTX) { //read zip archive
if (!GetEepromInterface()->loadFile(radioData, fileName)) {
ui->modelsList->refreshList();
if (resetCurrentFile)
setCurrentFile(fileName);
return true;
}
}
return false;
}
bool MdiChild::save() bool MdiChild::save()
{ {
@ -383,78 +453,28 @@ bool MdiChild::saveAs(bool isNew)
return saveFile(fileName,true); return saveFile(fileName,true);
} }
bool MdiChild::saveFile(const QString &fileName, bool setCurrent) bool MdiChild::saveFile(const QString & filename, bool setCurrent)
{ {
QString myFile; BoardEnum board = GetEepromInterface()->getBoard();
myFile = fileName; QString path = filename;
if (IS_SKY9X(GetEepromInterface()->getBoard())) { if (IS_SKY9X(board)) {
myFile.replace(".eepe", ".bin"); path.replace(".eepe", ".bin");
}
QFile file(myFile);
int fileType = getFileType(myFile);
uint8_t * eeprom = (uint8_t*)malloc(GetEepromInterface()->getEEpromSize());
int eeprom_size = 0;
if (fileType != FILE_TYPE_XML) {
eeprom_size = GetEepromInterface()->save(eeprom, radioData, 0, GetCurrentFirmware()->getVariantNumber());
if (!eeprom_size) {
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
return false;
}
} }
if (!file.open(fileType == FILE_TYPE_BIN ? QIODevice::WriteOnly : (QIODevice::WriteOnly | QIODevice::Text))) { radioData.fixModelFilenames();
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString())); Storage storage(path);
return false; bool result = storage.write(radioData);
if (result && setCurrent) {
setCurrentFile(path);
} }
QTextStream outputStream(&file); return result;
}
#if 0 QString MdiChild::userFriendlyCurrentFile() const
if (fileType==FILE_TYPE_XML) {
if (!XmlInterface(outputStream).save(radioData)) {
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
file.close();
return false;
}
}
else
#endif
if (fileType==FILE_TYPE_HEX || fileType==FILE_TYPE_EEPE) { // write hex
if (fileType==FILE_TYPE_EEPE)
outputStream << EEPE_EEPROM_FILE_HEADER << "\n";
if (!HexInterface(outputStream).save(eeprom, eeprom_size)) {
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
file.close();
return false;
}
}
else if (fileType==FILE_TYPE_BIN) // write binary
{ {
long result = file.write((char*)eeprom, eeprom_size); return QFileInfo(curFile).fileName();
if(result!=eeprom_size) {
QMessageBox::warning(this, tr("Error"),tr("Error writing file %1:\n%2.").arg(myFile).arg(file.errorString()));
return false;
}
}
else {
QMessageBox::warning(this, tr("Error"),tr("Error writing file %1:\n%2.").arg(myFile).arg("Unknown format"));
return false;
}
free(eeprom); // TODO free in all cases ...
file.close();
if(setCurrent) setCurrentFile(myFile);
return true;
}
QString MdiChild::userFriendlyCurrentFile()
{
return strippedName(curFile);
} }
void MdiChild::closeEvent(QCloseEvent *event) void MdiChild::closeEvent(QCloseEvent *event)
@ -502,15 +522,9 @@ void MdiChild::setCurrentFile(const QString &fileName)
files.prepend(fileName); files.prepend(fileName);
while (files.size() > MaxRecentFiles) while (files.size() > MaxRecentFiles)
files.removeLast(); files.removeLast();
g.recentFiles(files); g.recentFiles(files);
} }
QString MdiChild::strippedName(const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName();
}
void MdiChild::writeEeprom() // write to Tx void MdiChild::writeEeprom() // write to Tx
{ {
QString tempFile = generateProcessUniqueTempFileName("temp.bin"); QString tempFile = generateProcessUniqueTempFileName("temp.bin");
@ -519,27 +533,35 @@ void MdiChild::writeEeprom() // write to Tx
QMessageBox::critical(this, tr("Error"), tr("Cannot write temporary file!")); QMessageBox::critical(this, tr("Error"), tr("Cannot write temporary file!"));
return; return;
} }
FlashEEpromDialog * cd = new FlashEEpromDialog(this, tempFile); FlashEEpromDialog * cd = new FlashEEpromDialog(this, tempFile);
cd->exec(); cd->exec();
} }
void MdiChild::simulate() void MdiChild::on_radioSettings_clicked()
{ {
if (getCurrentRow() > 0) { generalEdit();
startSimulation(this, radioData, getCurrentRow()-1);
}
} }
void MdiChild::print(int model, QString filename) void MdiChild::radioSimulate()
{ {
startSimulation(this, radioData, -1);
}
void MdiChild::modelSimulate()
{
startSimulation(this, radioData, getCurrentRow());
}
void MdiChild::print(int model, const QString & filename)
{
// TODO
PrintDialog * pd = NULL; PrintDialog * pd = NULL;
if (model>=0 && !filename.isEmpty()) { if (model>=0 && !filename.isEmpty()) {
pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[model], filename); pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[model], filename);
} }
else if (getCurrentRow() > 0) { else if (getCurrentRow()) {
pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[getCurrentRow()-1]); pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[getCurrentRow()]);
} }
if (pd) { if (pd) {
@ -553,14 +575,9 @@ void MdiChild::viableModelSelected(bool viable)
emit copyAvailable(viable); emit copyAvailable(viable);
} }
void MdiChild::setEEpromAvail(int eavail)
{
EEPromAvail=eavail;
}
int MdiChild::getCurrentRow() const int MdiChild::getCurrentRow() const
{ {
return ui->modelsList->currentRow(); return modelsListModel->getModelIndex(ui->modelsList->currentIndex());
} }
bool MdiChild::loadBackup() bool MdiChild::loadBackup()
@ -574,8 +591,8 @@ bool MdiChild::loadBackup()
QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName)); QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
return false; return false;
} }
if(getCurrentRow() < 1) return false;
int index = getCurrentRow() - 1; // TODO int index = getCurrentRow();
int eeprom_size = file.size(); int eeprom_size = file.size();
if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
@ -598,6 +615,7 @@ bool MdiChild::loadBackup()
return false; return false;
} }
#if 0
std::bitset<NUM_ERRORS> errorsEeprom((unsigned long long)LoadBackup(radioData, (uint8_t *)eeprom.data(), eeprom_size, index)); std::bitset<NUM_ERRORS> errorsEeprom((unsigned long long)LoadBackup(radioData, (uint8_t *)eeprom.data(), eeprom_size, index));
if (!errorsEeprom.test(ALL_OK)) { if (!errorsEeprom.test(ALL_OK)) {
ShowEepromErrors(this, tr("Error"), tr("Invalid binary backup File %1").arg(fileName), (errorsEeprom).to_ulong()); ShowEepromErrors(this, tr("Error"), tr("Invalid binary backup File %1").arg(fileName), (errorsEeprom).to_ulong());
@ -607,7 +625,9 @@ bool MdiChild::loadBackup()
ShowEepromWarnings(this, tr("Warning"), errorsEeprom.to_ulong()); ShowEepromWarnings(this, tr("Warning"), errorsEeprom.to_ulong());
} }
ui->modelsList->refreshList(); refresh(true);
return true; return true;
#else
return false;
#endif
} }

View file

@ -23,6 +23,7 @@
#include <QtGui> #include <QtGui>
#include "eeprominterface.h" #include "eeprominterface.h"
#include "modelslist.h"
namespace Ui { namespace Ui {
class MdiChild; class MdiChild;
@ -44,18 +45,18 @@ class MdiChild : public QWidget
void newFile(); void newFile();
bool loadFile(const QString & fileName, bool resetCurrentFile=true); bool loadFile(const QString & fileName, bool resetCurrentFile=true);
bool loadBackup();
bool save(); bool save();
bool saveAs(bool isNew=false); bool saveAs(bool isNew=false);
bool saveFile(const QString & fileName, bool setCurrent=true); bool saveFile(const QString & fileName, bool setCurrent=true);
bool hasSelection(); bool hasSelection() const;
QString userFriendlyCurrentFile(); bool hasPasteData() const;
QString currentFile() { return curFile; } QString userFriendlyCurrentFile() const;
bool hasPasteData(); QString currentFile() const { return curFile; }
void viableModelSelected(bool viable); void viableModelSelected(bool viable);
void eepromInterfaceChanged(); void eepromInterfaceChanged();
void setEEpromAvail(int eavail);
int getCurrentRow() const; int getCurrentRow() const;
void refresh(bool expand=false);
void keyPressEvent(QKeyEvent * event);
signals: signals:
void copyAvailable(bool val); void copyAvailable(bool val);
@ -63,33 +64,43 @@ class MdiChild : public QWidget
protected: protected:
void closeEvent(QCloseEvent * event); void closeEvent(QCloseEvent * event);
private slots: protected slots:
void documentWasModified(); void documentWasModified();
void on_simulateButton_clicked(); void on_simulateButton_clicked();
void on_radioSettings_clicked();
void setDefault();
public slots: public slots:
void showModelsListContextMenu(const QPoint & pos);
void checkAndInitModel(int row); void checkAndInitModel(int row);
void generalEdit(); void generalEdit();
void modelEdit(); void modelEdit();
void wizardEdit(); void wizardEdit();
void openEditWindow(); void openModelEditWindow();
bool loadBackup();
void confirmDelete();
void deleteSelectedModels();
void cut(); void cut();
void copy(); void copy();
void paste(); void paste();
void writeEeprom(); void writeEeprom();
void simulate(); void modelSimulate();
void print(int model=-1, QString filename=""); void radioSimulate();
void print(int model=-1, const QString & filename="");
void setModified(); void setModified();
void updateTitle(); void updateTitle();
private: private:
bool maybeSave(); bool maybeSave();
void setCurrentFile(const QString & fileName); void setCurrentFile(const QString & fileName);
QString strippedName(const QString & fullFileName);
bool loadOtxFile(const QString & fileName); bool loadOtxFile(const QString & fileName);
void doCopy(QByteArray * gmData);
void doPaste(QByteArray * gmData, int index);
Ui::MdiChild * ui; Ui::MdiChild * ui;
TreeModel * modelsListModel;
QString curFile; QString curFile;
@ -98,7 +109,6 @@ class MdiChild : public QWidget
bool isUntitled; bool isUntitled;
bool fileChanged; bool fileChanged;
int EEPromAvail;
}; };
#endif // _MDICHILD_H_ #endif // _MDICHILD_H_

View file

@ -15,7 +15,14 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="ModelsListWidget" name="modelsList"/> <widget class="QPushButton" name="radioSettings">
<property name="text">
<string>Radio settings</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="modelsList"/>
</item> </item>
<item> <item>
<widget class="QPushButton" name="simulateButton"> <widget class="QPushButton" name="simulateButton">
@ -26,13 +33,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ModelsListWidget</class>
<extends>QListWidget</extends>
<header location="global">modelslist.h</header>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="companion.qrc"/> <include location="companion.qrc"/>
</resources> </resources>

View file

@ -28,7 +28,7 @@ LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row
displayStep(0.1) displayStep(0.1)
{ {
BoardEnum board = firmware->getBoard(); BoardEnum board = firmware->getBoard();
bool allowGVars = (IS_TARANIS(board) || IS_HORUS(board)); bool allowGVars = IS_HORUS_OR_TARANIS(board);
int internalStep = 1; int internalStep = 1;
spinbox->setProperty("index", row); spinbox->setProperty("index", row);

View file

@ -165,7 +165,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1); ui->trainerMode->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, 0, Qt::UserRole - 1);
} }
ui->trainerMode->setCurrentIndex(model.trainerMode); ui->trainerMode->setCurrentIndex(model.trainerMode);
if (!IS_TARANIS(firmware->getBoard())) { if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
ui->label_trainerMode->hide(); ui->label_trainerMode->hide();
ui->trainerMode->hide(); ui->trainerMode->hide();
} }
@ -174,7 +174,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
ui->label_trainerMode->hide(); ui->label_trainerMode->hide();
ui->trainerMode->hide(); ui->trainerMode->hide();
if (firmware->getCapability(NumModules) > 1) { if (firmware->getCapability(NumModules) > 1) {
if (IS_TARANIS(firmware->getBoard()) || IS_HORUS(firmware->getBoard())) { if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
if (moduleIdx == 0) if (moduleIdx == 0)
label = tr("Internal Radio System"); label = tr("Internal Radio System");
else else
@ -294,7 +294,7 @@ void ModulePanel::update()
break; break;
} }
} }
else if (IS_TARANIS(firmware->getBoard()) || IS_HORUS(firmware->getBoard())) { else if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
if (model->trainerMode == TRAINER_SLAVE_JACK) { if (model->trainerMode == TRAINER_SLAVE_JACK) {
mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT; mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
} }
@ -675,7 +675,7 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
// Startup switches warnings // Startup switches warnings
for (int i=0; i<firmware->getCapability(Switches); i++) { for (int i=0; i<firmware->getCapability(Switches); i++) {
Firmware::Switch sw = firmware->getSwitch(i); Firmware::Switch sw = firmware->getSwitch(i);
if (IS_TARANIS(board) || IS_HORUS(board)) { if (IS_HORUS_OR_TARANIS(board)) {
sw.type = Firmware::SwitchType(generalSettings.switchConfig[i]); sw.type = Firmware::SwitchType(generalSettings.switchConfig[i]);
} }
if (sw.type == Firmware::SWITCH_NONE || sw.type == Firmware::SWITCH_TOGGLE) { if (sw.type == Firmware::SWITCH_NONE || sw.type == Firmware::SWITCH_TOGGLE) {

View file

@ -787,7 +787,7 @@ TelemetryPanel::~TelemetryPanel()
void TelemetryPanel::update() void TelemetryPanel::update()
{ {
if (IS_TARANIS(firmware->getBoard())) { if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
if (model->moduleData[0].protocol == PULSES_OFF && model->moduleData[1].protocol == PULSES_PPM) { if (model->moduleData[0].protocol == PULSES_OFF && model->moduleData[1].protocol == PULSES_PPM) {
ui->telemetryProtocol->setEnabled(true); ui->telemetryProtocol->setEnabled(true);
} }
@ -835,7 +835,7 @@ void TelemetryPanel::setup()
ui->rssiAlarm1SB->setValue(model->frsky.rssiAlarms[0].value); ui->rssiAlarm1SB->setValue(model->frsky.rssiAlarms[0].value);
ui->rssiAlarm2SB->setValue(model->frsky.rssiAlarms[1].value); ui->rssiAlarm2SB->setValue(model->frsky.rssiAlarms[1].value);
if (!IS_TARANIS(firmware->getBoard())) { if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
ui->rssiAlarm1CB->setCurrentIndex(model->frsky.rssiAlarms[0].level); ui->rssiAlarm1CB->setCurrentIndex(model->frsky.rssiAlarms[0].level);
ui->rssiAlarm2CB->setCurrentIndex(model->frsky.rssiAlarms[1].level); ui->rssiAlarm2CB->setCurrentIndex(model->frsky.rssiAlarms[1].level);
} }

View file

@ -21,6 +21,7 @@
#include "helpers.h" #include "helpers.h"
#include "modelprinter.h" #include "modelprinter.h"
#include <QPainter> #include <QPainter>
#include <QFile>
QString changeColor(const QString & input, const QString & to, const QString & from) QString changeColor(const QString & input, const QString & to, const QString & from)
{ {

View file

@ -19,138 +19,314 @@
*/ */
#include "modelslist.h" #include "modelslist.h"
#include "mdichild.h"
#include "helpers.h"
class DragDropHeader { TreeItem::TreeItem(const QVector<QVariant> & itemData):
public: itemData(itemData),
DragDropHeader(): parentItem(NULL),
general_settings(false), modelIndex(-1)
models_count(0)
{ {
} }
bool general_settings;
uint8_t models_count;
uint8_t models[CPN_MAX_MODELS];
};
ModelsListWidget::ModelsListWidget(QWidget * parent): TreeItem::TreeItem(TreeItem * parent, int modelIndex):
QTreeWidget(parent) itemData(parent->columnCount()),
parentItem(parent),
modelIndex(modelIndex)
{
}
TreeItem::~TreeItem()
{
qDeleteAll(childItems);
}
TreeItem * TreeItem::child(int number)
{
return childItems.value(number);
}
int TreeItem::childCount() const
{
return childItems.count();
}
int TreeItem::childNumber() const
{
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}
int TreeItem::columnCount() const
{
return itemData.count();
}
QVariant TreeItem::data(int column) const
{
return itemData.value(column);
}
TreeItem * TreeItem::appendChild(int modelIndex)
{
TreeItem * item = new TreeItem(this, modelIndex);
childItems.insert(childItems.size(), item);
return item;
}
TreeItem * TreeItem::parent()
{
return parentItem;
}
bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position + count > childItems.size())
return false;
for (int row = 0; row < count; ++row)
delete childItems.takeAt(position);
return true;
}
bool TreeItem::setData(int column, const QVariant & value)
{
if (column < 0 || column >= itemData.size())
return false;
itemData[column] = value;
return true;
}
TreeModel::TreeModel(RadioData * radioData, QObject * parent):
QAbstractItemModel(parent),
radioData(radioData),
availableEEpromSize(-1)
{ {
BoardEnum board = GetCurrentFirmware()->getBoard(); BoardEnum board = GetCurrentFirmware()->getBoard();
QStringList labels; QVector<QVariant> labels;
labels << tr("Index") << tr("Name"); if (!IS_HORUS(board))
labels << tr("Index");
labels << tr("Name");
if (!(IS_HORUS(board) || IS_SKY9X(board))) { if (!(IS_HORUS(board) || IS_SKY9X(board))) {
labels << tr("Size"); labels << tr("Size");
} }
setColumnCount(labels.size()); rootItem = new TreeItem(labels);
setHeaderLabels(labels); refresh();
}
TreeModel::~TreeModel()
{
delete rootItem;
}
int TreeModel::columnCount(const QModelIndex & /* parent */) const
{
return rootItem->columnCount();
}
QVariant TreeModel::data(const QModelIndex & index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole) {
return QVariant();
}
TreeItem * item = getItem(index);
if (role == Qt::FontRole) {
if (item->getModelIndex() == (int)radioData->generalSettings.currModelIndex) {
QFont font;
font.setBold(true);
return font;
}
}
return item->data(index.column());
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}
TreeItem * TreeModel::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItem * item = static_cast<TreeItem*>(index.internalPointer());
if (item) {
return item;
}
}
return rootItem;
}
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return rootItem->data(section);
return QVariant();
}
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0)
return QModelIndex();
TreeItem * parentItem = getItem(parent);
TreeItem * childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = getItem(index);
TreeItem *parentItem = childItem->parent();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->childNumber(), 0, parentItem);
}
bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent)
{
TreeItem * parentItem = getItem(parent);
bool success = true;
beginRemoveRows(parent, position, position + rows - 1);
success = parentItem->removeChildren(position, rows);
endRemoveRows();
return success;
}
int TreeModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem = getItem(parent);
return parentItem->childCount();
}
bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::EditRole)
return false;
TreeItem *item = getItem(index);
bool result = item->setData(index.column(), value);
if (result)
emit dataChanged(index, index);
return result;
}
void TreeModel::refresh()
{
EEPROMInterface * eepromInterface = GetEepromInterface();
BoardEnum board = eepromInterface->getBoard();
if (!IS_SKY9X(board) && !IS_HORUS(board)) {
availableEEpromSize = getEEpromSize(board) - 64; // let's consider fat
availableEEpromSize -= 16 * ((eepromInterface->getSize(radioData->generalSettings) + 14) / 15);
}
removeRows(0, rowCount());
TreeItem * defaultCategoryItem = NULL;
if (IS_HORUS(board)) {
for (unsigned int i = 0; i < radioData->categories.size(); i++) {
TreeItem * current = rootItem->appendChild(-1);
current->setData(0, QString(radioData->categories[i].name));
}
}
for (unsigned int i=0; i<(unsigned)GetCurrentFirmware()->getCapability(Models) && i<radioData->models.size(); i++) {
ModelData & model = radioData->models[i];
int currentColumn = 0;
TreeItem * current;
if (IS_HORUS(board)) {
if (!model.isEmpty()) {
TreeItem * categoryItem;
// TODO category should be set to -1 if not Horus
if (model.category >= 0 && model.category < rootItem->childCount()) {
categoryItem = rootItem->child(model.category);
}
else {
if (!defaultCategoryItem) {
defaultCategoryItem = rootItem->appendChild(-1);
defaultCategoryItem->setData(0, QObject::tr("Models"));
}
categoryItem = defaultCategoryItem;
}
current = categoryItem->appendChild(i);
}
}
else {
current = rootItem->appendChild(i);
current->setData(currentColumn++, QString().sprintf("%02d", i + 1));
}
if (!model.isEmpty()) {
QString modelName;
if (strlen(model.name) > 0)
modelName = model.name;
else
modelName = QString().sprintf("Model%02d", i+1);
current->setData(currentColumn++, modelName);
if (!IS_SKY9X(board) && !IS_HORUS(board)) {
int size = eepromInterface->getSize(model);
current->setData(currentColumn++, QString().sprintf("%5d", size));
size = 16 * ((size + 14) / 15);
availableEEpromSize -= size;
if (i == radioData->generalSettings.currModelIndex) {
// Because we need this space for a TEMP model each time we have to write it again
availableEEpromSize -= size;
}
}
/* TODO if (i == radioData->generalSettings.currModelIndex) {
QFont font = item->font(0);
font.setBold(true);
for (int j=0; j<columnCount(); j++) {
item->setFont(j, font);
}
} */
}
// addTopLevelItem(item);
}
if (!IS_SKY9X(board) && !IS_HORUS(board)) {
availableEEpromSize = (availableEEpromSize / 16) * 15;
}
}
#if 0
ModelsListWidget::ModelsListWidget(QWidget * parent):
QTreeView(parent),
radioData(NULL)
{
setColumnWidth(0, 50); setColumnWidth(0, 50);
setColumnWidth(2, 100); setColumnWidth(2, 100);
connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OpenEditWindow()));
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&)));
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setDragEnabled(true);
setAcceptDrops(true);
setDragDropOverwriteMode(true);
setDropIndicatorShown(true);
if (!IS_HORUS(board)) {
setIndentation(0);
}
active_highlight_color = palette().color(QPalette::Active, QPalette::Highlight); active_highlight_color = palette().color(QPalette::Active, QPalette::Highlight);
radioData = &((MdiChild *)parent)->radioData;
refreshList();
for (int i=0; i<labels.size(); i++) {
resizeColumnToContents(i);
}
}
void ModelsListWidget::ShowContextMenu(const QPoint& pos)
{
QPoint globalPos = this->mapToGlobal(pos);
QMenu contextMenu;
if (((MdiChild *)parent())->getCurrentRow() > 0) {
// context menu for model
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat("application/x-companion");
contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(EditModel()));
contextMenu.addAction(CompanionIcon("open.png"), tr("&Restore from backup"), this, SLOT(LoadBackup()));
contextMenu.addAction(CompanionIcon("wizard.png"), tr("&Model Wizard"), this, SLOT(OpenWizard()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"), this, SLOT(confirmDelete()), tr("Delete"));
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"), this, SLOT(copy()), tr("Ctrl+C"));
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"), this, SLOT(cut()), tr("Ctrl+X"));
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"), this, SLOT(paste()), tr("Ctrl+V"))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("duplicate.png"), tr("D&uplicate"), this, SLOT(duplicate()), tr("Ctrl+U"));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("currentmodel.png"), tr("&Use as default"), this, SLOT(setdefault()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("print.png"), tr("P&rint model"), this, SLOT(print()),QKeySequence(tr("Ctrl+P")));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("simulate.png"), tr("&Simulate model"), this, SLOT(simulate()), tr("Alt+S"));
}
else {
// context menu for radio settings
contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(EditModel()));
}
contextMenu.exec(globalPos);
}
int ModelsListWidget::currentRow() const
{
return indexOfTopLevelItem(currentItem());
}
void ModelsListWidget::EditModel()
{
((MdiChild *)parent())->modelEdit();
}
void ModelsListWidget::OpenEditWindow()
{
((MdiChild *)parent())->openEditWindow();
}
void ModelsListWidget::OpenWizard()
{
((MdiChild *)parent())->wizardEdit();
}
void ModelsListWidget::LoadBackup()
{
((MdiChild *)parent())->loadBackup();
}
void ModelsListWidget::simulate()
{
((MdiChild *)parent())->simulate();
}
void ModelsListWidget::print()
{
((MdiChild *)parent())->print();
}
void ModelsListWidget::setdefault()
{
if (currentRow() > 0) {
unsigned int currModel = currentRow() - 1;
if (!radioData->models[currModel].isEmpty() && radioData->generalSettings.currModelIndex != currModel) {
radioData->setCurrentModel(currModel);
refreshList();
((MdiChild *) parent())->setModified();
}
}
} }
void ModelsListWidget::mousePressEvent(QMouseEvent *event) void ModelsListWidget::mousePressEvent(QMouseEvent *event)
@ -158,7 +334,7 @@ void ModelsListWidget::mousePressEvent(QMouseEvent *event)
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton)
dragStartPosition = event->pos(); dragStartPosition = event->pos();
QTreeWidget::mousePressEvent(event); QTreeView::mousePressEvent(event);
} }
void ModelsListWidget::mouseMoveEvent(QMouseEvent *event) void ModelsListWidget::mouseMoveEvent(QMouseEvent *event)
@ -188,18 +364,18 @@ void ModelsListWidget::mouseMoveEvent(QMouseEvent *event)
void ModelsListWidget::saveSelection() void ModelsListWidget::saveSelection()
{ {
currentSelection.current_item = currentItem(); /*currentSelection.current_item = currentItem();
for (int i=0; i<GetEepromInterface()->getMaxModels()+1; ++i) { for (int i=0; i<GetCurrentFirmware()->getCapability(Models)+1; ++i) {
currentSelection.selected[i] = selectionModel()->isSelected(model()->index(i, 0)); currentSelection.selected[i] = selectionModel()->isSelected(model()->index(i, 0));
} }*/
} }
void ModelsListWidget::restoreSelection() void ModelsListWidget::restoreSelection()
{ {
setCurrentItem(currentSelection.current_item); /*setCurrentItem(currentSelection.current_item);
for (int i=0; i<GetEepromInterface()->getMaxModels()+1; ++i) { for (int i=0; i<GetCurrentFirmware()->getCapability(Models)+1; ++i) {
selectionModel()->select(model()->index(i, 0), currentSelection.selected[i] ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); selectionModel()->select(model()->index(i, 0), currentSelection.selected[i] ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
} }*/
} }
void ModelsListWidget::dragEnterEvent(QDragEnterEvent *event) void ModelsListWidget::dragEnterEvent(QDragEnterEvent *event)
@ -227,7 +403,7 @@ void ModelsListWidget::dragMoveEvent(QDragMoveEvent *event)
if (row >= 0) { if (row >= 0) {
if (header->general_settings) if (header->general_settings)
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::Select); selectionModel()->select(model()->index(0, 0), QItemSelectionModel::Select);
for (int i=row, end=std::min(GetEepromInterface()->getMaxModels()+1, row+header->models_count); i<end; i++) for (int i=row, end=std::min(GetCurrentFirmware()->getCapability(Models)+1, row+header->models_count); i<end; i++)
selectionModel()->select(model()->index(i, 0), QItemSelectionModel::Select); selectionModel()->select(model()->index(i, 0), QItemSelectionModel::Select);
} }
} }
@ -248,11 +424,11 @@ void ModelsListWidget::dropEvent(QDropEvent *event)
((ModelsListWidget*)event->source())->doCut(&gmData); ((ModelsListWidget*)event->source())->doCut(&gmData);
doPaste(&gmData, row); doPaste(&gmData, row);
clearSelection(); clearSelection();
setCurrentItem(topLevelItem(row)); // setCurrentItem(topLevelItem(row));
DragDropHeader * header = (DragDropHeader *)gmData.data(); DragDropHeader * header = (DragDropHeader *)gmData.data();
if (header->general_settings) if (header->general_settings)
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::Select); selectionModel()->select(model()->index(0, 0), QItemSelectionModel::Select);
for (int i=row, end=std::min(GetEepromInterface()->getMaxModels()+1, row+header->models_count); i<end; i++) for (int i=row, end=std::min(GetCurrentFirmware()->getCapability(Models)+1, row+header->models_count); i<end; i++)
selectionModel()->select(model()->index(i, 0), QItemSelectionModel::Select); selectionModel()->select(model()->index(i, 0), QItemSelectionModel::Select);
} }
event->acceptProposedAction(); event->acceptProposedAction();
@ -261,7 +437,7 @@ void ModelsListWidget::dropEvent(QDropEvent *event)
#ifndef WIN32 #ifndef WIN32
void ModelsListWidget::focusInEvent ( QFocusEvent * event ) void ModelsListWidget::focusInEvent ( QFocusEvent * event )
{ {
QTreeWidget::focusInEvent(event); QTreeView::focusInEvent(event);
QPalette palette = this->palette(); QPalette palette = this->palette();
palette.setColor(QPalette::Active, QPalette::Highlight, active_highlight_color); palette.setColor(QPalette::Active, QPalette::Highlight, active_highlight_color);
palette.setColor(QPalette::Inactive, QPalette::Highlight, active_highlight_color); palette.setColor(QPalette::Inactive, QPalette::Highlight, active_highlight_color);
@ -270,7 +446,7 @@ void ModelsListWidget::focusInEvent ( QFocusEvent * event )
void ModelsListWidget::focusOutEvent ( QFocusEvent * event ) void ModelsListWidget::focusOutEvent ( QFocusEvent * event )
{ {
QTreeWidget::focusOutEvent(event); QTreeView::focusOutEvent(event);
QPalette palette = this->palette(); QPalette palette = this->palette();
palette.setColor(QPalette::Active, QPalette::Highlight, palette.color(QPalette::Active, QPalette::Midlight)); palette.setColor(QPalette::Active, QPalette::Highlight, palette.color(QPalette::Active, QPalette::Midlight));
palette.setColor(QPalette::Inactive, QPalette::Highlight, palette.color(QPalette::Active, QPalette::Midlight)); palette.setColor(QPalette::Inactive, QPalette::Highlight, palette.color(QPalette::Active, QPalette::Midlight));
@ -278,113 +454,6 @@ void ModelsListWidget::focusOutEvent ( QFocusEvent * event )
} }
#endif #endif
void ModelsListWidget::refreshList()
{
int current = std::max(0, indexOfTopLevelItem(currentItem()));
clear();
QTreeWidgetItem * item = new QTreeWidgetItem();
item->setText(1, tr("General Settings"));
addTopLevelItem(item);
EEPROMInterface * eepromInterface = GetEepromInterface();
BoardEnum board = eepromInterface->getBoard();
// TODO here we calculate the size used by the RLE format, this is clearly not the right place to do that...
int availableEEpromSize = eepromInterface->getEEpromSize() - 64; // let's consider fat
availableEEpromSize -= 16 * ((eepromInterface->getSize(radioData->generalSettings) + 14) / 15);
for (uint8_t i=0; i<GetEepromInterface()->getMaxModels(); i++) {
QTreeWidgetItem * item = new QTreeWidgetItem();
item->setTextAlignment(0, Qt::AlignLeft);
item->setText(0, QString().sprintf("%02d", i+1));
if (!radioData->models[i].isEmpty()) {
QString modelName;
if (strlen(radioData->models[i].name) > 0)
modelName = radioData->models[i].name;
else
modelName = QString().sprintf("Model%02d", i+1);
item->setText(1, modelName);
if (!IS_SKY9X(board) && !IS_HORUS(board)) {
int size = eepromInterface->getSize(radioData->models[i]);
item->setText(2, QString().sprintf("%5d", size));
size = 16 * ((size + 14) / 15);
availableEEpromSize -= size;
if (i == radioData->generalSettings.currModelIndex) {
// Because we need this space for a TEMP model each time we have to write it again
availableEEpromSize -= size;
}
}
if (i == radioData->generalSettings.currModelIndex) {
QFont font = item->font(0);
font.setBold(true);
for (int j=0; j<columnCount(); j++) {
item->setFont(j, font);
}
}
}
addTopLevelItem(item);
}
selectionModel()->select(model()->index(current, 0), QItemSelectionModel::Current | QItemSelectionModel::Select | QItemSelectionModel::Rows);
setCurrentItem(topLevelItem(current));
if (!IS_SKY9X(board) && !IS_HORUS(board)) {
((MdiChild*)parent())->setEEpromAvail((availableEEpromSize/16)*15);
}
}
void ModelsListWidget::cut()
{
copy();
deleteSelected(false);
}
void ModelsListWidget::confirmDelete()
{
deleteSelected(true);
}
void ModelsListWidget::deleteSelected(bool ask=true)
{
bool isModel=false;
unsigned int selModel;
QMessageBox::StandardButton ret = QMessageBox::Yes;
if (ask) {
foreach (QModelIndex index, this->selectionModel()->selectedIndexes()) {
if (index.row()>0 && !radioData->models[index.row()-1].isEmpty()) {
isModel = true;
selModel=index.row()-1;
}
}
if (isModel) {
if (radioData->generalSettings.currModelIndex != selModel) {
ret = QMessageBox::warning(this, "Companion", tr("Delete Selected Models?"), QMessageBox::Yes | QMessageBox::No);
}
else {
ret = QMessageBox::warning(this, "Companion", tr("Cannot delete default model."), QMessageBox::Ok);
}
}
}
if (ret == QMessageBox::Yes) {
foreach (QModelIndex index, this->selectionModel()->selectedIndexes()) {
if (index.row() > 0 && radioData->generalSettings.currModelIndex != (unsigned int)(index.row()-1)) {
radioData->models[index.row()-1].clear();
((MdiChild *)parent())->setModified();
}
else if (index.row()>0) {
if (ask) {
QMessageBox::warning(this, "Companion", tr("Cannot delete default model."), QMessageBox::Ok);
}
else {
QMessageBox::warning(this, "Companion", tr("Cannot cut default model."), QMessageBox::Ok);
}
}
}
}
}
void ModelsListWidget::doCut(QByteArray * gmData) void ModelsListWidget::doCut(QByteArray * gmData)
{ {
bool modified = false; bool modified = false;
@ -400,127 +469,12 @@ void ModelsListWidget::doCut(QByteArray * gmData)
} }
} }
void ModelsListWidget::doCopy(QByteArray * gmData)
{
DragDropHeader header;
qDebug() << selectionModel()->selectedIndexes();
foreach(QModelIndex index, selectionModel()->selectedIndexes()) {
char column = index.column();
if (column == 0) {
char row = index.row();
if (!row) {
header.general_settings = true;
gmData->append('G');
gmData->append((char *) &radioData->generalSettings, sizeof(GeneralSettings));
}
else {
header.models[header.models_count++] = row;
gmData->append('M');
gmData->append((char *) &radioData->models[row - 1], sizeof(ModelData));
}
}
}
gmData->prepend((char *)&header, sizeof(header));
}
void ModelsListWidget::copy()
{
QByteArray gmData;
doCopy(&gmData);
QMimeData * mimeData = new QMimeData;
mimeData->setData("application/x-companion", gmData);
QClipboard * clipboard = QApplication::clipboard();
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
}
void ModelsListWidget::doPaste(QByteArray * gmData, int index)
{
// QByteArray gmData = mimeD->data("application/x-companion");
char * gData = gmData->data() + sizeof(DragDropHeader); // new char[gmData.size() + 1];
int i = sizeof(DragDropHeader);
int id = index;
int ret, modified=0;
if(!id) id++;
while (i<gmData->size() && id<=GetEepromInterface()->getMaxModels()) {
qDebug() << i << gmData->size();
char c = *gData;
i++;
gData++;
if (c == 'G') {
// General settings
ret = QMessageBox::question(this, "Companion", tr("Do you want to overwrite radio general settings?"),
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
radioData->generalSettings = *((GeneralSettings *)gData);
modified = 1;
}
gData += sizeof(GeneralSettings);
i += sizeof(GeneralSettings);
}
else {
// Model data
if (!radioData->models[id-1].isEmpty()) {
ret = QMessageBox::question(this, "Companion", tr("You are pasting on an not empty model, are you sure?"),
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
radioData->models[id-1] = *((ModelData *)gData);
strcpy(radioData->models[id-1].filename, radioData->getNextModelFilename().toStdString().c_str());
gData += sizeof(ModelData);
i += sizeof(ModelData);
id++;
modified = 1;
}
else {
gData += sizeof(ModelData);
i += sizeof(ModelData);
id++;
}
}
else {
radioData->models[id-1] = *((ModelData *)gData);
strcpy(radioData->models[id-1].filename, radioData->getNextModelFilename().toStdString().c_str());
gData += sizeof(ModelData);
i += sizeof(ModelData);
id++;
modified=1;
}
}
}
if (modified==1) {
((MdiChild *)parent())->setModified();
}
}
bool ModelsListWidget::hasPasteData()
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
return mimeData->hasFormat("application/x-companion");
}
void ModelsListWidget::paste()
{
if (hasPasteData()) {
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
QByteArray gmData = mimeData->data("application/x-companion");
doPaste(&gmData, currentRow());
}
}
void ModelsListWidget::duplicate() void ModelsListWidget::duplicate()
{ {
int i = this->currentRow(); int i = this->currentRow();
if (i && i<GetEepromInterface()->getMaxModels()) { if (i && i<GetCurrentFirmware()->getCapability(Models)) {
ModelData * model = &radioData->models[i-1]; ModelData * model = &radioData->models[i-1];
while (i<GetEepromInterface()->getMaxModels()) { while (i<GetCurrentFirmware()->getCapability(Models)) {
if (radioData->models[i].isEmpty()) { if (radioData->models[i].isEmpty()) {
radioData->models[i] = *model; radioData->models[i] = *model;
strcpy(radioData->models[i].filename, radioData->getNextModelFilename().toStdString().c_str()); strcpy(radioData->models[i].filename, radioData->getNextModelFilename().toStdString().c_str());
@ -529,54 +483,20 @@ void ModelsListWidget::duplicate()
} }
i++; i++;
} }
if (i==GetEepromInterface()->getMaxModels()) { if (i==GetCurrentFirmware()->getCapability(Models)) {
QMessageBox::warning(this, "Companion", tr("No free slot available, cannot duplicate"), QMessageBox::Ok); QMessageBox::warning(this, "Companion", tr("No free slot available, cannot duplicate"), QMessageBox::Ok);
} }
} }
} }
bool ModelsListWidget::hasSelection()
{
return (this->selectionModel()->hasSelection());
}
void ModelsListWidget::keyPressEvent(QKeyEvent *event)
{
if (event->matches(QKeySequence::Delete)) {
deleteSelected();
return;
}
if (event->matches(QKeySequence::Cut)) {
cut();
return;
}
if (event->matches(QKeySequence::Copy)) {
copy();
return;
}
if (event->matches(QKeySequence::Paste)) {
paste();
return;
}
if (event->matches(QKeySequence::Underline)) {
duplicate();
return;
}
QTreeWidget::keyPressEvent(event);//run the standard event in case we didn't catch an action
}
void ModelsListWidget::onCurrentItemChanged(QTreeWidgetItem * current, QTreeWidgetItem *) void ModelsListWidget::onCurrentItemChanged(QTreeWidgetItem * current, QTreeWidgetItem *)
{ {
int index = indexOfTopLevelItem(current); /*int index = indexOfTopLevelItem(current);
if (!isVisible()) if (!isVisible())
((MdiChild*)parent())->viableModelSelected(false); ((MdiChild*)parent())->viableModelSelected(false);
else if (index<1) else if (index<1)
((MdiChild*)parent())->viableModelSelected(false); ((MdiChild*)parent())->viableModelSelected(false);
else else
((MdiChild*)parent())->viableModelSelected(!radioData->models[currentRow()-1].isEmpty()); ((MdiChild*)parent())->viableModelSelected(!radioData->models[currentRow()-1].isEmpty()); */
} }
#endif

View file

@ -21,8 +21,8 @@
#ifndef _MODELSLIST_H_ #ifndef _MODELSLIST_H_
#define _MODELSLIST_H_ #define _MODELSLIST_H_
#include <QtWidgets>
#include "eeprominterface.h" #include "eeprominterface.h"
#include <QtWidgets>
struct CurrentSelection struct CurrentSelection
{ {
@ -30,13 +30,84 @@ struct CurrentSelection
bool selected[CPN_MAX_MODELS+1]; bool selected[CPN_MAX_MODELS+1];
}; };
class ModelsListWidget : public QTreeWidget class TreeItem
{
public:
explicit TreeItem(const QVector<QVariant> & itemData);
explicit TreeItem(TreeItem * parent, int modelIndex = -1);
~TreeItem();
TreeItem *child(int number);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
TreeItem * appendChild(int modelIndex);
TreeItem * parent();
bool removeChildren(int position, int count);
int childNumber() const;
bool setData(int column, const QVariant &value);
int getModelIndex() const { return modelIndex; }
private:
QList<TreeItem*> childItems;
QVector<QVariant> itemData;
TreeItem * parentItem;
int modelIndex;
};
class TreeModel : public QAbstractItemModel
{
// Q_OBJECT
public:
TreeModel(RadioData * radioData, QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) Q_DECL_OVERRIDE;
bool removeRows(int position, int rows,
const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
void refresh();
int getAvailableEEpromSize() { return availableEEpromSize; }
int getModelIndex(const QModelIndex & index) const {
return getItem(index)->getModelIndex();
}
private:
TreeItem * getItem(const QModelIndex & index) const;
TreeItem * rootItem;
RadioData * radioData;
int availableEEpromSize;
};
#if 0
class ModelsListWidget : public QTreeView
{ {
Q_OBJECT Q_OBJECT
public: public:
ModelsListWidget(QWidget * parent = 0); ModelsListWidget(QWidget * parent = 0);
void setRadioData(RadioData * radioData);
bool hasSelection(); bool hasSelection();
void keyPressEvent(QKeyEvent * event); void keyPressEvent(QKeyEvent * event);
bool hasPasteData(); bool hasPasteData();
@ -56,18 +127,16 @@ protected:
public slots: public slots:
void refreshList(); void refreshList();
void ShowContextMenu(const QPoint& pos);
void cut(); void cut();
void copy(); void copy();
void paste(); void paste();
void print(); void print();
void EditModel(); void EditModel();
void OpenEditWindow();
void LoadBackup(); void LoadBackup();
void OpenWizard(); void OpenWizard();
void simulate();
void duplicate(); void duplicate();
void setdefault();
void deleteSelected(bool ask); void deleteSelected(bool ask);
void confirmDelete(); void confirmDelete();
void onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *); void onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
@ -86,5 +155,6 @@ private:
QColor active_highlight_color; QColor active_highlight_color;
}; };
#endif
#endif // _MODELSLIST_H_ #endif // _MODELSLIST_H_

View file

@ -20,11 +20,11 @@
#include "process_flash.h" #include "process_flash.h"
#include "progresswidget.h" #include "progresswidget.h"
#include "eeprominterface.h"
#include <QFile> #include <QFile>
#include <QMessageBox> #include <QMessageBox>
#include <QProcess> #include <QProcess>
#include "eeprominterface.h" #include <QEventLoop>
//#include "firmwareinterface.h"
#if defined _MSC_VER || !defined __GNUC__ #if defined _MSC_VER || !defined __GNUC__
#include <Windows.h> #include <Windows.h>

1321
companion/src/radiodata.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@
#include "releasenotesdialog.h" #include "releasenotesdialog.h"
#include "ui_htmldialog.h" #include "ui_htmldialog.h"
#include <QFile>
ReleaseNotesDialog::ReleaseNotesDialog(QWidget * parent) : ReleaseNotesDialog::ReleaseNotesDialog(QWidget * parent) :
QDialog(parent), QDialog(parent),

View file

@ -1,14 +1,18 @@
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
set(storage_NAMES set(storage_NAMES
storage_eeprom
storage_sdcard
hexinterface hexinterface
# xmlinterface
mountlist mountlist
rlefile rlefile
appdata appdata
firmwareinterface firmwareinterface
storage
bineeprom
eepe
hexeeprom
categorized
sdcard
otx
) )
set(storage_SRCS set(storage_SRCS

View file

@ -0,0 +1,103 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "bineeprom.h"
#include "eeprominterface.h"
#include <QFile>
#include <bitset>
// TODO should be RleFormat, RawFormat etc.
bool BinEepromFormat::load(RadioData & radioData)
{
QFile file(filename);
int size = file.size();
if (!file.open(QFile::ReadOnly)) {
qDebug() << "Unable to open" << filename << file.errorString();
return false;
}
QByteArray eeprom(size, 0);
int result = file.read((char *)eeprom.data(), size);
if (result != size) {
setError(QObject::tr("Error reading %1: %2").arg(filename).arg(file.errorString()));
return false;
}
return extract(radioData, eeprom);
}
bool BinEepromFormat::write(const RadioData & radioData)
{
bool result;
EEPROMInterface * eepromInterface = GetEepromInterface();
uint8_t * eeprom = (uint8_t *)malloc(getEEpromSize(eepromInterface->getBoard()));
int eeprom_size = eepromInterface->save(eeprom, radioData, 0, GetCurrentFirmware()->getVariantNumber());
if (eeprom_size) {
result = writeToFile(eeprom, eeprom_size);
}
else {
setError(QObject::tr("Cannot save EEPROM"));
result = false;
}
free(eeprom);
return result;
}
bool BinEepromFormat::writeToFile(const uint8_t * eeprom, uint32_t size)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
setError(QObject::tr("Cannot open file %1:\n%2.").arg(filename).arg(file.errorString()));
return false;
}
QTextStream outputStream(&file);
long len = file.write((char *)eeprom, size);
if (len != size) {
setError(QObject::tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
return false;
}
return true;
}
bool BinEepromFormat::extract(RadioData & radioData, const QByteArray & eeprom)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface * eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->load(radioData, (uint8_t *)eeprom.data(), eeprom.size()));
if (result.test(ALL_OK)) {
if (errors.test(HAS_WARNINGS)) {
// TODO ShowEepromWarnings(this, QObject::tr("Warning"), errors.to_ulong());
}
return true;
}
else {
errors |= result;
}
}
setError(QObject::tr("Invalid EEPROM File %1: %2").arg(filename).arg(errors.to_ulong()));
return false;
}

View file

@ -18,16 +18,25 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#ifndef _STORAGE_EEPROM_H_ #ifndef _BINEEPROM_H_
#define _STORAGE_EEPROM_H_ #define _BINEEPROM_H_
#include <QDomDocument> #include "storage.h"
#include <QString>
#include "eeprominterface.h"
unsigned long LoadBackup(RadioData &radioData, uint8_t *eeprom, int esize, int index); class BinEepromFormat : public StorageFormat
unsigned long LoadEeprom(RadioData &radioData, const uint8_t *eeprom, int size); {
unsigned long LoadEepromXml(RadioData &radioData, QDomDocument &doc); public:
bool convertEEprom(const QString &sourceEEprom, const QString &destinationEEprom, const QString &firmware); BinEepromFormat(const QString & filename):
StorageFormat(filename)
{
}
#endif // _STORAGE_EEPROM_H_ virtual bool load(RadioData & radioData);
virtual bool write(const RadioData & radioData);
protected:
bool extract(RadioData & radioData, const QByteArray & eeprom);
virtual bool writeToFile(const uint8_t * eeprom, uint32_t size);
};
#endif // _BINEEPROM_H_

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "categorized.h"
#include "firmwares/opentx/opentxinterface.h"
bool CategorizedStorageFormat::load(RadioData & radioData)
{
QByteArray radioSettingsBuffer;
if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) {
setError(QObject::tr("Can't extract RADIO/radio.bin"));
return false;
}
if (!loadRadioSettingsFromByteArray(radioData.generalSettings, radioSettingsBuffer)) {
return false;
}
QByteArray modelsListBuffer;
if (!loadFile(modelsListBuffer, "RADIO/models.txt")) {
setError(QObject::tr("Can't extract RADIO/models.txt"));
return false;
}
QList<QByteArray> lines = modelsListBuffer.split('\n');
int modelIndex = 0;
int categoryIndex = -1;
foreach (const QByteArray & line, lines) {
if (!line.isEmpty()) {
if (line.startsWith('[') && line.endsWith(']')) {
QString name = line.mid(1, line.size() - 2);
CategoryData category(name.toStdString().c_str());
radioData.categories.push_back(category);
categoryIndex++;
}
else {
qDebug() << "Loading" << line;
QByteArray modelBuffer;
if (!loadFile(modelBuffer, QString("MODELS/%1").arg(QString(line)))) {
setError(QObject::tr("Can't extract %1").arg(QString(line)));
return false;
}
if (!loadModelFromByteArray(radioData.models[modelIndex], modelBuffer)) {
return false;
}
strncpy(radioData.models[modelIndex].filename, line.data(), sizeof(radioData.models[modelIndex].filename));
if (strcmp(radioData.generalSettings.currModelFilename, line.data()) == 0) {
radioData.generalSettings.currModelIndex = modelIndex;
}
radioData.models[modelIndex].category = categoryIndex;
radioData.models[modelIndex].used = true;
modelIndex++;
}
}
}
return true;
}
bool CategorizedStorageFormat::write(const RadioData & radioData)
{
// models.txt
QByteArray modelsList;
int currentCategoryIndex = -1;
// radio.bin
QByteArray radioSettingsData;
writeRadioSettingsToByteArray(radioData.generalSettings, radioSettingsData);
if (!writeFile(radioSettingsData, "RADIO/radio.bin")) {
return false;
}
// all models
for (unsigned int i=0; i<radioData.models.size(); i++) {
const ModelData & model = radioData.models[i];
if (!model.isEmpty()) {
QString modelFilename = QString("MODELS/%1").arg(model.filename);
QByteArray modelData;
writeModelToByteArray(model, modelData);
if (!writeFile(modelData, modelFilename)) {
return false;
}
int categoryIndex = model.category;
if (currentCategoryIndex != categoryIndex) {
modelsList.append(QString().sprintf("[%s]\n", radioData.categories[model.category].name));
currentCategoryIndex = categoryIndex;
}
modelsList.append(QString(model.filename) + "\n");
}
}
if (!writeFile(modelsList, "RADIO/models.txt")) {
return false;
}
return true;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CATEGORIZED_H_
#define _CATEGORIZED_H_
#include "storage.h"
class CategorizedStorageFormat : public StorageFormat
{
public:
CategorizedStorageFormat(const QString & filename):
StorageFormat(filename)
{
}
virtual bool load(RadioData & radioData);
virtual bool write(const RadioData & radioData);
protected:
virtual bool loadFile(QByteArray & fileData, const QString & fileName) = 0;
virtual bool writeFile(const QByteArray & fileData, const QString & fileName) = 0;
};
#endif // _CATEGORIZED_H_

View file

@ -0,0 +1,53 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "eepe.h"
#include <QFile>
#include "eeprominterface.h"
#include "hexinterface.h"
bool EepeFormat::load(RadioData & radioData)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Unable to open" << filename << file.errorString();
return false;
}
QTextStream inputStream(&file);
QString hline = inputStream.readLine();
if (hline != EEPE_EEPROM_FILE_HEADER) {
qDebug() << "No EEPE header";
return false;
}
qDebug() << "EEPE header found";
QByteArray eeprom(EESIZE_MAX, 0);
int eeprom_size = HexInterface(inputStream).load((uint8_t *)eeprom.data(), EESIZE_MAX);
if (!eeprom_size) {
setError(QObject::tr("Invalid EEPROM File %1").arg(filename));
return false;
}
eeprom.resize(eeprom_size);
return extract(radioData, eeprom);
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _EEPE_H_
#define _EEPE_H_
#include "hexeeprom.h"
class EepeFormat : public HexEepromFormat
{
public:
EepeFormat(const QString & filename):
HexEepromFormat(filename)
{
}
virtual bool load(RadioData & radioData);
};
#endif // _EEPE_H_

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// TODO not enabled for now
bool EepeXmlFormat::load(RadioData & radioData)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Unable to open" << filename << file.errorString();
return false;
}
QDomDocument doc(ER9X_EEPROM_FILE_TYPE);
bool xmlOK = doc.setContent(&file);
if (xmlOK) {
std::bitset<NUM_ERRORS> errors((unsigned long long) LoadEepromXml(radioData, doc));
if (errors.test(ALL_OK)) {
return true;
}
else {
qDebug() << "XML parsing error";
}
}
else {
qDebug() << "No XML content";
}
return false;
}

View file

@ -18,11 +18,12 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <QtGui>
#include "hexinterface.h" #include "hexinterface.h"
#include "splash.h" #include "splash.h"
#include "firmwareinterface.h" #include "firmwareinterface.h"
#include "helpers.h" #include "helpers.h"
#include "storage.h"
#include <QtGui>
#define FW_MARK "FW" #define FW_MARK "FW"
#define VERS_MARK "VERS" #define VERS_MARK "VERS"
@ -30,25 +31,6 @@
#define TIME_MARK "TIME" #define TIME_MARK "TIME"
#define EEPR_MARK "EEPR" #define EEPR_MARK "EEPR"
int getFileType(const QString &fullFileName)
{
QString suffix = QFileInfo(fullFileName).suffix().toUpper();
if (suffix == "HEX")
return FILE_TYPE_HEX;
else if (suffix == "BIN")
return FILE_TYPE_BIN;
else if (suffix == "EEPM")
return FILE_TYPE_EEPM;
else if (suffix == "EEPE")
return FILE_TYPE_EEPE;
else if (suffix == "XML")
return FILE_TYPE_XML;
else if (suffix == "OTX")
return FILE_TYPE_OTX;
else
return 0;
}
FirmwareInterface::FirmwareInterface(const QString &filename): FirmwareInterface::FirmwareInterface(const QString &filename):
flash(FSIZE_MAX, 0), flash(FSIZE_MAX, 0),
flashSize(0), flashSize(0),
@ -355,9 +337,9 @@ unsigned int FirmwareInterface::save(QString fileName)
memcpy(binflash, flash.constData(), flashSize); memcpy(binflash, flash.constData(), flashSize);
QFile file(fileName); QFile file(fileName);
int fileType = getFileType(fileName); int fileType = getStorageType(fileName);
if (fileType == FILE_TYPE_HEX) { if (fileType == STORAGE_TYPE_HEX) {
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { //reading HEX TEXT file if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { //reading HEX TEXT file
free(binflash); free(binflash);
return -1; return -1;

View file

@ -36,15 +36,6 @@
#define ERSKY9X_SPE "SPE" #define ERSKY9X_SPE "SPE"
#define ERSKY9X_OFFSET (7) #define ERSKY9X_OFFSET (7)
#define FILE_TYPE_BIN 1
#define FILE_TYPE_HEX 2
#define FILE_TYPE_EEPE 3
#define FILE_TYPE_EEPM 4
#define FILE_TYPE_XML 5
#define FILE_TYPE_OTX 6
int getFileType(const QString &fullFileName);
class FirmwareInterface class FirmwareInterface
{ {
public: public:

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "hexeeprom.h"
#include "eeprominterface.h"
#include "hexinterface.h"
#include <QFile>
bool HexEepromFormat::load(RadioData & radioData)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Unable to open" << filename << file.errorString();
return false;
}
QTextStream inputStream(&file);
// TODO remove EESIZE_MAX
QByteArray eeprom(EESIZE_MAX, 0);
int eeprom_size = HexInterface(inputStream).load((uint8_t *)eeprom.data(), EESIZE_MAX);
if (!eeprom_size) {
setError(QObject::tr("Invalid EEPROM File %1").arg(filename));
return false;
}
eeprom.resize(eeprom_size);
return extract(radioData, eeprom);
}
bool HexEepromFormat::writeToFile(const uint8_t * eeprom, uint32_t size)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
setError(QObject::tr("Cannot open file %1:\n%2.").arg(filename).arg(file.errorString()));
return false;
}
QTextStream outputStream(&file);
if (!HexInterface(outputStream).save(eeprom, size)) {
setError(QObject::tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
return false;
}
return true;
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _HEXEEPROM_H_
#define _HEXEEPROM_H_
#include "bineeprom.h"
class HexEepromFormat : public BinEepromFormat
{
public:
HexEepromFormat(const QString & filename):
BinEepromFormat(filename)
{
}
virtual bool load(RadioData & radioData);
protected:
virtual bool writeToFile(const uint8_t * eeprom, uint32_t size);
};
#endif // _HEXEEPROM_H_

View file

@ -84,7 +84,7 @@ int HexInterface::load(uint8_t *data, int maxsize)
} }
bool HexInterface::save(uint8_t *data, const int size) bool HexInterface::save(const uint8_t * data, const int size)
{ {
int addr = 0; int addr = 0;
int nextbank = 1; int nextbank = 1;
@ -103,7 +103,7 @@ bool HexInterface::save(uint8_t *data, const int size)
return true; return true;
} }
QString HexInterface::iHEXLine(quint8 * data, quint32 addr, quint8 len) QString HexInterface::iHEXLine(const quint8 * data, quint32 addr, quint8 len)
{ {
unsigned int bankaddr; unsigned int bankaddr;
bankaddr=addr&0xffff; bankaddr=addr&0xffff;

View file

@ -29,12 +29,12 @@ class HexInterface {
HexInterface(QTextStream &stream); HexInterface(QTextStream &stream);
int load(uint8_t * output, int maxsize); int load(uint8_t * output, int maxsize);
bool save(uint8_t *data, const int size); bool save(const uint8_t * data, const int size);
protected: protected:
int getValueFromLine(const QString &line, int pos, int len=2); int getValueFromLine(const QString &line, int pos, int len=2);
QString iHEXLine(quint8 * data, quint32 addr, quint8 len); QString iHEXLine(const quint8 * data, quint32 addr, quint8 len);
QString iHEXExtRec(quint8 bank); QString iHEXExtRec(quint8 bank);
QTextStream & stream; QTextStream & stream;

View file

@ -0,0 +1,116 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "otx.h"
#include "miniz.c"
#include <QFile>
#define MZ_ALLOCATION_SIZE (32*1024)
bool OtxFormat::load(RadioData & radioData)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
setError(QObject::tr("Error opening file %1:\n%2.").arg(filename).arg(file.errorString()));
return false;
}
QByteArray archiveContents = file.readAll();
qDebug() << "File" << filename << "read, size:" << archiveContents.size();
// open zip file
memset(&zip_archive, 0, sizeof(zip_archive));
if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) {
qDebug() << QObject::tr("Error opening OTX archive %1").arg(filename);
return false;
}
bool result = CategorizedStorageFormat::load(radioData);
mz_zip_reader_end(&zip_archive);
return result;
}
bool OtxFormat::write(const RadioData & radioData)
{
qDebug() << "Saving to archive" << filename;
memset(&zip_archive, 0, sizeof(zip_archive));
if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) {
setError(QObject::tr("Error initializing OTX archive writer"));
return false;
}
bool result = CategorizedStorageFormat::write(radioData);
if (result) {
// finalize archive and get contents
char * archiveContents;
size_t archiveSize;
if (mz_zip_writer_finalize_heap_archive(&zip_archive, (void **)&archiveContents, &archiveSize)) {
qDebug() << "Archive size" << archiveSize;
// write contents to file
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
qint64 len = file.write(archiveContents, archiveSize);
if (len != (qint64)archiveSize) {
setError(QObject::tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
result = false;
}
}
else {
setError(QObject::tr("Error creating OTX file %1:\n%2.").arg(filename).arg(file.errorString()));
result = false;
}
}
else {
setError(QObject::tr("Error creating OTX archive"));
result = false;
}
}
mz_zip_writer_end(&zip_archive);
return result;
}
bool OtxFormat::loadFile(QByteArray & filedata, const QString & filename)
{
size_t size;
void * data = mz_zip_reader_extract_file_to_heap(&zip_archive, filename.toStdString().c_str(), &size, 0);
if (!data) {
return false;
}
qDebug() << QString("Extracted file %1, size=%2").arg(filename).arg(size);
filedata.clear();
filedata.append((char *)data, size);
mz_free(data);
return true;
}
bool OtxFormat::writeFile(const QByteArray & filedata, const QString & filename)
{
if (!mz_zip_writer_add_mem(&zip_archive, filename.toStdString().c_str(), filedata.data(), filedata.size(), MZ_DEFAULT_LEVEL)) {
setError(QObject::tr("Error adding %1 to OTX archive").arg(filename));
return false;
}
return true;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _OTX_H_
#define _OTX_H_
#include "categorized.h"
#define MINIZ_HEADER_FILE_ONLY
#include "miniz.c"
#undef MINIZ_HEADER_FILE_ONLY
class OtxFormat : public CategorizedStorageFormat
{
public:
OtxFormat(const QString & filename):
CategorizedStorageFormat(filename)
{
}
virtual bool load(RadioData & radioData);
virtual bool write(const RadioData & radioData);
protected:
virtual bool loadFile(QByteArray & fileData, const QString & fileName);
virtual bool writeFile(const QByteArray & fileData, const QString & fileName);
mz_zip_archive zip_archive;
};
#endif // _OTX_H_

View file

@ -20,21 +20,6 @@
// TODO should be rle // TODO should be rle
/*
* Author - Bertrand Songis <bsongis@gmail.com>
*
* Based on th9x -> http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _RLEFILE_H_ #ifndef _RLEFILE_H_
#define _RLEFILE_H_ #define _RLEFILE_H_

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "sdcard.h"
#include <QFile>
#include <QDir>
bool SdcardFormat::write(const RadioData & radioData)
{
QDir dir(filename);
dir.mkdir("RADIO");
dir.mkdir("MODELS");
return CategorizedStorageFormat::write(radioData);
}
bool SdcardFormat::loadFile(QByteArray & filedata, const QString & filename)
{
QString path = this->filename + "/" + filename;
QFile file(path);
if (!file.open(QFile::ReadOnly)) {
setError(QObject::tr("Error opening file %1:\n%2.").arg(path).arg(file.errorString()));
return false;
}
filedata = file.readAll();
qDebug() << "File" << path << "read, size:" << filedata.size();
return true;
}
bool SdcardFormat::writeFile(const QByteArray & data, const QString & filename)
{
QString path = this->filename + "/" + filename;
QFile file(path);
if (!file.open(QFile::WriteOnly)) {
setError(QObject::tr("Error opening file %1:\n%2.").arg(path).arg(file.errorString()));
qDebug() << "File" << path << "write error";
return false;
}
file.write(data.data(), data.size());
file.close();
qDebug() << "File" << path << "written, size:" << data.size();
return true;
}
bool SdcardStorageFactory::probe(const QString & path)
{
return QDir(path).exists();
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SDCARD_H2_
#define _SDCARD_H2_
#include "categorized.h"
class SdcardFormat : public CategorizedStorageFormat
{
public:
SdcardFormat(const QString & filename):
CategorizedStorageFormat(filename)
{
}
virtual bool write(const RadioData & radioData);
protected:
virtual bool loadFile(QByteArray & fileData, const QString & fileName);
virtual bool writeFile(const QByteArray & fileData, const QString & fileName);
};
class SdcardStorageFactory : public DefaultStorageFactory<SdcardFormat>
{
public:
SdcardStorageFactory():
DefaultStorageFactory<SdcardFormat>("sdcard")
{
}
virtual bool probe(const QString & name);
};
#endif // _SDCARD_H2_

View file

@ -0,0 +1,170 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "bineeprom.h"
#include "eepe.h"
#include "otx.h"
#include "sdcard.h"
#include "firmwareinterface.h"
#include "eeprominterface.h"
#include <QFileInfo>
StorageType getStorageType(const QString & filename)
{
QString suffix = QFileInfo(filename).suffix().toUpper();
if (suffix == "HEX")
return STORAGE_TYPE_HEX;
else if (suffix == "BIN")
return STORAGE_TYPE_BIN;
else if (suffix == "EEPM")
return STORAGE_TYPE_EEPM;
else if (suffix == "EEPE")
return STORAGE_TYPE_EEPE;
else if (suffix == "XML")
return STORAGE_TYPE_XML;
else if (suffix == "OTX")
return STORAGE_TYPE_OTX;
else
return STORAGE_TYPE_UNKNOWN;
}
void registerStorageFactory(StorageFactory * factory);
QList<StorageFactory *> registeredStorageFactories;
void registerStorageFactory(StorageFactory * factory)
{
qDebug() << "register storage" << factory->name();
registeredStorageFactories.push_back(factory);
}
void registerStorageFactories()
{
registerStorageFactory(new DefaultStorageFactory<BinEepromFormat>("bin"));
registerStorageFactory(new DefaultStorageFactory<EepeFormat>("eepe"));
registerStorageFactory(new DefaultStorageFactory<HexEepromFormat>("hex"));
registerStorageFactory(new DefaultStorageFactory<OtxFormat>("otx"));
registerStorageFactory(new SdcardStorageFactory());
}
bool Storage::load(RadioData & radioData)
{
QFile file(filename);
if (!file.exists()) {
setError(QObject::tr("Unable to find file %1!").arg(filename));
return false;
}
foreach(StorageFactory * factory, registeredStorageFactories) {
StorageFormat * format = factory->instance(filename);
if (format->load(radioData)) {
setWarning(format->warning());
return true;
}
else {
setError(format->error());
}
}
return false;
}
bool Storage::write(const RadioData & radioData)
{
foreach(StorageFactory * factory, registeredStorageFactories) {
if (factory->probe(filename)) {
return factory->instance(filename)->write(radioData);
}
}
return false;
}
bool convertEEprom(const QString & sourceEEprom, const QString & destinationEEprom, const QString & firmwareFilename)
{
Firmware * currentFirmware = GetCurrentFirmware();
FirmwareInterface firmware(firmwareFilename);
if (!firmware.isValid())
return false;
uint8_t version = firmware.getEEpromVersion();
unsigned int variant = firmware.getEEpromVariant();
QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
Storage storage(sourceEEprom);
if (!storage.load(*radioData))
return false;
QByteArray eeprom(EESIZE_MAX, 0);
int size = currentFirmware->saveEEPROM((uint8_t *)eeprom.data(), *radioData, version, variant);
if (size == 0) {
return false;
}
QFile destinationFile(destinationEEprom);
if (!destinationFile.open(QIODevice::WriteOnly))
return false;
int result = destinationFile.write(eeprom.constData(), size);
destinationFile.close();
return (result == size);
}
#if 0
unsigned long LoadBackup(RadioData & radioData, uint8_t * eeprom, int size, int index)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface *eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->loadBackup(radioData, eeprom, size, index));
if (result.test(ALL_OK)) {
return result.to_ulong();
}
else {
errors |= result;
}
}
if (errors.none()) {
errors.set(UNKNOWN_ERROR);
}
return errors.to_ulong();
}
unsigned long LoadEepromXml(RadioData & radioData, QDomDocument & doc)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface *eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->loadxml(radioData, doc));
if (result.test(ALL_OK)) {
return result.to_ulong();
}
else {
errors |= result;
}
}
if (errors.none()) {
errors.set(UNKNOWN_ERROR);
}
return errors.to_ulong();
}
#endif

View file

@ -0,0 +1,143 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _STORAGE_H_
#define _STORAGE_H_
#include "radiodata.h"
#include <QString>
#include <QDebug>
enum StorageType
{
STORAGE_TYPE_UNKNOWN,
STORAGE_TYPE_BIN,
STORAGE_TYPE_HEX,
STORAGE_TYPE_EEPE,
STORAGE_TYPE_EEPM,
STORAGE_TYPE_XML,
STORAGE_TYPE_SDCARD,
STORAGE_TYPE_OTX
};
StorageType getStorageType(const QString & filename);
class StorageFormat
{
public:
StorageFormat(const QString & filename, uint8_t version=0):
filename(filename),
version(version)
{
}
virtual bool load(RadioData & radioData) = 0;
virtual bool write(const RadioData & radioData) = 0;
QString error() {
return _error;
}
QString warning() {
return _warning;
}
protected:
void setError(const QString & error)
{
qDebug() << "error:" << error;
_error = error;
}
void setWarning(const QString & warning)
{
if (!warning.isEmpty())
qDebug() << "warning:" << warning;
_warning = warning;
}
QString filename;
uint8_t version;
QString _error;
QString _warning;
};
class StorageFactory
{
public:
StorageFactory()
{
}
virtual QString name() = 0;
virtual bool probe(const QString & filename) = 0;
virtual StorageFormat * instance(const QString & filename) = 0;
};
template <class T>
class DefaultStorageFactory : public StorageFactory
{
public:
DefaultStorageFactory(const QString & name):
StorageFactory(),
_name(name)
{
}
virtual QString name()
{
return _name;
}
virtual bool probe(const QString & filename)
{
return filename.toLower().endsWith("." + _name);
}
virtual StorageFormat * instance(const QString & filename)
{
return new T(filename);
}
QString _name;
};
class Storage : public StorageFormat
{
public:
Storage(const QString & filename):
StorageFormat(filename)
{
}
virtual bool load(RadioData & radioData);
virtual bool write(const RadioData & radioData);
};
void registerStorageFactories();
#if 0
unsigned long LoadBackup(RadioData &radioData, uint8_t *eeprom, int esize, int index);
unsigned long LoadEeprom(RadioData &radioData, const uint8_t *eeprom, int size);
unsigned long LoadEepromXml(RadioData &radioData, QDomDocument &doc);
#endif
bool convertEEprom(const QString & sourceEEprom, const QString & destinationEEprom, const QString & firmware);
#endif // _STORAGE_H_

View file

@ -1,124 +0,0 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <QFile>
#include "firmwareinterface.h"
#include "storage_eeprom.h"
unsigned long LoadEeprom(RadioData & radioData, const uint8_t * eeprom, const int size)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface * eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->load(radioData, eeprom, size));
if (result.test(ALL_OK)) {
return result.to_ulong();
}
else {
errors |= result;
}
}
if (errors.none()) {
errors.set(UNKNOWN_ERROR);
}
return errors.to_ulong();
}
unsigned long LoadBackup(RadioData & radioData, uint8_t * eeprom, int size, int index)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface *eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->loadBackup(radioData, eeprom, size, index));
if (result.test(ALL_OK)) {
return result.to_ulong();
}
else {
errors |= result;
}
}
if (errors.none()) {
errors.set(UNKNOWN_ERROR);
}
return errors.to_ulong();
}
unsigned long LoadEepromXml(RadioData & radioData, QDomDocument & doc)
{
std::bitset<NUM_ERRORS> errors;
foreach(EEPROMInterface *eepromInterface, eepromInterfaces) {
std::bitset<NUM_ERRORS> result((unsigned long long)eepromInterface->loadxml(radioData, doc));
if (result.test(ALL_OK)) {
return result.to_ulong();
}
else {
errors |= result;
}
}
if (errors.none()) {
errors.set(UNKNOWN_ERROR);
}
return errors.to_ulong();
}
bool convertEEprom(const QString & sourceEEprom, const QString & destinationEEprom, const QString & firmwareFilename)
{
Firmware * currentFirmware = GetCurrentFirmware();
FirmwareInterface firmware(firmwareFilename);
if (!firmware.isValid())
return false;
uint8_t version = firmware.getEEpromVersion();
unsigned int variant = firmware.getEEpromVariant();
QFile sourceFile(sourceEEprom);
int eeprom_size = sourceFile.size();
if (!eeprom_size)
return false;
if (!sourceFile.open(QIODevice::ReadOnly))
return false;
QByteArray eeprom(eeprom_size, 0);
long result = sourceFile.read(eeprom.data(), eeprom_size);
sourceFile.close();
QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
std::bitset<NUM_ERRORS> errors((unsigned long long)LoadEeprom(*radioData, (uint8_t *)eeprom.data(), eeprom_size));
if (!errors.test(ALL_OK) || !currentFirmware->saveEEPROM((uint8_t *)eeprom.data(), *radioData, version, variant)) {
return false;
}
QFile destinationFile(destinationEEprom);
if (!destinationFile.open(QIODevice::WriteOnly))
return false;
result = destinationFile.write(eeprom.constData(), eeprom_size);
destinationFile.close();
if (result != eeprom_size)
return false;
return true;
}

View file

@ -1,300 +0,0 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <QFileInfo>
#include <QObject>
#include <QDebug>
#include <QRegularExpression>
#include "storage_sdcard.h"
// defines for miniz
#include "miniz.c"
int readFromArchive(QByteArray & data, mz_zip_archive * zip_archive, unsigned int index)
{
size_t uncompSize;
void * uncompData = mz_zip_reader_extract_to_heap(zip_archive, index, &uncompSize, 0);
if (!uncompData) {
return -1;
}
qDebug() << "Extracted file with index" << index << ",size" << uncompSize;
data.append((const char *)uncompData, uncompSize);
mz_free(uncompData);
return 0;
}
int StorageSdcard::read(const QString & path)
{
return QFileInfo(path).isDir() ? readSdcard(path) : readOtx(path);
}
int StorageSdcard::write(const QString & path)
{
return QFileInfo(path).isDir() ? writeSdcard(path) : writeOtx(path);
}
int StorageSdcard::readOtx(const QString & path)
{
QFile file(path);
if (!file.open(QFile::ReadOnly)) {
lastErrorMessage = QObject::tr("Error opening file %1:\n%2.").arg(path).arg(file.errorString());
return -1;
}
QByteArray archiveContents = file.readAll();
file.close();
qDebug() << "File" << path << "read, size:" << archiveContents.size();
// open zip file
mz_zip_archive zip_archive;
memset(&zip_archive, 0, sizeof(zip_archive));
if (!mz_zip_reader_init_mem(&zip_archive, archiveContents.data(), archiveContents.size(), 0)) {
lastErrorMessage = QObject::tr("Error opening OTX archive %1.").arg(path);
qDebug() << lastErrorMessage;
return -1;
}
// go trough all files in an archive
QRegularExpression regexModel("MODELS/\\w+.bin", QRegularExpression::CaseInsensitiveOption);
for (unsigned int i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) {
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) {
lastErrorMessage = QObject::tr("mz_zip_reader_file_stat() failed!");
qDebug() << lastErrorMessage;
mz_zip_reader_end(&zip_archive);
return -1;
}
// printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", file_stat.m_filename, file_stat.m_comment, (uint)file_stat.m_uncomp_size, (uint)file_stat.m_comp_size, mz_zip_reader_is_file_a_directory(&zip_archive, i));
if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) continue;
QString filename(file_stat.m_filename);
if (regexModel.match(filename).hasMatch()) {
qDebug() << "found model:" << filename;
models.append(ModelFile());
ModelFile & newModel = models.last();
newModel.filename = QFileInfo(filename).fileName();
if (readFromArchive(newModel.data, &zip_archive, i) < 0) {
lastErrorMessage = QObject::tr("Can't extract file %1").arg(filename);
qDebug() << lastErrorMessage;
mz_zip_reader_end(&zip_archive);
return -1;
}
}
else if (QString::compare(filename, "RADIO/radio.bin", Qt::CaseInsensitive) == 0) {
if (readFromArchive(radio, &zip_archive, i) < 0) {
lastErrorMessage = QObject::tr("Can't extract file %1").arg(filename);
qDebug() << lastErrorMessage;
mz_zip_reader_end(&zip_archive);
return -1;
}
}
else if (QString::compare(filename, "RADIO/models.txt", Qt::CaseInsensitive) == 0) {
if (readFromArchive(modelList, &zip_archive, i) < 0) {
lastErrorMessage = QObject::tr("Can't extract file %1").arg(filename);
qDebug() << lastErrorMessage;
mz_zip_reader_end(&zip_archive);
return -1;
}
}
else {
qDebug() << "Unknown file " << filename;
}
}
mz_zip_reader_end(&zip_archive);
return 0;
}
void StorageSdcard::readFile(QByteArray & data, const QString & path)
{
QFile file(path);
if (!file.open(QFile::ReadOnly)) {
lastErrorMessage = QObject::tr("Error opening file %1:\n%2.").arg(path).arg(file.errorString());
throw StorageSdcardReadFileError();
}
data = file.readAll();
file.close();
qDebug() << "File" << path << "read, size:" << data.size();
}
int StorageSdcard::readSdcard(const QString & path)
{
try {
readFile(radio, path + "/RADIO/radio.bin");
readFile(modelList, path + "RADIO/models.txt");
QDir dir(path + "MODELS/");
QStringList filters;
filters << "*.bin";
foreach(QString filename, dir.entryList(filters, QDir::Files)) {
qDebug() << "found" << filename;
models.append(ModelFile());
ModelFile & newModel = models.last();
newModel.filename = QFileInfo(filename).fileName();
readFile(newModel.data, path + "MODELS/" + filename);
}
}
catch (StorageSdcardReadFileError) {
return -1;
}
return 0;
}
void StorageSdcard::writeFile(const QByteArray & data, const QString & path)
{
QFile file(path);
if (!file.open(QFile::WriteOnly)) {
lastErrorMessage = QObject::tr("Error opening file %1:\n%2.").arg(path).arg(file.errorString());
qDebug() << "File" << path << "write error";
throw StorageSdcardWriteFileError();
}
file.write(data.data(), data.size());
file.close();
qDebug() << "File" << path << "written, size:" << data.size();
}
int StorageSdcard::writeSdcard(const QString & path)
{
try {
QDir dir(path);
dir.mkdir("RADIO");
writeFile(radio, path + "/RADIO/radio.bin");
writeFile(modelList, path + "/RADIO/models.txt");
dir.mkdir("MODELS");
for (QList<ModelFile>::const_iterator i = models.begin(); i != models.end(); ++i) {
qDebug() << "writing" << i->filename;
writeFile(i->data, path + "/MODELS/" + i->filename);
}
}
catch (StorageSdcardWriteFileError) {
return -1;
}
return 0;
}
#define MZ_ALLOCATION_SIZE (32*1024)
int StorageSdcard::writeOtx(const QString & path)
{
qDebug() << "Saving to archive" << path;
mz_zip_archive zip_archive;
memset(&zip_archive, 0, sizeof(zip_archive));
if (!mz_zip_writer_init_heap(&zip_archive, 0, MZ_ALLOCATION_SIZE)) {
lastErrorMessage = QObject::tr("Error initializing OTX archive writer");
qDebug() << lastErrorMessage;
return -1;
}
// add radio.bin
if (!mz_zip_writer_add_mem(&zip_archive, "RADIO/radio.bin", radio.data(), radio.size(), MZ_DEFAULT_LEVEL)) {
lastErrorMessage = QObject::tr("Error adding %1 to OTX archive").arg("RADIO/radio.bin");
qDebug() << lastErrorMessage;
mz_zip_writer_end(&zip_archive);
return -1;
}
// add models.txt
if (!mz_zip_writer_add_mem(&zip_archive, "RADIO/models.txt", modelList.data(), modelList.size(), MZ_DEFAULT_LEVEL)) {
lastErrorMessage = QObject::tr("Error adding %1 to OTX archive").arg("RADIO/models.txt");
qDebug() << lastErrorMessage;
mz_zip_writer_end(&zip_archive);
return -1;
}
// add all models
for (QList<ModelFile>::iterator i = models.begin(); i != models.end(); ++i) {
QString filename = "MODELS/" + i->filename;
qDebug() << "\tadding model:" << filename << "size" << i->data.size();
if (!mz_zip_writer_add_mem(&zip_archive, filename.toLatin1(), i->data.data(), i->data.size(), MZ_DEFAULT_LEVEL)) {
lastErrorMessage = QObject::tr("Error adding %1 to OTX archive").arg(filename);
qDebug() << lastErrorMessage;
mz_zip_writer_end(&zip_archive);
return -1;
}
}
// finalize archive and get contents
char * archiveContents;
size_t archiveSize;
if (!mz_zip_writer_finalize_heap_archive(&zip_archive, (void **)&archiveContents, &archiveSize)) {
lastErrorMessage = QObject::tr("Error creating OTX archive");
qDebug() << lastErrorMessage;
mz_zip_writer_end(&zip_archive);
return -1;
}
qDebug() << "Archive size" << archiveSize;
// write contents to file
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
lastErrorMessage = QObject::tr("Error creating OTX file %1:\n%2.").arg(path).arg(file.errorString());
qDebug() << lastErrorMessage;
mz_zip_writer_end(&zip_archive);
return -1;
}
qint64 result = file.write(archiveContents, archiveSize);
if(result != (qint64)archiveSize) {
lastErrorMessage = QObject::tr("Error writing file %1:\n%2.").arg(path).arg(file.errorString());
mz_zip_writer_end(&zip_archive);
return -1;
}
file.close();
mz_zip_writer_end(&zip_archive);
return 0;
}
const QByteArray & StorageSdcard::getModelData(const QString & filename) const
{
for (QList<ModelFile>::const_iterator i = models.begin(); i != models.end(); ++i) {
if (filename == i->filename) return i->data;
}
throw StorageSdcardModelNotFound();
}
QList<ModelFile>::iterator StorageSdcard::getModelIterator(const QString & filename)
{
for (QList<ModelFile>::iterator i = models.begin(); i != models.end(); ++i) {
if (filename == i->filename) return i;
}
return models.end();
}
QList<ModelFile>::const_iterator StorageSdcard::getModelIterator(const QString & filename) const
{
for (QList<ModelFile>::const_iterator i = models.begin(); i != models.end(); ++i) {
if (filename == i->filename) return i;
}
return models.end();
}
QList<QString> StorageSdcard::getModelsFileNames() const
{
QList<QString> result;
for (QList<ModelFile>::const_iterator i = models.begin(); i != models.end(); ++i) {
result.append(i->filename);
}
return result;
}

View file

@ -1,99 +0,0 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _STORAGE_SDCARD_H_
#define _STORAGE_SDCARD_H_
#include <QList>
#include <QByteArray>
#include <QString>
#include <QDir>
/*
This class implements a storage model used for radios that
store all settings on the SD card (currently only Hours)
Disk storage format:
* uses extension OTX
* its a normal ZIP archive containing the same directory
structure as the SD card in the radio. Only the relevant
directories and files are included.
*/
class StorageSdcardModelNotFound {};
class StorageSdcardReadFileError {};
class StorageSdcardWriteFileError {};
// representation of modelXX.bin file
struct ModelFile {
QString filename; // file name (without path)
QByteArray data; // file contents
};
class StorageSdcard {
public:
/*
Reads models and radio settings from:
* if a file is specified in path, from that file (OTX archive format)
* if a path is specified, from that path (where it expects to find files like on the SD card)
*/
int read(const QString & path);
/*
|Writes models and radio settings to:
* if a file is specified in path, to that file (OTX archive format)
* if a path is specified, to that path (layout created is like on the SD card)
*/
int write(const QString & path);
/*
Returns a model data for specified model
*/
const QByteArray & getModelData(const QString & filename) const;
/*
Returns a model iterator for specified model
*/
QList<ModelFile>::iterator getModelIterator(const QString & filename);
QList<ModelFile>::const_iterator getModelIterator(const QString & filename) const;
/*
Returns a list of all model bin files (their filenames)
*/
QList<QString> getModelsFileNames() const;
QString lastErrorMessage;
QByteArray radio; // radio settings (radio.bin)
QByteArray modelList; // model names and categories (models.txt)
QList<ModelFile> models; // collection of model data (modelXX.bin)
private:
int readOtx(const QString & path);
int readSdcard(const QString & path);
int writeOtx(const QString & path);
int writeSdcard(const QString & path);
void readFile(QByteArray & data, const QString & path);
void writeFile(const QByteArray & data, const QString & path);
};
#endif // _STORAGE_SDCARD_H_

View file

@ -195,7 +195,7 @@ bool XmlInterface::save(RadioData &radioData)
// the models // the models
models xml_models; models xml_models;
models::model_sequence & model_sequence (xml_models.model()); models::model_sequence & model_sequence (xml_models.model());
for (int i=0; i<CPN_MAX_MODELS; i++) { for (int i=0; i<radioData.models.size(); i++) {
ModelData & m = radioData.models[i]; ModelData & m = radioData.models[i];
if (m.used) { if (m.used) {
model xm(m.name); model xm(m.name);

View file

@ -23,6 +23,7 @@
#include "eeprominterface.h" #include "eeprominterface.h"
#include <QTextStream> #include <QTextStream>
#include <QDomDocument>
class XmlInterface class XmlInterface
{ {