mirror of
https://github.com/opentx/opentx.git
synced 2025-07-14 11:59:50 +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:
parent
d6b84371a9
commit
a65aa3d6c7
60 changed files with 3539 additions and 3153 deletions
|
@ -185,7 +185,6 @@ set(companion_MOC_HDRS
|
|||
flashfirmwaredialog.h
|
||||
flasheepromdialog.h
|
||||
downloaddialog.h
|
||||
modelslist.h
|
||||
mdichild.h
|
||||
mainwindow.h
|
||||
radionotfound.h
|
||||
|
|
|
@ -20,21 +20,16 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QSplashScreen>
|
||||
#include <QThread>
|
||||
#include <iostream>
|
||||
#if defined(JOYSTICKS) || defined(SIMU_AUDIO)
|
||||
#include <SDL.h>
|
||||
#undef main
|
||||
#endif
|
||||
#include "mainwindow.h"
|
||||
#include "version.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "appdata.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
|
@ -107,6 +102,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
#endif
|
||||
|
||||
registerStorageFactories();
|
||||
registerEEpromInterfaces();
|
||||
registerOpenTxFirmwares();
|
||||
registerSimulators();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "contributorsdialog.h"
|
||||
#include "ui_htmldialog.h"
|
||||
#include "helpers.h"
|
||||
#include <QFile>
|
||||
|
||||
ContributorsDialog::ContributorsDialog(QWidget * parent):
|
||||
QDialog(parent),
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define _EEPROMIMPORTEXPORT_H_
|
||||
|
||||
#include "customdebug.h"
|
||||
#include <QBitArray>
|
||||
|
||||
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
|
||||
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
#include <float.h>
|
||||
#include <QtWidgets>
|
||||
#include <stdlib.h>
|
||||
#include "eeprominterface.h"
|
||||
#include "firmwares/er9x/er9xinterface.h"
|
||||
#include "firmwares/ersky9x/ersky9xinterface.h"
|
||||
|
@ -32,9 +27,41 @@
|
|||
#include "helpers.h"
|
||||
#include "wizarddata.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
#include <float.h>
|
||||
#include <QtWidgets>
|
||||
#include <stdlib.h>
|
||||
#include <bitset>
|
||||
|
||||
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
|
||||
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,
|
||||
|
@ -631,7 +658,7 @@ QString RawSwitch::toString() const
|
|||
BoardEnum board = GetEepromInterface()->getBoard();
|
||||
switch(type) {
|
||||
case SWITCH_TYPE_SWITCH:
|
||||
if (IS_HORUS(board) || IS_TARANIS(board)) {
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
div_t qr = div(index-1, 3);
|
||||
Firmware::Switch sw = GetCurrentFirmware()->getSwitch(qr.quot);
|
||||
const char * positions[] = { ARROW_UP, "-", ARROW_DOWN };
|
||||
|
@ -1402,6 +1429,11 @@ void ModelData::clearMixes()
|
|||
mixData[i].clear();
|
||||
}
|
||||
|
||||
RadioData::RadioData()
|
||||
{
|
||||
models.resize(GetCurrentFirmware()->getCapability(Models));
|
||||
}
|
||||
|
||||
void ModelData::clear()
|
||||
{
|
||||
memset(this, 0, sizeof(ModelData));
|
||||
|
@ -1412,7 +1444,7 @@ void ModelData::clear()
|
|||
moduleData[1].ppm.delay = 300;
|
||||
moduleData[2].ppm.delay = 300;
|
||||
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[1].protocol = PULSES_OFF;
|
||||
}
|
||||
|
@ -1627,16 +1659,10 @@ int ModelData::getChannelsMax(bool forceExtendedLimits) const
|
|||
}
|
||||
|
||||
QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
void registerEEpromInterfaces()
|
||||
{
|
||||
eepromInterfaces.push_back(new OpenTxEepromInterface(BOARD_STOCK));
|
||||
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));
|
||||
registerOpenTxEEpromInterfaces();
|
||||
// eepromInterfaces.push_back(new Ersky9xInterface());
|
||||
// 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) {
|
||||
Firmware * result = firmware->getFirmwareVariant(id);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -92,11 +92,6 @@ Er9xGeneral::operator GeneralSettings ()
|
|||
result.vBatWarn = vBatWarn;
|
||||
result.txVoltageCalibration = txVoltageCalibration;
|
||||
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.disableThrottleWarning = disableThrottleWarning;
|
||||
|
@ -123,9 +118,6 @@ Er9xGeneral::operator GeneralSettings ()
|
|||
result.preBeep = preBeep;
|
||||
result.flashBeep = flashBeep;
|
||||
result.splashMode = disableSplashScreen;
|
||||
result.disablePotScroll=(disablePotScroll==1);
|
||||
result.disableBG=(disableBG==1);
|
||||
result.frskyinternalalarm = frskyinternalalarm;
|
||||
|
||||
result.backlightMode = 0;
|
||||
if (lightSw == 22) {
|
||||
|
|
|
@ -18,11 +18,12 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "er9xinterface.h"
|
||||
#include "er9xeeprom.h"
|
||||
#include "rlefile.h"
|
||||
#include "appdata.h"
|
||||
// #include "appdata.h"
|
||||
// #include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
@ -31,8 +32,8 @@
|
|||
#define FILE_MODEL(n) (1+n)
|
||||
|
||||
Er9xInterface::Er9xInterface():
|
||||
EEPROMInterface(BOARD_STOCK),
|
||||
efile(new RleFile())
|
||||
EEPROMInterface(BOARD_STOCK),
|
||||
efile(new RleFile())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,20 +47,6 @@ const char * Er9xInterface::getName()
|
|||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
||||
{
|
||||
std::cout << "trying er9x xml import... ";
|
||||
|
@ -108,7 +96,7 @@ unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
|||
radioData.generalSettings=er9xGeneral;
|
||||
std::cout << "version " << (unsigned int)er9xGeneral.myVers << " ";
|
||||
}
|
||||
for (int i=0; i<getMaxModels(); i++) {
|
||||
for (int i=0; i<getCapability(Models); i++) {
|
||||
Er9xModelData er9xModel;
|
||||
memset(&er9xModel,0,sizeof(er9xModel));
|
||||
if(loadModelDataXML(&doc, &er9xModel, i)) {
|
||||
|
@ -120,6 +108,7 @@ unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
|||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
if (size != getEEpromSize()) {
|
||||
if (size != getEEpromSize(BOARD_STOCK)) {
|
||||
std::cout << "wrong size\n";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
|
@ -176,7 +165,7 @@ unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, i
|
|||
}
|
||||
radioData.generalSettings = er9xGeneral;
|
||||
|
||||
for (int i=0; i<getMaxModels(); i++) {
|
||||
for (int i=0; i<getCapability(Models); i++) {
|
||||
Er9xModelData er9xModel;
|
||||
efile->openRd(FILE_MODEL(i));
|
||||
if (!efile->readRlc1((uint8_t*)&er9xModel, sizeof(Er9xModelData))) {
|
||||
|
@ -273,13 +262,13 @@ QDomElement Er9xInterface::getModelDataXML(QDomDocument * qdoc, Er9xModelData *
|
|||
|
||||
bool Er9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Er9xGeneral * tgen)
|
||||
{
|
||||
//look for "GENERAL_DATA" tag
|
||||
// look for "GENERAL_DATA" tag
|
||||
QDomElement gde = qdoc->elementsByTagName("GENERAL_DATA").at(0).toElement();
|
||||
|
||||
if(gde.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
//load cdata into tgen
|
||||
// load cdata into tgen
|
||||
QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
|
@ -291,17 +280,17 @@ bool Er9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Er9xGeneral *
|
|||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
//check version?
|
||||
// check version?
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Er9xInterface::loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum)
|
||||
{
|
||||
//look for MODEL_DATA with modelNum attribute.
|
||||
//if modelNum = -1 then just pick the first one
|
||||
// look for MODEL_DATA with modelNum attribute.
|
||||
// if modelNum = -1 then just pick the first one
|
||||
QDomNodeList ndl = qdoc->elementsByTagName("MODEL_DATA");
|
||||
|
||||
//cycle through nodes to find correct model number
|
||||
// cycle through nodes to find correct model number
|
||||
QDomNode k = ndl.at(0);
|
||||
if(modelNum>=0) {
|
||||
while(!k.isNull()) {
|
||||
|
@ -312,11 +301,11 @@ bool Er9xInterface::loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod,
|
|||
}
|
||||
}
|
||||
|
||||
if(k.isNull()) // couldn't find
|
||||
if (k.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
|
||||
//load cdata into tgen
|
||||
// load cdata into tgen
|
||||
QDomNode n = k.toElement().elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
|
@ -328,6 +317,16 @@ bool Er9xInterface::loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod,
|
|||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
//check version?
|
||||
// check version?
|
||||
return true;
|
||||
}
|
||||
|
||||
int Er9xInterface::getCapability(Capability capability)
|
||||
{
|
||||
switch (capability) {
|
||||
case Models:
|
||||
return 16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -37,10 +37,6 @@ class Er9xInterface : public EEPROMInterface
|
|||
|
||||
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 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 getCapability(Capability capability);
|
||||
|
||||
protected:
|
||||
|
||||
RleFile * efile;
|
||||
|
|
|
@ -143,8 +143,6 @@ Ersky9xGeneral::operator GeneralSettings ()
|
|||
result.preBeep = preBeep;
|
||||
result.flashBeep = flashBeep;
|
||||
result.splashMode = disableSplashScreen;
|
||||
result.disablePotScroll=(disablePotScroll==1);
|
||||
result.disableBG=(disableBG==1);
|
||||
result.templateSetup = templateSetup;
|
||||
result.PPM_Multiplier = PPM_Multiplier;
|
||||
getEEPROMString(result.ownerName, ownerName, sizeof(ownerName));
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "ersky9xinterface.h"
|
||||
#include "ersky9xeeprom.h"
|
||||
#include "rlefile.h"
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
@ -48,16 +49,6 @@ const char * Ersky9xInterface::getName()
|
|||
return "Ersky9x";
|
||||
}
|
||||
|
||||
const int Ersky9xInterface::getEEpromSize()
|
||||
{
|
||||
return EESIZE_SKY9X;
|
||||
}
|
||||
|
||||
const int Ersky9xInterface::getMaxModels()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
inline void applyStickModeToModel(Ersky9xModelData_v10 & model, unsigned int mode)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
||||
{
|
||||
std::cout << "trying ersky9x xml import... ";
|
||||
|
@ -138,7 +130,7 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
|||
radioData.generalSettings=ersky9xGeneral;
|
||||
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 (!loadModelDataXML<Ersky9xModelData_v10>(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) {
|
||||
std::cout << "ko\n";
|
||||
|
@ -158,6 +150,7 @@ unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
|||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
|
||||
{
|
||||
|
@ -206,14 +199,14 @@ unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom
|
|||
}
|
||||
radioData.generalSettings = ersky9xGeneral;
|
||||
|
||||
for (int i=0; i<getMaxModels(); i++) {
|
||||
for (int i=0; i<getCapability(Models); i++) {
|
||||
uint8_t buffer[4096];
|
||||
uint size;
|
||||
memset(buffer,0,sizeof(buffer));
|
||||
efile->openRd(FILE_MODEL(i));
|
||||
|
||||
// if (!efile->readRlc2((uint8_t*)&ersky9xModel, sizeof(Ersky9xModelData))) {
|
||||
size=efile->readRlc2(buffer, 4096);
|
||||
size = efile->readRlc2(buffer, 4096);
|
||||
if (!size) {
|
||||
radioData.models[i].clear();
|
||||
}
|
||||
|
@ -317,13 +310,13 @@ QDomElement Ersky9xInterface::getModelDataXML(QDomDocument * qdoc, Ersky9xModelD
|
|||
|
||||
bool Ersky9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Ersky9xGeneral * tgen)
|
||||
{
|
||||
//look for "GENERAL_DATA" tag
|
||||
// look for "GENERAL_DATA" tag
|
||||
QDomElement gde = qdoc->elementsByTagName("GENERAL_DATA").at(0).toElement();
|
||||
|
||||
if(gde.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
//load cdata into tgen
|
||||
// load cdata into tgen
|
||||
QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
|
@ -335,7 +328,7 @@ bool Ersky9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Ersky9xGene
|
|||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
//check version?
|
||||
// check version?
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -345,11 +338,11 @@ bool Ersky9xInterface::loadModelDataXML(QDomDocument * qdoc, ModelData *model, i
|
|||
T ersky9xModel;
|
||||
memset(&ersky9xModel, 0, sizeof(ersky9xModel));
|
||||
|
||||
//look for MODEL_DATA with modelNum attribute.
|
||||
// look for MODEL_DATA with modelNum attribute.
|
||||
//if modelNum = -1 then just pick the first one
|
||||
QDomNodeList ndl = qdoc->elementsByTagName("MODEL_DATA");
|
||||
|
||||
//cycle through nodes to find correct model number
|
||||
// cycle through nodes to find correct model number
|
||||
QDomNode k = ndl.at(0);
|
||||
if (modelNum>=0) {
|
||||
while(!k.isNull()) {
|
||||
|
@ -363,7 +356,7 @@ bool Ersky9xInterface::loadModelDataXML(QDomDocument * qdoc, ModelData *model, i
|
|||
if (k.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
//load cdata into tgen
|
||||
// load cdata into tgen
|
||||
QDomNode n = k.toElement().elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
|
@ -380,3 +373,13 @@ bool Ersky9xInterface::loadModelDataXML(QDomDocument * qdoc, ModelData *model, i
|
|||
*model = ersky9xModel;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Ersky9xInterface::getCapability(Capability capability)
|
||||
{
|
||||
switch (capability) {
|
||||
case Models:
|
||||
return 20;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -37,16 +37,11 @@ class Ersky9xInterface : public EEPROMInterface
|
|||
|
||||
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 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)
|
||||
{
|
||||
return 0;
|
||||
|
@ -58,6 +53,8 @@ class Ersky9xInterface : public EEPROMInterface
|
|||
|
||||
virtual int isAvailable(PulsesProtocol proto, int port=0);
|
||||
|
||||
virtual int getCapability(Capability capability);
|
||||
|
||||
protected:
|
||||
|
||||
RleFile * efile;
|
||||
|
|
|
@ -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_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_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_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_MIXERS(board, version) (IS_ARM(board) ? 64 : 32)
|
||||
#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_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)
|
||||
|
@ -58,7 +59,7 @@
|
|||
inline int switchIndex(int i, BoardEnum board, unsigned int 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));
|
||||
else
|
||||
return i;
|
||||
|
@ -102,7 +103,7 @@ class SwitchesConversionTable: public ConversionTable {
|
|||
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++) {
|
||||
addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, -i), -val+offset);
|
||||
addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, i), val++);
|
||||
|
@ -110,7 +111,7 @@ class SwitchesConversionTable: public ConversionTable {
|
|||
}
|
||||
|
||||
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++);
|
||||
}
|
||||
|
@ -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++);
|
||||
}
|
||||
|
||||
|
@ -267,7 +268,7 @@ class SourcesConversionTable: public ConversionTable {
|
|||
}
|
||||
|
||||
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++);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <QMessageBox>
|
||||
#include "opentxinterface.h"
|
||||
#include "opentxeeprom.h"
|
||||
#include "rlefile.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_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) {
|
||||
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_HORUS:
|
||||
return 0x3478746F;
|
||||
case BOARD_TARANIS_X7:
|
||||
case BOARD_TARANIS_X9D:
|
||||
case BOARD_TARANIS_X9DP:
|
||||
case BOARD_TARANIS_X9E:
|
||||
case BOARD_FLAMENCO:
|
||||
return EESIZE_TARANIS;
|
||||
return 0x3378746F;
|
||||
case BOARD_SKY9X:
|
||||
case BOARD_AR9X:
|
||||
return 0x3278746F;
|
||||
case BOARD_MEGA2560:
|
||||
case BOARD_GRUVIN9X:
|
||||
return 0x3178746F;
|
||||
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)
|
||||
{
|
||||
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>
|
||||
bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version)
|
||||
{
|
||||
if (version == 0) {
|
||||
version = getLastDataVersion(getBoard());
|
||||
}
|
||||
QByteArray raw;
|
||||
M manager((T&)src, board, version, 0);
|
||||
manager.Dump();
|
||||
// manager.Dump();
|
||||
manager.Export(raw);
|
||||
data.resize(8);
|
||||
*((uint32_t*)&data.data()[0]) = 0x3178396F;
|
||||
*((uint32_t*)&data.data()[0]) = getFourCC();
|
||||
data[4] = version;
|
||||
data[5] = 'M';
|
||||
*((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);
|
||||
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;
|
||||
}
|
||||
|
||||
template <class T, class M>
|
||||
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];
|
||||
QByteArray raw = data.right(data.size() - 8);
|
||||
return loadFromByteArray<T, M>(dest, raw, version);
|
||||
|
@ -215,84 +208,26 @@ bool OpenTxEepromInterface::saveModel(unsigned int index, ModelData &model, uint
|
|||
return (sz == eeprom.size());
|
||||
}
|
||||
|
||||
unsigned long OpenTxEepromInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
||||
QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
|
||||
void registerOpenTxEEpromInterface(BoardEnum board)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
OpenTxEepromInterface * interface = new OpenTxEepromInterface(board);
|
||||
opentxEEpromInterfaces.push_back(interface);
|
||||
eepromInterfaces.push_back(interface);
|
||||
}
|
||||
|
||||
int OpenTxEepromInterface::loadFile(RadioData & radioData, const QString & filename)
|
||||
void registerOpenTxEEpromInterfaces()
|
||||
{
|
||||
StorageSdcard storage;
|
||||
|
||||
storage.read(filename);
|
||||
|
||||
// Radio settings
|
||||
qDebug() << "Radio settings:" << storage.radio.size();
|
||||
loadFromByteArray<GeneralSettings, OpenTxGeneralData>(radioData.generalSettings, storage.radio);
|
||||
|
||||
// Models
|
||||
int modelIndex = 0;
|
||||
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;
|
||||
registerOpenTxEEpromInterface(BOARD_STOCK);
|
||||
registerOpenTxEEpromInterface(BOARD_M128);
|
||||
registerOpenTxEEpromInterface(BOARD_GRUVIN9X);
|
||||
registerOpenTxEEpromInterface(BOARD_SKY9X);
|
||||
registerOpenTxEEpromInterface(BOARD_9XRPRO);
|
||||
registerOpenTxEEpromInterface(BOARD_TARANIS_X9D);
|
||||
registerOpenTxEEpromInterface(BOARD_TARANIS_X9DP);
|
||||
registerOpenTxEEpromInterface(BOARD_TARANIS_X9E);
|
||||
registerOpenTxEEpromInterface(BOARD_TARANIS_X7);
|
||||
registerOpenTxEEpromInterface(BOARD_HORUS);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (size != getEEpromSize()) {
|
||||
if (size != getEEpromSize(board)) {
|
||||
if (size == 4096) {
|
||||
int notnull = false;
|
||||
for (int i = 2048; i < 4096; i++) {
|
||||
|
@ -321,7 +256,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
|
|||
}
|
||||
}
|
||||
else {
|
||||
std::cout << " wrong size (" << size << "/" << getEEpromSize() << ")\n";
|
||||
std::cout << " wrong size (" << size << "/" << getEEpromSize(board) << ")\n";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
@ -362,7 +297,7 @@ unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t *
|
|||
}
|
||||
|
||||
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)) {
|
||||
std::cout << " ko\n";
|
||||
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();
|
||||
|
||||
|
@ -397,7 +332,7 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, RadioData & radioData, uint8_t
|
|||
version = getLastDataVersion(board);
|
||||
}
|
||||
|
||||
int size = getEEpromSize();
|
||||
int size = getEEpromSize(board);
|
||||
|
||||
efile->EeFsCreate(eeprom, size, board, version);
|
||||
|
||||
|
@ -408,14 +343,14 @@ int OpenTxEepromInterface::save(uint8_t * eeprom, RadioData & radioData, uint8_t
|
|||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < getMaxModels(); i++) {
|
||||
for (int i = 0; i < GetCurrentFirmware()->getCapability(Models); i++) {
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -501,6 +436,15 @@ Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
|
|||
int OpenTxFirmware::getCapability(Capability 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:
|
||||
if (IS_ARM(board))
|
||||
return 0;
|
||||
|
@ -533,12 +477,12 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case FlightModesHaveFades:
|
||||
return 1;
|
||||
case Heli:
|
||||
if (IS_TARANIS(board) || IS_HORUS(board))
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return id.contains("noheli") ? 0 : 1;
|
||||
else
|
||||
return id.contains("heli") ? 1 : 0;
|
||||
case Gvars:
|
||||
if (IS_TARANIS(board) || IS_HORUS(board))
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return id.contains("nogvars") ? 0 : 9;
|
||||
else if (id.contains("gvars"))
|
||||
return IS_ARM(board) ? 9 : 5;
|
||||
|
@ -547,7 +491,7 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case ModelName:
|
||||
return (IS_HORUS(board) ? 15 : (HAS_LARGE_LCD(board) ? 12 : 10));
|
||||
case FlightModesName:
|
||||
return ((IS_TARANIS(board) || IS_HORUS(board)) ? 10 : 6);
|
||||
return (IS_HORUS_OR_TARANIS(board) ? 10 : 6);
|
||||
case GvarsName:
|
||||
return (IS_9X(board) ? 0 : 6);
|
||||
case GvarsInCS:
|
||||
|
@ -598,14 +542,14 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
return 18;
|
||||
else if (board == BOARD_TARANIS_X7)
|
||||
return 6;
|
||||
else if (IS_TARANIS(board) || board == BOARD_HORUS)
|
||||
else if (IS_HORUS_OR_TARANIS(board))
|
||||
return 8;
|
||||
else
|
||||
return 7;
|
||||
case SwitchesPositions:
|
||||
if (IS_TARANIS_X9E(board))
|
||||
return 18 * 3;
|
||||
else if (IS_TARANIS(board))
|
||||
else if (IS_HORUS_OR_TARANIS(board))
|
||||
return 8 * 3;
|
||||
else
|
||||
return 9;
|
||||
|
@ -652,7 +596,7 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case Haptic:
|
||||
return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || id.contains("haptic"));
|
||||
case ModelTrainerEnable:
|
||||
if (IS_TARANIS(board))
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
@ -669,15 +613,15 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case NumCurves:
|
||||
return (HAS_LARGE_LCD(board) ? 32 : (IS_ARM(board) ? 16 : 8));
|
||||
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:
|
||||
return (IS_ARM(board) ? (IS_TARANIS(board) ? 8 : 6) : false);
|
||||
return (IS_ARM(board) ? (IS_HORUS_OR_TARANIS(board) ? 8 : 6) : false);
|
||||
case HasNoExpo:
|
||||
return (IS_TARANIS(board) ? false : true);
|
||||
return (IS_HORUS_OR_TARANIS(board) ? false : true);
|
||||
case ChannelsName:
|
||||
return (IS_ARM(board) ? (HAS_LARGE_LCD(board) ? 6 : 4) : 0);
|
||||
case HasCvNames:
|
||||
return (IS_TARANIS(board) ? 1 : 0);
|
||||
return (IS_HORUS_OR_TARANIS(board) ? 1 : 0);
|
||||
case Telemetry:
|
||||
if (IS_2560(board) || IS_ARM(board) || id.contains("frsky") || id.contains("telemetrez"))
|
||||
return TM_HASTELEMETRY | TM_HASOFFSET | TM_HASWSHH;
|
||||
|
@ -686,6 +630,9 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case TelemetryBars:
|
||||
return 1;
|
||||
case TelemetryCustomScreens:
|
||||
if (IS_HORUS(board))
|
||||
return 0;
|
||||
else
|
||||
return IS_ARM(board) ? 4 : 2;
|
||||
case TelemetryCustomScreensFieldsPerLine:
|
||||
return HAS_LARGE_LCD(board) ? 3 : 2;
|
||||
|
@ -732,6 +679,8 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case LcdWidth:
|
||||
if (IS_HORUS(board))
|
||||
return 480;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
return 128;
|
||||
else if (IS_TARANIS(board))
|
||||
return 212;
|
||||
else
|
||||
|
@ -744,6 +693,8 @@ int OpenTxFirmware::getCapability(Capability capability)
|
|||
case LcdDepth:
|
||||
if (IS_HORUS(board))
|
||||
return 16;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
return 1;
|
||||
else if (IS_TARANIS(board))
|
||||
return 4;
|
||||
else
|
||||
|
@ -869,7 +820,7 @@ Firmware::Switch OpenTxFirmware::getSwitch(unsigned int index)
|
|||
{SWITCH_TOGGLE, "SH"}};
|
||||
return switches[index];
|
||||
}
|
||||
else if (IS_TARANIS(board) || board == BOARD_HORUS) {
|
||||
else if (IS_HORUS_OR_TARANIS(board)) {
|
||||
const Switch switches[] = {{SWITCH_3POS, "SA"},
|
||||
{SWITCH_3POS, "SB"},
|
||||
{SWITCH_3POS, "SC"},
|
||||
|
@ -904,7 +855,7 @@ Firmware::Switch OpenTxFirmware::getSwitch(unsigned int index)
|
|||
|
||||
QTime OpenTxFirmware::getMaxTimerStart()
|
||||
{
|
||||
if (IS_TARANIS(board) || IS_HORUS(board))
|
||||
if (IS_HORUS_OR_TARANIS(board))
|
||||
return QTime(23, 59, 59);
|
||||
else if (IS_ARM(board))
|
||||
return QTime(8, 59, 59);
|
||||
|
@ -925,7 +876,7 @@ bool OpenTxFirmware::isTelemetrySourceAvailable(int source)
|
|||
|
||||
int OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
|
||||
{
|
||||
if (IS_TARANIS(board) || IS_HORUS(board)) {
|
||||
if (IS_HORUS_OR_TARANIS(board)) {
|
||||
switch (port) {
|
||||
case 0:
|
||||
switch (proto) {
|
||||
|
@ -1604,3 +1555,46 @@ void unregisterOpenTxFirmwares()
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -33,28 +33,18 @@ class OpenTxEepromInterface : public EEPROMInterface
|
|||
|
||||
virtual ~OpenTxEepromInterface();
|
||||
|
||||
virtual const int getEEpromSize();
|
||||
|
||||
virtual const int getMaxModels();
|
||||
|
||||
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);
|
||||
|
||||
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, const RadioData & radioData, uint8_t version=0, uint32_t variant=0);
|
||||
|
||||
virtual int getSize(const ModelData &);
|
||||
|
||||
virtual int getSize(const GeneralSettings &);
|
||||
|
||||
virtual int loadFile(RadioData & radioData, const QString & filename);
|
||||
|
||||
virtual int saveFile(const RadioData & radioData, const QString & filename);
|
||||
|
||||
protected:
|
||||
|
||||
const char * getName();
|
||||
|
@ -66,11 +56,12 @@ class OpenTxEepromInterface : public EEPROMInterface
|
|||
template <class T, class M>
|
||||
bool loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant=0);
|
||||
|
||||
public:
|
||||
template <class T, class M>
|
||||
bool loadFromByteArray(T & dest, const QByteArray & data);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -84,6 +75,8 @@ class OpenTxEepromInterface : public EEPROMInterface
|
|||
|
||||
uint8_t getLastDataVersion(BoardEnum board);
|
||||
|
||||
uint32_t getFourCC();
|
||||
|
||||
RleFile * efile;
|
||||
|
||||
};
|
||||
|
@ -152,5 +145,14 @@ class OpenTxFirmware: public Firmware
|
|||
|
||||
void registerOpenTxFirmwares();
|
||||
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_
|
||||
|
|
|
@ -22,12 +22,10 @@
|
|||
#include "ui_flasheepromdialog.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "helpers.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "hexinterface.h"
|
||||
#include "storage.h"
|
||||
#include "appdata.h"
|
||||
#include "progressdialog.h"
|
||||
#include "radiointerface.h"
|
||||
#include "storage_eeprom.h"
|
||||
#include "splashlibrarydialog.h"
|
||||
|
||||
FlashEEpromDialog::FlashEEpromDialog(QWidget *parent, const QString &filename):
|
||||
|
@ -107,88 +105,17 @@ void FlashEEpromDialog::on_eepromLoad_clicked()
|
|||
}
|
||||
}
|
||||
|
||||
int FlashEEpromDialog::getEEpromVersion(const QString &filename)
|
||||
int FlashEEpromDialog::getEEpromVersion(const QString & filename)
|
||||
{
|
||||
int result = -1;
|
||||
int eeprom_size = 0;
|
||||
|
||||
if (filename.isEmpty()) {
|
||||
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 {
|
||||
QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
|
||||
Storage storage(filename);
|
||||
if (storage.load(*radioData)) {
|
||||
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 {
|
||||
result = radioData->generalSettings.version;
|
||||
QMessageBox::warning(this, tr("Error"), storage.error());
|
||||
}
|
||||
delete radioData;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -196,16 +123,16 @@ bool FlashEEpromDialog::patchCalibration()
|
|||
{
|
||||
QString calib = g.profile[g.id()].stickPotCalib();
|
||||
QString trainercalib = g.profile[g.id()].trainerCalib();
|
||||
int potsnum=GetCurrentFirmware()->getCapability(Pots);
|
||||
int8_t txVoltageCalibration=(int8_t) g.profile[g.id()].txVoltageCalibration();
|
||||
int8_t txCurrentCalibration=(int8_t) g.profile[g.id()].txCurrentCalibration();
|
||||
int8_t PPM_Multiplier=(int8_t) g.profile[g.id()].ppmMultiplier();
|
||||
int potsnum = GetCurrentFirmware()->getCapability(Pots);
|
||||
int8_t txVoltageCalibration = (int8_t) g.profile[g.id()].txVoltageCalibration();
|
||||
int8_t txCurrentCalibration = (int8_t) g.profile[g.id()].txCurrentCalibration();
|
||||
int8_t PPM_Multiplier = (int8_t) g.profile[g.id()].ppmMultiplier();
|
||||
|
||||
if ((calib.length()==(CPN_MAX_STICKS+potsnum)*12) && (trainercalib.length()==16)) {
|
||||
QString Byte;
|
||||
int16_t byte16;
|
||||
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);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
|
@ -296,7 +223,7 @@ void FlashEEpromDialog::on_burnButton_clicked()
|
|||
if (patch) {
|
||||
QString filename = generateProcessUniqueTempFileName("temp.bin");
|
||||
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());
|
||||
if (!eeprom_size) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
|
|
|
@ -21,16 +21,13 @@
|
|||
#include "flashfirmwaredialog.h"
|
||||
#include "ui_flashfirmwaredialog.h"
|
||||
#include "appdata.h"
|
||||
#include "storage_eeprom.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "process_flash.h"
|
||||
#include "helpers.h"
|
||||
#include "hexinterface.h"
|
||||
#include "progressdialog.h"
|
||||
#include "radiointerface.h"
|
||||
#include "progresswidget.h"
|
||||
#include "splashlibrarydialog.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
|
@ -242,7 +239,7 @@ void FlashFirmwareDialog::on_burnButton_clicked()
|
|||
}
|
||||
// write the customized firmware
|
||||
QString tempFile;
|
||||
if (getFileType(fwName) == FILE_TYPE_HEX)
|
||||
if (getStorageType(fwName) == STORAGE_TYPE_HEX)
|
||||
tempFile = generateProcessUniqueTempFileName("flash.hex");
|
||||
else
|
||||
tempFile = generateProcessUniqueTempFileName("flash.bin");
|
||||
|
|
|
@ -23,22 +23,12 @@
|
|||
|
||||
void HardwarePanel::setupSwitchConfig(int index, QLabel *label, AutoLineEdit *name, AutoComboBox *type, bool threePos = true)
|
||||
{
|
||||
bool enabled = false;
|
||||
|
||||
if (IS_TARANIS(firmware->getBoard())) {
|
||||
if (IS_TARANIS_X9E(firmware->getBoard())) {
|
||||
enabled = true;
|
||||
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Switches)) {
|
||||
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"), 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);
|
||||
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)
|
||||
{
|
||||
bool enabled = false;
|
||||
|
||||
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) {
|
||||
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Pots)) {
|
||||
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+index).toString());
|
||||
type->addItem(tr("None"), GeneralSettings::POT_NONE);
|
||||
type->addItem(tr("Pot with detent"), GeneralSettings::POT_WITH_DETENT);
|
||||
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)
|
||||
{
|
||||
bool enabled = false;
|
||||
|
||||
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) {
|
||||
if (IS_STM32(firmware->getBoard()) && index < firmware->getCapability(Sliders)) {
|
||||
label->setText(RawSource(SOURCE_TYPE_STICK, CPN_MAX_STICKS+firmware->getCapability(Pots)+index).toString());
|
||||
type->addItem(tr("None"), GeneralSettings::SLIDER_NONE);
|
||||
type->addItem(tr("Slider with detent"), GeneralSettings::SLIDER_WITH_DETENT);
|
||||
name->setField(generalSettings.sliderName[index], 3, this);
|
||||
|
@ -114,7 +79,7 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
|
|||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (IS_TARANIS(firmware->getBoard())) {
|
||||
if (IS_STM32(firmware->getBoard())) {
|
||||
ui->rudName->setField(generalSettings.stickName[0], 3, this);
|
||||
ui->eleName->setField(generalSettings.stickName[1], 3, this);
|
||||
ui->thrName->setField(generalSettings.stickName[2], 3, this);
|
||||
|
|
|
@ -31,10 +31,9 @@
|
|||
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "modeledit/modeledit.h"
|
||||
#include "simulatordialog.h"
|
||||
#include "simulatorinterface.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "storage/storage_sdcard.h"
|
||||
#include "storage/sdcard.h"
|
||||
|
||||
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)
|
||||
{
|
||||
BoardEnum board = GetCurrentFirmware()->getBoard();
|
||||
RawSwitch item;
|
||||
|
||||
b->clear();
|
||||
|
||||
if (context != MixesContext && context != GlobalFunctionsContext) {
|
||||
// !FMx
|
||||
if (IS_ARM(GetCurrentFirmware()->getBoard())) {
|
||||
if (IS_ARM(board)) {
|
||||
for (int i=-GetCurrentFirmware()->getCapability(FlightModes); i<0; i++) {
|
||||
item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i);
|
||||
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++) {
|
||||
item = RawSwitch(SWITCH_TYPE_SWITCH, i);
|
||||
if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings.switchPositionAllowedTaranis(i)){
|
||||
if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchPositionAllowedTaranis(i)) {
|
||||
continue;
|
||||
}
|
||||
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++) {
|
||||
item = RawSwitch(SWITCH_TYPE_SWITCH, i);
|
||||
if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings.switchPositionAllowedTaranis(i)){
|
||||
if (IS_HORUS_OR_TARANIS(board) && !generalSettings.switchPositionAllowedTaranis(i)) {
|
||||
continue;
|
||||
}
|
||||
b->addItem(item.toString(), item.toValue());
|
||||
|
@ -496,7 +496,7 @@ void populateSwitchCB(QComboBox *b, const RawSwitch & value, const GeneralSettin
|
|||
|
||||
// FMx
|
||||
if (context != MixesContext && context != GlobalFunctionsContext) {
|
||||
if (IS_ARM(GetCurrentFirmware()->getBoard())) {
|
||||
if (IS_ARM(board)) {
|
||||
for (int i=1; i<=GetCurrentFirmware()->getCapability(FlightModes); i++) {
|
||||
item = RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i);
|
||||
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++) {
|
||||
item = RawSource(SOURCE_TYPE_SWITCH, i);
|
||||
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);
|
||||
QVariant v(0);
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
else if (board == BOARD_FLAMENCO) {
|
||||
dialog = new SimulatorDialogFlamenco(parent, simulator, flags);
|
||||
QByteArray eeprom(GetEepromInterface()->getEEpromSize(), 0);
|
||||
QByteArray eeprom(getEEpromSize(board), 0);
|
||||
firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData);
|
||||
dialog->start(eeprom);
|
||||
}
|
||||
|
@ -856,13 +857,13 @@ void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
|
|||
}
|
||||
}
|
||||
dialog = new SimulatorDialogTaranis(parent, simulator, flags);
|
||||
QByteArray eeprom(GetEepromInterface()->getEEpromSize(), 0);
|
||||
QByteArray eeprom(getEEpromSize(board), 0);
|
||||
firmware->saveEEPROM((uint8_t *)eeprom.data(), *simuData);
|
||||
dialog->start(eeprom);
|
||||
}
|
||||
else {
|
||||
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));
|
||||
dialog->start(eeprom);
|
||||
}
|
||||
|
|
|
@ -21,13 +21,15 @@
|
|||
#ifndef _HELPERS_H_
|
||||
#define _HELPERS_H_
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "modeledit/modeledit.h"
|
||||
#include <QCheckBox>
|
||||
#include <QSpinBox>
|
||||
#include <QTableWidget>
|
||||
#include <QGridLayout>
|
||||
#include <QDebug>
|
||||
#include "eeprominterface.h"
|
||||
#include "modeledit/modeledit.h"
|
||||
#include <QTime>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
extern const QColor colors[CPN_MAX_CURVES];
|
||||
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <QtGui>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QFileInfo>
|
||||
#include <QDesktopServices>
|
||||
#include "mainwindow.h"
|
||||
#include "mdichild.h"
|
||||
#include "burnconfigdialog.h"
|
||||
|
@ -48,7 +44,11 @@
|
|||
#include "process_sync.h"
|
||||
#include "radiointerface.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 DONATE_STR "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QUZ48K4SEXDP2"
|
||||
|
@ -128,22 +128,22 @@ MainWindow::MainWindow():
|
|||
}
|
||||
if (strl.count()>1) str = strl[1];
|
||||
if (!str.isEmpty()) {
|
||||
int fileType = getFileType(str);
|
||||
int fileType = getStorageType(str);
|
||||
|
||||
if (fileType==FILE_TYPE_HEX) {
|
||||
if (fileType==STORAGE_TYPE_HEX) {
|
||||
writeFlash(str);
|
||||
}
|
||||
|
||||
if (fileType==FILE_TYPE_EEPE || fileType==FILE_TYPE_EEPM || fileType==FILE_TYPE_BIN) {
|
||||
MdiChild *child = createMdiChild();
|
||||
if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN) {
|
||||
MdiChild * child = createMdiChild();
|
||||
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);
|
||||
child->show();
|
||||
}
|
||||
else {
|
||||
child->show();
|
||||
child->print(model,printfilename);
|
||||
child->print(model, printfilename);
|
||||
child->close();
|
||||
}
|
||||
}
|
||||
|
@ -735,8 +735,9 @@ void MainWindow::writeEeprom()
|
|||
|
||||
void MainWindow::simulate()
|
||||
{
|
||||
if (activeMdiChild())
|
||||
activeMdiChild()->simulate();
|
||||
if (activeMdiChild()) {
|
||||
activeMdiChild()->radioSimulate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -754,49 +755,13 @@ void MainWindow::loadBackup()
|
|||
|
||||
void MainWindow::readEeprom()
|
||||
{
|
||||
if(GetCurrentFirmware()->getBoard()== BOARD_HORUS && HORUS_READY_FOR_RELEASE()) {
|
||||
// just an example
|
||||
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("./");
|
||||
|
||||
if (GetCurrentFirmware()->getBoard()== BOARD_HORUS && HORUS_READY_FOR_RELEASE()) {
|
||||
// TODO
|
||||
}
|
||||
else {
|
||||
QString tempFile;
|
||||
|
||||
EEPROMInterface *eepromInterface = GetEepromInterface();
|
||||
EEPROMInterface * eepromInterface = GetEepromInterface();
|
||||
|
||||
if (IS_ARM(eepromInterface->getBoard()))
|
||||
tempFile = generateProcessUniqueTempFileName("temp.bin");
|
||||
|
@ -861,16 +826,6 @@ void MainWindow::writeBackup()
|
|||
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)
|
||||
{
|
||||
FlashFirmwareDialog *cd = new FlashFirmwareDialog(this);
|
||||
|
|
|
@ -164,7 +164,6 @@ class MainWindow : public QMainWindow
|
|||
void updateLanguageActions();
|
||||
void updateIconThemeActions();
|
||||
|
||||
int getFileType(const QString & fullFileName);
|
||||
QString Theme;
|
||||
QString ISize;
|
||||
QString strippedName(const QString & fullFileName);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "appdata.h"
|
||||
#include "wizarddialog.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
#include "storage_eeprom.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
|
@ -48,13 +48,38 @@ MdiChild::MdiChild():
|
|||
isUntitled(true),
|
||||
fileChanged(false)
|
||||
{
|
||||
BoardEnum board = GetCurrentFirmware()->getBoard();
|
||||
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("open.png"));
|
||||
|
||||
modelsListModel = new TreeModel(&radioData, this);
|
||||
ui->modelsList->setModel(modelsListModel);
|
||||
ui->simulateButton->setIcon(CompanionIcon("simulate.png"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
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())) {
|
||||
adjustSize();
|
||||
}
|
||||
|
@ -65,9 +90,12 @@ MdiChild::~MdiChild()
|
|||
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()) {
|
||||
ui->simulateButton->setEnabled(false);
|
||||
}
|
||||
|
@ -77,64 +105,230 @@ void MdiChild::eepromInterfaceChanged()
|
|||
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()
|
||||
{
|
||||
ui->modelsList->cut();
|
||||
copy();
|
||||
deleteSelectedModels();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
QString title = userFriendlyCurrentFile() + "[*]" + " (" + GetCurrentFirmware()->getName() + QString(")");
|
||||
if (!IS_SKY9X(GetCurrentFirmware()->getBoard()))
|
||||
title += QString(" - %1 ").arg(EEPromAvail) + tr("free bytes");
|
||||
int availableEEpromSize = modelsListModel->getAvailableEEpromSize();
|
||||
if (availableEEpromSize >= 0) {
|
||||
title += QString(" - %1 ").arg(availableEEpromSize) + tr("free bytes");
|
||||
}
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void MdiChild::setModified()
|
||||
{
|
||||
ui->modelsList->refreshList();
|
||||
refresh();
|
||||
fileChanged = true;
|
||||
updateTitle();
|
||||
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()
|
||||
{
|
||||
startSimulation(this, radioData, -1);
|
||||
radioSimulate();
|
||||
}
|
||||
|
||||
void MdiChild::checkAndInitModel(int row)
|
||||
{
|
||||
ModelData &model = radioData.models[row - 1];
|
||||
ModelData & model = radioData.models[row];
|
||||
if (model.isEmpty()) {
|
||||
model.setDefaultValues(row - 1, radioData.generalSettings);
|
||||
model.setDefaultValues(row, radioData.generalSettings);
|
||||
setModified();
|
||||
}
|
||||
}
|
||||
|
||||
void MdiChild::generalEdit()
|
||||
{
|
||||
GeneralEdit *t = new GeneralEdit(this, radioData, GetCurrentFirmware()/*firmware*/);
|
||||
GeneralEdit * t = new GeneralEdit(this, radioData, GetCurrentFirmware()/*firmware*/);
|
||||
connect(t, SIGNAL(modified()), this, SLOT(setModified()));
|
||||
t->show();
|
||||
}
|
||||
|
@ -142,49 +336,47 @@ void MdiChild::generalEdit()
|
|||
void MdiChild::modelEdit()
|
||||
{
|
||||
int row = getCurrentRow();
|
||||
|
||||
if (row == 0) {
|
||||
generalEdit();
|
||||
}
|
||||
else {
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
checkAndInitModel( row );
|
||||
ModelData & model = radioData.models[row - 1];
|
||||
checkAndInitModel(row);
|
||||
ModelData & model = radioData.models[row];
|
||||
gStopwatch.restart();
|
||||
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");
|
||||
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()));
|
||||
gStopwatch.report("STARTING MODEL EDIT");
|
||||
t->show();
|
||||
QApplication::restoreOverrideCursor();
|
||||
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()
|
||||
{
|
||||
int row = getCurrentRow();
|
||||
if (row > 0) {
|
||||
checkAndInitModel(row);
|
||||
WizardDialog * wizard = new WizardDialog(radioData.generalSettings, row, this);
|
||||
WizardDialog * wizard = new WizardDialog(radioData.generalSettings, row+1, this);
|
||||
wizard->exec();
|
||||
if (wizard->mix.complete /*TODO rather test the exec() result?*/) {
|
||||
radioData.models[row - 1] = wizard->mix;
|
||||
radioData.models[row] = wizard->mix;
|
||||
setModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MdiChild::openEditWindow()
|
||||
void MdiChild::openModelEditWindow()
|
||||
{
|
||||
int row = getCurrentRow();
|
||||
if (row == 0){
|
||||
generalEdit();
|
||||
}
|
||||
else{
|
||||
ModelData & model = radioData.models[row - 1];
|
||||
if (row >= 0) {
|
||||
ModelData & model = radioData.models[row];
|
||||
if (model.isEmpty() && g.useWizard()) {
|
||||
wizardEdit();
|
||||
}
|
||||
|
@ -197,151 +389,29 @@ void MdiChild::openEditWindow()
|
|||
void MdiChild::newFile()
|
||||
{
|
||||
static int sequenceNumber = 1;
|
||||
|
||||
isUntitled = true;
|
||||
curFile = QString("document%1.eepe").arg(sequenceNumber++);
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
bool MdiChild::loadFile(const QString & fileName, bool resetCurrentFile)
|
||||
bool MdiChild::loadFile(const QString & filename, bool resetCurrentFile)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.exists()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
|
||||
Storage storage(filename);
|
||||
if (!storage.load(radioData)) {
|
||||
QMessageBox::critical(this, tr("Error"), storage.error());
|
||||
return false;
|
||||
}
|
||||
|
||||
int fileType = getFileType(fileName);
|
||||
|
||||
#if 0
|
||||
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;
|
||||
QString warning = storage.warning();
|
||||
if (!warning.isEmpty()) {
|
||||
// TODO ShowEepromWarnings(this, tr("Warning"), warning);
|
||||
}
|
||||
|
||||
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)) {
|
||||
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();
|
||||
refresh(true);
|
||||
if (resetCurrentFile)
|
||||
setCurrentFile(fileName);
|
||||
setCurrentFile(filename);
|
||||
|
||||
free(eeprom);
|
||||
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()
|
||||
|
@ -383,78 +453,28 @@ bool MdiChild::saveAs(bool isNew)
|
|||
return saveFile(fileName,true);
|
||||
}
|
||||
|
||||
bool MdiChild::saveFile(const QString &fileName, bool setCurrent)
|
||||
bool MdiChild::saveFile(const QString & filename, bool setCurrent)
|
||||
{
|
||||
QString myFile;
|
||||
myFile = fileName;
|
||||
if (IS_SKY9X(GetEepromInterface()->getBoard())) {
|
||||
myFile.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;
|
||||
}
|
||||
BoardEnum board = GetEepromInterface()->getBoard();
|
||||
QString path = filename;
|
||||
if (IS_SKY9X(board)) {
|
||||
path.replace(".eepe", ".bin");
|
||||
}
|
||||
|
||||
if (!file.open(fileType == FILE_TYPE_BIN ? QIODevice::WriteOnly : (QIODevice::WriteOnly | QIODevice::Text))) {
|
||||
QMessageBox::warning(this, tr("Error"),tr("Cannot write file %1:\n%2.").arg(myFile).arg(file.errorString()));
|
||||
return false;
|
||||
radioData.fixModelFilenames();
|
||||
Storage storage(path);
|
||||
bool result = storage.write(radioData);
|
||||
|
||||
if (result && setCurrent) {
|
||||
setCurrentFile(path);
|
||||
}
|
||||
|
||||
QTextStream outputStream(&file);
|
||||
|
||||
#if 0
|
||||
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);
|
||||
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;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString MdiChild::userFriendlyCurrentFile()
|
||||
QString MdiChild::userFriendlyCurrentFile() const
|
||||
{
|
||||
return strippedName(curFile);
|
||||
return QFileInfo(curFile).fileName();
|
||||
}
|
||||
|
||||
void MdiChild::closeEvent(QCloseEvent *event)
|
||||
|
@ -502,44 +522,46 @@ void MdiChild::setCurrentFile(const QString &fileName)
|
|||
files.prepend(fileName);
|
||||
while (files.size() > MaxRecentFiles)
|
||||
files.removeLast();
|
||||
|
||||
g.recentFiles( files );
|
||||
}
|
||||
|
||||
QString MdiChild::strippedName(const QString &fullFileName)
|
||||
{
|
||||
return QFileInfo(fullFileName).fileName();
|
||||
g.recentFiles(files);
|
||||
}
|
||||
|
||||
void MdiChild::writeEeprom() // write to Tx
|
||||
{
|
||||
QString tempFile = generateProcessUniqueTempFileName("temp.bin");
|
||||
saveFile(tempFile, false);
|
||||
if(!QFileInfo(tempFile).exists()) {
|
||||
if (!QFileInfo(tempFile).exists()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot write temporary file!"));
|
||||
return;
|
||||
}
|
||||
|
||||
FlashEEpromDialog *cd = new FlashEEpromDialog(this, tempFile);
|
||||
FlashEEpromDialog * cd = new FlashEEpromDialog(this, tempFile);
|
||||
cd->exec();
|
||||
}
|
||||
|
||||
void MdiChild::simulate()
|
||||
void MdiChild::on_radioSettings_clicked()
|
||||
{
|
||||
if (getCurrentRow() > 0) {
|
||||
startSimulation(this, radioData, getCurrentRow()-1);
|
||||
}
|
||||
generalEdit();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (model>=0 && !filename.isEmpty()) {
|
||||
pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[model], filename);
|
||||
}
|
||||
else if (getCurrentRow() > 0) {
|
||||
pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[getCurrentRow()-1]);
|
||||
else if (getCurrentRow()) {
|
||||
pd = new PrintDialog(this, GetCurrentFirmware()/*firmware*/, radioData.generalSettings, radioData.models[getCurrentRow()]);
|
||||
}
|
||||
|
||||
if (pd) {
|
||||
|
@ -553,19 +575,14 @@ void MdiChild::viableModelSelected(bool viable)
|
|||
emit copyAvailable(viable);
|
||||
}
|
||||
|
||||
void MdiChild::setEEpromAvail(int eavail)
|
||||
{
|
||||
EEPromAvail=eavail;
|
||||
}
|
||||
|
||||
int MdiChild::getCurrentRow() const
|
||||
{
|
||||
return ui->modelsList->currentRow();
|
||||
return modelsListModel->getModelIndex(ui->modelsList->currentIndex());
|
||||
}
|
||||
|
||||
bool MdiChild::loadBackup()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open backup Models and Settings file"), g.eepromDir(),tr(EEPROM_FILES_FILTER));
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open backup Models and Settings file"), g.eepromDir(), tr(EEPROM_FILES_FILTER));
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
QFile file(fileName);
|
||||
|
@ -574,8 +591,8 @@ bool MdiChild::loadBackup()
|
|||
QMessageBox::critical(this, tr("Error"), tr("Unable to find file %1!").arg(fileName));
|
||||
return false;
|
||||
}
|
||||
if(getCurrentRow() < 1) return false;
|
||||
int index = getCurrentRow() - 1;
|
||||
|
||||
// TODO int index = getCurrentRow();
|
||||
|
||||
int eeprom_size = file.size();
|
||||
if (!file.open(QFile::ReadOnly)) { //reading binary file - TODO HEX support
|
||||
|
@ -598,6 +615,7 @@ bool MdiChild::loadBackup()
|
|||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::bitset<NUM_ERRORS> errorsEeprom((unsigned long long)LoadBackup(radioData, (uint8_t *)eeprom.data(), eeprom_size, index));
|
||||
if (!errorsEeprom.test(ALL_OK)) {
|
||||
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());
|
||||
}
|
||||
|
||||
ui->modelsList->refreshList();
|
||||
|
||||
refresh(true);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <QtGui>
|
||||
#include "eeprominterface.h"
|
||||
#include "modelslist.h"
|
||||
|
||||
namespace Ui {
|
||||
class MdiChild;
|
||||
|
@ -44,18 +45,18 @@ class MdiChild : public QWidget
|
|||
|
||||
void newFile();
|
||||
bool loadFile(const QString & fileName, bool resetCurrentFile=true);
|
||||
bool loadBackup();
|
||||
bool save();
|
||||
bool saveAs(bool isNew=false);
|
||||
bool saveFile(const QString & fileName, bool setCurrent=true);
|
||||
bool hasSelection();
|
||||
QString userFriendlyCurrentFile();
|
||||
QString currentFile() { return curFile; }
|
||||
bool hasPasteData();
|
||||
bool hasSelection() const;
|
||||
bool hasPasteData() const;
|
||||
QString userFriendlyCurrentFile() const;
|
||||
QString currentFile() const { return curFile; }
|
||||
void viableModelSelected(bool viable);
|
||||
void eepromInterfaceChanged();
|
||||
void setEEpromAvail(int eavail);
|
||||
int getCurrentRow() const;
|
||||
void refresh(bool expand=false);
|
||||
void keyPressEvent(QKeyEvent * event);
|
||||
|
||||
signals:
|
||||
void copyAvailable(bool val);
|
||||
|
@ -63,33 +64,43 @@ class MdiChild : public QWidget
|
|||
protected:
|
||||
void closeEvent(QCloseEvent * event);
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void documentWasModified();
|
||||
void on_simulateButton_clicked();
|
||||
void on_radioSettings_clicked();
|
||||
void setDefault();
|
||||
|
||||
public slots:
|
||||
void showModelsListContextMenu(const QPoint & pos);
|
||||
void checkAndInitModel(int row);
|
||||
void generalEdit();
|
||||
void modelEdit();
|
||||
void wizardEdit();
|
||||
void openEditWindow();
|
||||
void openModelEditWindow();
|
||||
bool loadBackup();
|
||||
void confirmDelete();
|
||||
void deleteSelectedModels();
|
||||
|
||||
void cut();
|
||||
void copy();
|
||||
void paste();
|
||||
void writeEeprom();
|
||||
void simulate();
|
||||
void print(int model=-1, QString filename="");
|
||||
void modelSimulate();
|
||||
void radioSimulate();
|
||||
void print(int model=-1, const QString & filename="");
|
||||
void setModified();
|
||||
void updateTitle();
|
||||
|
||||
private:
|
||||
bool maybeSave();
|
||||
void setCurrentFile(const QString & fileName);
|
||||
QString strippedName(const QString & fullFileName);
|
||||
bool loadOtxFile(const QString & fileName);
|
||||
void doCopy(QByteArray * gmData);
|
||||
void doPaste(QByteArray * gmData, int index);
|
||||
|
||||
|
||||
Ui::MdiChild * ui;
|
||||
TreeModel * modelsListModel;
|
||||
|
||||
QString curFile;
|
||||
|
||||
|
@ -98,7 +109,6 @@ class MdiChild : public QWidget
|
|||
|
||||
bool isUntitled;
|
||||
bool fileChanged;
|
||||
int EEPromAvail;
|
||||
};
|
||||
|
||||
#endif // _MDICHILD_H_
|
||||
|
|
|
@ -15,7 +15,14 @@
|
|||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<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>
|
||||
<widget class="QPushButton" name="simulateButton">
|
||||
|
@ -26,13 +33,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModelsListWidget</class>
|
||||
<extends>QListWidget</extends>
|
||||
<header location="global">modelslist.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
|
|
|
@ -28,7 +28,7 @@ LimitsGroup::LimitsGroup(Firmware * firmware, TableLayout * tableLayout, int row
|
|||
displayStep(0.1)
|
||||
{
|
||||
BoardEnum board = firmware->getBoard();
|
||||
bool allowGVars = (IS_TARANIS(board) || IS_HORUS(board));
|
||||
bool allowGVars = IS_HORUS_OR_TARANIS(board);
|
||||
int internalStep = 1;
|
||||
|
||||
spinbox->setProperty("index", row);
|
||||
|
|
|
@ -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->setCurrentIndex(model.trainerMode);
|
||||
if (!IS_TARANIS(firmware->getBoard())) {
|
||||
if (!IS_HORUS_OR_TARANIS(firmware->getBoard())) {
|
||||
ui->label_trainerMode->hide();
|
||||
ui->trainerMode->hide();
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ ModulePanel::ModulePanel(QWidget * parent, ModelData & model, ModuleData & modul
|
|||
ui->label_trainerMode->hide();
|
||||
ui->trainerMode->hide();
|
||||
if (firmware->getCapability(NumModules) > 1) {
|
||||
if (IS_TARANIS(firmware->getBoard()) || IS_HORUS(firmware->getBoard())) {
|
||||
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
|
||||
if (moduleIdx == 0)
|
||||
label = tr("Internal Radio System");
|
||||
else
|
||||
|
@ -294,7 +294,7 @@ void ModulePanel::update()
|
|||
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) {
|
||||
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
|
||||
for (int i=0; i<firmware->getCapability(Switches); 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]);
|
||||
}
|
||||
if (sw.type == Firmware::SWITCH_NONE || sw.type == Firmware::SWITCH_TOGGLE) {
|
||||
|
|
|
@ -787,7 +787,7 @@ TelemetryPanel::~TelemetryPanel()
|
|||
|
||||
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) {
|
||||
ui->telemetryProtocol->setEnabled(true);
|
||||
}
|
||||
|
@ -835,7 +835,7 @@ void TelemetryPanel::setup()
|
|||
|
||||
ui->rssiAlarm1SB->setValue(model->frsky.rssiAlarms[0].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->rssiAlarm2CB->setCurrentIndex(model->frsky.rssiAlarms[1].level);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "helpers.h"
|
||||
#include "modelprinter.h"
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
|
||||
QString changeColor(const QString & input, const QString & to, const QString & from)
|
||||
{
|
||||
|
|
|
@ -19,138 +19,314 @@
|
|||
*/
|
||||
|
||||
#include "modelslist.h"
|
||||
#include "mdichild.h"
|
||||
#include "helpers.h"
|
||||
|
||||
class DragDropHeader {
|
||||
public:
|
||||
DragDropHeader():
|
||||
general_settings(false),
|
||||
models_count(0)
|
||||
{
|
||||
}
|
||||
bool general_settings;
|
||||
uint8_t models_count;
|
||||
uint8_t models[CPN_MAX_MODELS];
|
||||
};
|
||||
TreeItem::TreeItem(const QVector<QVariant> & itemData):
|
||||
itemData(itemData),
|
||||
parentItem(NULL),
|
||||
modelIndex(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ModelsListWidget::ModelsListWidget(QWidget * parent):
|
||||
QTreeWidget(parent)
|
||||
TreeItem::TreeItem(TreeItem * parent, int modelIndex):
|
||||
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();
|
||||
QStringList labels;
|
||||
labels << tr("Index") << tr("Name");
|
||||
QVector<QVariant> labels;
|
||||
if (!IS_HORUS(board))
|
||||
labels << tr("Index");
|
||||
labels << tr("Name");
|
||||
if (!(IS_HORUS(board) || IS_SKY9X(board))) {
|
||||
labels << tr("Size");
|
||||
}
|
||||
setColumnCount(labels.size());
|
||||
setHeaderLabels(labels);
|
||||
rootItem = new TreeItem(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(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);
|
||||
|
||||
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)
|
||||
|
@ -158,7 +334,7 @@ void ModelsListWidget::mousePressEvent(QMouseEvent *event)
|
|||
if (event->button() == Qt::LeftButton)
|
||||
dragStartPosition = event->pos();
|
||||
|
||||
QTreeWidget::mousePressEvent(event);
|
||||
QTreeView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void ModelsListWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
|
@ -188,18 +364,18 @@ void ModelsListWidget::mouseMoveEvent(QMouseEvent *event)
|
|||
|
||||
void ModelsListWidget::saveSelection()
|
||||
{
|
||||
currentSelection.current_item = currentItem();
|
||||
for (int i=0; i<GetEepromInterface()->getMaxModels()+1; ++i) {
|
||||
/*currentSelection.current_item = currentItem();
|
||||
for (int i=0; i<GetCurrentFirmware()->getCapability(Models)+1; ++i) {
|
||||
currentSelection.selected[i] = selectionModel()->isSelected(model()->index(i, 0));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void ModelsListWidget::restoreSelection()
|
||||
{
|
||||
setCurrentItem(currentSelection.current_item);
|
||||
for (int i=0; i<GetEepromInterface()->getMaxModels()+1; ++i) {
|
||||
/*setCurrentItem(currentSelection.current_item);
|
||||
for (int i=0; i<GetCurrentFirmware()->getCapability(Models)+1; ++i) {
|
||||
selectionModel()->select(model()->index(i, 0), currentSelection.selected[i] ? QItemSelectionModel::Select : QItemSelectionModel::Deselect);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void ModelsListWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||
|
@ -227,7 +403,7 @@ void ModelsListWidget::dragMoveEvent(QDragMoveEvent *event)
|
|||
if (row >= 0) {
|
||||
if (header->general_settings)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -248,11 +424,11 @@ void ModelsListWidget::dropEvent(QDropEvent *event)
|
|||
((ModelsListWidget*)event->source())->doCut(&gmData);
|
||||
doPaste(&gmData, row);
|
||||
clearSelection();
|
||||
setCurrentItem(topLevelItem(row));
|
||||
// setCurrentItem(topLevelItem(row));
|
||||
DragDropHeader * header = (DragDropHeader *)gmData.data();
|
||||
if (header->general_settings)
|
||||
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);
|
||||
}
|
||||
event->acceptProposedAction();
|
||||
|
@ -261,7 +437,7 @@ void ModelsListWidget::dropEvent(QDropEvent *event)
|
|||
#ifndef WIN32
|
||||
void ModelsListWidget::focusInEvent ( QFocusEvent * event )
|
||||
{
|
||||
QTreeWidget::focusInEvent(event);
|
||||
QTreeView::focusInEvent(event);
|
||||
QPalette palette = this->palette();
|
||||
palette.setColor(QPalette::Active, 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 )
|
||||
{
|
||||
QTreeWidget::focusOutEvent(event);
|
||||
QTreeView::focusOutEvent(event);
|
||||
QPalette palette = this->palette();
|
||||
palette.setColor(QPalette::Active, 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
|
||||
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
int i = this->currentRow();
|
||||
if (i && i<GetEepromInterface()->getMaxModels()) {
|
||||
if (i && i<GetCurrentFirmware()->getCapability(Models)) {
|
||||
ModelData * model = &radioData->models[i-1];
|
||||
while (i<GetEepromInterface()->getMaxModels()) {
|
||||
while (i<GetCurrentFirmware()->getCapability(Models)) {
|
||||
if (radioData->models[i].isEmpty()) {
|
||||
radioData->models[i] = *model;
|
||||
strcpy(radioData->models[i].filename, radioData->getNextModelFilename().toStdString().c_str());
|
||||
|
@ -529,54 +483,20 @@ void ModelsListWidget::duplicate()
|
|||
}
|
||||
i++;
|
||||
}
|
||||
if (i==GetEepromInterface()->getMaxModels()) {
|
||||
if (i==GetCurrentFirmware()->getCapability(Models)) {
|
||||
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 *)
|
||||
{
|
||||
int index = indexOfTopLevelItem(current);
|
||||
/*int index = indexOfTopLevelItem(current);
|
||||
if (!isVisible())
|
||||
((MdiChild*)parent())->viableModelSelected(false);
|
||||
else if (index<1)
|
||||
((MdiChild*)parent())->viableModelSelected(false);
|
||||
else
|
||||
((MdiChild*)parent())->viableModelSelected(!radioData->models[currentRow()-1].isEmpty());
|
||||
((MdiChild*)parent())->viableModelSelected(!radioData->models[currentRow()-1].isEmpty()); */
|
||||
}
|
||||
#endif
|
|
@ -21,8 +21,8 @@
|
|||
#ifndef _MODELSLIST_H_
|
||||
#define _MODELSLIST_H_
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "eeprominterface.h"
|
||||
#include <QtWidgets>
|
||||
|
||||
struct CurrentSelection
|
||||
{
|
||||
|
@ -30,13 +30,84 @@ struct CurrentSelection
|
|||
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
|
||||
|
||||
public:
|
||||
ModelsListWidget(QWidget * parent = 0);
|
||||
|
||||
void setRadioData(RadioData * radioData);
|
||||
bool hasSelection();
|
||||
void keyPressEvent(QKeyEvent * event);
|
||||
bool hasPasteData();
|
||||
|
@ -56,18 +127,16 @@ protected:
|
|||
|
||||
public slots:
|
||||
void refreshList();
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
|
||||
void cut();
|
||||
void copy();
|
||||
void paste();
|
||||
void print();
|
||||
void EditModel();
|
||||
void OpenEditWindow();
|
||||
void LoadBackup();
|
||||
void OpenWizard();
|
||||
void simulate();
|
||||
void duplicate();
|
||||
void setdefault();
|
||||
|
||||
void deleteSelected(bool ask);
|
||||
void confirmDelete();
|
||||
void onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
|
||||
|
@ -79,12 +148,13 @@ private:
|
|||
void saveSelection();
|
||||
void restoreSelection();
|
||||
|
||||
RadioData *radioData;
|
||||
RadioData * radioData;
|
||||
QPoint dragStartPosition;
|
||||
|
||||
CurrentSelection currentSelection;
|
||||
QColor active_highlight_color;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // _MODELSLIST_H_
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
|
||||
#include "process_flash.h"
|
||||
#include "progresswidget.h"
|
||||
#include "eeprominterface.h"
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include "eeprominterface.h"
|
||||
//#include "firmwareinterface.h"
|
||||
#include <QEventLoop>
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <Windows.h>
|
||||
|
|
1321
companion/src/radiodata.h
Normal file
1321
companion/src/radiodata.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "releasenotesdialog.h"
|
||||
#include "ui_htmldialog.h"
|
||||
#include <QFile>
|
||||
|
||||
ReleaseNotesDialog::ReleaseNotesDialog(QWidget * parent) :
|
||||
QDialog(parent),
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(storage_NAMES
|
||||
storage_eeprom
|
||||
storage_sdcard
|
||||
hexinterface
|
||||
# xmlinterface
|
||||
mountlist
|
||||
rlefile
|
||||
appdata
|
||||
firmwareinterface
|
||||
storage
|
||||
bineeprom
|
||||
eepe
|
||||
hexeeprom
|
||||
categorized
|
||||
sdcard
|
||||
otx
|
||||
)
|
||||
|
||||
set(storage_SRCS
|
||||
|
|
103
companion/src/storage/bineeprom.cpp
Normal file
103
companion/src/storage/bineeprom.cpp
Normal 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;
|
||||
}
|
|
@ -18,16 +18,25 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _STORAGE_EEPROM_H_
|
||||
#define _STORAGE_EEPROM_H_
|
||||
#ifndef _BINEEPROM_H_
|
||||
#define _BINEEPROM_H_
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QString>
|
||||
#include "eeprominterface.h"
|
||||
#include "storage.h"
|
||||
|
||||
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);
|
||||
bool convertEEprom(const QString &sourceEEprom, const QString &destinationEEprom, const QString &firmware);
|
||||
class BinEepromFormat : public StorageFormat
|
||||
{
|
||||
public:
|
||||
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_
|
114
companion/src/storage/categorized.cpp
Normal file
114
companion/src/storage/categorized.cpp
Normal 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;
|
||||
}
|
42
companion/src/storage/categorized.h
Normal file
42
companion/src/storage/categorized.h
Normal 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_
|
53
companion/src/storage/eepe.cpp
Normal file
53
companion/src/storage/eepe.cpp
Normal 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);
|
||||
}
|
37
companion/src/storage/eepe.h
Normal file
37
companion/src/storage/eepe.h
Normal 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_
|
48
companion/src/storage/eepexml.cpp
Normal file
48
companion/src/storage/eepexml.cpp
Normal 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;
|
||||
}
|
|
@ -18,11 +18,12 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <QtGui>
|
||||
#include "hexinterface.h"
|
||||
#include "splash.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "helpers.h"
|
||||
#include "storage.h"
|
||||
#include <QtGui>
|
||||
|
||||
#define FW_MARK "FW"
|
||||
#define VERS_MARK "VERS"
|
||||
|
@ -30,25 +31,6 @@
|
|||
#define TIME_MARK "TIME"
|
||||
#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):
|
||||
flash(FSIZE_MAX, 0),
|
||||
flashSize(0),
|
||||
|
@ -355,9 +337,9 @@ unsigned int FirmwareInterface::save(QString fileName)
|
|||
memcpy(binflash, flash.constData(), flashSize);
|
||||
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
|
||||
free(binflash);
|
||||
return -1;
|
||||
|
|
|
@ -36,15 +36,6 @@
|
|||
#define ERSKY9X_SPE "SPE"
|
||||
#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
|
||||
{
|
||||
public:
|
||||
|
|
63
companion/src/storage/hexeeprom.cpp
Normal file
63
companion/src/storage/hexeeprom.cpp
Normal 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;
|
||||
}
|
40
companion/src/storage/hexeeprom.h
Normal file
40
companion/src/storage/hexeeprom.h
Normal 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_
|
|
@ -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 nextbank = 1;
|
||||
|
@ -103,7 +103,7 @@ bool HexInterface::save(uint8_t *data, const int size)
|
|||
return true;
|
||||
}
|
||||
|
||||
QString HexInterface::iHEXLine(quint8 * data, quint32 addr, quint8 len)
|
||||
QString HexInterface::iHEXLine(const quint8 * data, quint32 addr, quint8 len)
|
||||
{
|
||||
unsigned int bankaddr;
|
||||
bankaddr=addr&0xffff;
|
||||
|
|
|
@ -28,13 +28,13 @@ class HexInterface {
|
|||
public:
|
||||
HexInterface(QTextStream &stream);
|
||||
|
||||
int load(uint8_t *output, int maxsize);
|
||||
bool save(uint8_t *data, const int size);
|
||||
int load(uint8_t * output, int maxsize);
|
||||
bool save(const uint8_t * data, const int size);
|
||||
|
||||
protected:
|
||||
|
||||
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);
|
||||
|
||||
QTextStream & stream;
|
||||
|
|
116
companion/src/storage/otx.cpp
Normal file
116
companion/src/storage/otx.cpp
Normal 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;
|
||||
}
|
48
companion/src/storage/otx.h
Normal file
48
companion/src/storage/otx.h
Normal 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_
|
|
@ -20,21 +20,6 @@
|
|||
|
||||
// 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_
|
||||
#define _RLEFILE_H_
|
||||
|
||||
|
|
65
companion/src/storage/sdcard.cpp
Normal file
65
companion/src/storage/sdcard.cpp
Normal 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();
|
||||
}
|
||||
|
52
companion/src/storage/sdcard.h
Normal file
52
companion/src/storage/sdcard.h
Normal 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_
|
170
companion/src/storage/storage.cpp
Normal file
170
companion/src/storage/storage.cpp
Normal 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
|
143
companion/src/storage/storage.h
Normal file
143
companion/src/storage/storage.h
Normal 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_
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_
|
|
@ -195,7 +195,7 @@ bool XmlInterface::save(RadioData &radioData)
|
|||
// the models
|
||||
models xml_models;
|
||||
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];
|
||||
if (m.used) {
|
||||
model xm(m.name);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "eeprominterface.h"
|
||||
#include <QTextStream>
|
||||
#include <QDomDocument>
|
||||
|
||||
class XmlInterface
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ class XmlInterface
|
|||
|
||||
bool load(RadioData &);
|
||||
|
||||
virtual bool loadxml(RadioData &radioData, QDomDocument &doc);
|
||||
virtual bool loadxml(RadioData & radioData, QDomDocument & doc);
|
||||
|
||||
bool save(RadioData &radioData);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue