Files
edgetx-gx12/companion/src/eepromimportexport.h
T

683 lines
14 KiB
C++

/*
* Author - Bertrand Songis <bsongis@gmail.com>
*
* Based on th9x -> http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef eeprom_importexport_h
#define eeprom_importexport_h
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
class DataField {
public:
DataField(const char *name=""):
name(name)
{
}
virtual const char *getName() { return name; }
virtual ~DataField() { }
virtual void ExportBits(QBitArray & output) = 0;
virtual void ImportBits(QBitArray & input) = 0;
virtual unsigned int size() = 0;
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;
}
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(QByteArray & input)
{
QBitArray bits = bytesToBits(input);
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(), bytes.count());
else
printf("%s (%dbits) ", getName(), 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:
const char *name;
};
template<int N>
class UnsignedField: public DataField {
public:
explicit UnsignedField(unsigned int & field):
DataField("Unsigned"),
field(field),
min(0),
max(UINT_MAX)
{
}
UnsignedField(unsigned int & field, const char *name):
DataField(name),
field(field),
min(0),
max(UINT_MAX)
{
}
UnsignedField(unsigned int & field, unsigned int min, unsigned int max, const char *name="Unsigned"):
DataField(name),
field(field),
min(min),
max(max)
{
}
virtual void ExportBits(QBitArray & output)
{
unsigned int value = field;
if (value > max) value = max;
if (value < min) value = min;
output.resize(N);
for (int i=0; i<N; i++) {
if (value & (1<<i))
output.setBit(i);
}
}
virtual void ImportBits(QBitArray & input)
{
field = 0;
for (int i=0; i<N; i++) {
if (input[i])
field |= (1<<i);
}
}
virtual unsigned int size()
{
return N;
}
protected:
unsigned int & field;
unsigned int min;
unsigned int max;
private:
UnsignedField();
};
template<int N>
class BoolField: public DataField {
public:
explicit BoolField(bool & field):
DataField("Bool"),
field(field)
{
}
virtual void ExportBits(QBitArray & output)
{
output.resize(N);
if (field) {
output.setBit(0);
}
}
virtual void ImportBits(QBitArray & input)
{
field = input[0] ? true : false;
}
virtual unsigned int size()
{
return N;
}
protected:
bool & field;
private:
BoolField();
};
template<int N>
class SignedField: public DataField {
public:
SignedField(int & field):
DataField("Signed"),
field(field),
min(INT_MIN),
max(INT_MAX)
{
}
SignedField(int & field, const char *name):
DataField(name),
field(field),
min(INT_MIN),
max(INT_MAX)
{
}
SignedField(int & field, int min, int max, const char *name="Signed"):
DataField(name),
field(field),
min(min),
max(max)
{
}
virtual void ExportBits(QBitArray & output)
{
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);
}
}
virtual void ImportBits(QBitArray & input)
{
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;
}
virtual unsigned int size()
{
return N;
}
protected:
int & field;
int min;
int max;
};
template<int N>
class SpareBitsField: public UnsignedField<N> {
public:
SpareBitsField():
UnsignedField<N>(spare, 0, 0, "Spare"),
spare(0)
{
}
protected:
unsigned int spare;
};
template<int N>
class CharField: public DataField {
public:
CharField(char *field):
DataField("Char"),
field(field)
{
}
virtual void ExportBits(QBitArray & output)
{
output.resize(N*8);
int b = 0;
int len = strlen(field);
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);
}
}
}
virtual void ImportBits(QBitArray & input)
{
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;
}
}
virtual unsigned int size()
{
return 8*N;
}
protected:
char * field;
};
int8_t char2idx(char c);
char idx2char(int8_t idx);
template<int N>
class ZCharField: public DataField {
public:
ZCharField(char *field):
DataField("ZChar"),
field(field)
{
}
virtual void ExportBits(QBitArray & output)
{
output.resize(N*8);
int b = 0;
int len = strlen(field);
for (int i=0; i<N; i++) {
int idx = i>=len ? 0 : char2idx(field[i]);
for (int j=0; j<8; j++, b++) {
if (idx & (1<<j))
output.setBit(b);
}
}
}
virtual void ImportBits(QBitArray & input)
{
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] = idx2char(idx);
}
field[N] = '\0';
for (int i=N-1; i>=0; i--) {
if (field[i] == ' ')
field[i] = '\0';
else
break;
}
}
virtual unsigned int size()
{
return 8*N;
}
protected:
char * field;
};
class StructField: public DataField {
public:
StructField(const char *name="Struct"):
DataField(name)
{
}
~StructField() {
foreach(DataField *field, fields) {
delete field;
}
}
inline void Append(DataField *field) {
fields.append(field);
}
virtual void ExportBits(QBitArray & output)
{
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];
}
}
virtual void ImportBits(QBitArray & input)
{
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);
}
}
virtual unsigned int size()
{
unsigned int result = 0;
foreach(DataField *field, fields) {
result += field->size();
}
return result;
}
virtual int Dump(int level=0, int offset=0)
{
for (int i=0; i<level; i++) printf(" ");
printf("%s (%d bytes)\n", getName(), 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 & field):
DataField(),
field(field)
{
}
virtual ~TransformedField()
{
}
virtual void ExportBits(QBitArray & output)
{
beforeExport();
field.ExportBits(output);
}
virtual void ImportBits(QBitArray & input)
{
field.ImportBits(input);
afterImport();
}
virtual const char *getName()
{
return field.getName();
}
virtual unsigned int size()
{
return field.size();
}
virtual void beforeExport() = 0;
virtual void afterImport() = 0;
virtual int Dump(int level=0, int offset=0)
{
beforeExport();
return field.Dump(level, offset);
}
protected:
DataField & field;
};
class ConversionTable {
public:
bool exportValue(const int before, int &after)
{
after = 0;
for (std::list<ConversionTuple>::iterator it=internalTable.begin(); it!=internalTable.end(); it++) {
ConversionTuple tuple = *it;
if (before == tuple.a) {
after = tuple.b;
return true;
}
}
return false;
}
bool importValue(const int before, int &after)
{
after = 0;
for (std::list<ConversionTuple>::iterator it=internalTable.begin(); it!=internalTable.end(); it++) {
ConversionTuple tuple = *it;
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)
{
internalTable.push_back(ConversionTuple(a, b));
}
std::list<ConversionTuple> internalTable;
};
template<class T>
class ConversionField: public TransformedField {
public:
ConversionField(int & field, ConversionTable *table, const char *name, const QString & error = ""):
TransformedField(internalField),
internalField(_field, name),
field(field),
_field(0),
table(table),
shift(0),
scale(1),
min(INT_MIN),
max(INT_MAX),
exportFunc(NULL),
importFunc(NULL),
error(error)
{
}
ConversionField(unsigned int & field, ConversionTable *table, const char *name, const QString & error = ""):
TransformedField(internalField),
internalField((unsigned int &)_field, name),
field((int &)field),
_field(0),
table(table),
shift(0),
scale(0),
min(INT_MIN),
max(INT_MAX),
exportFunc(NULL),
importFunc(NULL),
error(error)
{
}
ConversionField(int & field, int (*exportFunc)(int), int (*importFunc)(int)):
TransformedField(internalField),
internalField(_field),
field(field),
_field(0),
table(NULL),
shift(0),
scale(0),
min(INT_MIN),
max(INT_MAX),
exportFunc(exportFunc),
importFunc(importFunc),
error("")
{
}
ConversionField(int & field, int shift, int scale=0, int min=INT_MIN, int max=INT_MAX, const char *name = "Signed shifted"):
TransformedField(internalField),
internalField(_field, name),
field(field),
_field(0),
table(NULL),
shift(shift),
scale(scale),
min(min),
max(max),
exportFunc(NULL),
importFunc(NULL),
error("")
{
}
ConversionField(unsigned int & field, int shift, int scale=0):
TransformedField(internalField),
internalField((unsigned int &)_field),
field((int &)field),
_field(0),
table(NULL),
shift(shift),
scale(scale),
min(INT_MIN),
max(INT_MAX),
exportFunc(NULL),
importFunc(NULL),
error("")
{
}
virtual void beforeExport()
{
int val = field;
if (scale) {
val /= scale;
}
if (table) {
if (table->exportValue(val, _field))
return;
if (!error.isEmpty())
EEPROMWarnings += error + "\n";
}
else if (shift) {
if (val < min) _field = min + shift;
else if (val > max) _field = max + shift;
else _field = val + shift;
}
else {
_field = exportFunc(val);
}
}
virtual void afterImport()
{
if (table) {
if (table->importValue(_field, field))
return;
}
else if (shift) {
field = _field - shift;
}
else {
field = importFunc(_field);
}
if (scale) {
field *= scale;
}
}
protected:
T internalField;
int & field;
int _field;
ConversionTable * table;
int shift;
int scale;
int min;
int max;
int (*exportFunc)(int);
int (*importFunc)(int);
const QString error;
};
#endif