/* * Copyright (C) OpenTX * * Based on code named * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef _EEPROMIMPORTEXPORT_H_ #define _EEPROMIMPORTEXPORT_H_ #include "customdebug.h" #include class DataField { public: DataField(DataField * parent, const char * name=""): parent(parent), name(name) { } virtual ~DataField() { } virtual const QString & getName() { return name; } virtual unsigned int size() = 0; virtual void ExportBits(QBitArray & output) = 0; virtual void ImportBits(const QBitArray & input) = 0; QBitArray bytesToBits(QByteArray bytes) { QBitArray bits(bytes.count()*8); // Convert from QByteArray to QBitArray for (int i=0; isetError(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 BaseUnsignedField: public DataField { public: BaseUnsignedField(DataField * parent, container & field): DataField(parent, "Unsigned"), field(field), min(0), max(std::numeric_limits::max()) { } BaseUnsignedField(DataField * parent, container & field, const char * name): DataField(parent, name), field(field), min(0), max(std::numeric_limits::max()) { } BaseUnsignedField(DataField * parent, container & field, container min, container max, const char * name="Unsigned"): DataField(parent, name), field(field), min(min), max(max) { } virtual void ExportBits(QBitArray & output) { container value = field; if (value > max) value = max; if (value < min) value = min; output.resize(N); for (int i=0; i: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field); } virtual unsigned int size() { return N; } protected: container & field; container min; container max; private: BaseUnsignedField(); }; template class UnsignedField : public BaseUnsignedField { public: UnsignedField(DataField * parent, unsigned int & field): BaseUnsignedField(parent, field) { } UnsignedField(DataField * parent, unsigned int & field, const char *name): BaseUnsignedField(parent, field, name) { } UnsignedField(DataField * parent, unsigned int & field, unsigned int min, unsigned int max, const char *name="Unsigned"): BaseUnsignedField(parent, field, min, max, name) { } }; template class BoolField: public DataField { public: explicit BoolField(DataField * parent, bool & field): DataField(parent, "Bool"), field(field) { } virtual void ExportBits(QBitArray & output) { output.resize(N); if (field) { output.setBit(0); } } virtual void ImportBits(const QBitArray & input) { field = input[0] ? true : false; qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field); } virtual unsigned int size() { return N; } protected: bool & field; private: BoolField(); }; template class SignedField: public DataField { public: SignedField(DataField * parent, int & field): DataField(parent, "Signed"), field(field), min(INT_MIN), max(INT_MAX) { } SignedField(DataField * parent, int & field, const char *name): DataField(parent, name), field(field), min(INT_MIN), max(INT_MAX) { } SignedField(DataField * parent, int & field, int min, int max, const char *name="Signed"): DataField(parent, 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: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field); } virtual unsigned int size() { return N; } protected: int & field; int min; int max; }; template class SpareBitsField: public UnsignedField { public: SpareBitsField(DataField * parent): UnsignedField(parent, spare, 0, 0, "Spare"), spare(0) { } protected: unsigned int spare; }; template class CharField: public DataField { public: CharField(DataField * parent, char * field, bool truncate=true, const char * name="Char"): DataField(parent, name), field(field), truncate(truncate) { } virtual void ExportBits(QBitArray & output) { output.resize(N*8); int b = 0; int len = truncate ? strlen(field) : N; for (int i=0; i=len ? 0 : field[i]); for (int j=0; j<8; j++, b++) { if (idx & (1<: '%3'").arg(name).arg(N).arg(field); } virtual unsigned int size() { return 8*N; } protected: char * field; bool truncate; }; int8_t char2idx(char c); char idx2char(int8_t idx); template class ZCharField: public DataField { public: ZCharField(DataField * parent, char * field, const char * name = "ZChar"): DataField(parent, name), field(field) { } virtual void ExportBits(QBitArray & output) { output.resize(N*8); int b = 0; int len = strlen(field); for (int i=0; i=len ? 0 : char2idx(field[i]); for (int j=0; j<8; j++, b++) { if (idx & (1<=0; i--) { if (field[i] == ' ') field[i] = '\0'; else break; } qCDebug(eepromImport) << QString("\timported %1<%2>: '%3'").arg(name).arg(N).arg(field); } virtual unsigned int size() { return 8*N; } protected: char * field; }; class StructField: public DataField { public: StructField(DataField * parent, const char * name="Struct"): DataField(parent, name) { } ~StructField() { 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); } virtual void ExportBits(QBitArray & output) { int offset = 0; output.resize(size()); foreach(DataField *field, fields) { QBitArray bits; field->ExportBits(bits); for (int i=0; isize(); QBitArray bits(size); for (unsigned int i=0; iImportBits(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; iDump(level+1, offset); } return offset; } protected: QList fields; }; class TransformedField: public DataField { public: TransformedField(DataField * parent, DataField & field): DataField(parent), field(field) { } virtual ~TransformedField() { } virtual void ExportBits(QBitArray & output) { beforeExport(); field.ExportBits(output); } virtual void ImportBits(const QBitArray & input) { qCDebug(eepromImport) << QString("\timporting TransformedField %1:").arg(field.getName()); field.ImportBits(input); afterImport(); } virtual const QString & 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::iterator it=exportTable.begin(); it!=exportTable.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::iterator it=importTable.begin(); it!=importTable.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) { 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 importTable; std::list exportTable; }; template class ConversionField: public TransformedField { public: ConversionField(DataField * parent, int & field, ConversionTable *table, const char *name, const QString & error = ""): TransformedField(parent, internalField), internalField(this, _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(DataField * parent, unsigned int & field, ConversionTable *table, const char *name, const QString & error = ""): TransformedField(parent, internalField), internalField(this, (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(DataField * parent, int & field, int (*exportFunc)(int), int (*importFunc)(int)): TransformedField(parent, internalField), internalField(this, _field), field(field), _field(0), table(NULL), shift(0), scale(0), min(INT_MIN), max(INT_MAX), exportFunc(exportFunc), importFunc(importFunc), error("") { } 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), _field(0), table(NULL), shift(shift), scale(scale), min(min), max(max), exportFunc(NULL), importFunc(NULL), error("") { } ConversionField(DataField * parent, unsigned int & field, int shift, int scale=0): TransformedField(parent, internalField), internalField(this, (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() { _field = field; if (scale) { _field /= scale; } if (table) { if (!table->exportValue(_field, _field)) { setError(error.isEmpty() ? QObject::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); } } virtual void afterImport() { 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; ConversionTable * table; int shift; int scale; int min; int max; int (*exportFunc)(int); int (*importFunc)(int); const QString error; }; #endif // _EEPROMIMPORTEXPORT_H_