Also play model name on model changes (#5416)
[opentx.git] / companion / src / eepromimportexport.h
blob96c1d2fd9bd0492ca8da044ef1e5ca01c5f8db13
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #ifndef _EEPROMIMPORTEXPORT_H_
22 #define _EEPROMIMPORTEXPORT_H_
24 #include "customdebug.h"
25 #include <QBitArray>
27 class DataField {
28 public:
29 DataField(DataField * parent, const char * name=""):
30 parent(parent),
31 name(name)
35 virtual ~DataField()
39 virtual const QString & getName()
41 return name;
44 virtual unsigned int size() = 0;
45 virtual void ExportBits(QBitArray & output) = 0;
46 virtual void ImportBits(const QBitArray & input) = 0;
48 QBitArray bytesToBits(QByteArray bytes)
50 QBitArray bits(bytes.count()*8);
51 // Convert from QByteArray to QBitArray
52 for (int i=0; i<bytes.count(); ++i)
53 for (int b=0; b<8; ++b)
54 bits.setBit(i*8+b, bytes.at(i)&(1<<b));
55 return bits;
58 QByteArray bitsToBytes(QBitArray bits, int offset=0)
60 QByteArray bytes;
61 bytes.resize((offset+bits.count()+7)/8);
62 bytes.fill(0);
63 // Convert from QBitArray to QByteArray
64 for (int b=0; b<bits.count(); ++b)
65 bytes[(b+offset)/8] = ( bytes.at((b+offset)/8) | ((bits[b]?1:0)<<((b+offset)%8)));
66 return bytes;
69 int Export(QByteArray & output)
71 QBitArray result;
72 ExportBits(result);
73 output = bitsToBytes(result);
74 return 0;
77 int Import(const QByteArray & input)
79 QBitArray bits = bytesToBits(input);
80 if ((unsigned int)bits.size() < size()) {
81 qDebug() << QString("Error importing %1: size to small %2/%3").arg(getName()).arg(input.size()).arg(size());
82 return -1;
84 ImportBits(bits);
85 return 0;
88 virtual int Dump(int level=0, int offset=0)
90 QBitArray bits;
91 ExportBits(bits);
92 QByteArray bytes = bitsToBytes(bits);
93 int result = (offset+bits.count()) % 8;
94 for (int i=0; i<level; i++) printf(" ");
95 if (bits.count() % 8 == 0)
96 printf("%s (%dbytes) ", getName().toLatin1().constData(), bytes.count());
97 else
98 printf("%s (%dbits) ", getName().toLatin1().constData(), bits.count());
99 for (int i=0; i<bytes.count(); i++) {
100 unsigned char c = bytes[i];
101 if ((i==0 && offset) || (i==bytes.count()-1 && result!=0))
102 printf("(%02x) ", c);
103 else
104 printf("%02x ", c);
106 printf("\n"); fflush(stdout);
107 return result;
110 protected:
111 virtual void setError(const QString & error)
113 if (parent) {
114 parent->setError(error);
116 else {
117 qWarning() << qPrintable(error);
121 DataField * parent;
122 QString name;
125 class ProxyField: public DataField {
126 public:
127 explicit ProxyField(DataField * parent):
128 DataField(parent, "Proxy")
132 virtual DataField * getField() = 0;
136 template<class container, int N>
137 class BaseUnsignedField: public DataField {
138 public:
139 BaseUnsignedField(DataField * parent, container & field):
140 DataField(parent, "Unsigned"),
141 field(field),
142 min(0),
143 max(std::numeric_limits<container>::max())
147 BaseUnsignedField(DataField * parent, container & field, const char * name):
148 DataField(parent, name),
149 field(field),
150 min(0),
151 max(std::numeric_limits<container>::max())
155 BaseUnsignedField(DataField * parent, container & field, container min, container max, const char * name="Unsigned"):
156 DataField(parent, name),
157 field(field),
158 min(min),
159 max(max)
163 virtual void ExportBits(QBitArray & output)
165 container value = field;
166 if (value > max) value = max;
167 if (value < min) value = min;
169 output.resize(N);
170 for (int i=0; i<N; i++) {
171 if (value & ((container)1<<i)) {
172 output.setBit(i);
177 virtual void ImportBits(const QBitArray & input)
179 field = 0;
180 for (int i=0; i<N; i++) {
181 if (input[i])
182 field |= ((container)1<<i);
184 qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
187 virtual unsigned int size()
189 return N;
192 protected:
193 container & field;
194 container min;
195 container max;
197 private:
198 BaseUnsignedField();
201 template <int N>
202 class UnsignedField : public BaseUnsignedField<unsigned int, N>
204 public:
205 UnsignedField(DataField * parent, unsigned int & field):
206 BaseUnsignedField<unsigned int, N>(parent, field)
210 UnsignedField(DataField * parent, unsigned int & field, const char *name):
211 BaseUnsignedField<unsigned int, N>(parent, field, name)
215 UnsignedField(DataField * parent, unsigned int & field, unsigned int min, unsigned int max, const char *name="Unsigned"):
216 BaseUnsignedField<unsigned int, N>(parent, field, min, max, name)
221 template<int N>
222 class BoolField: public DataField {
223 public:
224 explicit BoolField(DataField * parent, bool & field):
225 DataField(parent, "Bool"),
226 field(field)
230 virtual void ExportBits(QBitArray & output)
232 output.resize(N);
233 if (field) {
234 output.setBit(0);
238 virtual void ImportBits(const QBitArray & input)
240 field = input[0] ? true : false;
241 qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
244 virtual unsigned int size()
246 return N;
249 protected:
250 bool & field;
252 private:
253 BoolField();
256 template<int N>
257 class SignedField: public DataField {
258 public:
259 SignedField(DataField * parent, int & field):
260 DataField(parent, "Signed"),
261 field(field),
262 min(INT_MIN),
263 max(INT_MAX)
267 SignedField(DataField * parent, int & field, const char *name):
268 DataField(parent, name),
269 field(field),
270 min(INT_MIN),
271 max(INT_MAX)
275 SignedField(DataField * parent, int & field, int min, int max, const char *name="Signed"):
276 DataField(parent, name),
277 field(field),
278 min(min),
279 max(max)
283 virtual void ExportBits(QBitArray & output)
285 int value = field;
286 if (value > max) value = max;
287 if (value < min) value = min;
289 output.resize(N);
290 for (int i=0; i<N; i++) {
291 if (((unsigned int)value) & (1<<i))
292 output.setBit(i);
296 virtual void ImportBits(const QBitArray & input)
298 unsigned int value = 0;
299 for (int i=0; i<N; i++) {
300 if (input[i])
301 value |= (1<<i);
304 if (input[N-1]) {
305 for (unsigned int i=N; i<8*sizeof(int); i++) {
306 value |= (1<<i);
310 field = (int)value;
311 qCDebug(eepromImport) << QString("\timported %1<%2>: 0x%3(%4)").arg(name).arg(N).arg(field, 0, 16).arg(field);
314 virtual unsigned int size()
316 return N;
319 protected:
320 int & field;
321 int min;
322 int max;
325 template<int N>
326 class SpareBitsField: public UnsignedField<N> {
327 public:
328 SpareBitsField(DataField * parent):
329 UnsignedField<N>(parent, spare, 0, 0, "Spare"),
330 spare(0)
333 protected:
334 unsigned int spare;
337 template<int N>
338 class CharField: public DataField {
339 public:
340 CharField(DataField * parent, char * field, bool truncate=true, const char * name="Char"):
341 DataField(parent, name),
342 field(field),
343 truncate(truncate)
347 virtual void ExportBits(QBitArray & output)
349 output.resize(N*8);
350 int b = 0;
351 int len = truncate ? strlen(field) : N;
352 for (int i=0; i<N; i++) {
353 int idx = (i>=len ? 0 : field[i]);
354 for (int j=0; j<8; j++, b++) {
355 if (idx & (1<<j))
356 output.setBit(b);
361 virtual void ImportBits(const QBitArray & input)
363 unsigned int b = 0;
364 for (int i=0; i<N; i++) {
365 int8_t idx = 0;
366 for (int j=0; j<8; j++) {
367 if (input[b++])
368 idx |= (1<<j);
370 field[i] = idx;
372 qCDebug(eepromImport) << QString("\timported %1<%2>: '%3'").arg(name).arg(N).arg(field);
375 virtual unsigned int size()
377 return 8*N;
380 protected:
381 char * field;
382 bool truncate;
385 int8_t char2idx(char c);
386 char idx2char(int8_t idx);
388 template<int N>
389 class ZCharField: public DataField {
390 public:
391 ZCharField(DataField * parent, char * field, const char * name = "ZChar"):
392 DataField(parent, name),
393 field(field)
397 virtual void ExportBits(QBitArray & output)
399 output.resize(N*8);
400 int b = 0;
401 int len = strlen(field);
402 for (int i=0; i<N; i++) {
403 int idx = i>=len ? 0 : char2idx(field[i]);
404 for (int j=0; j<8; j++, b++) {
405 if (idx & (1<<j))
406 output.setBit(b);
411 virtual void ImportBits(const QBitArray & input)
413 unsigned int b = 0;
414 for (int i=0; i<N; i++) {
415 int8_t idx = 0;
416 for (int j=0; j<8; j++) {
417 if (input[b++])
418 idx |= (1<<j);
420 field[i] = idx2char(idx);
423 field[N] = '\0';
424 for (int i=N-1; i>=0; i--) {
425 if (field[i] == ' ')
426 field[i] = '\0';
427 else
428 break;
430 qCDebug(eepromImport) << QString("\timported %1<%2>: '%3'").arg(name).arg(N).arg(field);
433 virtual unsigned int size()
435 return 8*N;
438 protected:
439 char * field;
442 class StructField: public DataField {
443 public:
444 StructField(DataField * parent, const char * name="Struct"):
445 DataField(parent, name)
449 ~StructField() {
450 foreach(DataField * field, fields) {
451 delete field;
455 inline void Append(DataField * field) {
456 //qCDebug(eepromImport) << QString("StructField(%1) appending field: %2").arg(name).arg(field->getName());
457 fields.append(field);
460 virtual void ExportBits(QBitArray & output)
462 int offset = 0;
463 output.resize(size());
464 foreach(DataField *field, fields) {
465 QBitArray bits;
466 field->ExportBits(bits);
467 for (int i=0; i<bits.size(); i++)
468 output[offset++] = bits[i];
472 virtual void ImportBits(const QBitArray & input)
474 qCDebug(eepromImport) << QString("\timporting %1[%2]:").arg(name).arg(fields.size());
475 int offset = 0;
476 foreach(DataField *field, fields) {
477 unsigned int size = field->size();
478 QBitArray bits(size);
479 for (unsigned int i=0; i<size; i++) {
480 bits[i] = input[offset++];
482 field->ImportBits(bits);
486 virtual unsigned int size()
488 unsigned int result = 0;
489 foreach(DataField *field, fields) {
490 result += field->size();
492 return result;
495 virtual int Dump(int level=0, int offset=0)
497 for (int i=0; i<level; i++) printf(" ");
498 printf("%s (%d bytes)\n", getName().toLatin1().constData(), size()/8);
499 foreach(DataField *field, fields) {
500 offset = field->Dump(level+1, offset);
502 return offset;
505 protected:
506 QList<DataField *> fields;
509 class TransformedField: public DataField {
510 public:
511 TransformedField(DataField * parent, DataField & field):
512 DataField(parent),
513 field(field)
517 virtual ~TransformedField()
521 virtual void ExportBits(QBitArray & output)
523 beforeExport();
524 field.ExportBits(output);
527 virtual void ImportBits(const QBitArray & input)
529 qCDebug(eepromImport) << QString("\timporting TransformedField %1:").arg(field.getName());
530 field.ImportBits(input);
531 afterImport();
535 virtual const QString & getName()
537 return field.getName();
540 virtual unsigned int size()
542 return field.size();
545 virtual void beforeExport() = 0;
547 virtual void afterImport() = 0;
549 virtual int Dump(int level=0, int offset=0)
551 beforeExport();
552 return field.Dump(level, offset);
555 protected:
556 DataField & field;
559 class ConversionTable {
561 public:
562 bool exportValue(const int before, int &after)
564 after = 0;
566 for (std::list<ConversionTuple>::iterator it=exportTable.begin(); it!=exportTable.end(); it++) {
567 ConversionTuple & tuple = *it;
568 if (before == tuple.a) {
569 after = tuple.b;
570 return true;
574 return false;
577 bool importValue(const int before, int &after)
579 after = 0;
581 for (std::list<ConversionTuple>::iterator it=importTable.begin(); it!=importTable.end(); it++) {
582 ConversionTuple & tuple = *it;
583 if (before == tuple.b) {
584 after = tuple.a;
585 return true;
589 return false;
592 protected:
594 class ConversionTuple {
595 public:
596 ConversionTuple(const int a, const int b):
597 a(a),
598 b(b)
602 int a;
603 int b;
606 void addConversion(const int a, const int b)
608 ConversionTuple conversion(a, b);
609 importTable.push_back(conversion);
610 exportTable.push_back(conversion);
613 void addImportConversion(const int a, const int b)
615 importTable.push_back(ConversionTuple(a, b));
618 void addExportConversion(const int a, const int b)
620 exportTable.push_back(ConversionTuple(a, b));
623 std::list<ConversionTuple> importTable;
624 std::list<ConversionTuple> exportTable;
627 template<class T>
628 class ConversionField: public TransformedField {
629 public:
630 ConversionField(DataField * parent, int & field, ConversionTable *table, const char *name, const QString & error = ""):
631 TransformedField(parent, internalField),
632 internalField(this, _field, name),
633 field(field),
634 _field(0),
635 table(table),
636 shift(0),
637 scale(1),
638 min(INT_MIN),
639 max(INT_MAX),
640 exportFunc(NULL),
641 importFunc(NULL),
642 error(error)
646 ConversionField(DataField * parent, unsigned int & field, ConversionTable *table, const char *name, const QString & error = ""):
647 TransformedField(parent, internalField),
648 internalField(this, (unsigned int &)_field, name),
649 field((int &)field),
650 _field(0),
651 table(table),
652 shift(0),
653 scale(0),
654 min(INT_MIN),
655 max(INT_MAX),
656 exportFunc(NULL),
657 importFunc(NULL),
658 error(error)
662 ConversionField(DataField * parent, int & field, int (*exportFunc)(int), int (*importFunc)(int)):
663 TransformedField(parent, internalField),
664 internalField(this, _field),
665 field(field),
666 _field(0),
667 table(NULL),
668 shift(0),
669 scale(0),
670 min(INT_MIN),
671 max(INT_MAX),
672 exportFunc(exportFunc),
673 importFunc(importFunc),
674 error("")
678 ConversionField(DataField * parent, int & field, int shift, int scale=0, int min=INT_MIN, int max=INT_MAX, const char *name = "Signed shifted"):
679 TransformedField(parent, internalField),
680 internalField(this, _field, name),
681 field(field),
682 _field(0),
683 table(NULL),
684 shift(shift),
685 scale(scale),
686 min(min),
687 max(max),
688 exportFunc(NULL),
689 importFunc(NULL),
690 error("")
694 ConversionField(DataField * parent, unsigned int & field, int shift, int scale=0):
695 TransformedField(parent, internalField),
696 internalField(this, (unsigned int &)_field),
697 field((int &)field),
698 _field(0),
699 table(NULL),
700 shift(shift),
701 scale(scale),
702 min(INT_MIN),
703 max(INT_MAX),
704 exportFunc(NULL),
705 importFunc(NULL),
706 error("")
710 virtual void beforeExport()
712 _field = field;
714 if (scale) {
715 _field /= scale;
718 if (table) {
719 if (!table->exportValue(_field, _field)) {
720 setError(error.isEmpty() ? QObject::tr("Conversion error on field %1").arg(name) : error);
722 return;
725 if (shift) {
726 if (_field < min)
727 _field = min + shift;
728 else if (_field > max)
729 _field = max + shift;
730 else
731 _field += shift;
734 if (exportFunc) {
735 _field = exportFunc(_field);
739 virtual void afterImport()
741 field = _field;
743 if (table) {
744 if (table->importValue(field, field))
745 return;
748 if (shift) {
749 field -= shift;
752 if (importFunc) {
753 field = importFunc(field);
756 if (scale) {
757 field *= scale;
759 qCDebug(eepromImport) << QString("\timported ConversionField<%1>:").arg(internalField.getName()) << QString(" before: %1, after: %2").arg(_field).arg(field);
762 protected:
763 T internalField;
764 int & field;
765 int _field;
766 ConversionTable * table;
767 int shift;
768 int scale;
769 int min;
770 int max;
771 int (*exportFunc)(int);
772 int (*importFunc)(int);
773 const QString error;
776 #endif // _EEPROMIMPORTEXPORT_H_