chore(cpn): remove binary file format models and settings support (#5653)
This commit is contained in:
@@ -224,7 +224,6 @@ set(companion_NAMES
|
||||
burnconfigdialog
|
||||
comparedialog
|
||||
customizesplashdialog
|
||||
flasheepromdialog
|
||||
flashfirmwaredialog
|
||||
helpers_html
|
||||
labels
|
||||
|
||||
@@ -72,15 +72,15 @@
|
||||
#define BIN_FILES_FILTER "BIN " % CPN_STR_FILES % " (*.bin);;"
|
||||
#define DFU_FILES_FILTER "DFU " % CPN_STR_FILES % " (*.dfu);;"
|
||||
#define EEPE_FILES_FILTER "EEPE " % CPN_STR_FILES % " (*.eepe);;"
|
||||
#define OTX_FILES_FILTER "OpenTX " % CPN_STR_FILES % " (*.otx);;"
|
||||
#define ETX_FILES_FILTER "EdgeTX " % CPN_STR_FILES % " (*.etx);;"
|
||||
#define YML_FILES_FILTER "EdgeTX YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml *.otx *.eepe *.bin *.hex);;" % ETX_FILES_FILTER % YML_FILES_FILTER % OTX_FILES_FILTER % EEPE_FILES_FILTER % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml);;" % ETX_FILES_FILTER % YML_FILES_FILTER
|
||||
#define FLASH_FILES_FILTER "FLASH " % CPN_STR_FILES % " (*.bin *.hex *.dfu);;" % BIN_FILES_FILTER % HEX_FILES_FILTER % DFU_FILES_FILTER
|
||||
#define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin *.hex);;" % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define ER9X_EEPROM_FILE_TYPE "ER9X_EEPROM_FILE"
|
||||
#define EEPE_EEPROM_FILE_HEADER "EEPE EEPROM FILE"
|
||||
#define EEPE_MODEL_FILE_HEADER "EEPE MODEL FILE"
|
||||
#define SIMU_FILES_FILTER ETX_FILES_FILTER
|
||||
|
||||
#define CPN_STR_APP_SETTINGS QCoreApplication::translate("Companion", "Application Settings")
|
||||
#define CPN_STR_APP_SETTINGS_FILES CPN_STR_APP_SETTINGS % " " % CPN_STR_FILES
|
||||
|
||||
@@ -31,9 +31,6 @@ set(${PROJECT_NAME}_NAMES
|
||||
sourcenumref
|
||||
telem_data
|
||||
timerdata
|
||||
ersky9x/ersky9xeeprom
|
||||
ersky9x/ersky9xinterface
|
||||
opentx/opentxeeprom
|
||||
opentx/opentxinterface
|
||||
edgetx/edgetxinterface
|
||||
edgetx/yaml_calibdata
|
||||
|
||||
@@ -1,834 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _EEPROMIMPORTEXPORT_H_
|
||||
#define _EEPROMIMPORTEXPORT_H_
|
||||
|
||||
#include "customdebug.h"
|
||||
#include <QtCore>
|
||||
#include <QBitArray>
|
||||
#include <utility>
|
||||
|
||||
class DataField {
|
||||
Q_DECLARE_TR_FUNCTIONS(DataField)
|
||||
|
||||
public:
|
||||
explicit DataField(DataField * parent, const char * name=""):
|
||||
parent(parent),
|
||||
name(name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~DataField()
|
||||
= default;
|
||||
|
||||
virtual const QString & getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
virtual unsigned int size() = 0; // size in bits
|
||||
virtual void ExportBits(QBitArray & output) = 0;
|
||||
virtual void ImportBits(const QBitArray & input) = 0;
|
||||
|
||||
static QBitArray bytesToBits(QByteArray bytes)
|
||||
{
|
||||
QBitArray bits(bytes.count()*8);
|
||||
// Convert from QByteArray to QBitArray
|
||||
for (int i=0; i<bytes.count(); ++i)
|
||||
for (int b=0; b<8; ++b)
|
||||
bits.setBit(i*8+b, bytes.at(i)&(1<<b));
|
||||
return bits;
|
||||
}
|
||||
|
||||
static QByteArray bitsToBytes(QBitArray bits, int offset=0)
|
||||
{
|
||||
QByteArray bytes;
|
||||
bytes.resize((offset+bits.count()+7)/8);
|
||||
bytes.fill(0);
|
||||
// Convert from QBitArray to QByteArray
|
||||
for (int b=0; b<bits.count(); ++b)
|
||||
bytes[(b+offset)/8] = ( bytes.at((b+offset)/8) | ((bits[b]?1:0)<<((b+offset)%8)));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int Export(QByteArray & output)
|
||||
{
|
||||
QBitArray result;
|
||||
ExportBits(result);
|
||||
output = bitsToBytes(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Import(const QByteArray & input)
|
||||
{
|
||||
QBitArray bits = bytesToBits(input);
|
||||
if (unsigned(bits.size()) < size()) {
|
||||
qDebug() << QString("Error importing %1: size too small %2 bits / %3 bits").arg(getName()).arg(bits.size()).arg(size());
|
||||
return -1;
|
||||
}
|
||||
ImportBits(bits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int dump(int level=0, int offset=0)
|
||||
{
|
||||
QBitArray bits;
|
||||
ExportBits(bits);
|
||||
QByteArray bytes = bitsToBytes(bits);
|
||||
int result = (offset+bits.count()) % 8;
|
||||
for (int i=0; i<level; i++) printf(" ");
|
||||
if (bits.count() % 8 == 0)
|
||||
printf("%s (%dbytes) ", getName().toLatin1().constData(), bytes.count());
|
||||
else
|
||||
printf("%s (%dbits) ", getName().toLatin1().constData(), bits.count());
|
||||
for (int i=0; i<bytes.count(); i++) {
|
||||
unsigned char c = bytes[i];
|
||||
if ((i==0 && offset) || (i==bytes.count()-1 && result!=0))
|
||||
printf("(%02x) ", c);
|
||||
else
|
||||
printf("%02x ", c);
|
||||
}
|
||||
printf("\n"); fflush(stdout);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void setError(const QString & error)
|
||||
{
|
||||
if (parent) {
|
||||
parent->setError(error);
|
||||
}
|
||||
else {
|
||||
qWarning() << qPrintable(error);
|
||||
}
|
||||
}
|
||||
|
||||
DataField * parent;
|
||||
QString name;
|
||||
};
|
||||
|
||||
//class ProxyField: public DataField {
|
||||
// public:
|
||||
// explicit ProxyField(DataField * parent):
|
||||
// DataField(parent, "Proxy")
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// virtual DataField * getField() = 0;
|
||||
//
|
||||
//};
|
||||
|
||||
template<class container, int N>
|
||||
class BaseUnsignedField: public DataField {
|
||||
public:
|
||||
BaseUnsignedField(DataField * parent, container & field):
|
||||
DataField(parent, "Unsigned"),
|
||||
field(field),
|
||||
min(0),
|
||||
max(std::numeric_limits<container>::max())
|
||||
{
|
||||
}
|
||||
|
||||
BaseUnsignedField(DataField * parent, container & field, const char * name):
|
||||
DataField(parent, name),
|
||||
field(field),
|
||||
min(0),
|
||||
max(std::numeric_limits<container>::max())
|
||||
{
|
||||
}
|
||||
|
||||
BaseUnsignedField(DataField * parent, container & field, container min, container max, const char * name="Unsigned"):
|
||||
DataField(parent, name),
|
||||
field(field),
|
||||
min(min),
|
||||
max(max)
|
||||
{
|
||||
}
|
||||
|
||||
BaseUnsignedField() = delete;
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
container value = field;
|
||||
if (value > max) value = max;
|
||||
if (value < min) value = min;
|
||||
|
||||
output.resize(N);
|
||||
for (int i=0; i<N; i++) {
|
||||
if (value & ((container)1<<i)) {
|
||||
output.setBit(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
field = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (input[i])
|
||||
field |= ((container)1<<i);
|
||||
}
|
||||
qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
protected:
|
||||
container & field;
|
||||
container min;
|
||||
container max;
|
||||
};
|
||||
|
||||
template <int N>
|
||||
class UnsignedField : public BaseUnsignedField<unsigned int, N>
|
||||
{
|
||||
public:
|
||||
UnsignedField(DataField * parent, unsigned int & field):
|
||||
BaseUnsignedField<unsigned int, N>(parent, field)
|
||||
{
|
||||
}
|
||||
|
||||
UnsignedField(DataField * parent, unsigned int & field, const char *name):
|
||||
BaseUnsignedField<unsigned int, N>(parent, field, name)
|
||||
{
|
||||
}
|
||||
|
||||
UnsignedField(DataField * parent, unsigned int & field, unsigned int min, unsigned int max, const char *name="Unsigned"):
|
||||
BaseUnsignedField<unsigned int, N>(parent, field, min, max, name)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class BoolField: public DataField {
|
||||
public:
|
||||
explicit BoolField(DataField * parent, bool & field):
|
||||
DataField(parent, "Bool"),
|
||||
field(field)
|
||||
{
|
||||
}
|
||||
|
||||
BoolField() = delete;
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
output.resize(N);
|
||||
if (field) {
|
||||
output.setBit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
field = input[0];
|
||||
qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool & field;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class SignedField: public DataField {
|
||||
public:
|
||||
SignedField(DataField * parent, int & field):
|
||||
DataField(parent, "Signed"),
|
||||
field(field)
|
||||
{
|
||||
}
|
||||
|
||||
SignedField(DataField * parent, int & field, const char *name):
|
||||
DataField(parent, name),
|
||||
field(field)
|
||||
{
|
||||
}
|
||||
|
||||
SignedField(DataField * parent, int & field, int min, int max, const char *name="Signed"):
|
||||
DataField(parent, name),
|
||||
field(field),
|
||||
min(min),
|
||||
max(max)
|
||||
{
|
||||
}
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
int value = field;
|
||||
if (value > max) value = max;
|
||||
if (value < min) value = min;
|
||||
|
||||
output.resize(N);
|
||||
for (int i=0; i<N; i++) {
|
||||
if (((unsigned int)value) & (1<<i))
|
||||
output.setBit(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
unsigned int value = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
if (input[i])
|
||||
value |= (1<<i);
|
||||
}
|
||||
|
||||
if (input[N-1]) {
|
||||
for (unsigned int i=N; i<8*sizeof(int); i++) {
|
||||
value |= (1<<i);
|
||||
}
|
||||
}
|
||||
|
||||
field = (int)value;
|
||||
qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
protected:
|
||||
int & field;
|
||||
int min = INT_MIN;
|
||||
int max = INT_MAX;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class SpareBitsField: public UnsignedField<N> {
|
||||
public:
|
||||
explicit SpareBitsField(DataField * parent):
|
||||
UnsignedField<N>(parent, spare, 0, 0, "Spare"),
|
||||
spare(0)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int spare;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class CharField: public DataField {
|
||||
public:
|
||||
CharField(DataField * parent, char * field, bool truncate=true, const char * name="Char"):
|
||||
DataField(parent, name),
|
||||
field(field),
|
||||
truncate(truncate)
|
||||
{
|
||||
}
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
output.resize(N*8);
|
||||
int b = 0;
|
||||
int len = truncate ? strlen(field) : N;
|
||||
for (int i=0; i<N; i++) {
|
||||
int idx = (i>=len ? 0 : field[i]);
|
||||
for (int j=0; j<8; j++, b++) {
|
||||
if (idx & (1<<j))
|
||||
output.setBit(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
unsigned int b = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
int8_t idx = 0;
|
||||
for (int j=0; j<8; j++) {
|
||||
if (input[b++])
|
||||
idx |= (1<<j);
|
||||
}
|
||||
field[i] = idx;
|
||||
}
|
||||
qCDebug(eepromImport) << QString("\timported %1<%2>: '%3'").arg(name).arg(N).arg(field);
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return 8 * N;
|
||||
}
|
||||
|
||||
protected:
|
||||
char * field;
|
||||
bool truncate;
|
||||
};
|
||||
|
||||
static const char specialCharsTab[] = "_-.,";
|
||||
static inline int8_t char2zchar(char c)
|
||||
{
|
||||
if (c==' ') return 0;
|
||||
if (c>='A' && c<='Z') return 1+c-'A';
|
||||
if (c>='a' && c<='z') return -1-c+'a';
|
||||
if (c>='0' && c<='9') return 27+c-'0';
|
||||
for (int8_t i=0;;i++) {
|
||||
char cc = specialCharsTab[i];
|
||||
if (cc==0) return 0;
|
||||
if (cc==c) return 37+i;
|
||||
}
|
||||
}
|
||||
|
||||
#define ZCHAR_MAX 40
|
||||
static inline char zchar2char(int8_t idx)
|
||||
{
|
||||
if (idx == 0) return ' ';
|
||||
if (idx < 0) {
|
||||
if (idx > -27) return 'a' - idx - 1;
|
||||
idx = -idx;
|
||||
}
|
||||
if (idx < 27) return 'A' + idx - 1;
|
||||
if (idx < 37) return '0' + idx - 27;
|
||||
if (idx <= ZCHAR_MAX) return specialCharsTab[idx-37];
|
||||
return ' ';
|
||||
}
|
||||
|
||||
template<int N>
|
||||
class ZCharField: public DataField {
|
||||
public:
|
||||
ZCharField(DataField * parent, char * field, const char * name = "ZChar"):
|
||||
DataField(parent, name),
|
||||
field(field)
|
||||
{
|
||||
}
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
output.resize(N*8);
|
||||
int b = 0;
|
||||
int len = strlen(field);
|
||||
for (int i=0; i<N; i++) {
|
||||
int idx = i>=len ? 0 : char2zchar(field[i]);
|
||||
for (int j=0; j<8; j++, b++) {
|
||||
if (idx & (1<<j))
|
||||
output.setBit(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
unsigned int b = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
int8_t idx = 0;
|
||||
for (int j=0; j<8; j++) {
|
||||
if (input[b++])
|
||||
idx |= (1<<j);
|
||||
}
|
||||
field[i] = zchar2char(idx);
|
||||
}
|
||||
|
||||
field[N] = '\0';
|
||||
for (int i=N-1; i>=0; i--) {
|
||||
if (field[i] == ' ')
|
||||
field[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
qCDebug(eepromImport) << QString("\timported %1<%2>: '%3'").arg(name).arg(N).arg(field);
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return 8*N;
|
||||
}
|
||||
|
||||
protected:
|
||||
char * field;
|
||||
};
|
||||
|
||||
class StructField: public DataField {
|
||||
public:
|
||||
explicit StructField(DataField * parent, const char * name = "Struct"):
|
||||
DataField(parent, name)
|
||||
{
|
||||
}
|
||||
|
||||
~StructField() override {
|
||||
foreach(DataField * field, fields) {
|
||||
delete field;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Append(DataField * field) {
|
||||
//qCDebug(eepromImport) << QString("StructField(%1) appending field: %2").arg(name).arg(field->getName());
|
||||
fields.append(field);
|
||||
}
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
int offset = 0;
|
||||
output.resize(size());
|
||||
foreach(DataField *field, fields) {
|
||||
QBitArray bits;
|
||||
field->ExportBits(bits);
|
||||
for (int i=0; i<bits.size(); i++)
|
||||
output[offset++] = bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
qCDebug(eepromImport) << QString("\timporting %1[%2]:").arg(name).arg(fields.size());
|
||||
int offset = 0;
|
||||
foreach(DataField *field, fields) {
|
||||
unsigned int size = field->size();
|
||||
QBitArray bits(size);
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
bits[i] = input[offset++];
|
||||
}
|
||||
field->ImportBits(bits);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
unsigned int result = 0;
|
||||
foreach(DataField *field, fields) {
|
||||
result += field->size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int dump(int level=0, int offset=0) override
|
||||
{
|
||||
for (int i=0; i<level; i++) printf(" ");
|
||||
printf("%s (%d bytes)\n", getName().toLatin1().constData(), size()/8);
|
||||
foreach(DataField *field, fields) {
|
||||
offset = field->dump(level+1, offset);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected:
|
||||
QList<DataField *> fields;
|
||||
};
|
||||
|
||||
class TransformedField: public DataField {
|
||||
public:
|
||||
TransformedField(DataField * parent, DataField & field):
|
||||
DataField(parent),
|
||||
field(field)
|
||||
{
|
||||
}
|
||||
|
||||
~TransformedField() override
|
||||
= default;
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
beforeExport();
|
||||
field.ExportBits(output);
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
qCDebug(eepromImport) << QString("\timporting TransformedField %1:").arg(field.getName());
|
||||
field.ImportBits(input);
|
||||
afterImport();
|
||||
}
|
||||
|
||||
|
||||
const QString & getName() override
|
||||
{
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return field.size();
|
||||
}
|
||||
|
||||
virtual void beforeExport() = 0;
|
||||
|
||||
virtual void afterImport() = 0;
|
||||
|
||||
int dump(int level=0, int offset=0) override
|
||||
{
|
||||
beforeExport();
|
||||
return field.dump(level, offset);
|
||||
}
|
||||
|
||||
protected:
|
||||
DataField & field;
|
||||
};
|
||||
|
||||
template<class selectorT>
|
||||
class UnionField: public DataField {
|
||||
public:
|
||||
|
||||
class UnionMember {
|
||||
public:
|
||||
virtual ~UnionMember() = default;
|
||||
virtual bool select(const selectorT& attr) const = 0;
|
||||
virtual DataField* getField() = 0;
|
||||
};
|
||||
|
||||
class TransformedMember: public UnionMember, public TransformedField {
|
||||
public:
|
||||
TransformedMember(DataField* parent, DataField& field):
|
||||
TransformedField(parent, field)
|
||||
{
|
||||
}
|
||||
|
||||
virtual DataField* getField()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
UnionField(DataField * parent, selectorT& selectField, const char * name="Union"):
|
||||
DataField(parent, name), selectField(selectField), maxSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
~UnionField() override {
|
||||
foreach(UnionMember *member, members) {
|
||||
delete member;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Append(UnionMember * member) {
|
||||
members.append(member);
|
||||
if (member->getField()->size() > maxSize)
|
||||
maxSize = member->getField()->size();
|
||||
}
|
||||
|
||||
void ExportBits(QBitArray & output) override
|
||||
{
|
||||
foreach(UnionMember *member, members) {
|
||||
if (member->select(selectField)) {
|
||||
member->getField()->ExportBits(output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
output.resize(maxSize);
|
||||
}
|
||||
|
||||
void ImportBits(const QBitArray & input) override
|
||||
{
|
||||
foreach(UnionMember *member, members) {
|
||||
if (member->select(selectField)) {
|
||||
member->getField()->ImportBits(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int size() override
|
||||
{
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
selectorT& selectField;
|
||||
QList<UnionMember *> members;
|
||||
unsigned int maxSize;
|
||||
};
|
||||
|
||||
class ConversionTable {
|
||||
|
||||
public:
|
||||
bool exportValue(const int before, int &after)
|
||||
{
|
||||
after = 0;
|
||||
|
||||
for (auto & tuple : exportTable) {
|
||||
if (before == tuple.a) {
|
||||
after = tuple.b;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool importValue(const int before, int &after)
|
||||
{
|
||||
after = 0;
|
||||
|
||||
for (auto & tuple : importTable) {
|
||||
if (before == tuple.b) {
|
||||
after = tuple.a;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
class ConversionTuple {
|
||||
public:
|
||||
ConversionTuple(const int a, const int b):
|
||||
a(a),
|
||||
b(b)
|
||||
{
|
||||
}
|
||||
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
void addConversion(const int a, const int b)
|
||||
{
|
||||
ConversionTuple conversion(a, b);
|
||||
importTable.push_back(conversion);
|
||||
exportTable.push_back(conversion);
|
||||
}
|
||||
|
||||
// void addImportConversion(const int a, const int b)
|
||||
// {
|
||||
// importTable.push_back(ConversionTuple(a, b));
|
||||
// }
|
||||
//
|
||||
// void addExportConversion(const int a, const int b)
|
||||
// {
|
||||
// exportTable.push_back(ConversionTuple(a, b));
|
||||
// }
|
||||
|
||||
std::list<ConversionTuple> importTable;
|
||||
std::list<ConversionTuple> exportTable;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class ConversionField: public TransformedField {
|
||||
public:
|
||||
ConversionField(DataField * parent, int & field, ConversionTable *table, const char *name, QString error = ""):
|
||||
TransformedField(parent, internalField),
|
||||
internalField(this, _field, name),
|
||||
field(field),
|
||||
table(table),
|
||||
error(std::move(error))
|
||||
{
|
||||
}
|
||||
|
||||
ConversionField(DataField * parent, unsigned int & field, ConversionTable *table, const char *name, QString error = ""):
|
||||
TransformedField(parent, internalField),
|
||||
internalField(this, (unsigned int &)_field, name),
|
||||
field((int &)field),
|
||||
table(table),
|
||||
error(std::move(error))
|
||||
{
|
||||
}
|
||||
|
||||
ConversionField(DataField * parent, int & field, int (*exportFunc)(int), int (*importFunc)(int)):
|
||||
TransformedField(parent, internalField),
|
||||
internalField(this, _field),
|
||||
field(field),
|
||||
exportFunc(exportFunc),
|
||||
importFunc(importFunc)
|
||||
{
|
||||
}
|
||||
|
||||
ConversionField(DataField * parent, int & field, int shift, int scale=0, int min=INT_MIN, int max=INT_MAX, const char *name = "Signed shifted"):
|
||||
TransformedField(parent, internalField),
|
||||
internalField(this, _field, name),
|
||||
field(field),
|
||||
shift(shift),
|
||||
scale(scale),
|
||||
min(min),
|
||||
max(max)
|
||||
{
|
||||
}
|
||||
|
||||
ConversionField(DataField * parent, unsigned int & field, int shift, int scale=0):
|
||||
TransformedField(parent, internalField),
|
||||
internalField(this, (unsigned int &)_field),
|
||||
field((int &)field),
|
||||
shift(shift),
|
||||
scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
void beforeExport() override
|
||||
{
|
||||
_field = scale ? field / scale : field;
|
||||
|
||||
if (table) {
|
||||
if (!table->exportValue(_field, _field)) {
|
||||
setError(error.isEmpty() ? DataField::tr("Conversion error on field %1").arg(name) : error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (shift) {
|
||||
if (_field < min)
|
||||
_field = min + shift;
|
||||
else if (_field > max)
|
||||
_field = max + shift;
|
||||
else
|
||||
_field += shift;
|
||||
}
|
||||
|
||||
if (exportFunc) {
|
||||
_field = exportFunc(_field);
|
||||
}
|
||||
}
|
||||
|
||||
void afterImport() override
|
||||
{
|
||||
field = _field;
|
||||
|
||||
if (table) {
|
||||
if (table->importValue(field, field))
|
||||
return;
|
||||
}
|
||||
|
||||
if (shift) {
|
||||
field -= shift;
|
||||
}
|
||||
|
||||
if (importFunc) {
|
||||
field = importFunc(field);
|
||||
}
|
||||
|
||||
if (scale) {
|
||||
field *= scale;
|
||||
}
|
||||
|
||||
qCDebug(eepromImport) << QString("\timported ConversionField<%1>:").arg(internalField.getName()) << QString(" before: %1, after: %2").arg(_field).arg(field);
|
||||
}
|
||||
|
||||
protected:
|
||||
T internalField;
|
||||
int & field;
|
||||
int _field = 0;
|
||||
ConversionTable * table = nullptr;
|
||||
int shift = 0;
|
||||
int scale = 0;
|
||||
int min = INT_MIN;
|
||||
int max = INT_MAX;
|
||||
int (*exportFunc)(int) = nullptr;
|
||||
int (*importFunc)(int) = nullptr;
|
||||
const QString error = "";
|
||||
};
|
||||
|
||||
#endif // _EEPROMIMPORTEXPORT_H_
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
#include "eeprominterface.h"
|
||||
#include "firmwares/opentx/opentxeeprom.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "boardfactories.h"
|
||||
|
||||
@@ -30,97 +29,24 @@
|
||||
|
||||
float ValToTim(int value)
|
||||
{
|
||||
return ((value < -109 ? 129+value : (value < 7 ? (113+value)*5 : (53+value)*10))/10.0);
|
||||
return ((value < -109 ? 129 + value : (value < 7 ? (113 + value) * 5 : (53 + value) * 10)) / 10.0);
|
||||
}
|
||||
|
||||
int TimToVal(float value)
|
||||
{
|
||||
int temp;
|
||||
if (value>60) {
|
||||
temp=136+round((value-60));
|
||||
if (value > 60) {
|
||||
temp = 136 + round((value - 60));
|
||||
}
|
||||
else if (value>2) {
|
||||
temp=20+round((value-2.0)*2.0);
|
||||
else if (value > 2) {
|
||||
temp = 20 + round((value - 2.0) * 2.0);
|
||||
}
|
||||
else {
|
||||
temp=round(value*10.0);
|
||||
temp = round(value * 10.0);
|
||||
}
|
||||
return (temp-129);
|
||||
return (temp - 129);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EEpromInterface globals
|
||||
*/
|
||||
|
||||
// TODO: No globals
|
||||
|
||||
QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
void unregisterEEpromInterfaces()
|
||||
{
|
||||
foreach(EEPROMInterface * intf, eepromInterfaces) {
|
||||
// qDebug() << "UnregisterEepromInterfaces(): deleting " << QString::number( reinterpret_cast<uint64_t>(intf), 16 );
|
||||
delete intf;
|
||||
}
|
||||
OpenTxEepromCleanup();
|
||||
}
|
||||
|
||||
#if 0 // TODO: remove if unused, currently commented out in mdiChild.cpp
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
void EEPROMInterface::showEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList errorsList;
|
||||
|
||||
errorsList << tr("Possible causes for this:");
|
||||
|
||||
if (errors.test(UNSUPPORTED_NEWER_VERSION)) { errorsList << tr("- Eeprom is from a newer version of OpenTX"); }
|
||||
if (errors.test(NOT_OPENTX)) { errorsList << tr("- Eeprom is not from OpenTX"); }
|
||||
if (errors.test(NOT_ERSKY9X)) { errorsList << tr("- Eeprom is not from ErSky9X"); }
|
||||
if (errors.test(WRONG_SIZE)) { errorsList << tr("- Eeprom size is invalid"); }
|
||||
if (errors.test(WRONG_FILE_SYSTEM)) { errorsList << tr("- Eeprom file system is invalid"); }
|
||||
if (errors.test(UNKNOWN_BOARD)) { errorsList << tr("- Eeprom is from a unknown board"); }
|
||||
if (errors.test(WRONG_BOARD)) { errorsList << tr("- Eeprom is from the wrong board"); }
|
||||
if (errors.test(BACKUP_NOT_SUPPORTED)) { errorsList << tr("- Eeprom backup not supported"); }
|
||||
|
||||
if (errors.test(UNKNOWN_ERROR)) { errorsList << tr("- Something that couldn't be guessed, sorry"); }
|
||||
|
||||
if (errors.test(HAS_WARNINGS)) {
|
||||
errorsList << tr("Warning:");
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) { errorsList << tr("- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
|
||||
}
|
||||
|
||||
QMessageBox msgBox(parent);
|
||||
msgBox.setWindowTitle(title);
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setText(mainMessage);
|
||||
msgBox.setInformativeText(errorsList.join("\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.exec();
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: No GUI here, e.g. return string list instead
|
||||
QString EEPROMInterface::getEepromWarnings(unsigned long errorsFound)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors((unsigned long long)errorsFound);
|
||||
QStringList warningsList;
|
||||
if (errors.test(WARNING_WRONG_FIRMWARE)) {
|
||||
warningsList << tr("- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used");
|
||||
}
|
||||
if (errors.test(OLD_VERSION)) {
|
||||
warningsList << tr("- Your eeprom is from an old version of OpenTX, upgrading!\n To keep your original file as a backup, please choose File -> Save As specifying a different name.");
|
||||
}
|
||||
|
||||
return warningsList.join("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Firmware
|
||||
*/
|
||||
|
||||
Firmware::Firmware(Firmware * base, const QString & id, const QString & name, Board::Type board,
|
||||
const QString & downloadId, const QString & simulatorId, const QString & hwdefnId) :
|
||||
id(id),
|
||||
@@ -128,7 +54,6 @@ Firmware::Firmware(Firmware * base, const QString & id, const QString & name, Bo
|
||||
board(board),
|
||||
variantBase(0),
|
||||
base(base),
|
||||
eepromInterface(nullptr),
|
||||
downloadId(downloadId),
|
||||
simulatorId(simulatorId),
|
||||
hwdefnId(hwdefnId)
|
||||
@@ -158,10 +83,10 @@ unsigned int Firmware::getVariantNumber()
|
||||
{
|
||||
unsigned int result = 0;
|
||||
const Firmware * base = getFirmwareBase();
|
||||
QStringList options = id.mid(base->getId().length()+1).split("-", Qt::SkipEmptyParts);
|
||||
foreach(QString option, options) {
|
||||
foreach(OptionsGroup group, base->opts) {
|
||||
foreach(Option opt, group) {
|
||||
QStringList options = id.mid(base->getId().length() + 1).split("-", Qt::SkipEmptyParts);
|
||||
foreach (QString option, options) {
|
||||
foreach (OptionsGroup group, base->opts) {
|
||||
foreach (Option opt, group) {
|
||||
if (opt.name == option) {
|
||||
result += opt.variant;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _EEPROMINTERFACE_H_
|
||||
#define _EEPROMINTERFACE_H_
|
||||
#pragma once
|
||||
|
||||
#include "boards.h"
|
||||
#include "macros.h"
|
||||
@@ -149,7 +148,6 @@ enum Capability {
|
||||
EnhancedCurves,
|
||||
HasFasOffset,
|
||||
HasMahPersistent,
|
||||
SimulatorVariant,
|
||||
MavlinkTelemetry,
|
||||
HasInputDiff,
|
||||
HasMixerExpo,
|
||||
@@ -178,98 +176,12 @@ enum Capability {
|
||||
BacklightLevelMin,
|
||||
};
|
||||
|
||||
class EEPROMInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(EEPROMInterface)
|
||||
|
||||
public:
|
||||
|
||||
EEPROMInterface(Board::Type board):
|
||||
board(board)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~EEPROMInterface() {}
|
||||
|
||||
inline Board::Type getBoard() { return board; }
|
||||
|
||||
virtual unsigned long load(RadioData &radioData, const uint8_t * eeprom, int size) = 0;
|
||||
|
||||
virtual unsigned long loadBackup(RadioData & radioData, const uint8_t * eeprom, int esize, int index) = 0;
|
||||
|
||||
virtual int save(uint8_t * eeprom, const RadioData & radioData, uint8_t version=0, uint32_t variant=0) = 0;
|
||||
|
||||
virtual int getSize(const ModelData &) = 0;
|
||||
|
||||
virtual int getSize(const GeneralSettings &) = 0;
|
||||
|
||||
//static void showEepromErrors(QWidget *parent, const QString &title, const QString &mainMessage, unsigned long errorsFound);
|
||||
static QString getEepromWarnings(unsigned long errorsFound);
|
||||
|
||||
protected:
|
||||
|
||||
Board::Type board;
|
||||
|
||||
private:
|
||||
|
||||
EEPROMInterface();
|
||||
|
||||
};
|
||||
|
||||
/* EEPROM string conversion function (used only by er9xeeprom and ersky9xeeprom) */
|
||||
inline void getEEPROMString(char *dst, const char *src, int size)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
dst[size] = '\0';
|
||||
for (int i=size-1; i>=0; i--) {
|
||||
if (dst[i] == ' ')
|
||||
dst[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// (used only by er9xeeprom and ersky9xeeprom)
|
||||
inline int applyStickMode(int stick, unsigned int mode)
|
||||
{
|
||||
if (mode == 0 || mode > 4) {
|
||||
std::cerr << "Incorrect stick mode" << mode;
|
||||
return stick;
|
||||
}
|
||||
|
||||
if (stick >= 1 && stick <= 4)
|
||||
return modn12x3[mode-1][stick-1];
|
||||
else
|
||||
return stick;
|
||||
}
|
||||
|
||||
float ValToTim(int value);
|
||||
int TimToVal(float value);
|
||||
|
||||
void registerEEpromInterfaces();
|
||||
void unregisterEEpromInterfaces();
|
||||
void registerOpenTxFirmwares();
|
||||
void unregisterOpenTxFirmwares();
|
||||
|
||||
enum EepromLoadErrors {
|
||||
ALL_OK,
|
||||
UNKNOWN_ERROR,
|
||||
UNSUPPORTED_NEWER_VERSION,
|
||||
WRONG_SIZE,
|
||||
WRONG_FILE_SYSTEM,
|
||||
NOT_OPENTX,
|
||||
NOT_ERSKY9X,
|
||||
UNKNOWN_BOARD,
|
||||
WRONG_BOARD,
|
||||
BACKUP_NOT_SUPPORTED,
|
||||
|
||||
HAS_WARNINGS,
|
||||
OLD_VERSION,
|
||||
WARNING_WRONG_FIRMWARE,
|
||||
|
||||
NUM_ERRORS
|
||||
};
|
||||
|
||||
constexpr char FIRMWARE_ID_PREFIX[] = { "edgetx-" };
|
||||
|
||||
class Firmware
|
||||
@@ -330,16 +242,6 @@ class Firmware
|
||||
return board;
|
||||
}
|
||||
|
||||
void setEEpromInterface(EEPROMInterface * eeprom)
|
||||
{
|
||||
eepromInterface = eeprom;
|
||||
}
|
||||
|
||||
EEPROMInterface * getEEpromInterface()
|
||||
{
|
||||
return eepromInterface;
|
||||
}
|
||||
|
||||
QString getName() const
|
||||
{
|
||||
return name;
|
||||
@@ -429,7 +331,6 @@ class Firmware
|
||||
Board::Type board;
|
||||
unsigned int variantBase;
|
||||
Firmware * base;
|
||||
EEPROMInterface * eepromInterface;
|
||||
QString downloadId;
|
||||
QString simulatorId;
|
||||
QString hwdefnId;
|
||||
@@ -449,11 +350,6 @@ inline Firmware * getCurrentFirmware()
|
||||
return Firmware::getCurrentVariant();
|
||||
}
|
||||
|
||||
inline EEPROMInterface * getCurrentEEpromInterface()
|
||||
{
|
||||
return Firmware::getCurrentVariant()->getEEpromInterface();
|
||||
}
|
||||
|
||||
inline Board::Type getCurrentBoard()
|
||||
{
|
||||
return Firmware::getCurrentVariant()->getBoard();
|
||||
@@ -461,15 +357,10 @@ inline Board::Type getCurrentBoard()
|
||||
|
||||
inline int divRoundClosest(const int n, const int d)
|
||||
{
|
||||
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
|
||||
return ((n < 0) ^ (d < 0)) ? ((n - d / 2) / d) : ((n + d / 2) / d);
|
||||
}
|
||||
|
||||
inline int calcRESXto100(int x)
|
||||
{
|
||||
return divRoundClosest(x*100, 1024);
|
||||
return divRoundClosest(x * 100, 1024);
|
||||
}
|
||||
|
||||
extern QList<EEPROMInterface *> eepromInterfaces;
|
||||
|
||||
|
||||
#endif // _EEPROMINTERFACE_H_
|
||||
|
||||
@@ -1,482 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 <algorithm>
|
||||
#include "er9xeeprom.h"
|
||||
#include "helpers.h"
|
||||
#include <QObject>
|
||||
|
||||
RawSwitch er9xToSwitch(int8_t sw)
|
||||
{
|
||||
uint8_t swa = abs(sw);
|
||||
if (swa == 0)
|
||||
return RawSwitch(SWITCH_TYPE_NONE);
|
||||
else if (swa <= 9)
|
||||
return RawSwitch(SWITCH_TYPE_SWITCH, sw);
|
||||
else if (swa <= 21)
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, sw > 0 ? sw-9 : sw+9);
|
||||
else if (sw == 22)
|
||||
return RawSwitch(SWITCH_TYPE_ON);
|
||||
else if (sw == -22)
|
||||
return RawSwitch(SWITCH_TYPE_OFF);
|
||||
else if (swa <= 22+9)
|
||||
return RawSwitch(SWITCH_TYPE_SWITCH, sw > 0 ? sw-22 : sw+22);
|
||||
else
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, sw > 0 ? sw-22-9 : sw+22+9);
|
||||
}
|
||||
|
||||
t_Er9xTrainerMix::t_Er9xTrainerMix()
|
||||
{
|
||||
memset(this, 0, sizeof(t_Er9xTrainerMix));
|
||||
}
|
||||
|
||||
t_Er9xTrainerMix::operator TrainerMix()
|
||||
{
|
||||
TrainerMix c9x;
|
||||
c9x.src = srcChn;
|
||||
c9x.swtch = er9xToSwitch(swtch);
|
||||
c9x.weight = (25 * studWeight) / 8;
|
||||
c9x.mode = mode;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Er9xTrainerData::t_Er9xTrainerData()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Er9xTrainerData));
|
||||
}
|
||||
|
||||
t_Er9xTrainerData::operator TrainerData ()
|
||||
{
|
||||
TrainerData c9x;
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
c9x.calib[i] = calib[i];
|
||||
c9x.mix[i] = mix[i];
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Er9xGeneral::t_Er9xGeneral()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Er9xGeneral));
|
||||
}
|
||||
|
||||
Er9xGeneral::operator GeneralSettings ()
|
||||
{
|
||||
GeneralSettings result;
|
||||
result.version = myVers;
|
||||
for (int i=0; i<CPN_MAX_STICKSnPOTS; i++) {
|
||||
result.calibMid[i] = calibMid[i];
|
||||
result.calibSpanNeg[i] = calibSpanNeg[i];
|
||||
result.calibSpanPos[i] = calibSpanPos[i];
|
||||
}
|
||||
|
||||
result.currModelIndex = currModel;
|
||||
result.contrast = contrast;
|
||||
result.vBatWarn = vBatWarn;
|
||||
result.txVoltageCalibration = txVoltageCalibration;
|
||||
result.trainer = trainer;
|
||||
|
||||
result.view = std::min((uint8_t)4, view);
|
||||
result.disableThrottleWarning = disableThrottleWarning;
|
||||
result.disableMemoryWarning = disableMemoryWarning;
|
||||
|
||||
switch (beeperVal) {
|
||||
case 0:
|
||||
result.beeperMode = GeneralSettings::BEEPER_QUIET;
|
||||
break;
|
||||
case 1:
|
||||
result.beeperMode = GeneralSettings::BEEPER_NOKEYS;
|
||||
break;
|
||||
default:
|
||||
result.beeperMode = GeneralSettings::BEEPER_ALL;
|
||||
result.beeperLength = beeperVal - 4;
|
||||
break;
|
||||
}
|
||||
|
||||
result.disableAlarmWarning = disableAlarmWarning;
|
||||
result.stickMode = std::max((uint8_t)0, std::min(stickMode, (uint8_t)3));
|
||||
result.inactivityTimer = inactivityTimer + 10;
|
||||
result.minuteBeep = minuteBeep;
|
||||
result.preBeep = preBeep;
|
||||
result.flashBeep = flashBeep;
|
||||
result.splashMode = disableSplashScreen;
|
||||
|
||||
result.backlightMode = 0;
|
||||
if (lightSw == 22) {
|
||||
result.backlightMode = 4;
|
||||
}
|
||||
else if (lightAutoOff) {
|
||||
result.backlightMode |= 1;
|
||||
result.backlightDelay = lightAutoOff;
|
||||
}
|
||||
else if (lightOnStickMove) {
|
||||
result.backlightMode |= 2;
|
||||
result.backlightDelay = lightOnStickMove;
|
||||
}
|
||||
|
||||
result.templateSetup = templateSetup;
|
||||
result.PPM_Multiplier = PPM_Multiplier;
|
||||
getEEPROMString(result.ownerName, ownerName, sizeof(ownerName));
|
||||
result.speakerPitch = speakerPitch;
|
||||
result.hapticStrength = hapticStrength - 3;
|
||||
result.speakerMode = speakerMode;
|
||||
return result;
|
||||
}
|
||||
|
||||
t_Er9xLimitData::t_Er9xLimitData()
|
||||
{
|
||||
memset(this, 0, sizeof(t_Er9xLimitData));
|
||||
}
|
||||
|
||||
t_Er9xLimitData::operator LimitData ()
|
||||
{
|
||||
LimitData c9x;
|
||||
c9x.min = 10*(min-100);
|
||||
c9x.max = 10*(max+100);
|
||||
c9x.revert = revert;
|
||||
c9x.offset = offset;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Er9xMixData::t_Er9xMixData()
|
||||
{
|
||||
memset(this, 0, sizeof(t_Er9xMixData));
|
||||
}
|
||||
|
||||
t_Er9xMixData::operator MixData ()
|
||||
{
|
||||
MixData c9x;
|
||||
c9x.destCh = destCh;
|
||||
if (abs(weight)>125) {
|
||||
int gvar;
|
||||
if (weight>0) {
|
||||
gvar=weight-125;
|
||||
} else {
|
||||
gvar=weight+131;
|
||||
}
|
||||
gvar+=10000;
|
||||
c9x.weight=gvar;
|
||||
} else {
|
||||
c9x.weight = weight;
|
||||
}
|
||||
if (abs(sOffset)>125) {
|
||||
int gvar;
|
||||
if (sOffset>0) {
|
||||
gvar=sOffset-125;
|
||||
} else {
|
||||
gvar=sOffset+131;
|
||||
}
|
||||
gvar+=10000;
|
||||
c9x.sOffset=gvar;
|
||||
} else {
|
||||
c9x.sOffset=sOffset;
|
||||
}
|
||||
c9x.swtch = er9xToSwitch(swtch);
|
||||
|
||||
if (srcRaw == 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw <= 7) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_INPUT, srcRaw-1);
|
||||
}
|
||||
else if (srcRaw == 8) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (srcRaw == 9) {
|
||||
if (swtch < 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch < -3 ? -swtch-3 : -swtch);
|
||||
c9x.weight = -weight;
|
||||
}
|
||||
else if (swtch > 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch > 3 ? swtch-3 : swtch);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
if (mltpx != MLTPX_REP)
|
||||
c9x.swtch = RawSwitch(SWITCH_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw <= 12) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CYC, srcRaw-10);
|
||||
}
|
||||
else if (srcRaw <= 20) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_PPM, srcRaw-13);
|
||||
}
|
||||
else if (srcRaw <=37) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CH, srcRaw-21);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_GVAR, srcRaw-38);
|
||||
}
|
||||
|
||||
if (differential==1) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_DIFF;
|
||||
c9x.curve.value = differential;
|
||||
}
|
||||
else if (curve > 6) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_CUSTOM;
|
||||
c9x.curve.value = curve - 6;
|
||||
}
|
||||
else if (curve > 0) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_FUNC;
|
||||
c9x.curve.value = curve;
|
||||
}
|
||||
|
||||
// c9x.lateOffset=lateOffset;
|
||||
c9x.delayUp = delayUp;
|
||||
c9x.delayDown = delayDown;
|
||||
c9x.speedUp = speedUp;
|
||||
c9x.speedDown = speedDown;
|
||||
c9x.carryTrim = carryTrim;
|
||||
c9x.mltpx = (MltpxValue)mltpx;
|
||||
c9x.mixWarn = mixWarn;
|
||||
// c9x.enableFmTrim=enableFmTrim;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
RawSource er9xToSource(int8_t value)
|
||||
{
|
||||
if (value == 0) {
|
||||
return RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (value <= 7) {
|
||||
return RawSource(SOURCE_TYPE_INPUT, value - 1);
|
||||
}
|
||||
else if (value == 8) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value == 9) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value <= 12) {
|
||||
return RawSource(SOURCE_TYPE_CYC, value-10);
|
||||
}
|
||||
else if (value <= 20) {
|
||||
return RawSource(SOURCE_TYPE_PPM, value-13);
|
||||
}
|
||||
else if (value <= 36) {
|
||||
return RawSource(SOURCE_TYPE_CH, value-21);
|
||||
}
|
||||
else {
|
||||
return RawSource(SOURCE_TYPE_TELEMETRY, value-36);
|
||||
}
|
||||
}
|
||||
|
||||
Er9xLogicalSwitchData::operator LogicalSwitchData ()
|
||||
{
|
||||
LogicalSwitchData c9x;
|
||||
c9x.func = func;
|
||||
c9x.val1 = v1;
|
||||
c9x.val2 = v2;
|
||||
|
||||
if ((c9x.func >= LS_FN_VPOS && c9x.func <= LS_FN_ANEG) || c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val1 = er9xToSource(v1).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val2 = er9xToSource(v2).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_AND && c9x.func <= LS_FN_XOR) {
|
||||
c9x.val1 = er9xToSwitch(v1).toValue();
|
||||
c9x.val2 = er9xToSwitch(v2).toValue();
|
||||
}
|
||||
|
||||
return c9x;
|
||||
}
|
||||
|
||||
|
||||
t_Er9xSafetySwData::t_Er9xSafetySwData()
|
||||
{
|
||||
memset(this, 0, sizeof(t_Er9xSafetySwData));
|
||||
}
|
||||
|
||||
t_Er9xFrSkyChannelData::t_Er9xFrSkyChannelData()
|
||||
{
|
||||
memset(this, 0, sizeof(t_Er9xFrSkyChannelData));
|
||||
}
|
||||
|
||||
t_Er9xFrSkyChannelData::operator FrSkyChannelData ()
|
||||
{
|
||||
FrSkyChannelData c9x;
|
||||
c9x.ratio = ratio;
|
||||
c9x.alarms[0].value = alarms_value[0];
|
||||
c9x.alarms[0].level = alarms_level & 3;
|
||||
c9x.alarms[0].greater = alarms_greater & 1;
|
||||
c9x.alarms[1].value = alarms_value[1];
|
||||
c9x.alarms[1].level = (alarms_level >> 2) & 3;
|
||||
c9x.alarms[1].greater = (alarms_greater >> 1) & 1;
|
||||
if (type==2) {
|
||||
c9x.type = 0;
|
||||
c9x.multiplier=1;
|
||||
} else {
|
||||
c9x.type = type;
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Er9xFrSkyData::t_Er9xFrSkyData()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Er9xFrSkyData));
|
||||
}
|
||||
|
||||
t_Er9xFrSkyData::operator FrSkyData ()
|
||||
{
|
||||
FrSkyData c9x;
|
||||
c9x.channels[0] = channels[0];
|
||||
c9x.channels[1] = channels[1];
|
||||
return c9x;
|
||||
}
|
||||
|
||||
RawSwitch getEr9xTimerMode(int mode)
|
||||
{
|
||||
/*
|
||||
if (mode <= -33)
|
||||
return TimerMode(TMRMODE_FIRST_NEG_SWITCH+(mode+33));
|
||||
else if (mode <= -1)
|
||||
return TimerMode(TMRMODE_FIRST_NEG_SWITCH+(mode+1));
|
||||
else if (mode < 16)
|
||||
return TimerMode(mode);
|
||||
else if (mode < 16+21)
|
||||
return TimerMode(TMRMODE_FIRST_SWITCH+(mode-16));
|
||||
else
|
||||
return TimerMode(TMRMODE_FIRST_SWITCH+(mode-16-21));
|
||||
*/
|
||||
return RawSwitch();
|
||||
}
|
||||
|
||||
t_Er9xModelData::operator ModelData ()
|
||||
{
|
||||
ModelData c9x;
|
||||
c9x.used = true;
|
||||
getEEPROMString(c9x.name, name, sizeof(name));
|
||||
c9x.timers[0].mode = getEr9xTimerMode(tmrMode);
|
||||
c9x.timers[0].val = tmrVal;
|
||||
switch(protocol) {
|
||||
case 1:
|
||||
c9x.moduleData[0].protocol = PULSES_PXX_DJT;
|
||||
break;
|
||||
case 2:
|
||||
c9x.moduleData[0].protocol = PULSES_DSM2;
|
||||
break;
|
||||
case 3:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM16;
|
||||
break;
|
||||
default:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM;
|
||||
break;
|
||||
}
|
||||
c9x.moduleData[0].ppm.frameLength=ppmFrameLength;
|
||||
c9x.moduleData[0].channelsCount = 8 + 2 * ppmNCH;
|
||||
c9x.thrTrim = thrTrim;
|
||||
c9x.trimInc = trimInc-2;
|
||||
c9x.moduleData[0].ppm.delay = 300 + 50 * ppmDelay;
|
||||
c9x.customFn[0].func = FuncInstantTrim;
|
||||
if (trimSw) {
|
||||
c9x.customFn[0].swtch = er9xToSwitch(trimSw);
|
||||
}
|
||||
c9x.beepANACenter = beepANACenter;
|
||||
c9x.moduleData[0].ppm.pulsePol = pulsePol;
|
||||
c9x.extendedLimits = extendedLimits;
|
||||
c9x.swashRingData.elevatorWeight = swashInvertELE ? -100 : 100;
|
||||
c9x.swashRingData.aileronWeight = swashInvertAIL ? -100 : 100;
|
||||
c9x.swashRingData.collectiveWeight = swashInvertCOL ? -100 : 100;
|
||||
c9x.swashRingData.type = swashType;
|
||||
c9x.swashRingData.collectiveSource = er9xToSource(swashCollectiveSource);
|
||||
c9x.swashRingData.value = swashRingValue;
|
||||
|
||||
for (int i=0; i<ER9X_MAX_MIXERS; i++) {
|
||||
Er9xMixData mix = mixData[i];
|
||||
c9x.mixData[i] = mix;
|
||||
}
|
||||
|
||||
for (int i=0; i<ER9X_NUM_CHNOUT; i++)
|
||||
c9x.limitData[i] = limitData[i];
|
||||
|
||||
// expoData
|
||||
int e = 0;
|
||||
for (int ch = 0; ch < 4 && e < CPN_MAX_EXPOS; ch++) {
|
||||
for (int dr = 0, pos = 0; dr < 3 && e < CPN_MAX_EXPOS; dr++, pos++) {
|
||||
if ((dr == 0 && !expoData[ch].drSw1) || (dr == 1 && !expoData[ch].drSw2))
|
||||
dr = 2;
|
||||
if (dr == 2 && !expoData[ch].expo[0][0][0] && !expoData[ch].expo[0][0][1] && !expoData[ch].expo[0][1][0] && !expoData[ch].expo[0][1][1])
|
||||
break;
|
||||
if (expoData[ch].drSw1 && !expoData[ch].drSw2) {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? expoData[ch].drSw1 : 0);
|
||||
pos = dr == 0 ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? -expoData[ch].drSw1 : (dr == 1 ? -expoData[ch].drSw2 : 0));
|
||||
}
|
||||
c9x.expoData[e].chn = ch;
|
||||
if (expoData[ch].expo[pos][0][0]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][0];
|
||||
}
|
||||
c9x.expoData[e].weight = 100 + expoData[ch].expo[pos][1][0];
|
||||
if (expoData[ch].expo[pos][0][0] == expoData[ch].expo[pos][0][1] && expoData[ch].expo[pos][1][0] == expoData[ch].expo[pos][1][1]) {
|
||||
c9x.expoData[e++].mode = 3;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].mode = 2;
|
||||
if (e < CPN_MAX_EXPOS - 1) {
|
||||
c9x.expoData[e + 1].swtch = c9x.expoData[e].swtch;
|
||||
c9x.expoData[++e].chn = ch;
|
||||
c9x.expoData[e].mode = 1;
|
||||
if (expoData[ch].expo[pos][0][1]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][1];
|
||||
}
|
||||
c9x.expoData[e++].weight = 100 + expoData[ch].expo[pos][1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++)
|
||||
c9x.flightModeData[0].trim[i] = trim[i];
|
||||
|
||||
for (int i=0; i<ER9X_MAX_CURVE5; i++) {
|
||||
c9x.curves[i].count = 5;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
c9x.curves[i].points[j].x = -100 + 50 * i;
|
||||
c9x.curves[i].points[j].y = curves5[i][j];
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ER9X_MAX_CURVE9; i++) {
|
||||
c9x.curves[ER9X_MAX_CURVE5 + i].count = 9;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
c9x.curves[ER9X_MAX_CURVE5 + i].points[j].x = -100 + 25 * i;
|
||||
c9x.curves[ER9X_MAX_CURVE5 + i].points[j].y = curves9[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<ER9X_NUM_CSW; i++)
|
||||
c9x.logicalSw[i] = logicalSw[i];
|
||||
|
||||
// for (int i=0; i<ER9X_NUM_CHNOUT; i++)
|
||||
// c9x.safetySw[i] = safetySw[i];
|
||||
|
||||
c9x.frsky = frsky;
|
||||
c9x.frsky.usrProto=FrSkyUsrProto;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _ER9XEEPROM_H_
|
||||
#define _ER9XEEPROM_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "eeprominterface.h"
|
||||
|
||||
//eeprom data
|
||||
#define ER9X_MAX_MIXERS 32
|
||||
#define ER9X_MAX_CURVE5 8
|
||||
#define ER9X_MAX_CURVE9 8
|
||||
#define ER9X_MAX_CSFUNC 13
|
||||
|
||||
#define MDVERS 10
|
||||
|
||||
#define ER9X_NUM_CHNOUT 16 //number of real outputchannels CH1-CH8
|
||||
#define ER9X_NUM_CSW 12 //number of custom switches
|
||||
#define CPN_MAX_STICKSnPOTS 7 //number of sticks and pots
|
||||
#define ER9X_MAX_GVARS 7
|
||||
|
||||
#define ER9X_MAX_MODES 4
|
||||
|
||||
PACK(typedef struct t_Er9xTrainerMix {
|
||||
uint8_t srcChn:3; //0-7 = ch1-8
|
||||
int8_t swtch:5;
|
||||
int8_t studWeight:6;
|
||||
uint8_t mode:2; // off, add-mode, subst-mode
|
||||
|
||||
operator TrainerMix();
|
||||
t_Er9xTrainerMix();
|
||||
}) Er9xTrainerMix; //
|
||||
|
||||
PACK(typedef struct t_Er9xTrainerData {
|
||||
int16_t calib[4];
|
||||
Er9xTrainerMix mix[4];
|
||||
|
||||
operator TrainerData();
|
||||
t_Er9xTrainerData();
|
||||
}) Er9xTrainerData;
|
||||
|
||||
PACK(typedef struct t_Er9xGeneral {
|
||||
uint8_t myVers;
|
||||
int16_t calibMid[CPN_MAX_STICKSnPOTS];
|
||||
int16_t calibSpanNeg[CPN_MAX_STICKSnPOTS];
|
||||
int16_t calibSpanPos[CPN_MAX_STICKSnPOTS];
|
||||
uint16_t chkSum;
|
||||
uint8_t currModel; //0..15
|
||||
uint8_t contrast;
|
||||
uint8_t vBatWarn;
|
||||
int8_t txVoltageCalibration;
|
||||
int8_t lightSw;
|
||||
Er9xTrainerData trainer;
|
||||
uint8_t view;
|
||||
uint8_t disableThrottleWarning:1;
|
||||
uint8_t disableSwitchWarning:1;
|
||||
uint8_t disableMemoryWarning:1;
|
||||
uint8_t beeperVal:3;
|
||||
uint8_t reserveWarning:1;
|
||||
uint8_t disableAlarmWarning:1;
|
||||
uint8_t stickMode;
|
||||
int8_t inactivityTimer;
|
||||
uint8_t throttleReversed:1;
|
||||
uint8_t minuteBeep:1;
|
||||
uint8_t preBeep:1;
|
||||
uint8_t flashBeep:1;
|
||||
uint8_t disableSplashScreen:1;
|
||||
uint8_t disablePotScroll:1;
|
||||
uint8_t disableBG:1;
|
||||
uint8_t frskyinternalalarm:1;
|
||||
uint8_t spare_filter ; // No longer needed, left for eepe compatibility for now
|
||||
uint8_t lightAutoOff;
|
||||
uint8_t templateSetup; //RETA order according to chout_ar array
|
||||
int8_t PPM_Multiplier;
|
||||
uint8_t unused1;
|
||||
uint8_t unused2:4;
|
||||
uint8_t hideNameOnSplash:1;
|
||||
uint8_t enablePpmsim:1;
|
||||
uint8_t blightinv:1;
|
||||
uint8_t stickScroll:1;
|
||||
uint8_t speakerPitch;
|
||||
uint8_t hapticStrength;
|
||||
uint8_t speakerMode;
|
||||
uint8_t lightOnStickMove;
|
||||
|
||||
char ownerName[10];
|
||||
uint8_t switchWarningStates;
|
||||
uint8_t volume ;
|
||||
uint8_t res[3];
|
||||
uint8_t crosstrim:1;
|
||||
uint8_t spare1:7;
|
||||
|
||||
operator GeneralSettings();
|
||||
t_Er9xGeneral();
|
||||
}) Er9xGeneral;
|
||||
|
||||
PACK(typedef struct t_Er9xExpoData {
|
||||
int8_t expo[3][2][2];
|
||||
int8_t drSw1;
|
||||
int8_t drSw2;
|
||||
|
||||
t_Er9xExpoData() { memset(this, 0, sizeof(t_Er9xExpoData)); }
|
||||
}) Er9xExpoData;
|
||||
|
||||
|
||||
PACK(typedef struct t_Er9xLimitData {
|
||||
int8_t min;
|
||||
int8_t max;
|
||||
bool revert;
|
||||
int16_t offset;
|
||||
|
||||
operator LimitData();
|
||||
t_Er9xLimitData();
|
||||
}) Er9xLimitData;
|
||||
|
||||
#define MLTPX_ADD 0
|
||||
#define MLTPX_MUL 1
|
||||
#define MLTPX_REP 2
|
||||
|
||||
PACK(typedef struct t_Er9xMixData {
|
||||
uint8_t destCh; // 1..CPN_MAX_CHNOUT
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; //0=symmetrisch 1=no neg 2=no pos
|
||||
uint8_t delayUp:4;
|
||||
uint8_t delayDown:4;
|
||||
uint8_t speedUp:4; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown:4; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
uint8_t mltpx:2; // multiplex method 0=+ 1=* 2=replace
|
||||
uint8_t lateOffset:1; // Add offset later
|
||||
uint8_t mixWarn:2; // mixer warning
|
||||
uint8_t enableFmTrim:1;
|
||||
uint8_t differential:1;
|
||||
int8_t sOffset;
|
||||
int8_t res;
|
||||
|
||||
operator MixData();
|
||||
t_Er9xMixData();
|
||||
}) Er9xMixData;
|
||||
|
||||
|
||||
PACK(typedef struct t_Er9xLogicalSwitchData { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func:4;
|
||||
uint8_t andsw:4;
|
||||
|
||||
operator LogicalSwitchData();
|
||||
t_Er9xLogicalSwitchData() { memset(this, 0, sizeof(t_Er9xLogicalSwitchData)); }
|
||||
}) Er9xLogicalSwitchData;
|
||||
|
||||
PACK(typedef struct t_Er9xSafetySwData { // Custom Switches data
|
||||
int8_t swtch;
|
||||
int8_t val;
|
||||
|
||||
t_Er9xSafetySwData();
|
||||
}) Er9xSafetySwData;
|
||||
|
||||
PACK(typedef struct t_Er9xFrSkyChannelData {
|
||||
uint8_t ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_value[2]; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_level:4;
|
||||
uint8_t alarms_greater:2; // 0=LT(<), 1=GT(>)
|
||||
uint8_t type:2; // future use: 0=volts, ...
|
||||
|
||||
operator FrSkyChannelData();
|
||||
t_Er9xFrSkyChannelData();
|
||||
}) Er9xFrSkyChannelData;
|
||||
|
||||
PACK(typedef struct t_Er9xFrSkyData {
|
||||
Er9xFrSkyChannelData channels[2];
|
||||
|
||||
operator FrSkyData();
|
||||
t_Er9xFrSkyData();
|
||||
}) Er9xFrSkyData;
|
||||
|
||||
PACK(typedef struct t_gvar {
|
||||
int8_t gvar ;
|
||||
uint8_t gvsource ;
|
||||
// int8_t gvswitch ;
|
||||
}) Er9xGvarData ;
|
||||
|
||||
PACK(typedef struct t_FlightModeData {
|
||||
// Trim store as -1001 to -1, trim value-501, 0-5 use trim of phase 0-5
|
||||
int16_t trim[4]; // -500..500 => trim value, 501 => use trim of phase 0, 502, 503, 504 => use trim of modes 1|2|3|4 instead
|
||||
int8_t swtch; // Try 0-5 use trim of phase 0-5, 1000-2000, trim + 1500 ???
|
||||
uint8_t fadeIn:4;
|
||||
uint8_t fadeOut:4;
|
||||
}) Er9xFlightModeData;
|
||||
|
||||
PACK(typedef struct t_Er9xModelData {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
uint8_t modelVoice ; // Index to model name voice (260+value)
|
||||
int8_t tmrMode; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
|
||||
uint8_t tmrDir:1; //0=>Count Down, 1=>Count Up
|
||||
uint8_t traineron:1; // 0 disable trainer, 1 allow trainer
|
||||
uint8_t t2throttle:1 ; // Start timer2 using throttle
|
||||
uint8_t FrSkyUsrProto:1 ; // Protocol in FrSky User Data, 0=FrSky Hub, 1=WS HowHigh
|
||||
uint8_t FrSkyGpsAlt:1 ; // Use Gps Altitude as main altitude reading
|
||||
uint8_t FrSkyImperial:1 ; // Convert FrSky values to imperial units
|
||||
uint8_t FrSkyAltAlarm:2;
|
||||
uint16_t tmrVal;
|
||||
uint8_t protocol;
|
||||
int8_t ppmNCH;
|
||||
uint8_t thrTrim:1; // Enable Throttle Trim
|
||||
uint8_t xnumBlades:2; // RPM scaling
|
||||
uint8_t spare10:1;
|
||||
uint8_t thrExpo:1; // Enable Throttle Expo
|
||||
uint8_t ppmStart:3 ; // Start channel for PPM
|
||||
int8_t trimInc; // Trim Increments
|
||||
int8_t ppmDelay;
|
||||
int8_t trimSw;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
uint8_t pulsePol:1;
|
||||
uint8_t extendedLimits:1;
|
||||
uint8_t swashInvertELE:1;
|
||||
uint8_t swashInvertAIL:1;
|
||||
uint8_t swashInvertCOL:1;
|
||||
uint8_t swashType:3;
|
||||
uint8_t swashCollectiveSource;
|
||||
uint8_t swashRingValue;
|
||||
int8_t ppmFrameLength;
|
||||
Er9xMixData mixData[ER9X_MAX_MIXERS];
|
||||
Er9xLimitData limitData[ER9X_NUM_CHNOUT];
|
||||
Er9xExpoData expoData[4];
|
||||
int8_t trim[4];
|
||||
int8_t curves5[ER9X_MAX_CURVE5][5];
|
||||
int8_t curves9[ER9X_MAX_CURVE9][9];
|
||||
Er9xLogicalSwitchData logicalSw[ER9X_NUM_CSW];
|
||||
uint8_t frSkyVoltThreshold ;
|
||||
int8_t tmrModeB;
|
||||
uint8_t numVoice;
|
||||
Er9xSafetySwData safetySw[ER9X_NUM_CHNOUT];
|
||||
Er9xFrSkyData frsky;
|
||||
uint8_t numBlades ;
|
||||
uint8_t unused1[8] ;
|
||||
uint8_t CustomDisplayIndex[6] ;
|
||||
Er9xGvarData gvars[ER9X_MAX_GVARS] ;
|
||||
Er9xFlightModeData flightModeData[ER9X_MAX_MODES] ;
|
||||
|
||||
operator ModelData();
|
||||
t_Er9xModelData() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Er9xModelData)); }
|
||||
}) Er9xModelData;
|
||||
|
||||
#endif // _ER9XEEPROM_H_
|
||||
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 "er9xinterface.h"
|
||||
#include "er9xeeprom.h"
|
||||
#include "rlefile.h"
|
||||
// #include "appdata.h"
|
||||
// #include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
||||
#define FILE_GENERAL 0
|
||||
#define FILE_MODEL(n) (1+n)
|
||||
|
||||
Er9xInterface::Er9xInterface():
|
||||
EEPROMInterface(Board::BOARD_9X_M64),
|
||||
efile(new RleFile())
|
||||
{
|
||||
}
|
||||
|
||||
Er9xInterface::~Er9xInterface()
|
||||
{
|
||||
delete efile;
|
||||
}
|
||||
|
||||
const char * Er9xInterface::getName()
|
||||
{
|
||||
return "Er9x";
|
||||
}
|
||||
|
||||
inline void applyStickModeToModel(Er9xModelData & model, unsigned int mode)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
int stick = applyStickMode(i+1, mode) - 1;
|
||||
{
|
||||
int tmp = model.trim[i];
|
||||
model.trim[i] = model.trim[stick];
|
||||
model.trim[stick] = tmp;
|
||||
}
|
||||
{
|
||||
Er9xExpoData tmp = model.expoData[i];
|
||||
model.expoData[i] = model.expoData[stick];
|
||||
model.expoData[stick] = tmp;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ER9X_MAX_MIXERS; i++)
|
||||
model.mixData[i].srcRaw = applyStickMode(model.mixData[i].srcRaw, mode);
|
||||
for (int i=0; i<ER9X_NUM_CSW; i++) {
|
||||
switch (LogicalSwitchData(model.logicalSw[i].func).getFunctionFamily()) {
|
||||
case LS_FAMILY_VCOMP:
|
||||
model.logicalSw[i].v2 = applyStickMode(model.logicalSw[i].v2, mode);
|
||||
// no break
|
||||
case LS_FAMILY_VOFS:
|
||||
model.logicalSw[i].v1 = applyStickMode(model.logicalSw[i].v1, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned long Er9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
||||
{
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying er9x xml import... ";
|
||||
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
Er9xGeneral er9xGeneral;
|
||||
memset(&er9xGeneral,0,sizeof(er9xGeneral));
|
||||
if (!loadRadioSettingsDataXML(&doc, &er9xGeneral)) {
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
else {
|
||||
radioData.generalSettings=er9xGeneral;
|
||||
dbg << "version " << (unsigned int)er9xGeneral.myVers << " ";
|
||||
}
|
||||
for (int i=0; i<getCapability(Models); i++) {
|
||||
Er9xModelData er9xModel;
|
||||
memset(&er9xModel,0,sizeof(er9xModel));
|
||||
if(loadModelDataXML(&doc, &er9xModel, i)) {
|
||||
applyStickModeToModel(er9xModel, radioData.generalSettings.stickMode+1);
|
||||
radioData.models[i] = er9xModel;
|
||||
}
|
||||
}
|
||||
dbg << "ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long Er9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
|
||||
{
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying er9x import... ";
|
||||
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
if (size != Boards::getEEpromSize(Board::BOARD_9X_M64)) {
|
||||
dbg << "wrong size";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (!efile->EeFsOpen((uint8_t *)eeprom, size, Board::BOARD_9X_M64)) {
|
||||
dbg << "wrong file system";
|
||||
errors.set(WRONG_FILE_SYSTEM);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
efile->openRd(FILE_GENERAL);
|
||||
Er9xGeneral er9xGeneral;
|
||||
|
||||
if (efile->readRlc1((uint8_t*)&er9xGeneral, 1) != 1) {
|
||||
dbg << "no";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
dbg << "version " << (unsigned int)er9xGeneral.myVers << " ";
|
||||
|
||||
switch(er9xGeneral.myVers) {
|
||||
case 3:
|
||||
dbg << "(old gruvin9x) ";
|
||||
case 4:
|
||||
// case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
break;
|
||||
default:
|
||||
dbg << "not er9x";
|
||||
errors.set(NOT_ER9X);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
efile->openRd(FILE_GENERAL);
|
||||
if (!efile->readRlc1((uint8_t*)&er9xGeneral, sizeof(Er9xGeneral))) {
|
||||
dbg << "ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
|
||||
}
|
||||
radioData.generalSettings = er9xGeneral;
|
||||
|
||||
for (int i=0; i<getCapability(Models); i++) {
|
||||
Er9xModelData er9xModel;
|
||||
efile->openRd(FILE_MODEL(i));
|
||||
if (!efile->readRlc1((uint8_t*)&er9xModel, sizeof(Er9xModelData))) {
|
||||
radioData.models[i].clear();
|
||||
}
|
||||
else {
|
||||
applyStickModeToModel(er9xModel, radioData.generalSettings.stickMode+1);
|
||||
radioData.models[i] = er9xModel;
|
||||
}
|
||||
}
|
||||
|
||||
dbg << "ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
unsigned long Er9xInterface::loadBackup(RadioData &radioData, const uint8_t *eeprom, int esize, int index)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
int Er9xInterface::getSize(const ModelData &model)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Er9xInterface::getSize(const GeneralSettings &settings)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Er9xInterface::isAvailable(PulsesProtocol prot, int port)
|
||||
{
|
||||
switch (prot) {
|
||||
case PULSES_PPM:
|
||||
case PULSES_DSM2:
|
||||
case PULSES_PXX_DJT:
|
||||
case PULSES_PPM16:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Er9xInterface::appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value)
|
||||
{
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomText t = qdoc->createTextNode(name);
|
||||
t.setNodeValue(value);
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
|
||||
void Er9xInterface::appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite)
|
||||
{
|
||||
if(value || forceZeroWrite) {
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomText t = qdoc->createTextNode(name);
|
||||
t.setNodeValue(QString("%1").arg(value));
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Er9xInterface::appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size)
|
||||
{
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomCDATASection t = qdoc->createCDATASection(name);
|
||||
t.setData(QByteArray(data, size).toBase64());
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
|
||||
QDomElement Er9xInterface::getGeneralDataXML(QDomDocument * qdoc, Er9xGeneral * tgen)
|
||||
{
|
||||
QDomElement gd = qdoc->createElement("GENERAL_DATA");
|
||||
appendNumberElement(qdoc, &gd, "Version", tgen->myVers, true); // have to write value here
|
||||
appendTextElement(qdoc, &gd, "Owner", QString::fromLatin1(tgen->ownerName,sizeof(tgen->ownerName)).trimmed());
|
||||
appendCDATAElement(qdoc, &gd, "Data", (const char *)tgen,sizeof(Er9xGeneral));
|
||||
return gd;
|
||||
}
|
||||
|
||||
QDomElement Er9xInterface::getModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum, int mdver)
|
||||
{
|
||||
QDomElement md = qdoc->createElement("MODEL_DATA");
|
||||
md.setAttribute("number", modelNum);
|
||||
appendNumberElement(qdoc, &md, "Version", mdver, true); // have to write value here
|
||||
appendTextElement(qdoc, &md, "Name", QString::fromLatin1(tmod->name,sizeof(tmod->name)).trimmed());
|
||||
appendCDATAElement(qdoc, &md, "Data", (const char *)tmod,sizeof(Er9xModelData));
|
||||
return md;
|
||||
}
|
||||
|
||||
bool Er9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Er9xGeneral * tgen)
|
||||
{
|
||||
// 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
|
||||
QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
QString ds = n.toCDATASection().data();
|
||||
QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
|
||||
const char * data = ba.data();
|
||||
memcpy(tgen, data, sizeof(Er9xGeneral));
|
||||
break;
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
// 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
|
||||
QDomNodeList ndl = qdoc->elementsByTagName("MODEL_DATA");
|
||||
|
||||
// cycle through nodes to find correct model number
|
||||
QDomNode k = ndl.at(0);
|
||||
if(modelNum>=0) {
|
||||
while(!k.isNull()) {
|
||||
int a = k.toElement().attribute("number").toInt();
|
||||
if(a==modelNum)
|
||||
break;
|
||||
k = k.nextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
if (k.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
|
||||
// load cdata into tgen
|
||||
QDomNode n = k.toElement().elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
QString ds = n.toCDATASection().data();
|
||||
QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
|
||||
const char * data = ba.data();
|
||||
memcpy(tmod, data, sizeof(Er9xModelData));
|
||||
break;
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
// check version?
|
||||
return true;
|
||||
}
|
||||
|
||||
int Er9xInterface::getCapability(Capability capability)
|
||||
{
|
||||
switch (capability) {
|
||||
case Models:
|
||||
return 16;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString Er9xInterface::getCapabilityStr(Capability capability)
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _ER9XINTERFACE_H_
|
||||
#define _ER9XINTERFACE_H_
|
||||
|
||||
#include <QtXml>
|
||||
#include "eeprominterface.h"
|
||||
#include "er9xeeprom.h"
|
||||
|
||||
class RleFile;
|
||||
|
||||
class Er9xInterface : public EEPROMInterface
|
||||
{
|
||||
public:
|
||||
|
||||
Er9xInterface();
|
||||
|
||||
virtual ~Er9xInterface();
|
||||
|
||||
virtual const char * getName();
|
||||
|
||||
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, const RadioData & radioData, uint8_t version=0, uint32_t variant=0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int getSize(const ModelData &);
|
||||
|
||||
virtual int getSize(const GeneralSettings &settings);
|
||||
|
||||
virtual bool isAvailable(PulsesProtocol proto, int port=0);
|
||||
|
||||
virtual int getCapability(Capability capability);
|
||||
|
||||
virtual QString getCapabilityStr(Capability);
|
||||
|
||||
protected:
|
||||
|
||||
RleFile * efile;
|
||||
|
||||
private:
|
||||
void appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value);
|
||||
|
||||
void appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite = false);
|
||||
|
||||
void appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size);
|
||||
|
||||
QDomElement getGeneralDataXML(QDomDocument * qdoc, Er9xGeneral * tgen); //parse out data to XML format
|
||||
|
||||
QDomElement getModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum, int mdver); //parse out data to XML format
|
||||
|
||||
bool loadRadioSettingsDataXML(QDomDocument * qdoc, Er9xGeneral * tgen); // get data from XML
|
||||
|
||||
bool loadModelDataXML(QDomDocument * qdoc, Er9xModelData * tmod, int modelNum = -1); // get data from XML
|
||||
|
||||
};
|
||||
|
||||
#endif // _ER9XINTERFACE_H_
|
||||
@@ -1,731 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 <algorithm>
|
||||
#include "helpers.h"
|
||||
#include "ersky9xeeprom.h"
|
||||
#include <QObject>
|
||||
|
||||
extern RawSwitch er9xToSwitch(int8_t sw);
|
||||
|
||||
RawSwitch getErSky9xTimerMode(int mode)
|
||||
{
|
||||
if (mode<4)
|
||||
return RawSwitch(SWITCH_TYPE_TIMER_MODE, mode);
|
||||
else
|
||||
return RawSwitch();
|
||||
}
|
||||
|
||||
RawSwitch ersky9xToSwitch(int8_t sw)
|
||||
{
|
||||
uint8_t swa = abs(sw);
|
||||
if (swa == 0)
|
||||
return RawSwitch(SWITCH_TYPE_NONE);
|
||||
else if (swa <= 9)
|
||||
return RawSwitch(SWITCH_TYPE_SWITCH, sw);
|
||||
else if (swa <= 33)
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, sw > 0 ? sw-9 : sw+9);
|
||||
else if (sw == 34)
|
||||
return RawSwitch(SWITCH_TYPE_ON);
|
||||
else if (sw == -34)
|
||||
return RawSwitch(SWITCH_TYPE_OFF);
|
||||
else if (swa <= 34+9)
|
||||
return RawSwitch(SWITCH_TYPE_SWITCH, sw > 0 ? sw-34 : sw+34);
|
||||
else
|
||||
return RawSwitch(SWITCH_TYPE_VIRTUAL, sw > 0 ? sw-34-9 : sw+34+9);
|
||||
}
|
||||
|
||||
t_Ersky9xTrainerMix::t_Ersky9xTrainerMix()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xTrainerMix));
|
||||
}
|
||||
|
||||
t_Ersky9xTrainerMix::operator TrainerMix()
|
||||
{
|
||||
TrainerMix c9x;
|
||||
c9x.src = srcChn;
|
||||
c9x.swtch = er9xToSwitch(swtch);
|
||||
c9x.weight = (25 * studWeight) / 8;
|
||||
c9x.mode = mode;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xTrainerData::t_Ersky9xTrainerData()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xTrainerData));
|
||||
}
|
||||
|
||||
t_Ersky9xTrainerData::operator TrainerData ()
|
||||
{
|
||||
TrainerData c9x;
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++) {
|
||||
c9x.calib[i] = calib[i];
|
||||
c9x.mix[i] = mix[i];
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xGeneral::t_Ersky9xGeneral()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xGeneral));
|
||||
}
|
||||
|
||||
Ersky9xGeneral::operator GeneralSettings ()
|
||||
{
|
||||
GeneralSettings result;
|
||||
|
||||
result.version = myVers;
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKSnPOTS; i++) {
|
||||
result.calibMid[i] = calibMid[i];
|
||||
result.calibSpanNeg[i] = calibSpanNeg[i];
|
||||
result.calibSpanPos[i] = calibSpanPos[i];
|
||||
}
|
||||
|
||||
result.currModelIndex = currModel;
|
||||
result.contrast = contrast;
|
||||
result.vBatWarn = vBatWarn;
|
||||
result.txVoltageCalibration = txVoltageCalibration;
|
||||
|
||||
result.backlightMode = 0;
|
||||
if (lightSw == 22) {
|
||||
result.backlightMode = 4;
|
||||
}
|
||||
else if (lightAutoOff) {
|
||||
result.backlightMode |= 1;
|
||||
result.backlightDelay = lightAutoOff;
|
||||
}
|
||||
else if (lightOnStickMove) {
|
||||
result.backlightMode |= 2;
|
||||
result.backlightDelay = lightOnStickMove;
|
||||
}
|
||||
|
||||
result.trainer = trainer;
|
||||
result.view = std::min((uint8_t)4, view);
|
||||
result.disableThrottleWarning = disableThrottleWarning;
|
||||
result.disableMemoryWarning = disableMemoryWarning;
|
||||
|
||||
switch (beeperVal) {
|
||||
case 0:
|
||||
result.beeperMode = GeneralSettings::BEEPER_QUIET;
|
||||
break;
|
||||
case 1:
|
||||
result.beeperMode = GeneralSettings::BEEPER_NOKEYS;
|
||||
break;
|
||||
default:
|
||||
result.beeperMode = GeneralSettings::BEEPER_ALL;
|
||||
result.beeperLength = beeperVal - 4;
|
||||
break;
|
||||
}
|
||||
|
||||
result.disableAlarmWarning = disableAlarmWarning;
|
||||
result.stickMode = std::max((uint8_t)0, std::min(stickMode, (uint8_t)3));
|
||||
result.inactivityTimer = inactivityTimer + 10;
|
||||
result.minuteBeep = minuteBeep;
|
||||
result.preBeep = preBeep;
|
||||
result.alarmsFlash = alarmsFlash;
|
||||
result.splashMode = disableSplashScreen;
|
||||
result.templateSetup = templateSetup;
|
||||
result.PPM_Multiplier = PPM_Multiplier;
|
||||
getEEPROMString(result.ownerName, ownerName, sizeof(ownerName));
|
||||
result.optrexDisplay = optrexDisplay;
|
||||
result.speakerPitch = speakerPitch;
|
||||
result.hapticStrength = hapticStrength - 3;
|
||||
result.speakerMode = speakerMode;
|
||||
result.speakerVolume = volume;
|
||||
result.backlightBright = bright ;
|
||||
result.txCurrentCalibration = current_calib;
|
||||
return result;
|
||||
}
|
||||
|
||||
t_Ersky9xLimitData::t_Ersky9xLimitData()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xLimitData));
|
||||
}
|
||||
|
||||
t_Ersky9xLimitData::operator LimitData ()
|
||||
{
|
||||
LimitData c9x;
|
||||
c9x.min = 10*(min-100);
|
||||
c9x.max = 10*(max+100);
|
||||
c9x.revert = revert;
|
||||
c9x.offset = offset;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xMixData_v10::t_Ersky9xMixData_v10()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xMixData_v10));
|
||||
}
|
||||
|
||||
t_Ersky9xMixData_v10::operator MixData ()
|
||||
{
|
||||
MixData c9x;
|
||||
c9x.destCh = destCh;
|
||||
c9x.weight = weight;
|
||||
c9x.swtch = er9xToSwitch(swtch);
|
||||
|
||||
if (srcRaw == 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw <= 7) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_INPUT, srcRaw-1);
|
||||
}
|
||||
else if (srcRaw == 8) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (srcRaw == 9) {
|
||||
if (swtch < 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch < -3 ? -swtch-3 : -swtch);
|
||||
c9x.weight = -weight;
|
||||
}
|
||||
else if (swtch > 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch > 3 ? swtch-3 : swtch);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
if (mltpx != MLTPX_REP)
|
||||
c9x.swtch = RawSwitch(SWITCH_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw == 37) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, 0);
|
||||
}
|
||||
else if (srcRaw <= 12) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CYC, srcRaw-10);
|
||||
}
|
||||
else if (srcRaw <= 20) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_PPM, srcRaw-13);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CH, srcRaw-21);
|
||||
}
|
||||
|
||||
if (curve > 6) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_CUSTOM;
|
||||
c9x.curve.value = curve - 6;
|
||||
}
|
||||
else if (curve > 0) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_FUNC;
|
||||
c9x.curve.value = curve;
|
||||
}
|
||||
|
||||
c9x.delayUp = delayUp;
|
||||
c9x.delayDown = delayDown;
|
||||
c9x.speedUp = speedUp;
|
||||
c9x.speedDown = speedDown;
|
||||
c9x.carryTrim = carryTrim;
|
||||
c9x.mltpx = (MltpxValue)mltpx;
|
||||
c9x.mixWarn = mixWarn;
|
||||
// c9x.enableFmTrim=enableFmTrim;
|
||||
c9x.sOffset = sOffset;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
|
||||
t_Ersky9xMixData_v11::t_Ersky9xMixData_v11()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xMixData_v11));
|
||||
}
|
||||
|
||||
t_Ersky9xMixData_v11::operator MixData ()
|
||||
{
|
||||
MixData c9x;
|
||||
c9x.destCh = destCh;
|
||||
c9x.weight = weight;
|
||||
c9x.swtch = ersky9xToSwitch(swtch);
|
||||
|
||||
if (srcRaw == 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw <= 7) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_INPUT, srcRaw-1);
|
||||
}
|
||||
else if (srcRaw == 8) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (srcRaw == 9) {
|
||||
if (swtch < 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch < -3 ? -swtch-3 : -swtch);
|
||||
c9x.weight = -weight;
|
||||
}
|
||||
else if (swtch > 0) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, swtch > 3 ? swtch-3 : swtch);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
if (mltpx != MLTPX_REP)
|
||||
c9x.swtch = RawSwitch(SWITCH_TYPE_NONE);
|
||||
}
|
||||
else if (srcRaw == 45) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_SWITCH, 0);
|
||||
}
|
||||
else if (srcRaw > 45) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_GVAR, srcRaw-46);
|
||||
}
|
||||
else if (srcRaw <= 12) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CYC, srcRaw-10);
|
||||
}
|
||||
else if (srcRaw <= 20) {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_PPM, srcRaw-13);
|
||||
}
|
||||
else {
|
||||
c9x.srcRaw = RawSource(SOURCE_TYPE_CH, srcRaw-21);
|
||||
}
|
||||
|
||||
if (curve > 6) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_CUSTOM;
|
||||
c9x.curve.value = curve - 6;
|
||||
}
|
||||
else if (curve > 0) {
|
||||
c9x.curve.type = CurveReference::CURVE_REF_FUNC;
|
||||
c9x.curve.value = curve;
|
||||
}
|
||||
|
||||
c9x.delayUp = delayUp;
|
||||
c9x.delayDown = delayDown;
|
||||
c9x.speedUp = speedUp;
|
||||
c9x.speedDown = speedDown;
|
||||
c9x.carryTrim = carryTrim;
|
||||
c9x.mltpx = (MltpxValue)mltpx;
|
||||
c9x.mixWarn = mixWarn;
|
||||
// c9x.enableFmTrim=enableFmTrim;
|
||||
c9x.sOffset = sOffset;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
RawSource ersky9xToSource_v10(int8_t value)
|
||||
{
|
||||
if (value == 0) {
|
||||
return RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (value <= 7) {
|
||||
return RawSource(SOURCE_TYPE_INPUT, value - 1);
|
||||
}
|
||||
else if (value == 8) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value == 9) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value <= 12) {
|
||||
return RawSource(SOURCE_TYPE_CYC, value-10);
|
||||
}
|
||||
else if (value <= 20) {
|
||||
return RawSource(SOURCE_TYPE_PPM, value-13);
|
||||
}
|
||||
else if (value <= 36) {
|
||||
return RawSource(SOURCE_TYPE_CH, value-21);
|
||||
}
|
||||
else {
|
||||
return RawSource(SOURCE_TYPE_TELEMETRY, value-36);
|
||||
}
|
||||
}
|
||||
|
||||
RawSource ersky9xToSource_v11(int8_t value)
|
||||
{
|
||||
if (value == 0) {
|
||||
return RawSource(SOURCE_TYPE_NONE);
|
||||
}
|
||||
else if (value <= 7) {
|
||||
return RawSource(SOURCE_TYPE_INPUT, value - 1);
|
||||
}
|
||||
else if (value == 8) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value == 9) {
|
||||
return RawSource(SOURCE_TYPE_MAX);
|
||||
}
|
||||
else if (value <= 12) {
|
||||
return RawSource(SOURCE_TYPE_CYC, value-10);
|
||||
}
|
||||
else if (value <= 20) {
|
||||
return RawSource(SOURCE_TYPE_PPM, value-13);
|
||||
}
|
||||
else if (value <= 36) {
|
||||
return RawSource(SOURCE_TYPE_CH, value-21);
|
||||
}
|
||||
else {
|
||||
return RawSource(SOURCE_TYPE_TELEMETRY, value-36);
|
||||
}
|
||||
}
|
||||
|
||||
Ersky9xLogicalSwitchData_v10::operator LogicalSwitchData ()
|
||||
{
|
||||
LogicalSwitchData c9x;
|
||||
c9x.func = func;
|
||||
c9x.val1 = v1;
|
||||
c9x.val2 = v2;
|
||||
|
||||
if ((c9x.func >= LS_FN_VPOS && c9x.func <= LS_FN_ANEG) || c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val1 = ersky9xToSource_v10(v1).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val2 = ersky9xToSource_v10(v2).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_AND && c9x.func <= LS_FN_XOR) {
|
||||
c9x.val1 = er9xToSwitch(v1).toValue();
|
||||
c9x.val2 = er9xToSwitch(v2).toValue();
|
||||
}
|
||||
|
||||
return c9x;
|
||||
}
|
||||
|
||||
Ersky9xLogicalSwitchData_v11::operator LogicalSwitchData ()
|
||||
{
|
||||
LogicalSwitchData c9x;
|
||||
c9x.func = func;
|
||||
c9x.val1 = v1;
|
||||
c9x.val2 = v2;
|
||||
|
||||
if ((c9x.func >= LS_FN_VPOS && c9x.func <= LS_FN_ANEG) || c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val1 = ersky9xToSource_v11(v1).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_EQUAL) {
|
||||
c9x.val2 = ersky9xToSource_v11(v2).toValue();
|
||||
}
|
||||
|
||||
if (c9x.func >= LS_FN_AND && c9x.func <= LS_FN_XOR) {
|
||||
c9x.val1 = er9xToSwitch(v1).toValue();
|
||||
c9x.val2 = er9xToSwitch(v2).toValue();
|
||||
}
|
||||
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xSafetySwData_v10::t_Ersky9xSafetySwData_v10()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xSafetySwData_v10));
|
||||
}
|
||||
|
||||
t_Ersky9xSafetySwData_v11::t_Ersky9xSafetySwData_v11()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xSafetySwData_v11));
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyChannelData_v10::t_Ersky9xFrSkyChannelData_v10()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xFrSkyChannelData_v10));
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyChannelData_v10::operator FrSkyChannelData ()
|
||||
{
|
||||
FrSkyChannelData c9x;
|
||||
c9x.ratio = ratio;
|
||||
c9x.alarms[0].value = alarms_value[0];
|
||||
c9x.alarms[0].level = alarms_level & 3;
|
||||
c9x.alarms[0].greater = alarms_greater & 1;
|
||||
c9x.alarms[1].value = alarms_value[1];
|
||||
c9x.alarms[1].level = (alarms_level >> 2) & 3;
|
||||
c9x.alarms[1].greater = (alarms_greater >> 1) & 1;
|
||||
if (type==2) {
|
||||
c9x.type = 0;
|
||||
c9x.multiplier=1;
|
||||
} else {
|
||||
c9x.type = type;
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyChannelData_v11::t_Ersky9xFrSkyChannelData_v11()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xFrSkyChannelData_v11));
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyChannelData_v11::operator FrSkyChannelData ()
|
||||
{
|
||||
FrSkyChannelData c9x;
|
||||
c9x.ratio = ratio;
|
||||
c9x.alarms[0].value = alarms_value[0];
|
||||
c9x.alarms[0].level = alarms_level & 3;
|
||||
c9x.alarms[0].greater = alarms_greater & 1;
|
||||
c9x.alarms[1].value = alarms_value[1];
|
||||
c9x.alarms[1].level = (alarms_level >> 2) & 3;
|
||||
c9x.alarms[1].greater = (alarms_greater >> 1) & 1;
|
||||
if (type==2) {
|
||||
c9x.type = 0;
|
||||
c9x.multiplier=1;
|
||||
} else {
|
||||
c9x.type = type;
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyData_v10::t_Ersky9xFrSkyData_v10()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xFrSkyData_v10));
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyData_v10::operator FrSkyData ()
|
||||
{
|
||||
FrSkyData c9x;
|
||||
c9x.channels[0] = channels[0];
|
||||
c9x.channels[1] = channels[1];
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyData_v11::t_Ersky9xFrSkyData_v11()
|
||||
{
|
||||
memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xFrSkyData_v11));
|
||||
}
|
||||
|
||||
t_Ersky9xFrSkyData_v11::operator FrSkyData ()
|
||||
{
|
||||
FrSkyData c9x;
|
||||
c9x.channels[0] = channels[0];
|
||||
c9x.channels[1] = channels[1];
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xModelData_v10::operator ModelData ()
|
||||
{
|
||||
ModelData c9x;
|
||||
c9x.used = true;
|
||||
getEEPROMString(c9x.name, name, sizeof(name));
|
||||
for (int i=0; i<2; i++) {
|
||||
c9x.timers[i].mode = timer[i].tmrModeA < 4 ? timer[i].tmrModeA : 0;
|
||||
c9x.timers[i].val = timer[i].tmrVal;
|
||||
}
|
||||
switch(protocol) {
|
||||
case 1:
|
||||
c9x.moduleData[0].protocol = PULSES_PXX_DJT;
|
||||
break;
|
||||
case 2:
|
||||
c9x.moduleData[0].protocol = PULSES_DSM2;
|
||||
break;
|
||||
case 3:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM16;
|
||||
break;
|
||||
default:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM;
|
||||
break;
|
||||
}
|
||||
c9x.moduleData[0].ppm.frameLength=ppmFrameLength;
|
||||
c9x.moduleData[0].channelsCount = 8 + 2 * ppmNCH;
|
||||
c9x.thrTrim = thrTrim;
|
||||
c9x.trimInc = trimInc-2;
|
||||
c9x.moduleData[0].ppm.delay = 300 + 50 * ppmDelay;
|
||||
c9x.customFn[0].func = FuncInstantTrim;
|
||||
if (trimSw) {
|
||||
c9x.customFn[0].swtch = er9xToSwitch(trimSw);
|
||||
}
|
||||
c9x.beepANACenter = beepANACenter;
|
||||
c9x.moduleData[0].ppm.pulsePol = pulsePol;
|
||||
c9x.extendedLimits = extendedLimits;
|
||||
c9x.swashRingData.elevatorWeight = swashInvertELE ? -100 : 100;
|
||||
c9x.swashRingData.aileronWeight = swashInvertAIL ? -100 : 100;
|
||||
c9x.swashRingData.collectiveWeight = swashInvertCOL ? -100 : 100;
|
||||
c9x.swashRingData.type = swashType;
|
||||
c9x.swashRingData.collectiveSource = ersky9xToSource_v10(swashCollectiveSource);
|
||||
c9x.swashRingData.value = swashRingValue;
|
||||
for (int i=0; i<ERSKY9X_MAX_MIXERS_V10; i++)
|
||||
c9x.mixData[i] = mixData[i];
|
||||
for (int i=0; i<ERSKY9X_NUM_CHNOUT_V10; i++)
|
||||
c9x.limitData[i] = limitData[i];
|
||||
|
||||
// expoData
|
||||
int e = 0;
|
||||
for (int ch = 0; ch < 4 && e < CPN_MAX_EXPOS; ch++) {
|
||||
for (int dr = 0, pos = 0; dr < 3 && e < CPN_MAX_EXPOS; dr++, pos++) {
|
||||
if ((dr == 0 && !expoData[ch].drSw1) || (dr == 1 && !expoData[ch].drSw2))
|
||||
dr = 2;
|
||||
if (dr == 2 && !expoData[ch].expo[0][0][0] && !expoData[ch].expo[0][0][1] && !expoData[ch].expo[0][1][0] && !expoData[ch].expo[0][1][1])
|
||||
break;
|
||||
if (expoData[ch].drSw1 && !expoData[ch].drSw2) {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? expoData[ch].drSw1 : 0);
|
||||
pos = dr == 0 ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? -expoData[ch].drSw1 : (dr == 1 ? -expoData[ch].drSw2 : 0));
|
||||
}
|
||||
c9x.expoData[e].chn = ch;
|
||||
if (expoData[ch].expo[pos][0][0]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][0];
|
||||
}
|
||||
c9x.expoData[e].weight = 100 + expoData[ch].expo[pos][1][0];
|
||||
if (expoData[ch].expo[pos][0][0] == expoData[ch].expo[pos][0][1] && expoData[ch].expo[pos][1][0] == expoData[ch].expo[pos][1][1]) {
|
||||
c9x.expoData[e++].mode = 3;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].mode = 2;
|
||||
if (e < CPN_MAX_EXPOS - 1) {
|
||||
c9x.expoData[e + 1].swtch = c9x.expoData[e].swtch;
|
||||
c9x.expoData[++e].chn = ch;
|
||||
c9x.expoData[e].mode = 1;
|
||||
if (expoData[ch].expo[pos][0][1]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][1];
|
||||
}
|
||||
c9x.expoData[e++].weight = 100 + expoData[ch].expo[pos][1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++)
|
||||
c9x.flightModeData[0].trim[i] = trim[i];
|
||||
|
||||
for (int i=0; i<ERSKY9X_MAX_CURVE5; i++) {
|
||||
c9x.curves[i].count = 5;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
c9x.curves[i].points[j].x = -100 + 50 * i;
|
||||
c9x.curves[i].points[j].y = curves5[i][j];
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ERSKY9X_MAX_CURVE9; i++) {
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].count = 9;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].points[j].x = -100 + 25 * i;
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].points[j].y = curves9[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<ERSKY9X_NUM_CSW_V10; i++)
|
||||
c9x.logicalSw[i] = logicalSw[i];
|
||||
|
||||
// for (int i=0; i<ERSKY9X_NUM_CHNOUT_V10; i++)
|
||||
// c9x.safetySw[i] = safetySw[i];
|
||||
|
||||
c9x.frsky = frsky;
|
||||
c9x.frsky.usrProto=FrSkyUsrProto;
|
||||
return c9x;
|
||||
}
|
||||
|
||||
t_Ersky9xModelData_v11::operator ModelData ()
|
||||
{
|
||||
ModelData c9x;
|
||||
c9x.used = true;
|
||||
getEEPROMString(c9x.name, name, sizeof(name));
|
||||
for (int i=0; i<2; i++) {
|
||||
c9x.timers[i].mode = timer[i].tmrModeA < 4 ? timer[i].tmrModeA : 0;
|
||||
c9x.timers[i].val = timer[i].tmrVal;
|
||||
}
|
||||
switch(protocol) {
|
||||
case 1:
|
||||
c9x.moduleData[0].protocol = PULSES_PXX_DJT;
|
||||
break;
|
||||
case 2:
|
||||
c9x.moduleData[0].protocol = PULSES_DSM2;
|
||||
break;
|
||||
case 3:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM16;
|
||||
break;
|
||||
default:
|
||||
c9x.moduleData[0].protocol = PULSES_PPM;
|
||||
break;
|
||||
}
|
||||
c9x.moduleData[0].ppm.frameLength=ppmFrameLength;
|
||||
c9x.moduleData[0].channelsCount = 8 + 2 * ppmNCH;
|
||||
c9x.thrTrim = thrTrim;
|
||||
c9x.trimInc = trimInc-2;
|
||||
c9x.moduleData[0].ppm.delay = 300 + 50 * ppmDelay;
|
||||
c9x.customFn[0].func = FuncInstantTrim;
|
||||
if (trimSw) {
|
||||
c9x.customFn[0].swtch = er9xToSwitch(trimSw);
|
||||
}
|
||||
c9x.beepANACenter = beepANACenter;
|
||||
c9x.moduleData[0].ppm.pulsePol = pulsePol;
|
||||
c9x.extendedLimits = extendedLimits;
|
||||
c9x.swashRingData.elevatorWeight = swashInvertELE ? -100 : 100;
|
||||
c9x.swashRingData.aileronWeight = swashInvertAIL ? -100 : 100;
|
||||
c9x.swashRingData.collectiveWeight = swashInvertCOL ? -100 : 100;
|
||||
c9x.swashRingData.type = swashType;
|
||||
c9x.swashRingData.collectiveSource = ersky9xToSource_v11(swashCollectiveSource);
|
||||
c9x.swashRingData.value = swashRingValue;
|
||||
for (int i=0; i<ERSKY9X_MAX_MIXERS_V11; i++)
|
||||
c9x.mixData[i] = mixData[i];
|
||||
for (int i=0; i<ERSKY9X_NUM_CHNOUT_V11; i++)
|
||||
c9x.limitData[i] = limitData[i];
|
||||
|
||||
// expoData
|
||||
int e = 0;
|
||||
for (int ch = 0; ch < 4 && e < CPN_MAX_EXPOS; ch++) {
|
||||
for (int dr = 0, pos = 0; dr < 3 && e < CPN_MAX_EXPOS; dr++, pos++) {
|
||||
if ((dr == 0 && !expoData[ch].drSw1) || (dr == 1 && !expoData[ch].drSw2))
|
||||
dr = 2;
|
||||
if (dr == 2 && !expoData[ch].expo[0][0][0] && !expoData[ch].expo[0][0][1] && !expoData[ch].expo[0][1][0] && !expoData[ch].expo[0][1][1])
|
||||
break;
|
||||
if (expoData[ch].drSw1 && !expoData[ch].drSw2) {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? expoData[ch].drSw1 : 0);
|
||||
pos = dr == 0 ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].swtch = er9xToSwitch(dr == 0 ? -expoData[ch].drSw1 : (dr == 1 ? -expoData[ch].drSw2 : 0));
|
||||
}
|
||||
c9x.expoData[e].chn = ch;
|
||||
if (expoData[ch].expo[pos][0][0]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][0];
|
||||
}
|
||||
c9x.expoData[e].weight = 100 + expoData[ch].expo[pos][1][0];
|
||||
if (expoData[ch].expo[pos][0][0] == expoData[ch].expo[pos][0][1] && expoData[ch].expo[pos][1][0] == expoData[ch].expo[pos][1][1]) {
|
||||
c9x.expoData[e++].mode = 3;
|
||||
}
|
||||
else {
|
||||
c9x.expoData[e].mode = 2;
|
||||
if (e < CPN_MAX_EXPOS - 1) {
|
||||
c9x.expoData[e + 1].swtch = c9x.expoData[e].swtch;
|
||||
c9x.expoData[++e].chn = ch;
|
||||
c9x.expoData[e].mode = 1;
|
||||
if (expoData[ch].expo[pos][0][1]) {
|
||||
c9x.expoData[e].curve.type = CurveReference::CURVE_REF_EXPO;
|
||||
c9x.expoData[e].curve.value = expoData[ch].expo[pos][0][1];
|
||||
}
|
||||
c9x.expoData[e++].weight = 100 + expoData[ch].expo[pos][1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<CPN_MAX_STICKS; i++)
|
||||
c9x.flightModeData[0].trim[i] = trim[i];
|
||||
|
||||
for (int i=0; i<ERSKY9X_MAX_CURVE5; i++) {
|
||||
c9x.curves[i].count = 5;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
c9x.curves[i].points[j].x = -100 + 50 * i;
|
||||
c9x.curves[i].points[j].y = curves5[i][j];
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ERSKY9X_MAX_CURVE9; i++) {
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].count = 9;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].points[j].x = -100 + 25 * i;
|
||||
c9x.curves[ERSKY9X_MAX_CURVE5 + i].points[j].y = curves9[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<ERSKY9X_NUM_CSW_V11; i++)
|
||||
c9x.logicalSw[i] = logicalSw[i];
|
||||
|
||||
c9x.frsky = frsky;
|
||||
c9x.frsky.usrProto=FrSkyUsrProto;
|
||||
for (int i=0; i<5;i++) {
|
||||
c9x.flightModeData[0].gvars[i]=gvars[i].gvar;
|
||||
}
|
||||
return c9x;
|
||||
}
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _ERSKY9XEEPROM_H_
|
||||
#define _ERSKY9XEEPROM_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "eeprominterface.h"
|
||||
|
||||
extern RawSwitch getEr9xTimerMode(int mode);
|
||||
|
||||
//eeprom data
|
||||
#define ERSKY9X_MAX_MIXERS_V10 32
|
||||
#define ERSKY9X_MAX_MIXERS_V11 48
|
||||
#define ERSKY9X_MAX_CURVE5 8
|
||||
#define ERSKY9X_MAX_CURVE9 8
|
||||
#define ERSKY9X_MAX_CSFUNC 13
|
||||
|
||||
#define ERSKY9X_MDVERS10 10
|
||||
#define ERSKY9X_MDVERS11 11
|
||||
|
||||
#define ERSKY9X_GENERAL_OWNER_NAME_LEN 10
|
||||
#define ERSKY9X_NUM_CHNOUT_V10 16 //number of real outputchannels CH1-CH8
|
||||
#define ERSKY9X_NUM_CHNOUT_V11 24 //number of real outputchannels CH1-CH8
|
||||
#define ERSKY9X_NUM_CSW_V10 12 //number of custom switches
|
||||
#define ERSKY9X_NUM_CSW_V11 24
|
||||
#define ERSKY9X_NUM_FSW 16
|
||||
#define ERSKY9X_NUM_VOICE 8
|
||||
#define ERSKY9X_MAX_GVARS 7
|
||||
|
||||
#define CPN_MAX_STICKSnPOTS 7 //number of sticks and pots
|
||||
|
||||
PACK(typedef struct t_Ersky9xTrainerMix {
|
||||
uint8_t srcChn:3; //0-7 = ch1-8
|
||||
int8_t swtch:5;
|
||||
int8_t studWeight:6;
|
||||
uint8_t mode:2; // off, add-mode, subst-mode
|
||||
|
||||
operator TrainerMix();
|
||||
t_Ersky9xTrainerMix();
|
||||
}) Ersky9xTrainerMix; //
|
||||
|
||||
PACK(typedef struct t_Ersky9xTrainerData {
|
||||
int16_t calib[4];
|
||||
Ersky9xTrainerMix mix[4];
|
||||
|
||||
operator TrainerData();
|
||||
t_Ersky9xTrainerData();
|
||||
}) Ersky9xTrainerData;
|
||||
|
||||
PACK(typedef struct t_Ersky9xGeneral {
|
||||
uint8_t myVers;
|
||||
int16_t calibMid[CPN_MAX_STICKSnPOTS];
|
||||
int16_t calibSpanNeg[CPN_MAX_STICKSnPOTS];
|
||||
int16_t calibSpanPos[CPN_MAX_STICKSnPOTS];
|
||||
uint16_t chkSum;
|
||||
uint8_t currModel; //0..15
|
||||
uint8_t contrast;
|
||||
uint8_t vBatWarn;
|
||||
int8_t txVoltageCalibration;
|
||||
int8_t lightSw;
|
||||
Ersky9xTrainerData trainer;
|
||||
uint8_t view;
|
||||
uint8_t disableThrottleWarning:1;
|
||||
uint8_t disableSwitchWarning:1;
|
||||
uint8_t disableMemoryWarning:1;
|
||||
uint8_t beeperVal:3;
|
||||
uint8_t reserveWarning:1;
|
||||
uint8_t disableAlarmWarning:1;
|
||||
uint8_t stickMode;
|
||||
int8_t inactivityTimer;
|
||||
uint8_t throttleReversed:1;
|
||||
uint8_t minuteBeep:1;
|
||||
uint8_t preBeep:1;
|
||||
uint8_t alarmsFlash:1;
|
||||
uint8_t disableSplashScreen:1;
|
||||
uint8_t disablePotScroll:1;
|
||||
uint8_t disableBG:1;
|
||||
uint8_t res1:1;
|
||||
uint8_t filterInput;
|
||||
uint8_t lightAutoOff;
|
||||
uint8_t templateSetup; //RETA order according to chout_ar array
|
||||
int8_t PPM_Multiplier;
|
||||
uint8_t FRSkyYellow:4;
|
||||
uint8_t FRSkyOrange:4;
|
||||
uint8_t FRSkyRed:4; //mike please check these are correct
|
||||
uint8_t hideNameOnSplash:1;
|
||||
uint8_t optrexDisplay:1;
|
||||
uint8_t spare:2;
|
||||
uint8_t speakerPitch;
|
||||
uint8_t hapticStrength;
|
||||
uint8_t speakerMode;
|
||||
uint8_t lightOnStickMove;
|
||||
|
||||
char ownerName[10];
|
||||
uint8_t switchWarningStates;
|
||||
uint8_t volume ;
|
||||
uint8_t bright ; // backlight
|
||||
uint8_t stickGain;
|
||||
uint8_t mAh_alarm ;
|
||||
uint16_t mAh_used ;
|
||||
uint16_t run_time ;
|
||||
int8_t current_calib ;
|
||||
uint8_t bt_baudrate ;
|
||||
uint8_t rotaryDivisor ;
|
||||
operator GeneralSettings();
|
||||
t_Ersky9xGeneral();
|
||||
}) Ersky9xGeneral;
|
||||
|
||||
PACK(typedef struct t_Ersky9xExpoData {
|
||||
int8_t expo[3][2][2];
|
||||
int8_t drSw1;
|
||||
int8_t drSw2;
|
||||
|
||||
t_Ersky9xExpoData() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xExpoData)); }
|
||||
}) Ersky9xExpoData;
|
||||
|
||||
|
||||
PACK(typedef struct t_Ersky9xLimitData {
|
||||
int8_t min;
|
||||
int8_t max;
|
||||
bool revert;
|
||||
int16_t offset;
|
||||
|
||||
operator LimitData();
|
||||
t_Ersky9xLimitData() ;
|
||||
}) Ersky9xLimitData;
|
||||
|
||||
#define MLTPX_ADD 0
|
||||
#define MLTPX_MUL 1
|
||||
#define MLTPX_REP 2
|
||||
|
||||
PACK(typedef struct t_Ersky9xMixData_v10 {
|
||||
uint8_t destCh; // 1..CPN_MAX_CHNOUT
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; //0=symmetrisch 1=no neg 2=no pos
|
||||
uint8_t delayUp:4;
|
||||
uint8_t delayDown:4;
|
||||
uint8_t speedUp:4; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown:4; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
uint8_t mltpx:3; // multiplex method 0=+ 1=* 2=replace
|
||||
uint8_t mixWarn:2; // mixer warning
|
||||
uint8_t enableFmTrim:1;
|
||||
uint8_t mixres:1;
|
||||
int8_t sOffset;
|
||||
int8_t res;
|
||||
|
||||
operator MixData();
|
||||
t_Ersky9xMixData_v10();
|
||||
}) Ersky9xMixData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xMixData_v11 {
|
||||
uint8_t destCh; // 1..CPN_MAX_CHNOUT
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; //0=symmetrisch 1=no neg 2=no pos
|
||||
uint8_t delayUp;
|
||||
uint8_t delayDown;
|
||||
uint8_t speedUp; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
uint8_t mltpx:3; // multiplex method 0=+ 1=* 2=replace
|
||||
uint8_t mixWarn:2; // mixer warning
|
||||
uint8_t enableFmTrim:1;
|
||||
uint8_t mixres:1;
|
||||
int8_t sOffset;
|
||||
uint8_t res[4];
|
||||
operator MixData();
|
||||
t_Ersky9xMixData_v11();
|
||||
}) Ersky9xMixData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xLogicalSwitchData_v10 { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func;
|
||||
|
||||
operator LogicalSwitchData();
|
||||
t_Ersky9xLogicalSwitchData_v10() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xLogicalSwitchData_v10)); }
|
||||
}) Ersky9xLogicalSwitchData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xLogicalSwitchData_v11 { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func;
|
||||
uint8_t andsw;
|
||||
uint8_t res ;
|
||||
|
||||
operator LogicalSwitchData();
|
||||
t_Ersky9xLogicalSwitchData_v11() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xLogicalSwitchData_v11)); }
|
||||
}) Ersky9xLogicalSwitchData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xSafetySwData_v10 { // Custom Switches data
|
||||
int8_t swtch;
|
||||
int8_t val;
|
||||
|
||||
t_Ersky9xSafetySwData_v10();
|
||||
}) Ersky9xSafetySwData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xSafetySwData_v11 { // Custom Switches data
|
||||
union opt {
|
||||
struct ss {
|
||||
int8_t swtch ;
|
||||
uint8_t mode ;
|
||||
int8_t val ;
|
||||
uint8_t res ;
|
||||
} ss ;
|
||||
struct vs {
|
||||
uint8_t vswtch ;
|
||||
uint8_t vmode ; // ON, OFF, BOTH, 15Secs, 30Secs, 60Secs, Varibl
|
||||
uint8_t vval;
|
||||
uint8_t vres ;
|
||||
} vs ;
|
||||
} opt ;
|
||||
|
||||
t_Ersky9xSafetySwData_v11();
|
||||
}) Ersky9xSafetySwData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xgvar {
|
||||
int8_t gvar ;
|
||||
uint8_t gvsource ;
|
||||
// int8_t gvswitch ;
|
||||
}) Ersky9xGvarData ;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFlightModeData {
|
||||
int16_t trim[4]; // -500..500 => trim value, 501 => use trim of phase 0, 502, 503, 504 => use trim of phases 1|2|3|4 instead
|
||||
int8_t swtch; // swtch of phase[0] is not used
|
||||
char name[6];
|
||||
uint8_t fadeIn:4;
|
||||
uint8_t fadeOut:4;
|
||||
uint16_t spare ; // Future expansion
|
||||
}) Ersky9xFlightModeData;
|
||||
|
||||
PACK(typedef struct t_Ersky9xCustomFunctionData { // Function Switches data
|
||||
int8_t swtch; //input
|
||||
uint8_t func;
|
||||
char param[6];
|
||||
uint8_t delay;
|
||||
uint8_t spare;
|
||||
}) Ersky9xCustomFunctionData;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyChannelData_v10 {
|
||||
uint8_t ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_value[2]; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_level:4;
|
||||
uint8_t alarms_greater:2; // 0=LT(<), 1=GT(>)
|
||||
uint8_t type:2; // future use: 0=volts, ...
|
||||
|
||||
operator FrSkyChannelData();
|
||||
t_Ersky9xFrSkyChannelData_v10();
|
||||
}) Ersky9xFrSkyChannelData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyData_v10 {
|
||||
Ersky9xFrSkyChannelData_v10 channels[2];
|
||||
|
||||
operator FrSkyData();
|
||||
t_Ersky9xFrSkyData_v10();
|
||||
}) Ersky9xFrSkyData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyChannelData_v11 {
|
||||
uint8_t ratio ; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t offset ; //
|
||||
uint8_t gain ; //
|
||||
uint8_t alarms_value[2] ; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_level ;
|
||||
uint8_t alarms_greater ; // 0=LT(<), 1=GT(>)
|
||||
uint8_t type ; // 0=volts, 1=raw, 2=volts*2, 3=Amps
|
||||
|
||||
operator FrSkyChannelData();
|
||||
t_Ersky9xFrSkyChannelData_v11();
|
||||
}) Ersky9xFrSkyChannelData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyData_v11 {
|
||||
Ersky9xFrSkyChannelData_v11 channels[2];
|
||||
|
||||
operator FrSkyData();
|
||||
t_Ersky9xFrSkyData_v11();
|
||||
}) Ersky9xFrSkyData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyalarms_v11 {
|
||||
uint8_t frskyAlarmType ;
|
||||
uint8_t frskyAlarmLimit ;
|
||||
uint8_t frskyAlarmSound ;
|
||||
}) Ersky9xFrSkyAlData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xFrSkyAlarmData_v11 {
|
||||
Ersky9xFrSkyAlData_v11 alarmData[8] ;
|
||||
}) Ersky9xFrSkyAlarmData_v11;
|
||||
|
||||
PACK(typedef struct t_Ersky9xTimerMode_v10 {
|
||||
uint8_t tmrModeA:7 ; // timer trigger source -> off, abs, stk, stk%, cx%
|
||||
uint8_t tmrDir:1 ; // Timer direction
|
||||
int8_t tmrModeB ; // timer trigger source -> !sw, none, sw, m_sw
|
||||
uint16_t tmrVal ;
|
||||
}) Ersky9xTimerMode_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xTimerMode_v11 {
|
||||
uint8_t tmrModeA:7 ; // timer trigger source -> off, abs, stk, stk%, cx%
|
||||
uint8_t tmrDir:1 ; // Timer direction
|
||||
int8_t tmrModeB ; // timer trigger source -> !sw, none, sw, m_sw
|
||||
uint16_t tmrVal ;
|
||||
}) Ersky9xTimerMode_v11;
|
||||
|
||||
PACK(typedef struct te_Ersky9xswVoice {
|
||||
uint8_t swtch ;
|
||||
uint8_t mode ; // ON, OFF, BOTH, 15Secs, 30Secs, 60Secs
|
||||
uint8_t val ;
|
||||
uint8_t vres ;
|
||||
}) Ersky9xvoiceSwData ;
|
||||
|
||||
PACK(typedef struct t_Ersky9xModelData_v10 {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
uint8_t reserved_spare; //used to be MDVERS - now depreciated
|
||||
int8_t spare21; // was timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
|
||||
// uint8_t sparex:1; // was tmrDir, now use tmrVal>0 => count down
|
||||
uint8_t sparex:1; // was tmrDir, now use tmrVal>0 => count down
|
||||
// uint8_t tmrDir:1; // was tmrDir, now use tmrVal>0 => count down
|
||||
uint8_t traineron:1; // 0 disable trainer, 1 allow trainer
|
||||
uint8_t spare22:1 ; // Start timer2 using throttle
|
||||
uint8_t FrSkyUsrProto:1 ; // Protocol in FrSky User Data, 0=FrSky Hub, 1=WS HowHigh
|
||||
uint8_t FrSkyGpsAlt:1 ; // Use Gps Altitude as main altitude reading
|
||||
uint8_t FrSkyImperial:1 ; // Convert FrSky values to imperial units
|
||||
uint8_t FrSkyAltAlarm:2;
|
||||
uint16_t spare_u16 ; // Was timerval
|
||||
uint8_t protocol;
|
||||
int8_t ppmNCH;
|
||||
int8_t thrTrim:4; // Enable Throttle Trim
|
||||
int8_t thrExpo:4; // Enable Throttle Expo
|
||||
int8_t trimInc; // Trim Increments
|
||||
int8_t ppmDelay;
|
||||
int8_t trimSw;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
uint8_t pulsePol:1;
|
||||
uint8_t extendedLimits:1;
|
||||
uint8_t swashInvertELE:1;
|
||||
uint8_t swashInvertAIL:1;
|
||||
uint8_t swashInvertCOL:1;
|
||||
uint8_t swashType:3;
|
||||
uint8_t swashCollectiveSource;
|
||||
uint8_t swashRingValue;
|
||||
int8_t ppmFrameLength; //0=22.5 (10msec-30msec) 0.5msec increments
|
||||
Ersky9xMixData_v10 mixData[ERSKY9X_MAX_MIXERS_V10];
|
||||
Ersky9xLimitData limitData[ERSKY9X_NUM_CHNOUT_V10];
|
||||
Ersky9xExpoData expoData[4];
|
||||
int8_t trim[4];
|
||||
int8_t curves5[ERSKY9X_MAX_CURVE5][5];
|
||||
int8_t curves9[ERSKY9X_MAX_CURVE9][9];
|
||||
Ersky9xLogicalSwitchData_v10 logicalSw[ERSKY9X_NUM_CSW_V10];
|
||||
uint8_t frSkyVoltThreshold ;
|
||||
uint8_t res3[2];
|
||||
Ersky9xSafetySwData_v10 safetySw[ERSKY9X_NUM_CHNOUT_V10];
|
||||
Ersky9xFrSkyData_v10 frsky;
|
||||
Ersky9xTimerMode_v10 timer[2] ;
|
||||
operator ModelData();
|
||||
t_Ersky9xModelData_v10() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xModelData_v10)); }
|
||||
}) Ersky9xModelData_v10;
|
||||
|
||||
PACK(typedef struct t_Ersky9xModelData_v11 {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
uint8_t modelVoice ; // Index to model name voice (261+value)
|
||||
uint8_t RxNum ; // was timer trigger source, now RxNum for model match
|
||||
uint8_t sparex:1; // was tmrDir, now use tmrVal>0 => count down
|
||||
uint8_t traineron:1; // 0 disable trainer, 1 allow trainer
|
||||
uint8_t spare22:1 ; // Start timer2 using throttle
|
||||
uint8_t FrSkyUsrProto:1 ; // Protocol in FrSky User Data, 0=FrSky Hub, 1=WS HowHigh
|
||||
uint8_t FrSkyGpsAlt:1 ; // Use Gps Altitude as main altitude reading
|
||||
uint8_t FrSkyImperial:1 ; // Convert FrSky values to imperial units
|
||||
uint8_t FrSkyAltAlarm:2;
|
||||
uint8_t version ;
|
||||
uint8_t protocol;
|
||||
int8_t ppmNCH;
|
||||
uint8_t thrTrim:1; // Enable Throttle Trim
|
||||
uint8_t numBlades:2; // RPM scaling
|
||||
uint8_t spare10:1;
|
||||
uint8_t thrExpo:1; // Enable Throttle Expo
|
||||
uint8_t spare11:3;
|
||||
int8_t trimInc; // Trim Increments
|
||||
int8_t ppmDelay;
|
||||
int8_t trimSw;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
uint8_t pulsePol:1;
|
||||
uint8_t extendedLimits:1;
|
||||
uint8_t swashInvertELE:1;
|
||||
uint8_t swashInvertAIL:1;
|
||||
uint8_t swashInvertCOL:1;
|
||||
uint8_t swashType:3;
|
||||
uint8_t swashCollectiveSource;
|
||||
uint8_t swashRingValue;
|
||||
int8_t ppmFrameLength; //0=22.5 (10msec-30msec) 0.5msec increments
|
||||
Ersky9xMixData_v11 mixData[ERSKY9X_MAX_MIXERS_V11];
|
||||
Ersky9xLimitData limitData[ERSKY9X_NUM_CHNOUT_V11];
|
||||
Ersky9xExpoData expoData[4];
|
||||
int8_t trim[4];
|
||||
int8_t curves5[ERSKY9X_MAX_CURVE5][5];
|
||||
int8_t curves9[ERSKY9X_MAX_CURVE9][9];
|
||||
int8_t curvexy[18];
|
||||
Ersky9xLogicalSwitchData_v11 logicalSw[ERSKY9X_NUM_CSW_V11];
|
||||
uint8_t frSkyVoltThreshold ;
|
||||
uint8_t bt_telemetry;
|
||||
uint8_t numVoice; // 0-16, rest are Safety switches
|
||||
Ersky9xSafetySwData_v11 safetySw[ERSKY9X_NUM_CHNOUT_V11];
|
||||
Ersky9xvoiceSwData voiceSwitches[ERSKY9X_NUM_VOICE] ;
|
||||
Ersky9xFrSkyData_v11 frsky;
|
||||
Ersky9xTimerMode_v11 timer[2] ;
|
||||
Ersky9xFrSkyAlarmData_v11 frskyAlarms ;
|
||||
// Add 6 bytes for custom telemetry screen
|
||||
uint8_t customDisplayIndex[6] ;
|
||||
Ersky9xCustomFunctionData customFn[ERSKY9X_NUM_FSW];
|
||||
Ersky9xFlightModeData flightModeData[6] ;
|
||||
Ersky9xGvarData gvars[ERSKY9X_MAX_GVARS] ;
|
||||
|
||||
operator ModelData();
|
||||
t_Ersky9xModelData_v11() { memset(reinterpret_cast<void *>(this), 0, sizeof(t_Ersky9xModelData_v11)); }
|
||||
}) Ersky9xModelData_v11;
|
||||
|
||||
#endif // _ERSKY9XEEPROM_H_
|
||||
@@ -1,395 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 "ersky9xinterface.h"
|
||||
#include "ersky9xeeprom.h"
|
||||
#include "rlefile.h"
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
||||
/// fileId of general file
|
||||
#define FILE_GENERAL 0
|
||||
/// convert model number 0..MAX_MODELS-1 int fileId
|
||||
#define FILE_MODEL(n) (1+n)
|
||||
#define FILE_TMP (1+16)
|
||||
|
||||
Ersky9xInterface::Ersky9xInterface():
|
||||
EEPROMInterface(Board::BOARD_SKY9X),
|
||||
efile(new RleFile())
|
||||
{
|
||||
}
|
||||
|
||||
Ersky9xInterface::~Ersky9xInterface()
|
||||
{
|
||||
delete efile;
|
||||
}
|
||||
|
||||
const char * Ersky9xInterface::getName()
|
||||
{
|
||||
return "Ersky9x";
|
||||
}
|
||||
|
||||
inline void applyStickModeToModel(Ersky9xModelData_v10 & model, unsigned int mode)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
int stick = applyStickMode(i+1, mode) - 1;
|
||||
{
|
||||
int tmp = model.trim[i];
|
||||
model.trim[i] = model.trim[stick];
|
||||
model.trim[stick] = tmp;
|
||||
}
|
||||
{
|
||||
Ersky9xExpoData tmp = model.expoData[i];
|
||||
model.expoData[i] = model.expoData[stick];
|
||||
model.expoData[stick] = tmp;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ERSKY9X_MAX_MIXERS_V10; i++)
|
||||
model.mixData[i].srcRaw = applyStickMode(model.mixData[i].srcRaw, mode);
|
||||
for (int i=0; i<ERSKY9X_NUM_CSW_V10; i++) {
|
||||
switch (LogicalSwitchData(model.logicalSw[i].func).getFunctionFamily()) {
|
||||
case LS_FAMILY_VCOMP:
|
||||
model.logicalSw[i].v2 = applyStickMode(model.logicalSw[i].v2, mode);
|
||||
// no break
|
||||
case LS_FAMILY_VOFS:
|
||||
model.logicalSw[i].v1 = applyStickMode(model.logicalSw[i].v1, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
|
||||
}
|
||||
|
||||
inline void applyStickModeToModel(Ersky9xModelData_v11 & model, unsigned int mode)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
int stick = applyStickMode(i+1, mode) - 1;
|
||||
{
|
||||
int tmp = model.trim[i];
|
||||
model.trim[i] = model.trim[stick];
|
||||
model.trim[stick] = tmp;
|
||||
}
|
||||
{
|
||||
Ersky9xExpoData tmp = model.expoData[i];
|
||||
model.expoData[i] = model.expoData[stick];
|
||||
model.expoData[stick] = tmp;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<ERSKY9X_MAX_MIXERS_V11; i++)
|
||||
model.mixData[i].srcRaw = applyStickMode(model.mixData[i].srcRaw, mode);
|
||||
for (int i=0; i<ERSKY9X_NUM_CSW_V11; i++) {
|
||||
switch (LogicalSwitchData(model.logicalSw[i].func).getFunctionFamily()) {
|
||||
case LS_FAMILY_VCOMP:
|
||||
model.logicalSw[i].v2 = applyStickMode(model.logicalSw[i].v2, mode);
|
||||
// no break
|
||||
case LS_FAMILY_VOFS:
|
||||
model.logicalSw[i].v1 = applyStickMode(model.logicalSw[i].v1, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
model.swashCollectiveSource = applyStickMode(model.swashCollectiveSource, mode);
|
||||
}
|
||||
|
||||
#if 0
|
||||
unsigned long Ersky9xInterface::loadxml(RadioData &radioData, QDomDocument &doc)
|
||||
{
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying ersky9x xml import... ";
|
||||
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
Ersky9xGeneral ersky9xGeneral;
|
||||
memset(&ersky9xGeneral,0,sizeof(ersky9xGeneral));
|
||||
if(!loadRadioSettingsDataXML(&doc, &ersky9xGeneral)) {
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
else {
|
||||
radioData.generalSettings=ersky9xGeneral;
|
||||
dbg << "version " << (unsigned int)ersky9xGeneral.myVers << " ";
|
||||
}
|
||||
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)) {
|
||||
dbg << "ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!loadModelDataXML<Ersky9xModelData_v11>(&doc, &radioData.models[i], i, radioData.generalSettings.stickMode+1)) {
|
||||
dbg << "ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
}
|
||||
}
|
||||
dbg << "ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long Ersky9xInterface::load(RadioData &radioData, const uint8_t *eeprom, int size)
|
||||
{
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying ersky9x import... ";
|
||||
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
if (size != Boards::getEEpromSize(Board::BOARD_SKY9X)) {
|
||||
dbg << "wrong size";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (!efile->EeFsOpen((uint8_t *)eeprom, size, Board::BOARD_SKY9X)) {
|
||||
dbg << "wrong file system";
|
||||
errors.set(WRONG_FILE_SYSTEM);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
efile->openRd(FILE_GENERAL);
|
||||
Ersky9xGeneral ersky9xGeneral;
|
||||
|
||||
if (efile->readRlc2((uint8_t*)&ersky9xGeneral, 1) != 1) {
|
||||
dbg << "no";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
dbg << "version " << (unsigned int)ersky9xGeneral.myVers << " ";
|
||||
|
||||
switch(ersky9xGeneral.myVers) {
|
||||
case 10:
|
||||
break;
|
||||
case 11:
|
||||
break;
|
||||
default:
|
||||
dbg << "not ersky9x";
|
||||
errors.set(NOT_ERSKY9X);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
efile->openRd(FILE_GENERAL);
|
||||
if (!efile->readRlc2((uint8_t*)&ersky9xGeneral, sizeof(Ersky9xGeneral))) {
|
||||
dbg << "ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
radioData.generalSettings = ersky9xGeneral;
|
||||
|
||||
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);
|
||||
if (!size) {
|
||||
radioData.models[i].clear();
|
||||
}
|
||||
else {
|
||||
if (size<720) {
|
||||
Ersky9xModelData_v10 ersky9xModel;
|
||||
memcpy(&ersky9xModel, buffer, sizeof(ersky9xModel));
|
||||
applyStickModeToModel(ersky9xModel, radioData.generalSettings.stickMode+1);
|
||||
radioData.models[i] = ersky9xModel;
|
||||
} else {
|
||||
Ersky9xModelData_v11 ersky9xModel;
|
||||
memcpy(&ersky9xModel, buffer, sizeof(ersky9xModel));
|
||||
applyStickModeToModel(ersky9xModel, radioData.generalSettings.stickMode+1);
|
||||
radioData.models[i] = ersky9xModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbg << "ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
unsigned long Ersky9xInterface::loadBackup(RadioData &radioData, const uint8_t *eeprom, int esize, int index)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
int Ersky9xInterface::getSize(const ModelData & model)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Ersky9xInterface::getSize(const GeneralSettings & settings)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Ersky9xInterface::isAvailable(PulsesProtocol prot, int port)
|
||||
{
|
||||
switch (prot) {
|
||||
case PULSES_PPM:
|
||||
case PULSES_DSM2:
|
||||
case PULSES_PXX_DJT:
|
||||
case PULSES_PPM16:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Ersky9xInterface::appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value)
|
||||
{
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomText t = qdoc->createTextNode(name);
|
||||
t.setNodeValue(value);
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
|
||||
void Ersky9xInterface::appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite)
|
||||
{
|
||||
if(value || forceZeroWrite) {
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomText t = qdoc->createTextNode(name);
|
||||
t.setNodeValue(QString("%1").arg(value));
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Ersky9xInterface::appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size)
|
||||
{
|
||||
QDomElement e = qdoc->createElement(name);
|
||||
QDomCDATASection t = qdoc->createCDATASection(name);
|
||||
t.setData(QByteArray(data, size).toBase64());
|
||||
e.appendChild(t);
|
||||
pe->appendChild(e);
|
||||
}
|
||||
|
||||
QDomElement Ersky9xInterface::getGeneralDataXML(QDomDocument * qdoc, Ersky9xGeneral * tgen)
|
||||
{
|
||||
QDomElement gd = qdoc->createElement("GENERAL_DATA");
|
||||
appendNumberElement(qdoc, &gd, "Version", tgen->myVers, true); // have to write value here
|
||||
appendTextElement(qdoc, &gd, "Owner", QString::fromLatin1(tgen->ownerName,sizeof(tgen->ownerName)).trimmed());
|
||||
appendCDATAElement(qdoc, &gd, "Data", (const char *)tgen,sizeof(Ersky9xGeneral));
|
||||
return gd;
|
||||
}
|
||||
|
||||
QDomElement Ersky9xInterface::getModelDataXML(QDomDocument * qdoc, Ersky9xModelData_v11 * tmod, int modelNum, int mdver)
|
||||
{
|
||||
QDomElement md = qdoc->createElement("MODEL_DATA");
|
||||
md.setAttribute("number", modelNum);
|
||||
appendNumberElement(qdoc, &md, "Version", mdver, true); // have to write value here
|
||||
appendTextElement(qdoc, &md, "Name", QString::fromLatin1(tmod->name,sizeof(tmod->name)).trimmed());
|
||||
appendCDATAElement(qdoc, &md, "Data", (const char *)tmod,sizeof(Ersky9xModelData_v11));
|
||||
return md;
|
||||
}
|
||||
|
||||
bool Ersky9xInterface::loadRadioSettingsDataXML(QDomDocument * qdoc, Ersky9xGeneral * tgen)
|
||||
{
|
||||
// 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
|
||||
QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
QString ds = n.toCDATASection().data();
|
||||
QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
|
||||
const char * data = ba.data();
|
||||
memcpy(tgen, data, std::min((unsigned int)ba.size(), (unsigned int)sizeof(Ersky9xGeneral)));
|
||||
break;
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
// check version?
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Ersky9xInterface::loadModelDataXML(QDomDocument * qdoc, ModelData *model, int modelNum, int stickMode)
|
||||
{
|
||||
T ersky9xModel;
|
||||
memset(&ersky9xModel, 0, sizeof(ersky9xModel));
|
||||
|
||||
// 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
|
||||
QDomNode k = ndl.at(0);
|
||||
if (modelNum>=0) {
|
||||
while(!k.isNull()) {
|
||||
int a = k.toElement().attribute("number").toInt();
|
||||
if(a==modelNum)
|
||||
break;
|
||||
k = k.nextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
if (k.isNull()) // couldn't find
|
||||
return false;
|
||||
|
||||
// load cdata into tgen
|
||||
QDomNode n = k.toElement().elementsByTagName("Data").at(0).firstChild();// get all children in Data
|
||||
while (!n.isNull()) {
|
||||
if (n.isCDATASection()) {
|
||||
QString ds = n.toCDATASection().data();
|
||||
QByteArray ba = QByteArray::fromBase64(ds.toLatin1());
|
||||
const char * data = ba.data();
|
||||
memcpy(&ersky9xModel, data, std::min(ba.size(), (int)sizeof(ersky9xModel)));
|
||||
break;
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
|
||||
applyStickModeToModel(ersky9xModel, stickMode);
|
||||
*model = ersky9xModel;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Ersky9xInterface::getCapability(Capability capability)
|
||||
{
|
||||
switch (capability) {
|
||||
case Models:
|
||||
return 20;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString Ersky9xInterface::getCapabilityStr(Capability capability)
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _ERSKY9XINTERFACE_H_
|
||||
#define _ERSKY9XINTERFACE_H_
|
||||
|
||||
#include <QtXml>
|
||||
#include "eeprominterface.h"
|
||||
#include "ersky9xeeprom.h"
|
||||
|
||||
class RleFile;
|
||||
|
||||
class Ersky9xInterface : public EEPROMInterface
|
||||
{
|
||||
public:
|
||||
|
||||
Ersky9xInterface();
|
||||
|
||||
virtual ~Ersky9xInterface();
|
||||
|
||||
virtual const char * getName();
|
||||
|
||||
|
||||
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 int save(uint8_t * eeprom, const RadioData & radioData, uint8_t version=0, uint32_t variant=0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int getSize(const ModelData &);
|
||||
|
||||
virtual int getSize(const GeneralSettings & settings);
|
||||
|
||||
virtual bool isAvailable(PulsesProtocol proto, int port=0);
|
||||
|
||||
virtual int getCapability(Capability capability);
|
||||
|
||||
virtual QString getCapabilityStr(Capability);
|
||||
|
||||
protected:
|
||||
|
||||
RleFile * efile;
|
||||
|
||||
private:
|
||||
void appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value);
|
||||
|
||||
void appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite = false);
|
||||
|
||||
void appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size);
|
||||
|
||||
QDomElement getGeneralDataXML(QDomDocument * qdoc, Ersky9xGeneral * tgen); //parse out data to XML format
|
||||
|
||||
QDomElement getModelDataXML(QDomDocument * qdoc, Ersky9xModelData_v11 * tmod, int modelNum, int mdver); //parse out data to XML format
|
||||
|
||||
bool loadRadioSettingsDataXML(QDomDocument * qdoc, Ersky9xGeneral * tgen); // get data from XML
|
||||
|
||||
template <class T>
|
||||
bool loadModelDataXML(QDomDocument * qdoc, ModelData * model, int modelNum, int stickMode); // get data from XML
|
||||
|
||||
};
|
||||
|
||||
#endif // _ERSKY9XINTERFACE_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _OPENTXEEPROM_H_
|
||||
#define _OPENTXEEPROM_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "eeprominterface.h"
|
||||
#include "eepromimportexport.h"
|
||||
#include <qbytearray.h>
|
||||
|
||||
#define GVARS_VARIANT 0x0001
|
||||
#define FRSKY_VARIANT 0x0002
|
||||
#define M128_VARIANT 0x8000
|
||||
#define TARANIS_X9E_VARIANT 0x8000
|
||||
#define TARANIS_X7_VARIANT 0x4000
|
||||
#define TARANIS_XLITE_VARIANT 0x2000
|
||||
#define TARANIS_XLITES_VARIANT 0x1000
|
||||
#define TARANIS_X9LITE_VARIANT 0x0800
|
||||
#define TARANIS_X9LITES_VARIANT 0x0801
|
||||
#define JUMPER_T12_VARIANT 0x4001
|
||||
#define RADIOMASTER_TX12_VARIANT 0x4002
|
||||
#define JUMPER_TLITE_VARIANT 0x4003
|
||||
#define RADIOMASTER_T8_VARIANT 0x4004
|
||||
#define JUMPER_TPRO_VARIANT 0x4005
|
||||
#define RADIOMASTER_ZORRO_VARIANT 0x4006
|
||||
#define BETAFPV_LR3PRO_VARIANT 0x4007
|
||||
#define RADIOMASTER_TX12_MK2_VARIANT 0x4008
|
||||
#define IFLIGHT_COMMANDO8_VARIANT 0x4009
|
||||
|
||||
class OpenTxGeneralData: public TransformedField {
|
||||
public:
|
||||
OpenTxGeneralData(GeneralSettings & generalData, Board::Type board, unsigned int version, unsigned int variant=0);
|
||||
|
||||
virtual const QString & getName() { return internalField.getName(); }
|
||||
|
||||
QStringList errors()
|
||||
{
|
||||
return _errors;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void beforeExport();
|
||||
virtual void afterImport();
|
||||
|
||||
virtual void setError(const QString & error)
|
||||
{
|
||||
qWarning() << error;
|
||||
_errors << error;
|
||||
}
|
||||
|
||||
StructField internalField;
|
||||
GeneralSettings & generalData;
|
||||
Board::Type board;
|
||||
unsigned int version;
|
||||
int inputsCount;
|
||||
unsigned int chkSum;
|
||||
QStringList _errors;
|
||||
};
|
||||
|
||||
class ProtocolsConversionTable: public ConversionTable
|
||||
{
|
||||
public:
|
||||
ProtocolsConversionTable(Board::Type board, int version)
|
||||
{
|
||||
int val = 0;
|
||||
addConversion(PULSES_OFF, val++);
|
||||
addConversion(PULSES_PPM, val++);
|
||||
|
||||
addConversion(PULSES_PXX_XJT_X16, val);
|
||||
addConversion(PULSES_PXX_XJT_D8, val);
|
||||
addConversion(PULSES_PXX_XJT_LR12, val++);
|
||||
|
||||
if (version >= 219) {
|
||||
addConversion(PULSES_ACCESS_ISRM, val);
|
||||
addConversion(PULSES_ACCST_ISRM_D16, val++);
|
||||
}
|
||||
|
||||
addConversion(PULSES_LP45, val);
|
||||
addConversion(PULSES_DSM2, val);
|
||||
addConversion(PULSES_DSMX, val++);
|
||||
|
||||
addConversion(PULSES_CROSSFIRE, val++);
|
||||
addConversion(PULSES_MULTIMODULE, val++);
|
||||
|
||||
addConversion(PULSES_PXX_R9M, val++);
|
||||
addConversion(PULSES_ACCESS_R9M, val++);
|
||||
addConversion(PULSES_PXX_R9M_LITE, val++);
|
||||
addConversion(PULSES_ACCESS_R9M_LITE, val++);
|
||||
addConversion(PULSES_GHOST, val++);
|
||||
addConversion(PULSES_ACCESS_R9M_LITE_PRO, val++);
|
||||
|
||||
addConversion(PULSES_SBUS, val++);
|
||||
|
||||
addConversion(PULSES_XJT_LITE_X16, val);
|
||||
addConversion(PULSES_XJT_LITE_D8, val);
|
||||
addConversion(PULSES_XJT_LITE_LR12, val++);
|
||||
}
|
||||
};
|
||||
|
||||
class ChannelsConversionTable: public ConversionTable
|
||||
{
|
||||
public:
|
||||
ChannelsConversionTable()
|
||||
{
|
||||
for (int i=4; i<=16; i+= 2)
|
||||
addConversion(i, -4+i/2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class OpenTxModelData: public TransformedField {
|
||||
public:
|
||||
OpenTxModelData(ModelData & modelData, Board::Type board, unsigned int version, unsigned int variant);
|
||||
|
||||
virtual const QString & getName() { return internalField.getName(); }
|
||||
|
||||
QStringList errors()
|
||||
{
|
||||
return _errors;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void beforeExport();
|
||||
virtual void afterImport();
|
||||
|
||||
virtual void setError(const QString & error)
|
||||
{
|
||||
qWarning() << error;
|
||||
_errors << error;
|
||||
}
|
||||
|
||||
StructField internalField;
|
||||
ModelData & modelData;
|
||||
Board::Type board;
|
||||
unsigned int version;
|
||||
unsigned int variant;
|
||||
char name[256];
|
||||
int subprotocols[CPN_MAX_MODULES+1/*trainer*/];
|
||||
ChannelsConversionTable channelsConversionTable;
|
||||
QStringList _errors;
|
||||
};
|
||||
|
||||
void OpenTxEepromCleanup(void);
|
||||
#endif // _OPENTXEEPROM_H_
|
||||
@@ -20,8 +20,6 @@
|
||||
*/
|
||||
|
||||
#include "opentxinterface.h"
|
||||
#include "opentxeeprom.h"
|
||||
#include "rlefile.h"
|
||||
#include "appdata.h"
|
||||
#include "constants.h"
|
||||
|
||||
@@ -42,463 +40,6 @@
|
||||
|
||||
using namespace Board;
|
||||
|
||||
QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
|
||||
|
||||
OpenTxEepromInterface::OpenTxEepromInterface(OpenTxFirmware * firmware):
|
||||
EEPROMInterface(firmware->getBoard()),
|
||||
efile(new RleFile()),
|
||||
firmware(firmware)
|
||||
{
|
||||
}
|
||||
|
||||
OpenTxEepromInterface::~OpenTxEepromInterface()
|
||||
{
|
||||
delete efile;
|
||||
}
|
||||
|
||||
const char * OpenTxEepromInterface::getName()
|
||||
{
|
||||
switch (board) {
|
||||
case BOARD_JUMPER_T12:
|
||||
return "EdgeTX for Jumper T12";
|
||||
case BOARD_JUMPER_TLITE:
|
||||
return "EdgeTX for Jumper T-Lite";
|
||||
case BOARD_JUMPER_TLITE_F4:
|
||||
return "EdgeTX for Jumper T-Lite (F4 MCU)";
|
||||
case BOARD_JUMPER_TPRO:
|
||||
return "EdgeTX for Jumper T-Pro";
|
||||
case BOARD_JUMPER_TPROV2:
|
||||
return "EdgeTX for Jumper T-Pro V2";
|
||||
case BOARD_JUMPER_TPROS:
|
||||
return "EdgeTX for Jumper T-Pro S";
|
||||
case BOARD_JUMPER_BUMBLEBEE:
|
||||
return "EdgeTX for Jumper Bumblebee";
|
||||
case BOARD_JUMPER_T12MAX:
|
||||
return "EdgeTX for Jumper T12 MAX";
|
||||
case BOARD_JUMPER_T14:
|
||||
return "EdgeTX for Jumper T14";
|
||||
case BOARD_JUMPER_T15:
|
||||
return "EdgeTX for Jumper T15";
|
||||
case BOARD_JUMPER_T16:
|
||||
return "EdgeTX for Jumper T16";
|
||||
case BOARD_JUMPER_T18:
|
||||
return "EdgeTX for Jumper T18";
|
||||
case BOARD_JUMPER_T20:
|
||||
return "EdgeTX for Jumper T20";
|
||||
case BOARD_JUMPER_T20V2:
|
||||
return "EdgeTX for Jumper T20 V2";
|
||||
case BOARD_RADIOMASTER_TX16S:
|
||||
return "EdgeTX for Radiomaster TX16S";
|
||||
case BOARD_RADIOMASTER_TX12:
|
||||
return "EdgeTX for Radiomaster TX12";
|
||||
case BOARD_RADIOMASTER_TX12_MK2:
|
||||
return "EdgeTX for Radiomaster TX12 Mark II";
|
||||
case BOARD_RADIOMASTER_ZORRO:
|
||||
return "EdgeTX for Radiomaster Zorro";
|
||||
case BOARD_RADIOMASTER_BOXER:
|
||||
return "EdgeTX for Radiomaster Boxer";
|
||||
case BOARD_RADIOMASTER_POCKET:
|
||||
return "EdgeTX for Radiomaster Pocket";
|
||||
case BOARD_RADIOMASTER_T8:
|
||||
return "EdgeTX for Radiomaster T8";
|
||||
case BOARD_TARANIS_X9D:
|
||||
return "EdgeTX for FrSky Taranis X9D";
|
||||
case BOARD_TARANIS_X9DP:
|
||||
return "EdgeTX for FrSky Taranis X9D+";
|
||||
case BOARD_TARANIS_X9DP_2019:
|
||||
return "EdgeTX for FrSky Taranis X9D+ 2019";
|
||||
case BOARD_TARANIS_X9E:
|
||||
return "EdgeTX for FrSky Taranis X9E";
|
||||
case BOARD_TARANIS_X7:
|
||||
return "EdgeTX for FrSky Taranis X7";
|
||||
case BOARD_TARANIS_X7_ACCESS:
|
||||
return "EdgeTX for FrSky Taranis X7 Access";
|
||||
case BOARD_TARANIS_X9LITES:
|
||||
return "EdgeTX for FrSky Taranis X9-Lite S";
|
||||
case BOARD_TARANIS_X9LITE:
|
||||
return "EdgeTX for FrSky Taranis X9-Lite";
|
||||
case BOARD_TARANIS_XLITE:
|
||||
return "EdgeTX for FrSky Taranis X-Lite";
|
||||
case BOARD_TARANIS_XLITES:
|
||||
return "EdgeTX for FrSky Taranis X-Lite S/Pro";
|
||||
case BOARD_SKY9X:
|
||||
return "EdgeTX for Sky9x board / 9X";
|
||||
case BOARD_9XRPRO:
|
||||
return "EdgeTX for 9XR-PRO";
|
||||
case BOARD_AR9X:
|
||||
return "EdgeTX for ar9x board / 9X";
|
||||
case BOARD_HORUS_X12S:
|
||||
return "EdgeTX for FrSky Horus";
|
||||
case BOARD_X10:
|
||||
return "EdgeTX for FrSky X10";
|
||||
case BOARD_X10_EXPRESS:
|
||||
return "EdgeTX for FrSky X10 Express";
|
||||
case BOARD_FLYSKY_NV14:
|
||||
return "EdgeTX for FlySky NV14";
|
||||
case BOARD_FLYSKY_EL18:
|
||||
return "EdgeTX for FlySky EL18";
|
||||
case BOARD_FLYSKY_PL18:
|
||||
return "EdgeTX for FlySky PL18";
|
||||
case BOARD_BETAFPV_LR3PRO:
|
||||
return "EdgeTx for BETAFPV LR3PRO";
|
||||
case BOARD_IFLIGHT_COMMANDO8:
|
||||
return "EdgeTX for iFlight Commando 8";
|
||||
case BOARD_FATFISH_F16:
|
||||
return "EdgeTX for Fatfish F16";
|
||||
case BOARD_HELLORADIOSKY_V16:
|
||||
return "EdgeTX for HelloRadioSky V16";
|
||||
default:
|
||||
return "Board is unknown to EdgeTX";
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenTxEepromInterface::loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version)
|
||||
{
|
||||
// Companion loads the current profile firmware and associated board hardware definition ONLY!!!!
|
||||
// For each OpenTxEepromInterface create a firmware variant to force the associated base firmware board hardware definition to be loaded.
|
||||
// Note: The base firmware instance does not do load its hardware definition to save unnecessary processing.
|
||||
// To create the variant take the base id and append the language from the current radio profile.
|
||||
Firmware *fw = Firmware::getFirmwareForId(firmware->getId().append("-%1").arg(g.currentProfile().fwType().split('-').last()));
|
||||
if (!fw) {
|
||||
qWarning() << " error unable to create firmware variant";
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data(sizeof(settings), 0); // GeneralSettings should be always bigger than the EEPROM struct
|
||||
OpenTxGeneralData open9xSettings(settings, board, version);
|
||||
efile->openRd(FILE_GENERAL);
|
||||
int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
|
||||
if (size) {
|
||||
open9xSettings.Import(data);
|
||||
return checkVariant(settings.version, settings.variant);
|
||||
}
|
||||
else {
|
||||
qWarning() << " error when loading general settings";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenTxEepromInterface::loadModelFromRLE(ModelData & model, RleFile * rleFile, unsigned int index, uint8_t version, uint32_t variant)
|
||||
{
|
||||
QByteArray data(sizeof(model), 0); // ModelData should be always bigger than the EEPROM struct
|
||||
rleFile->openRd(FILE_MODEL(index));
|
||||
int size = rleFile->readRlc2((uint8_t *)data.data(), data.size());
|
||||
if (size) {
|
||||
if (loadFromByteArray<ModelData, OpenTxModelData>(model, data, version, variant)) {
|
||||
model.used = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
model.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class M>
|
||||
bool OpenTxEepromInterface::saveToByteArray(const T & src, QByteArray & data, uint8_t version)
|
||||
{
|
||||
if (version == 0) {
|
||||
version = getLastDataVersion(getBoard());
|
||||
}
|
||||
QByteArray raw;
|
||||
T srcCopy(src); // work on a copy of radio data, because Export() will modify it!
|
||||
M manager(srcCopy, board, version, 0);
|
||||
// manager.dump();
|
||||
manager.Export(raw);
|
||||
data.resize(8);
|
||||
*((uint32_t*)&data.data()[0]) = Boards::getFourCC(board);
|
||||
data[4] = version;
|
||||
data[5] = 'M';
|
||||
*((uint16_t*)&data.data()[6]) = raw.size();
|
||||
data.append(raw);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class M>
|
||||
bool OpenTxEepromInterface::loadFromByteArray(T & dest, const QByteArray & data, uint8_t version, uint32_t variant)
|
||||
{
|
||||
// Companion loads the current profile firmware and associated board hardware definition ONLY!!!!
|
||||
// For each OpenTxEepromInterface create a firmware variant to force the associated base firmware board hardware definition to be loaded.
|
||||
// Note: The base firmware instance does not do load its hardware definition to save unnecessary processing.
|
||||
// To create the variant take the base id and append the language from the current radio profile.
|
||||
Firmware *fw = Firmware::getFirmwareForId(firmware->getId().append("-%1").arg(g.currentProfile().fwType().split('-').last()));
|
||||
if (!fw) {
|
||||
qWarning() << " error unable to create firmware variant";
|
||||
return false;
|
||||
}
|
||||
|
||||
M manager(dest, board, version, variant);
|
||||
if (manager.Import(data) != 0) {
|
||||
return false;
|
||||
}
|
||||
// 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 (Boards::getFourCC(board) != fourcc) {
|
||||
if (IS_FAMILY_HORUS_OR_T16(board) && fourcc == 0x3178396F) {
|
||||
qDebug() << QString("%1: Deprecated fourcc used %2 vs %3").arg(getName()).arg(fourcc).arg(Boards::getFourCC(board));
|
||||
}
|
||||
else {
|
||||
qDebug() << QString("%1: Wrong fourcc %2 vs %3").arg(getName()).arg(fourcc).arg(Boards::getFourCC(board));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Boards::getFourCC(board) == Boards::getFourCC(getCurrentBoard()) &&
|
||||
board != getCurrentFirmware()->getBoard()) {
|
||||
qDebug() << QString("%1: Fourcc not unique and does not match profile board: %2").arg(getName()).arg(Boards::getBoardName(getCurrentBoard()));
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << QString("%1: OK").arg(getName());
|
||||
uint8_t version = data[4];
|
||||
QByteArray raw = data.right(data.size() - 8);
|
||||
return loadFromByteArray<T, M>(dest, raw, version);
|
||||
}
|
||||
|
||||
unsigned long OpenTxEepromInterface::load(RadioData &radioData, const uint8_t * eeprom, int size)
|
||||
{
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying " << getName() << " import...";
|
||||
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
if (size != Boards::getEEpromSize(board)) {
|
||||
if (size == 4096) {
|
||||
int notnull = false;
|
||||
for (int i = 2048; i < 4096; i++) {
|
||||
if (eeprom[i] != 255) {
|
||||
notnull = true;
|
||||
}
|
||||
}
|
||||
if (notnull) {
|
||||
dbg << " wrong size (" << size << ")";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
else {
|
||||
errors.set(HAS_WARNINGS);
|
||||
errors.set(WARNING_WRONG_FIRMWARE);
|
||||
size = 2048;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg << " wrong size (" << size << "/" << Boards::getEEpromSize(board) << ")";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
}
|
||||
|
||||
if (!efile->EeFsOpen((uint8_t *) eeprom, size, board)) {
|
||||
dbg << " wrong file system";
|
||||
errors.set(WRONG_FILE_SYSTEM);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
efile->openRd(FILE_GENERAL);
|
||||
|
||||
uint8_t version;
|
||||
if (efile->readRlc2(&version, 1) != 1) {
|
||||
dbg << " no";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
dbg << " version " << (unsigned int) version;
|
||||
|
||||
EepromLoadErrors version_error = checkVersion(version);
|
||||
if (version_error == OLD_VERSION) {
|
||||
errors.set(version_error);
|
||||
errors.set(HAS_WARNINGS);
|
||||
}
|
||||
else if (version_error == NOT_OPENTX) {
|
||||
dbg << " not OpenTX";
|
||||
errors.set(version_error);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (!loadRadioSettingsFromRLE(radioData.generalSettings, efile, version)) {
|
||||
dbg << " ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
dbg << " variant " << radioData.generalSettings.variant;
|
||||
if (getCurrentFirmware()->getCapability(Models) == 0) {
|
||||
radioData.models.resize(firmware->getCapability(Models));
|
||||
}
|
||||
for (int i = 0; i < firmware->getCapability(Models); i++) {
|
||||
if (i < (int)radioData.models.size() && !loadModelFromRLE(radioData.models[i], efile, i, version, radioData.generalSettings.variant)) {
|
||||
dbg << " ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
if (getCurrentFirmware()->getCapability(Models) == 0) {
|
||||
radioData.models.resize(i);
|
||||
}
|
||||
return errors.to_ulong();
|
||||
}
|
||||
}
|
||||
dbg << " ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
uint8_t OpenTxEepromInterface::getLastDataVersion(Board::Type board)
|
||||
{
|
||||
return 220; // Note: this is the last bin format before the switch to YAML introduced in Companion version 2.6
|
||||
}
|
||||
|
||||
void OpenTxEepromInterface::showErrors(const QString & title, const QStringList & errors)
|
||||
{
|
||||
QString msg;
|
||||
if (errors.empty()) {
|
||||
msg = tr("Unknown error");
|
||||
}
|
||||
else {
|
||||
int noErrorsToDisplay = std::min((int)errors.size(), 10);
|
||||
for (int n = 0; n < noErrorsToDisplay; n++) {
|
||||
msg += " -" + errors.at(n) + "\n";
|
||||
}
|
||||
if (noErrorsToDisplay < errors.size()) {
|
||||
msg += tr(" ... plus %1 errors").arg(errors.size() - noErrorsToDisplay) + "\n" + msg;
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::warning(NULL,
|
||||
CPN_STR_TTL_ERROR,
|
||||
title + "\n" + msg);
|
||||
}
|
||||
|
||||
int OpenTxEepromInterface::save(uint8_t * eeprom, const RadioData & radioData, uint8_t version, uint32_t variant)
|
||||
{
|
||||
// TODO QMessageBox::warning should not be called here
|
||||
|
||||
if (version == 0) {
|
||||
version = getLastDataVersion(board);
|
||||
}
|
||||
|
||||
int size = Boards::getEEpromSize(board);
|
||||
|
||||
efile->EeFsCreate(eeprom, size, board, version);
|
||||
|
||||
if (IS_TARANIS_X9E(board)) {
|
||||
variant |= TARANIS_X9E_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_X9LITES(board)) {
|
||||
variant |= TARANIS_X9LITES_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_X9LITE(board)) {
|
||||
variant |= TARANIS_X9LITE_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_X7_ACCESS(board)) {
|
||||
variant |= TARANIS_X7_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
variant |= TARANIS_X7_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_XLITES(board)) {
|
||||
variant |= TARANIS_XLITES_VARIANT;
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
variant |= TARANIS_XLITE_VARIANT;
|
||||
}
|
||||
else if (IS_JUMPER_T12(board)) {
|
||||
variant |= JUMPER_T12_VARIANT;
|
||||
}
|
||||
else if (IS_JUMPER_TLITE(board)) {
|
||||
variant |= JUMPER_TLITE_VARIANT;
|
||||
}
|
||||
else if (IS_JUMPER_TPRO(board)) {
|
||||
variant |= JUMPER_TPRO_VARIANT;
|
||||
}
|
||||
else if (IS_RADIOMASTER_TX12(board)) {
|
||||
variant |= RADIOMASTER_TX12_VARIANT;
|
||||
}
|
||||
else if (IS_RADIOMASTER_TX12_MK2(board)) {
|
||||
variant |= RADIOMASTER_TX12_MK2_VARIANT;
|
||||
}
|
||||
else if (IS_RADIOMASTER_ZORRO(board)) {
|
||||
variant |= RADIOMASTER_ZORRO_VARIANT;
|
||||
}
|
||||
else if (IS_RADIOMASTER_T8(board)) {
|
||||
variant |= RADIOMASTER_T8_VARIANT;
|
||||
}
|
||||
OpenTxGeneralData generator((GeneralSettings &)radioData.generalSettings, board, version, variant);
|
||||
// generator.dump();
|
||||
QByteArray data;
|
||||
generator.Export(data);
|
||||
int sz = efile->writeRlc2(FILE_GENERAL, FILE_TYP_GENERAL, (const uint8_t *)data.constData(), data.size());
|
||||
if (sz == 0 || generator.errors().count() > 0) {
|
||||
showErrors(tr("Cannot write radio settings"), generator.errors());
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < getCurrentFirmware()->getCapability(Models); i++) {
|
||||
if (i < (int)radioData.models.size() && !radioData.models[i].isEmpty()) {
|
||||
OpenTxModelData generator((ModelData &)radioData.models[i], board, version, variant);
|
||||
// generator.dump();
|
||||
QByteArray data;
|
||||
generator.Export(data);
|
||||
int sz = efile->writeRlc2(FILE_MODEL(i), FILE_TYP_MODEL, (const uint8_t *)data.constData(), data.size());
|
||||
if (sz == 0 || generator.errors().count() > 0) {
|
||||
showErrors(tr("Cannot write model %1").arg(radioData.models[i].name), generator.errors());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int OpenTxEepromInterface::getSize(const ModelData &model)
|
||||
{
|
||||
if (IS_SKY9X(board))
|
||||
return 0;
|
||||
|
||||
if (model.isEmpty())
|
||||
return 0;
|
||||
|
||||
QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
|
||||
efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255/*version max*/);
|
||||
|
||||
ModelData srcCopy(model); // work on a copy of model data, because Export() may modify it!
|
||||
OpenTxModelData open9xModel(srcCopy, board, 255/*version max*/, getCurrentFirmware()->getVariantNumber());
|
||||
|
||||
QByteArray eeprom;
|
||||
open9xModel.Export(eeprom);
|
||||
int sz = efile->writeRlc2(0, FILE_TYP_MODEL, (const uint8_t *) eeprom.constData(), eeprom.size());
|
||||
if (sz != eeprom.size()) {
|
||||
return -1;
|
||||
}
|
||||
return efile->size(0);
|
||||
}
|
||||
|
||||
int OpenTxEepromInterface::getSize(const GeneralSettings &settings)
|
||||
{
|
||||
if (IS_SKY9X(board))
|
||||
return 0;
|
||||
|
||||
QByteArray tmp(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
|
||||
efile->EeFsCreate((uint8_t *) tmp.data(), Boards::getEEpromSize(Board::BOARD_UNKNOWN), board, 255);
|
||||
|
||||
GeneralSettings srcCopy(settings); // work on a copy of settings data, because Export() may modify it!
|
||||
OpenTxGeneralData open9xGeneral(srcCopy, board, 255, getCurrentFirmware()->getVariantNumber());
|
||||
// open9xGeneral.dump();
|
||||
|
||||
QByteArray eeprom;
|
||||
open9xGeneral.Export(eeprom);
|
||||
int sz = efile->writeRlc2(0, FILE_TYP_GENERAL, (const uint8_t *) eeprom.constData(), eeprom.size());
|
||||
if (sz != eeprom.size()) {
|
||||
return -1;
|
||||
}
|
||||
return efile->size(0);
|
||||
}
|
||||
|
||||
Firmware * OpenTxFirmware::getFirmwareVariant(const QString &id)
|
||||
{
|
||||
if (id == getId()) {
|
||||
@@ -736,33 +277,6 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
||||
return true;
|
||||
case HasMahPersistent:
|
||||
return true;
|
||||
case SimulatorVariant:
|
||||
if (IS_TARANIS_X9E(board))
|
||||
return TARANIS_X9E_VARIANT;
|
||||
else if (IS_TARANIS_X9LITES(board))
|
||||
return TARANIS_X9LITES_VARIANT;
|
||||
else if (IS_TARANIS_X9LITE(board))
|
||||
return TARANIS_X9LITE_VARIANT;
|
||||
else if (IS_TARANIS_X7(board))
|
||||
return TARANIS_X7_VARIANT;
|
||||
else if (IS_TARANIS_XLITES(board))
|
||||
return TARANIS_XLITES_VARIANT;
|
||||
else if (IS_TARANIS_XLITE(board))
|
||||
return TARANIS_XLITE_VARIANT;
|
||||
else if (IS_BETAFPV_LR3PRO(board))
|
||||
return BETAFPV_LR3PRO_VARIANT;
|
||||
else if (IS_IFLIGHT_COMMANDO8(board))
|
||||
return IFLIGHT_COMMANDO8_VARIANT;
|
||||
else if (IS_JUMPER_T12(board))
|
||||
return JUMPER_T12_VARIANT;
|
||||
else if (IS_JUMPER_TLITE(board))
|
||||
return JUMPER_TLITE_VARIANT;
|
||||
else if (IS_RADIOMASTER_TX12(board))
|
||||
return RADIOMASTER_TX12_VARIANT;
|
||||
else if (IS_RADIOMASTER_T8(board))
|
||||
return RADIOMASTER_T8_VARIANT;
|
||||
else
|
||||
return 0;
|
||||
case MavlinkTelemetry:
|
||||
return id.contains("mavlink") ? 1 : 0;
|
||||
case SportTelemetry:
|
||||
@@ -873,273 +387,6 @@ size_t getSizeA(T (&)[SIZE])
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
EepromLoadErrors OpenTxEepromInterface::checkVersion(unsigned int version)
|
||||
{
|
||||
switch (version) {
|
||||
case 201:
|
||||
// first version
|
||||
case 202:
|
||||
// channel order is now always RUD - ELE - THR - AIL
|
||||
// changes in timers
|
||||
// ppmFrameLength added
|
||||
// thrTraceSrc added
|
||||
case 203:
|
||||
// mixers changed (for the trims use for change the offset of a mix)
|
||||
// telemetry offset raised to -127 +127
|
||||
// function switches now have a param on 4 bits
|
||||
case 204:
|
||||
// telemetry changes (bars)
|
||||
case 205:
|
||||
// mixer changes (differential, negative curves)...
|
||||
// case 206:
|
||||
case 207:
|
||||
// V4: Rotary Encoders position in FlightModes
|
||||
case 208:
|
||||
// Trim value in 16bits
|
||||
// FrSky A1/A2 offset on 12bits
|
||||
// ARM: More Mixers / Expos / CSW / FSW / CHNOUT
|
||||
case 209:
|
||||
// Add TrmR, TrmE, TrmT, TrmA as Mix sources
|
||||
// Trims are now OFF / ON / Rud / Ele / Thr / Ail
|
||||
case 210:
|
||||
// Add names in Mixes / Expos
|
||||
// Add a new telemetry screen
|
||||
// Add support for Play Track <filename>
|
||||
case 211:
|
||||
// Curves big change
|
||||
case 212:
|
||||
// Big changes in mixers / limitse
|
||||
case 213:
|
||||
// GVARS / Variants introduction
|
||||
case 214:
|
||||
// Massive EEPROM change!
|
||||
case 215:
|
||||
// M128 revert because too much RAM used!
|
||||
case 216:
|
||||
// A lot of things (first github release)
|
||||
case 217:
|
||||
// 3 logical switches removed on M128 / gruvin9x boards
|
||||
return OLD_VERSION;
|
||||
case 218:
|
||||
// ACCESS
|
||||
// switches add for X7/X10/X12S
|
||||
// 60 sensors for X12
|
||||
return OLD_VERSION;
|
||||
|
||||
case 219:
|
||||
// 60 (Horus / X9) / 40 (others) telemetry sensors instead of 32
|
||||
// ALL: ReceiverData array added
|
||||
// ALL: registrationId added
|
||||
// ALL: failsafeChannels moved from ModuleData to ModelData
|
||||
// ALL: ModuleData / TrainerModuleData modified
|
||||
// PCBX9 : 6 chars for expos / mixes names instead of 8
|
||||
// on X7: 2 additional switches
|
||||
// on X9D / X9D+: 1 additional switch
|
||||
// on xlite : 2 more storage switches
|
||||
// on X10: 2 additional pots => 12 multipos switches
|
||||
return OLD_VERSION;
|
||||
|
||||
case 220:
|
||||
// Refer radio/src/storage/conversions/conversions_219_220.cpp
|
||||
// ALL: TimerData split mode into separate mode and switch and change modes
|
||||
// ALL: TimerData countdownStart invert value
|
||||
// ALL: convert more fields from zchar to normal string
|
||||
// COLORLCD: change CustomScreenData and TopBarPersistentData
|
||||
return OLD_VERSION;
|
||||
|
||||
case 221:
|
||||
// ALL: YAML storage
|
||||
// X10PCB: add pots EXT3 and EXT4 (conversion required as shifts slider settings in multiple fields)
|
||||
// RM TX16S: add Flysky gimbals firmware build option and repurpose EXT3 and EXT4 if selected
|
||||
// ??: add source TX GPS
|
||||
break;
|
||||
|
||||
default:
|
||||
return NOT_OPENTX;
|
||||
}
|
||||
|
||||
return ALL_OK;
|
||||
}
|
||||
|
||||
bool OpenTxEepromInterface::checkVariant(unsigned int version, unsigned int variant)
|
||||
{
|
||||
bool variantError = false;
|
||||
if (IS_TARANIS_X9E(board)) {
|
||||
if (variant != TARANIS_X9E_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X7(board)) {
|
||||
if (variant != TARANIS_X7_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_XLITES(board)) {
|
||||
if (variant != TARANIS_XLITES_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_XLITE(board)) {
|
||||
if (variant != TARANIS_XLITE_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X9LITES(board)) {
|
||||
if (variant != TARANIS_X9LITES_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS_X9LITE(board)) {
|
||||
if (variant != TARANIS_X9LITE_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_JUMPER_T12(board)) {
|
||||
if (variant != JUMPER_T12_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_JUMPER_TLITE(board)) {
|
||||
if (variant != JUMPER_TLITE_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_JUMPER_TPRO(board)) {
|
||||
if (variant != JUMPER_TPRO_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_RADIOMASTER_TX12(board)) {
|
||||
if (variant != RADIOMASTER_TX12_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_RADIOMASTER_TX12_MK2(board)) {
|
||||
if (variant != RADIOMASTER_TX12_MK2_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_RADIOMASTER_ZORRO(board)) {
|
||||
if (variant != RADIOMASTER_ZORRO_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_RADIOMASTER_T8(board)) {
|
||||
if (variant != RADIOMASTER_T8_VARIANT) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
else if (IS_TARANIS(board)) {
|
||||
if (variant != 0) {
|
||||
variantError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (variantError) {
|
||||
qWarning() << " wrong variant (" << variant << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
OpenTxEepromInterface::loadModelFromBackup(ModelData & model, const uint8_t * data, unsigned int size, uint8_t version, uint32_t variant)
|
||||
{
|
||||
QByteArray backupData((char *) data, size);
|
||||
QByteArray modelData;
|
||||
if (IS_SKY9X(board)) {
|
||||
modelData = QByteArray((char *) data, size);
|
||||
}
|
||||
else {
|
||||
importRlc(modelData, backupData);
|
||||
}
|
||||
if (modelData.size()) {
|
||||
if (loadFromByteArray<ModelData, OpenTxModelData>(model, modelData, version, variant)) {
|
||||
model.used = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
model.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long OpenTxEepromInterface::loadBackup(RadioData &radioData, const uint8_t * eeprom, int esize, int index)
|
||||
{
|
||||
std::bitset<NUM_ERRORS> errors;
|
||||
|
||||
QDebug dbg = qDebug();
|
||||
dbg.setAutoInsertSpaces(false);
|
||||
dbg << "trying " << getName() << " backup import...";
|
||||
|
||||
if (esize < 8 || memcmp(eeprom, "o9x", 3) != 0) {
|
||||
dbg << " no\n";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
Type backupBoard = (Type) -1;
|
||||
switch (eeprom[3]) {
|
||||
case 0x33:
|
||||
backupBoard = BOARD_TARANIS_X9D;
|
||||
break;
|
||||
case 0x32:
|
||||
backupBoard = BOARD_SKY9X;
|
||||
break;
|
||||
default:
|
||||
dbg << " unknown board";
|
||||
errors.set(UNKNOWN_BOARD);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (backupBoard != board) {
|
||||
dbg << " not right board";
|
||||
errors.set(WRONG_BOARD);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
uint8_t version = eeprom[4];
|
||||
uint8_t bcktype = eeprom[5];
|
||||
uint16_t size = ((uint16_t) eeprom[7] << 8) + eeprom[6];
|
||||
uint16_t variant = ((uint16_t) eeprom[9] << 8) + eeprom[8];
|
||||
|
||||
dbg << " version " << (unsigned int) version << " ";
|
||||
|
||||
EepromLoadErrors version_error = checkVersion(version);
|
||||
if (version_error == OLD_VERSION) {
|
||||
errors.set(version_error);
|
||||
errors.set(HAS_WARNINGS);
|
||||
}
|
||||
else if (version_error == NOT_OPENTX) {
|
||||
dbg << " not open9x";
|
||||
errors.set(version_error);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (size > esize - 8) {
|
||||
dbg << " wrong size";
|
||||
errors.set(WRONG_SIZE);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
if (bcktype == 'M') {
|
||||
if (!loadModelFromBackup(radioData.models[index], &eeprom[8], size, version, variant)) {
|
||||
dbg << " ko";
|
||||
errors.set(UNKNOWN_ERROR);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg << " backup type not supported";
|
||||
errors.set(BACKUP_NOT_SUPPORTED);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
dbg << " ok";
|
||||
errors.set(ALL_OK);
|
||||
return errors.to_ulong();
|
||||
}
|
||||
|
||||
QString OpenTxFirmware::getReleaseNotesUrl()
|
||||
{
|
||||
return QString("%1/downloads").arg(EDGETX_HOME_PAGE_URL);
|
||||
@@ -1150,10 +397,6 @@ QString OpenTxFirmware::getReleaseNotesUrl()
|
||||
|
||||
void registerOpenTxFirmware(OpenTxFirmware * firmware, bool deprecated = false)
|
||||
{
|
||||
OpenTxEepromInterface * eepromInterface = new OpenTxEepromInterface(firmware);
|
||||
firmware->setEEpromInterface(eepromInterface);
|
||||
opentxEEpromInterfaces.push_back(eepromInterface);
|
||||
eepromInterfaces.push_back(eepromInterface);
|
||||
if (!deprecated)
|
||||
Firmware::addRegisteredFirmware(firmware);
|
||||
}
|
||||
@@ -1215,24 +458,6 @@ void addOpenTxTaranisOptions(OpenTxFirmware * firmware)
|
||||
addOpenTxFontOptions(firmware);
|
||||
}
|
||||
|
||||
void addOpenTxArm9xOptions(OpenTxFirmware * firmware, bool dblkeys = true)
|
||||
{
|
||||
addOpenTxCommonOptions(firmware);
|
||||
firmware->addOption("heli", Firmware::tr("Enable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("gvars", Firmware::tr("Global variables"), GVARS_VARIANT);
|
||||
firmware->addOption("potscroll", Firmware::tr("Pots use in menus navigation"));
|
||||
firmware->addOption("autosource", Firmware::tr("In model setup menus automatically set source by moving the control"));
|
||||
firmware->addOption("autoswitch", Firmware::tr("In model setup menus automatically set switch by moving the control"));
|
||||
firmware->addOption("nographics", Firmware::tr("No graphical check boxes and sliders"));
|
||||
firmware->addOption("battgraph", Firmware::tr("Battery graph"));
|
||||
firmware->addOption("nobold", Firmware::tr("Don't use bold font for highlighting active items"));
|
||||
//firmware->addOption("bluetooth", Firmware::tr("Bluetooth interface"));
|
||||
if (dblkeys)
|
||||
firmware->addOption("dblkeys", Firmware::tr("Enable resetting values by pressing up and down at the same time"));
|
||||
addOpenTxFontOptions(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
}
|
||||
|
||||
// TODO: refactoring OpenTxFirmware constructor - need to check if used elsewhere and how
|
||||
#define FIRMWAREID(flavour) std::string(FIRMWARE_ID_PREFIX).append(flavour).c_str()
|
||||
|
||||
@@ -1585,48 +810,4 @@ void unregisterOpenTxFirmwares()
|
||||
foreach (Firmware * f, Firmware::getRegisteredFirmwares()) {
|
||||
delete f;
|
||||
}
|
||||
unregisterEEpromInterfaces();
|
||||
}
|
||||
|
||||
template <class T, class M>
|
||||
OpenTxEepromInterface * loadFromByteArray(T & dest, const QByteArray & data)
|
||||
{
|
||||
foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
|
||||
if (eepromInterface->loadFromByteArray<T, M>(dest, data)) {
|
||||
return eepromInterface;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <class T, class M>
|
||||
bool saveToByteArray(const T & dest, QByteArray & data)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
foreach(OpenTxEepromInterface * eepromInterface, opentxEEpromInterfaces) {
|
||||
if (eepromInterface->getBoard() == board) {
|
||||
return eepromInterface->saveToByteArray<T, M>(dest, data);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenTxEepromInterface * loadModelFromByteArray(ModelData & model, const QByteArray & data)
|
||||
{
|
||||
return loadFromByteArray<ModelData, OpenTxModelData>(model, data);
|
||||
}
|
||||
|
||||
OpenTxEepromInterface * 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);
|
||||
}
|
||||
|
||||
@@ -19,70 +19,12 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _OPENTXINTERFACE_H_
|
||||
#define _OPENTXINTERFACE_H_
|
||||
#pragma once
|
||||
|
||||
#include "eeprominterface.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class RleFile;
|
||||
class OpenTxFirmware;
|
||||
|
||||
class OpenTxEepromInterface : public EEPROMInterface
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(OpenTxEepromInterface)
|
||||
|
||||
public:
|
||||
|
||||
OpenTxEepromInterface(OpenTxFirmware * firmware);
|
||||
|
||||
virtual ~OpenTxEepromInterface();
|
||||
|
||||
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 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 &);
|
||||
|
||||
protected:
|
||||
|
||||
const char * getName();
|
||||
|
||||
EepromLoadErrors checkVersion(unsigned int version);
|
||||
|
||||
bool checkVariant(unsigned int version, unsigned int variant);
|
||||
|
||||
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=0);
|
||||
|
||||
bool loadRadioSettingsFromRLE(GeneralSettings & settings, RleFile * rleFile, uint8_t version);
|
||||
|
||||
bool loadModelFromRLE(ModelData & model, RleFile * rleFile, unsigned int index, uint8_t version, uint32_t variant);
|
||||
|
||||
void showErrors(const QString & title, const QStringList & errors);
|
||||
|
||||
uint8_t getLastDataVersion(Board::Type board);
|
||||
|
||||
RleFile * efile;
|
||||
|
||||
OpenTxFirmware * firmware;
|
||||
|
||||
};
|
||||
|
||||
class OpenTxFirmware: public Firmware
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(OpenTxFirmware)
|
||||
@@ -92,7 +34,6 @@ class OpenTxFirmware: public Firmware
|
||||
Firmware(parent, id, parent->getName(), parent->getBoard(),
|
||||
parent->getDownloadId(), parent->getSimulatorId(), parent->getHwDefnId())
|
||||
{
|
||||
setEEpromInterface(parent->getEEpromInterface());
|
||||
}
|
||||
|
||||
OpenTxFirmware(const QString & id, const QString & name, const Board::Type board,
|
||||
@@ -157,13 +98,3 @@ class OpenTxFirmware: public Firmware
|
||||
|
||||
void registerOpenTxFirmwares();
|
||||
void unregisterOpenTxFirmwares();
|
||||
|
||||
extern QList<OpenTxEepromInterface *> opentxEEpromInterfaces;
|
||||
|
||||
OpenTxEepromInterface * loadModelFromByteArray(ModelData & model, const QByteArray & data);
|
||||
OpenTxEepromInterface * loadRadioSettingsFromByteArray(GeneralSettings & settings, const QByteArray & data);
|
||||
|
||||
bool writeModelToByteArray(const ModelData & model, QByteArray & data);
|
||||
bool writeRadioSettingsToByteArray(const GeneralSettings & settings, QByteArray & data);
|
||||
|
||||
#endif // _OPENTXINTERFACE_H_
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 "flasheepromdialog.h"
|
||||
#include "ui_flasheepromdialog.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "helpers.h"
|
||||
#include "storage.h"
|
||||
#include "appdata.h"
|
||||
#include "progressdialog.h"
|
||||
#include "radiointerface.h"
|
||||
#include "splashlibrarydialog.h"
|
||||
|
||||
FlashEEpromDialog::FlashEEpromDialog(QWidget *parent, const QString &filename):
|
||||
QDialog(parent),
|
||||
ui(new Ui::FlashEEpromDialog),
|
||||
eepromFilename(filename)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->profileLabel->setText(tr("Current profile: %1").arg(g.profile[g.id()].name()));
|
||||
if (!filename.isEmpty()) {
|
||||
ui->eepromFilename->hide();
|
||||
ui->eepromLoad->hide();
|
||||
}
|
||||
QString backupPath = g.profile[g.id()].pBackupDir();
|
||||
if (backupPath.isEmpty()) {
|
||||
backupPath = g.backupDir();
|
||||
ui->backupBeforeWrite->setChecked(g.enableBackup() || g.profile[g.id()].penableBackup());
|
||||
}
|
||||
if (backupPath.isEmpty() || !QDir(backupPath).exists()) {
|
||||
ui->backupBeforeWrite->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
FlashEEpromDialog::~FlashEEpromDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::updateUI()
|
||||
{
|
||||
// ui->burnButton->setEnabled(true);
|
||||
ui->eepromFilename->setText(eepromFilename);
|
||||
if (!eepromFilename.isEmpty() && getEEpromVersion(eepromFilename) >= 0) {
|
||||
ui->profileLabel->show();
|
||||
ui->patchCalibration->show();
|
||||
ui->patchHardwareSettings->show();
|
||||
QString name = g.profile[g.id()].name();
|
||||
QString calib = g.profile[g.id()].stickPotCalib();
|
||||
QString trainercalib = g.profile[g.id()].trainerCalib();
|
||||
QString DisplaySet = g.profile[g.id()].display();
|
||||
QString BeeperSet = g.profile[g.id()].beeper();
|
||||
QString HapticSet = g.profile[g.id()].haptic();
|
||||
QString SpeakerSet = g.profile[g.id()].speaker();
|
||||
if (!name.isEmpty()) {
|
||||
ui->profileLabel->show();
|
||||
ui->patchCalibration->show();
|
||||
ui->patchHardwareSettings->show();
|
||||
// TODO I hardcode the number of pots here, should be dependant on the board?
|
||||
if (!((calib.length()==(CPN_MAX_STICKS+3)*12) && (trainercalib.length()==16))) {
|
||||
ui->patchCalibration->setDisabled(true);
|
||||
}
|
||||
if (!((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6))) {
|
||||
ui->patchHardwareSettings->setDisabled(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->profileLabel->hide();
|
||||
}
|
||||
ui->burnButton->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
ui->profileLabel->hide();
|
||||
ui->patchCalibration->hide();
|
||||
ui->patchHardwareSettings->hide();
|
||||
}
|
||||
QTimer::singleShot(0, this, SLOT(shrink()));
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::on_eepromLoad_clicked()
|
||||
{
|
||||
QString filename = QFileDialog::getOpenFileName(this, tr("Choose Radio Backup file"), g.eepromDir(), EXTERNAL_EEPROM_FILES_FILTER);
|
||||
if (!filename.isEmpty()) {
|
||||
eepromFilename = filename;
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
int FlashEEpromDialog::getEEpromVersion(const QString & filename)
|
||||
{
|
||||
int result = -1;
|
||||
QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
|
||||
Storage storage(filename);
|
||||
if (storage.load(*radioData)) {
|
||||
result = radioData->generalSettings.version;
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, storage.error());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FlashEEpromDialog::patchCalibration(RadioData * radioData)
|
||||
{
|
||||
QString calib = g.profile[g.id()].stickPotCalib();
|
||||
QString trainercalib = g.profile[g.id()].trainerCalib();
|
||||
int potsnum = getBoardCapability(getCurrentBoard(), Board::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++) {
|
||||
Byte=calib.mid(i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
radioData->generalSettings.calibMid[i]=byte16;
|
||||
Byte=calib.mid(4+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
radioData->generalSettings.calibSpanNeg[i]=byte16;
|
||||
Byte=calib.mid(8+i*12,4);
|
||||
byte16=(int16_t)Byte.toInt(&ok,16);
|
||||
if (ok)
|
||||
radioData->generalSettings.calibSpanPos[i]=byte16;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
Byte = trainercalib.mid(i*4,4);
|
||||
byte16 = (int16_t)Byte.toInt(&ok,16);
|
||||
if (ok) {
|
||||
radioData->generalSettings.trainer.calib[i] = byte16;
|
||||
}
|
||||
}
|
||||
radioData->generalSettings.txCurrentCalibration = txCurrentCalibration;
|
||||
radioData->generalSettings.txVoltageCalibration = txVoltageCalibration;
|
||||
radioData->generalSettings.PPM_Multiplier = PPM_Multiplier;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio calibration data in profile, Settings not patched"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlashEEpromDialog::patchHardwareSettings(RadioData * radioData)
|
||||
{
|
||||
QString DisplaySet = g.profile[g.id()].display();
|
||||
QString BeeperSet = g.profile[g.id()].beeper();
|
||||
QString HapticSet = g.profile[g.id()].haptic();
|
||||
QString SpeakerSet = g.profile[g.id()].speaker();
|
||||
uint8_t GSStickMode=(uint8_t) g.profile[g.id()].gsStickMode();
|
||||
uint8_t vBatWarn=(uint8_t) g.profile[g.id()].vBatWarn();
|
||||
|
||||
if ((DisplaySet.length()==6) && (BeeperSet.length()==4) && (HapticSet.length()==6) && (SpeakerSet.length()==6)) {
|
||||
radioData->generalSettings.vBatWarn = vBatWarn;
|
||||
radioData->generalSettings.stickMode = GSStickMode;
|
||||
uint8_t byte8u;
|
||||
int8_t byte8;
|
||||
bool ok;
|
||||
byte8=(int8_t)DisplaySet.mid(0,2).toInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.optrexDisplay=(byte8==1 ? true : false);
|
||||
byte8u=(uint8_t)DisplaySet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.contrast=byte8u;
|
||||
byte8u=(uint8_t)DisplaySet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.backlightBright=byte8u;
|
||||
byte8u=(uint8_t)BeeperSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.beeperMode=(GeneralSettings::BeeperMode)byte8u;
|
||||
byte8=(int8_t)BeeperSet.mid(2,2).toInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.beeperLength=byte8;
|
||||
byte8u=(uint8_t)HapticSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.hapticMode=(GeneralSettings::BeeperMode)byte8u;
|
||||
byte8u=(uint8_t)HapticSet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.hapticStrength=byte8u;
|
||||
byte8=(int8_t)HapticSet.mid(4,2).toInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.hapticLength=byte8;
|
||||
byte8u=(uint8_t)SpeakerSet.mid(0,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.speakerMode=byte8u;
|
||||
byte8u=(uint8_t)SpeakerSet.mid(2,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.speakerPitch=byte8u;
|
||||
byte8u=(uint8_t)SpeakerSet.mid(4,2).toUInt(&ok,16);
|
||||
if (ok) radioData->generalSettings.speakerVolume=byte8u;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Wrong radio setting data in profile, Settings not patched"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::on_burnButton_clicked()
|
||||
{
|
||||
QString filename = eepromFilename;
|
||||
bool patch = false;
|
||||
|
||||
if (ui->patchCalibration->isChecked() || ui->patchHardwareSettings->isChecked()) {
|
||||
QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
|
||||
Storage storage(eepromFilename);
|
||||
if (storage.load(*radioData)) {
|
||||
if (ui->patchCalibration->isChecked())
|
||||
patch |= patchCalibration(radioData.data());
|
||||
if (ui->patchHardwareSettings->isChecked())
|
||||
patch |= patchHardwareSettings(radioData.data());
|
||||
}
|
||||
|
||||
if (patch) {
|
||||
filename = generateProcessUniqueTempFileName("patched.bin");
|
||||
QFile file(filename);
|
||||
uint8_t *eeprom = (uint8_t*)malloc(Boards::getEEpromSize(getCurrentBoard()));
|
||||
int eeprom_size = getCurrentEEpromInterface()->save(eeprom, *radioData, 0, getCurrentFirmware()->getVariantNumber());
|
||||
if (eeprom_size == 0) {
|
||||
return;
|
||||
}
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Cannot write file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
QTextStream outputStream(&file);
|
||||
long result = file.write((char*)eeprom, eeprom_size);
|
||||
if (result != eeprom_size) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
ProgressDialog progressDialog(this, tr("Write Models and Settings to Radio"), CompanionIcon("write_eeprom.png"));
|
||||
|
||||
// backup previous EEPROM if requested
|
||||
QString backupFilename;
|
||||
QString backupPath;
|
||||
if (ui->backupBeforeWrite->isChecked()) {
|
||||
backupPath = g.profile[g.id()].pBackupDir();
|
||||
if (backupPath.isEmpty()) {
|
||||
backupPath=g.backupDir();
|
||||
}
|
||||
backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
}
|
||||
else if (ui->checkFirmwareCompatibility->isChecked()) {
|
||||
backupFilename = generateProcessUniqueTempFileName("eeprom.bin");
|
||||
}
|
||||
if (!backupFilename.isEmpty()) {
|
||||
if (!readSettings(backupFilename, progressDialog.progress())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check EEPROM compatibility if requested
|
||||
if (ui->checkFirmwareCompatibility->isChecked()) {
|
||||
int eepromVersion = getEEpromVersion(filename);
|
||||
QString firmwareFilename = generateProcessUniqueTempFileName("flash.bin");
|
||||
if (!readFirmware(firmwareFilename, progressDialog.progress()))
|
||||
return;
|
||||
QString compatEEprom = generateProcessUniqueTempFileName("compat.bin");
|
||||
if (convertEEprom(filename, compatEEprom, firmwareFilename)) {
|
||||
int compatVersion = getEEpromVersion(compatEEprom);
|
||||
if ((compatVersion / 100) != (eepromVersion / 100)) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware belongs to another product family, check file and preferences!"));
|
||||
return;
|
||||
}
|
||||
else if (compatVersion < eepromVersion) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("The radio firmware is outdated, please upgrade!"));
|
||||
return;
|
||||
}
|
||||
filename = compatEEprom;
|
||||
}
|
||||
else if (QMessageBox::question(this, CPN_STR_TTL_ERROR, tr("Cannot check Models and Settings compatibility! Continue anyway?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
qunlink(firmwareFilename);
|
||||
}
|
||||
|
||||
// and write...
|
||||
bool result = writeSettings(filename, progressDialog.progress());
|
||||
if (!result && !progressDialog.isEmpty()) {
|
||||
progressDialog.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::on_cancelButton_clicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void FlashEEpromDialog::shrink()
|
||||
{
|
||||
resize(0, 0);
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 _FLASHEEPROMDIALOG_H_
|
||||
#define _FLASHEEPROMDIALOG_H_
|
||||
|
||||
#include <constants.h>
|
||||
#include <QtWidgets>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class FlashEEpromDialog;
|
||||
}
|
||||
|
||||
class RadioData;
|
||||
|
||||
class FlashEEpromDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FlashEEpromDialog(QWidget *parent, const QString &fileName="");
|
||||
~FlashEEpromDialog();
|
||||
|
||||
private slots:
|
||||
void on_eepromLoad_clicked();
|
||||
void on_burnButton_clicked();
|
||||
void on_cancelButton_clicked();
|
||||
void shrink();
|
||||
|
||||
protected:
|
||||
void updateUI();
|
||||
bool isValidEEprom(const QString &filename);
|
||||
int getEEpromVersion(const QString &filename);
|
||||
bool patchCalibration(RadioData * radioData);
|
||||
bool patchHardwareSettings(RadioData * radioData);
|
||||
virtual void showEvent(QShowEvent *);
|
||||
|
||||
private:
|
||||
Ui::FlashEEpromDialog *ui;
|
||||
QString eepromFilename;
|
||||
};
|
||||
|
||||
#endif // _FLASHEEPROMDIALOG_H_
|
||||
@@ -1,198 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FlashEEpromDialog</class>
|
||||
<widget class="QDialog" name="FlashEEpromDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>399</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Write Models and Settings to Radio</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="companion.qrc">
|
||||
<normaloff>:/themes/classic/16/write_eeprom.png</normaloff>:/themes/classic/16/write_eeprom.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="filanameLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="eepromFilename">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="eepromLoad">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="profileLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Current Profile</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkFirmwareCompatibility">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Allows Companion to write to older version of the firmware</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check Firmware compatibility</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="backupBeforeWrite">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Saves a dated copy of your eeprom to the backup folder you specified in the Companion settings before writing the current model to the radio.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup before Write</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="patchCalibration">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Modify calibration parameters using settings from current profile</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Patch calibration setting from profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="patchHardwareSettings">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Modify HW parameters using settings from current profile</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Patch HW settings from profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonsLayout">
|
||||
<item>
|
||||
<spacer name="spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="burnButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Write to TX</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>burnButton</tabstop>
|
||||
<tabstop>eepromFilename</tabstop>
|
||||
<tabstop>eepromLoad</tabstop>
|
||||
<tabstop>cancelButton</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -267,7 +267,7 @@ void FlashFirmwareDialog::shrink()
|
||||
|
||||
void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
{
|
||||
bool backup = g.backupOnFlash();
|
||||
// bool backup = g.backupOnFlash();
|
||||
|
||||
close();
|
||||
|
||||
@@ -297,34 +297,35 @@ void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
|
||||
if (checkPassed) {
|
||||
// backup if requested
|
||||
bool result = true;
|
||||
QString backupFilename;
|
||||
QString backupPath;
|
||||
if (backup) {
|
||||
backupPath = g.profile[g.id()].pBackupDir();
|
||||
if (backupPath.isEmpty()) {
|
||||
backupPath=g.backupDir();
|
||||
}
|
||||
backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
result = readSettings(backupFilename, progressDialog.progress());
|
||||
sleep(2);
|
||||
}
|
||||
// bool result = true;
|
||||
// QString backupFilename;
|
||||
// QString backupPath;
|
||||
// if (backup) {
|
||||
// backupPath = g.profile[g.id()].pBackupDir();
|
||||
// if (backupPath.isEmpty()) {
|
||||
// backupPath=g.backupDir();
|
||||
// }
|
||||
// backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
// result = readSettings(backupFilename, progressDialog.progress());
|
||||
// sleep(2);
|
||||
// }
|
||||
|
||||
// flash
|
||||
result = (result && writeFirmware(filename, progressDialog.progress()));
|
||||
//result = (result && writeFirmware(filename, progressDialog.progress()));
|
||||
writeFirmware(filename, progressDialog.progress());
|
||||
|
||||
// restore if backup requested
|
||||
if (backup && result) {
|
||||
sleep(2);
|
||||
QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
|
||||
if (!convertEEprom(backupFilename, restoreFilename, filename)) {
|
||||
QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
|
||||
restoreFilename = backupFilename;
|
||||
}
|
||||
if (!writeSettings(restoreFilename, progressDialog.progress())) {
|
||||
QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
|
||||
}
|
||||
}
|
||||
// if (backup && result) {
|
||||
// sleep(2);
|
||||
// QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
|
||||
// if (!convertEEprom(backupFilename, restoreFilename, filename)) {
|
||||
// QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
|
||||
// restoreFilename = backupFilename;
|
||||
// }
|
||||
// if (!writeSettings(restoreFilename, progressDialog.progress())) {
|
||||
// QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
|
||||
// }
|
||||
// }
|
||||
|
||||
progressDialog.progress()->setInfo(tr("Flashing done"));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "printdialog.h"
|
||||
#include "version.h"
|
||||
#include "customizesplashdialog.h"
|
||||
#include "flasheepromdialog.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
#include "hexinterface.h"
|
||||
#include "warnings.h"
|
||||
@@ -125,7 +124,7 @@ MainWindow::MainWindow():
|
||||
if (!str.isEmpty()) {
|
||||
int fileType = getStorageType(str);
|
||||
|
||||
if (fileType==STORAGE_TYPE_EEPE || fileType==STORAGE_TYPE_EEPM || fileType==STORAGE_TYPE_BIN || fileType==STORAGE_TYPE_ETX) {
|
||||
if (fileType == STORAGE_TYPE_ETX) {
|
||||
MdiChild * child = createMdiChild();
|
||||
if (child->loadFile(str)) {
|
||||
if (!(printing && model >= 0 && (getCurrentFirmware()->getCapability(Models) == 0 || model<getCurrentFirmware()->getCapability(Models)) && !printfilename.isEmpty())) {
|
||||
@@ -582,13 +581,7 @@ bool MainWindow::readSettingsFromRadio(const QString & filename)
|
||||
|
||||
void MainWindow::writeBackup()
|
||||
{
|
||||
if (IS_FAMILY_HORUS_OR_T16(getCurrentBoard())) {
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("This function is not yet implemented"));
|
||||
return;
|
||||
// TODO implementation
|
||||
}
|
||||
FlashEEpromDialog *cd = new FlashEEpromDialog(this);
|
||||
cd->exec();
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("This function is not yet implemented"));
|
||||
}
|
||||
|
||||
void MainWindow::writeFlash(QString fileToFlash)
|
||||
|
||||
+12
-28
@@ -25,7 +25,6 @@
|
||||
#include "generaledit/generaledit.h"
|
||||
#include "burnconfigdialog.h"
|
||||
#include "printdialog.h"
|
||||
#include "flasheepromdialog.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
#include "wizarddialog.h"
|
||||
@@ -1500,36 +1499,21 @@ void MdiChild::writeSettings(StatusDialog * status) // write to Tx
|
||||
return;
|
||||
}
|
||||
|
||||
Board::Type board = getCurrentBoard();
|
||||
QString radioPath = findMassstoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
if (radioPath.isEmpty()) {
|
||||
qDebug() << "Radio SD card not found";
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find radio SD card!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Boards::getCapability(board, Board::HasSDCard)) {
|
||||
QString radioPath = findMassstoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
if (radioPath.isEmpty()) {
|
||||
qDebug() << "Radio SD card not found";
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find radio SD card!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (saveFile(radioPath, false)) {
|
||||
status->hide();
|
||||
QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Models and settings written to radio"));
|
||||
}
|
||||
else {
|
||||
qDebug() << "MdiChild::writeEeprom(): saveFile error";
|
||||
status->hide();
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error writing models and settings to radio!"));
|
||||
}
|
||||
if (saveFile(radioPath, false)) {
|
||||
status->hide();
|
||||
QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Models and settings written to radio"));
|
||||
}
|
||||
else {
|
||||
QString tempFile = generateProcessUniqueTempFileName("temp.bin");
|
||||
saveFile(tempFile, false);
|
||||
if (!QFileInfo(tempFile).exists()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Cannot write temporary file!"));
|
||||
return;
|
||||
}
|
||||
FlashEEpromDialog * cd = new FlashEEpromDialog(this, tempFile);
|
||||
cd->exec();
|
||||
status->hide();
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error writing models and settings to radio!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,11 +154,6 @@ QString ModelPrinter::printBoolean(const bool val, const int typ)
|
||||
}
|
||||
}
|
||||
|
||||
QString ModelPrinter::printEEpromSize()
|
||||
{
|
||||
return QString("%1 ").arg(getCurrentEEpromInterface()->getSize(model)) + tr("bytes");
|
||||
}
|
||||
|
||||
QString ModelPrinter::printChannelName(int idx)
|
||||
{
|
||||
QString str = RawSource(SOURCE_TYPE_CH, idx + 1).toString(&model, &generalSettings);
|
||||
|
||||
@@ -41,7 +41,6 @@ class ModelPrinter: public QObject
|
||||
virtual ~ModelPrinter();
|
||||
|
||||
QString printBoolean(const bool val, const int typ);
|
||||
QString printEEpromSize();
|
||||
QString printTrimIncrementMode();
|
||||
QString printThrottle();
|
||||
QString printFlightModeSwitch(const RawSwitch & swtch);
|
||||
|
||||
@@ -81,11 +81,7 @@ QStringList getSambaArgs(const QString & tcl)
|
||||
QStringList getReadEEpromCmd(const QString & filename)
|
||||
{
|
||||
QStringList result;
|
||||
EEPROMInterface *eepromInterface = getCurrentEEpromInterface();
|
||||
if (IS_STM32(eepromInterface->getBoard())) {
|
||||
// impossible
|
||||
}
|
||||
else {
|
||||
if (!IS_STM32(getCurrentBoard())) {
|
||||
result = getSambaArgs(QString("SERIALFLASH::Init 0\n") + "receive_file {SerialFlash AT25} \"" + filename + "\" 0x0 0x80000 0\n");
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -304,7 +304,7 @@ void SimulatorStartupDialog::onRadioTypeChanged(int index)
|
||||
|
||||
void SimulatorStartupDialog::onDataFileSelect(bool)
|
||||
{
|
||||
QString filter = EEPROM_FILES_FILTER % tr("All files (*.*)");
|
||||
QString filter = SIMU_FILES_FILTER;
|
||||
QString file = QFileDialog::getSaveFileName(this, tr("Select a data file"), ui->dataFile->text(),
|
||||
filter, NULL, QFileDialog::DontConfirmOverwrite);
|
||||
if (!file.isEmpty()) {
|
||||
|
||||
@@ -316,8 +316,10 @@ bool SimulatorWidget::setStartupData(const QByteArray & dataSource, bool fromFil
|
||||
}
|
||||
// Assume a byte array of radio data was passed, load it.
|
||||
else if (!dataSource.isEmpty()) {
|
||||
ret = firmware->getEEpromInterface()->load(simuData, (uint8_t *)dataSource.constData(), Boards::getEEpromSize(m_board));
|
||||
startupData = dataSource; // save the data for start()
|
||||
//ret = firmware->getEEpromInterface()->load(simuData, (uint8_t *)dataSource.constData(), Boards::getEEpromSize(m_board));
|
||||
//startupData = dataSource; // save the data for start()
|
||||
error = tr("Unable to handle byte array.");
|
||||
ret = 0;
|
||||
}
|
||||
// we're :-(
|
||||
else {
|
||||
@@ -352,11 +354,11 @@ bool SimulatorWidget::setRadioData(RadioData * radioData)
|
||||
if (ret) {
|
||||
if (!hasSdCard) {
|
||||
startupData.fill(0, Boards::getEEpromSize(m_board));
|
||||
if (firmware->getEEpromInterface()->save(
|
||||
(uint8_t *)startupData.data(), *radioData, 0,
|
||||
firmware->getCapability(SimulatorVariant)) <= 0) {
|
||||
//if (firmware->getEEpromInterface()->save(
|
||||
// (uint8_t *)startupData.data(), *radioData, 0,
|
||||
// firmware->getCapability(SimulatorVariant)) <= 0) {
|
||||
ret = false;
|
||||
}
|
||||
//}
|
||||
} else {
|
||||
ret = saveRadioData(radioData, radioDataPath);
|
||||
}
|
||||
@@ -452,13 +454,14 @@ bool SimulatorWidget::saveTempData()
|
||||
fh.close();
|
||||
}
|
||||
|
||||
if (!firmware->getEEpromInterface()->load(radioData, (uint8_t *)startupData.constData(), Boards::getEEpromSize(m_board))) {
|
||||
error = tr("Error saving data: could not get data from simulator interface.");
|
||||
}
|
||||
else {
|
||||
radioData.fixModelFilenames();
|
||||
ret = true;
|
||||
}
|
||||
qDebug() << "ERROR: WE DO NOT WANT TO BE HERE";
|
||||
// if (!firmware->getEEpromInterface()->load(radioData, (uint8_t *)startupData.constData(), Boards::getEEpromSize(m_board))) {
|
||||
// error = tr("Error saving data: could not get data from simulator interface.");
|
||||
// }
|
||||
// else {
|
||||
// radioData.fixModelFilenames();
|
||||
// ret = true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -4,17 +4,14 @@ project(storage)
|
||||
set(${PROJECT_NAME}_NAMES
|
||||
hexinterface
|
||||
mountlist
|
||||
rlefile
|
||||
appdata
|
||||
firmwareinterface
|
||||
storage
|
||||
bineeprom
|
||||
eepe
|
||||
hexeeprom
|
||||
labeled
|
||||
sdcard
|
||||
etx
|
||||
otx
|
||||
yaml
|
||||
crc
|
||||
minizinterface
|
||||
|
||||
@@ -25,159 +25,20 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
bool LabelsStorageFormat::load(RadioData & radioData)
|
||||
{
|
||||
StorageType st = getStorageType(filename);
|
||||
if (st == STORAGE_TYPE_UNKNOWN) {
|
||||
st = probeFormat();
|
||||
}
|
||||
if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML
|
||||
|| st == STORAGE_TYPE_UNKNOWN) {
|
||||
return loadYaml(radioData);
|
||||
} else {
|
||||
return loadBin(radioData);
|
||||
}
|
||||
}
|
||||
|
||||
bool LabelsStorageFormat::write(const RadioData & radioData)
|
||||
{
|
||||
StorageType st = getStorageType(filename);
|
||||
if (st == STORAGE_TYPE_ETX || st == STORAGE_TYPE_YML ||
|
||||
st == STORAGE_TYPE_UNKNOWN) {
|
||||
return writeYaml(radioData);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
StorageType LabelsStorageFormat::probeFormat()
|
||||
{
|
||||
if (QFile(filename + "/RADIO/radio.yml").exists()) // converted
|
||||
return getStorageType("radio.yml");
|
||||
else if (QFile(filename + "/RADIO/radio.bin").exists()) // unconverted
|
||||
return getStorageType("radio.bin");
|
||||
else
|
||||
return getStorageType(filename);
|
||||
}
|
||||
|
||||
bool LabelsStorageFormat::loadBin(RadioData & radioData)
|
||||
bool LabelsStorageFormat::load(RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!loadFile(radioSettingsBuffer, "RADIO/radio.bin")) {
|
||||
setError(tr("Cannot extract RADIO/radio.bin"));
|
||||
return false;
|
||||
}
|
||||
StorageType st = getStorageType(filename);
|
||||
if (st == STORAGE_TYPE_UNKNOWN)
|
||||
st = probeFormat();
|
||||
|
||||
OpenTxEepromInterface * loadInterface = loadRadioSettingsFromByteArray(radioData.generalSettings, radioSettingsBuffer);
|
||||
if (!loadInterface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
board = loadInterface->getBoard();
|
||||
|
||||
radioData.generalSettings.convertLegacyConfiguration(board);
|
||||
|
||||
QByteArray modelsListBuffer;
|
||||
if (!loadFile(modelsListBuffer, "RADIO/models.txt")) {
|
||||
setError(tr("Cannot extract RADIO/models.txt"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QByteArray> lines = modelsListBuffer.split('\n');
|
||||
int modelIndex = 0;
|
||||
foreach (const QByteArray & lineArray, lines) {
|
||||
QString line = QString(lineArray).trimmed();
|
||||
if (line.isEmpty()) continue;
|
||||
// qDebug() << "parsing line" << line;
|
||||
|
||||
if (line.startsWith('[') && line.endsWith(']')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine if we have a model number
|
||||
QStringList parts = line.split(QRegExp("\\s+"), Qt::SkipEmptyParts);
|
||||
if (parts.size() == 2) {
|
||||
// parse model number
|
||||
int modelNumber = parts[0].toInt();
|
||||
if (modelNumber > 0 && modelNumber > modelIndex && modelNumber < getCurrentFirmware()->getCapability(Models)) {
|
||||
modelIndex = modelNumber;
|
||||
qDebug() << "advanced model number to" << modelIndex;
|
||||
}
|
||||
else {
|
||||
if (modelNumber != modelIndex) qDebug() << "Invalid model number" << parts[0];
|
||||
}
|
||||
parts.removeFirst();
|
||||
}
|
||||
if (parts.size() == 1) {
|
||||
// parse model file name and load
|
||||
QString fileName = parts[0];
|
||||
qDebug() << "Loading model from file" << fileName << "into slot" << modelIndex;
|
||||
QByteArray modelBuffer;
|
||||
if (!loadFile(modelBuffer, QString("MODELS/%1").arg(fileName))) {
|
||||
setError(tr("Cannot extract %1").arg(fileName));
|
||||
return false;
|
||||
}
|
||||
if ((int)radioData.models.size() <= modelIndex) {
|
||||
radioData.models.resize(modelIndex + 1);
|
||||
}
|
||||
if (!loadModelFromByteArray(radioData.models[modelIndex], modelBuffer)) {
|
||||
setError(tr("Error loading models"));
|
||||
return false;
|
||||
}
|
||||
strncpy(radioData.models[modelIndex].filename, qPrintable(fileName), sizeof(radioData.models[modelIndex].filename));
|
||||
if (IS_FAMILY_HORUS_OR_T16(board) && !strcmp(radioData.generalSettings.currModelFilename, qPrintable(fileName))) {
|
||||
radioData.generalSettings.currModelIndex = modelIndex;
|
||||
qDebug() << "currModelIndex =" << modelIndex;
|
||||
}
|
||||
radioData.models[modelIndex].used = true;
|
||||
modelIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// invalid line
|
||||
// TODO add to parsing report
|
||||
qDebug() << "Invalid line" <<line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add a Favorites label
|
||||
if(getCurrentFirmware()->getCapability(HasModelLabels)) {
|
||||
RadioData::LabelData ld = { tr("Favorites"), false };
|
||||
radioData.labels.append(ld);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabelsStorageFormat::writeBin(const RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsData; // radio.bin
|
||||
size_t numModels = radioData.models.size();
|
||||
size_t numCategories = radioData.labels.size();
|
||||
std::vector<std::vector<QString>> sortedModels(numCategories);
|
||||
|
||||
writeRadioSettingsToByteArray(radioData.generalSettings, radioSettingsData);
|
||||
if (!writeFile(radioSettingsData, "RADIO/radio.bin")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t m=0; m<numModels; m++) {
|
||||
const ModelData & model = radioData.models[m];
|
||||
if (model.isEmpty()) continue;
|
||||
|
||||
QString modelFilename = QString("MODELS/%1").arg(model.filename);
|
||||
QByteArray modelData;
|
||||
writeModelToByteArray(model, modelData);
|
||||
if (!writeFile(modelData, modelFilename)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabelsStorageFormat::loadYaml(RadioData & radioData)
|
||||
{
|
||||
if (getStorageType(filename) == STORAGE_TYPE_UNKNOWN && probeFormat() == STORAGE_TYPE_ETX) {
|
||||
if (!QFile(filename + "/" + "RADIO/radio.yml").exists())
|
||||
qDebug() << tr("Cannot find %1/RADIO/radio.yml").arg(filename);
|
||||
@@ -238,11 +99,11 @@ bool LabelsStorageFormat::loadYaml(RadioData & radioData)
|
||||
|
||||
// Scan for all models
|
||||
std::list<std::string> filelist;
|
||||
if (!getFileList(filelist)) {
|
||||
if (!getFileList(filelist))
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::regex yml_regex("MODELS/(model([0-9]+)\\.yml)");
|
||||
|
||||
for(const auto& f : filelist) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(f, match, yml_regex)) {
|
||||
@@ -302,10 +163,8 @@ bool LabelsStorageFormat::loadYaml(RadioData & radioData)
|
||||
model.modelIndex = modelIdx;
|
||||
strncpy(model.filename, mc.filename.c_str(), sizeof(model.filename)-1);
|
||||
|
||||
if (hasLabels && !strncmp(radioData.generalSettings.currModelFilename,
|
||||
model.filename, sizeof(model.filename))) {
|
||||
if (hasLabels && !strncmp(radioData.generalSettings.currModelFilename, model.filename, sizeof(model.filename)))
|
||||
radioData.generalSettings.currModelIndex = modelIdx;
|
||||
}
|
||||
|
||||
model.used = true;
|
||||
modelIdx++;
|
||||
@@ -325,16 +184,14 @@ bool LabelsStorageFormat::loadYaml(RadioData & radioData)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabelsStorageFormat::writeYaml(const RadioData & radioData)
|
||||
bool LabelsStorageFormat::write(const RadioData & radioData)
|
||||
{
|
||||
QByteArray radioSettingsBuffer;
|
||||
if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer)) {
|
||||
if (!writeRadioSettingsToYaml(radioData.generalSettings, radioSettingsBuffer))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!writeFile(radioSettingsBuffer, "RADIO/radio.yml")) {
|
||||
if (!writeFile(radioSettingsBuffer, "RADIO/radio.yml"))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasLabels = getCurrentFirmware()->getCapability(HasModelLabels);
|
||||
|
||||
@@ -347,7 +204,7 @@ bool LabelsStorageFormat::writeYaml(const RadioData & radioData)
|
||||
|
||||
// Delete all old modelxx.yml from radio MODELS folder before writing new modelxx.yml files
|
||||
const std::regex yml_regex("MODELS/(model([0-9s]+)\\.yml)");
|
||||
for(const auto& f : filelist) {
|
||||
for (const auto& f : filelist) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(f, match, yml_regex)) {
|
||||
if (match.size() == 3) {
|
||||
@@ -368,28 +225,22 @@ bool LabelsStorageFormat::writeYaml(const RadioData & radioData)
|
||||
QString modelFilename;
|
||||
if (hasLabels) {
|
||||
std::string ymlFilename = patchFilenameToYaml(model.filename);
|
||||
modelFilename =
|
||||
QString("MODELS/%1").arg(QString::fromStdString(ymlFilename));
|
||||
modelFiles.push_back(
|
||||
{ymlFilename, std::string(model.name)});
|
||||
modelFilename = QString("MODELS/%1").arg(QString::fromStdString(ymlFilename));
|
||||
modelFiles.push_back({ymlFilename, std::string(model.name)});
|
||||
} else {
|
||||
modelFilename = QString("MODELS/model%1.yml")
|
||||
.arg(model.modelIndex, 2, 10, QLatin1Char('0'));
|
||||
modelFilename = QString("MODELS/model%1.yml").arg(model.modelIndex, 2, 10, QLatin1Char('0'));
|
||||
}
|
||||
|
||||
QByteArray modelData;
|
||||
writeModelToYaml(model, modelData);
|
||||
if (!writeFile(modelData, modelFilename)) {
|
||||
if (!writeFile(modelData, modelFilename))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLabels) {
|
||||
QByteArray labelsListBuffer;
|
||||
if (!writeLabelsListToYaml(radioData, labelsListBuffer)
|
||||
|| !writeFile(labelsListBuffer, "MODELS/labels.yml")) {
|
||||
if (!writeLabelsListToYaml(radioData, labelsListBuffer) || !writeFile(labelsListBuffer, "MODELS/labels.yml"))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -47,10 +47,5 @@ class LabelsStorageFormat : public StorageFormat
|
||||
virtual bool getFileList(std::list<std::string>& filelist) = 0;
|
||||
virtual bool deleteFile(const QString & fileName) = 0;
|
||||
|
||||
virtual bool loadBin(RadioData & radioData);
|
||||
virtual bool writeBin(const RadioData & radioData);
|
||||
virtual bool loadYaml(RadioData & radioData);
|
||||
virtual bool writeYaml(const RadioData & radioData);
|
||||
|
||||
StorageType probeFormat();
|
||||
};
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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 <QFile>
|
||||
|
||||
#define MZ_ALLOCATION_SIZE (32*1024)
|
||||
|
||||
bool OtxFormat::load(RadioData & radioData)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
setError(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() << tr("Error opening OpenTX archive %1").arg(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = LabelsStorageFormat::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(tr("Error initializing OpenTX archive writer"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = LabelsStorageFormat::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(tr("Error writing file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating OpenTX file %1:\n%2.").arg(filename).arg(file.errorString()));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
setError(tr("Error creating OpenTX 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, qPrintable(filename), &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(tr("Error adding %1 to OpenTX archive").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "labeled.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class OtxFormat : public LabelsStorageFormat
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(OtxFormat)
|
||||
|
||||
public:
|
||||
OtxFormat(const QString & filename):
|
||||
LabelsStorageFormat(filename)
|
||||
{
|
||||
}
|
||||
|
||||
virtual QString name() { return "otx"; }
|
||||
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);
|
||||
virtual bool getFileList(std::list<std::string>& filelist) { return false; }
|
||||
virtual bool deleteFile(const QString & fileName) { return false; }
|
||||
|
||||
mz_zip_archive zip_archive;
|
||||
};
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _SDCARD_H2_
|
||||
#define _SDCARD_H2_
|
||||
#pragma once
|
||||
|
||||
#include "labeled.h"
|
||||
|
||||
@@ -56,5 +55,3 @@ class SdcardStorageFactory : public DefaultStorageFactory<SdcardFormat>
|
||||
|
||||
virtual bool probe(const QString & name);
|
||||
};
|
||||
|
||||
#endif // _SDCARD_H2_
|
||||
|
||||
@@ -19,32 +19,17 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "bineeprom.h"
|
||||
#include "eepe.h"
|
||||
#include "otx.h"
|
||||
#include "etx.h"
|
||||
#include "sdcard.h"
|
||||
#include "yaml.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "sdcard.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 if (suffix == "ETX")
|
||||
|
||||
if (suffix == "ETX")
|
||||
return STORAGE_TYPE_ETX;
|
||||
else if (suffix == "YML")
|
||||
return STORAGE_TYPE_YML;
|
||||
@@ -64,10 +49,6 @@ void registerStorageFactory(StorageFactory * 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 DefaultStorageFactory<EtxFormat>("etx"));
|
||||
registerStorageFactory(new DefaultStorageFactory<YamlFormat>("yml"));
|
||||
registerStorageFactory(new SdcardStorageFactory());
|
||||
@@ -88,7 +69,7 @@ bool Storage::load(RadioData & radioData)
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
foreach(StorageFactory * factory, registeredStorageFactories) {
|
||||
foreach (StorageFactory * factory, registeredStorageFactories) {
|
||||
if (factory->probe(filename)) {
|
||||
StorageFormat * format = factory->instance(filename);
|
||||
if (format->load(radioData)) {
|
||||
@@ -111,7 +92,7 @@ bool Storage::load(RadioData & radioData)
|
||||
bool Storage::write(const RadioData & radioData)
|
||||
{
|
||||
bool ret = false;
|
||||
foreach(StorageFactory * factory, registeredStorageFactories) {
|
||||
foreach (StorageFactory * factory, registeredStorageFactories) {
|
||||
if (factory->probe(filename)) {
|
||||
StorageFormat * format = factory->instance(filename);
|
||||
ret = format->write(radioData);
|
||||
@@ -125,7 +106,7 @@ bool Storage::write(const RadioData & radioData)
|
||||
bool Storage::writeModel(const RadioData & radioData, const int modelIndex)
|
||||
{
|
||||
bool ret = false;
|
||||
foreach(StorageFactory * factory, registeredStorageFactories) {
|
||||
foreach (StorageFactory * factory, registeredStorageFactories) {
|
||||
if (factory->probe(filename)) {
|
||||
StorageFormat * format = factory->instance(filename);
|
||||
ret = format->writeModel(radioData, modelIndex);
|
||||
@@ -135,76 +116,3 @@ bool Storage::writeModel(const RadioData & radioData, const int modelIndex)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool convertEEprom(const QString & sourceEEprom, const QString & destinationEEprom, const QString & firmwareFilename)
|
||||
{
|
||||
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(Boards::getEEpromSize(Board::BOARD_UNKNOWN), 0);
|
||||
int size = getCurrentEEpromInterface()->save((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
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _STORAGE_H_
|
||||
#define _STORAGE_H_
|
||||
#pragma once
|
||||
|
||||
#include "radiodata.h"
|
||||
|
||||
@@ -31,13 +30,8 @@
|
||||
enum StorageType
|
||||
{
|
||||
STORAGE_TYPE_UNKNOWN,
|
||||
STORAGE_TYPE_BIN,
|
||||
STORAGE_TYPE_HEX,
|
||||
STORAGE_TYPE_EEPE,
|
||||
STORAGE_TYPE_EEPM,
|
||||
STORAGE_TYPE_XML,
|
||||
STORAGE_TYPE_HEX, // needed for FirmwareInterface
|
||||
STORAGE_TYPE_SDCARD,
|
||||
STORAGE_TYPE_OTX,
|
||||
STORAGE_TYPE_ETX,
|
||||
STORAGE_TYPE_YML
|
||||
};
|
||||
@@ -164,13 +158,3 @@ class Storage : public StorageFormat
|
||||
|
||||
void registerStorageFactories();
|
||||
void unregisterStorageFactories();
|
||||
|
||||
#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_
|
||||
|
||||
Reference in New Issue
Block a user