[Companion] Another fix for #4224
[opentx.git] / companion / src / firmwares / opentx / opentxeeprom.cpp
blob6c0133da36b9294ab72e66981dd7ec6736eb1a42
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 #include "helpers.h"
22 #include "opentxeeprom.h"
23 #include "customdebug.h"
24 #include <stdlib.h>
25 #include <algorithm>
27 #define IS_DBLEEPROM(board, version) ((IS_2560(board) || board==BOARD_M128) && version >= 213)
28 // Macro used for Gruvin9x board and M128 board between versions 213 and 214 (when there were stack overflows!)
29 #define IS_DBLRAM(board, version) ((IS_2560(board) && version >= 213) || (board==BOARD_M128 && version >= 213 && version <= 214))
31 #define HAS_PERSISTENT_TIMERS(board) (IS_ARM(board) || IS_2560(board))
32 #define MAX_VIEWS(board) (HAS_LARGE_LCD(board) ? 2 : 256)
33 #define MAX_POTS(board, version) (IS_HORUS(board) ? 3 : (board == BOARD_TARANIS_X7 ? 2 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : (version >= 216 ? 3 : 2)) : 3)))
34 #define MAX_SLIDERS(board) (IS_HORUS(board) ? 4 : (board == BOARD_TARANIS_X7 ? 0 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 4 : 2) : 0)))
35 #define MAX_MOUSE_ANALOGS(board) (IS_HORUS(board) ? 2 : 0)
36 #define MAX_SWITCHES(board, version) (IS_HORUS(board) ? 8 : (board == BOARD_TARANIS_X7 ? 6 : (IS_TARANIS(board) ? (IS_TARANIS_X9E(board) ? 18 : 8) : 7)))
37 #define MAX_SWITCHES_POSITION(board, version) (IS_TARANIS_X7(board) ? 6*3 : (IS_TARANIS_X9E(board) ? 18*3 : (IS_HORUS_OR_TARANIS(board) ? 8*3 : 9)))
38 #define MAX_ROTARY_ENCODERS(board) (IS_2560(board) ? 2 : (IS_SKY9X(board) ? 1 : 0))
39 #define MAX_FLIGHT_MODES(board, version) (IS_ARM(board) ? 9 : (IS_DBLRAM(board, version) ? 6 : 5))
40 #define MAX_TIMERS(board, version) ((IS_ARM(board) && version >= 217) ? 3 : 2)
41 #define MAX_MIXERS(board, version) (IS_ARM(board) ? 64 : 32)
42 #define MAX_CHANNELS(board, version) (IS_ARM(board) ? 32 : 16)
43 #define MAX_TRIMS(board) (IS_HORUS(board) ? 6 : 4)
44 #define MAX_EXPOS(board, version) (IS_ARM(board) ? ((IS_HORUS_OR_TARANIS(board) && version >= 216) ? 64 : 32) : (IS_DBLRAM(board, version) ? 16 : 14))
45 #define MAX_LOGICAL_SWITCHES(board, version) (IS_ARM(board) ? (version >= 218 ? 64 : 32) : ((IS_DBLEEPROM(board, version) && version<217) ? 15 : 12))
46 #define MAX_CUSTOM_FUNCTIONS(board, version) (IS_ARM(board) ? (version >= 216 ? 64 : 32) : (IS_DBLEEPROM(board, version) ? 24 : 16))
47 #define MAX_CURVES(board, version) (IS_ARM(board) ? ((HAS_LARGE_LCD(board) && version >= 216) ? 32 : 16) : 8)
48 #define MAX_GVARS(board, version) ((IS_ARM(board) && version >= 216) ? 9 : 5)
49 #define MAX_SCRIPTS(board) (IS_HORUS(board) ? 9 : 7)
50 #define MAX_TELEMETRY_SENSORS(board, version) (32)
51 #define NUM_PPM_INPUTS(board, version) ((IS_ARM(board) && version >= 216) ? 16 : 8)
52 #define ROTENC_COUNT(board, version) (IS_ARM(board) ? ((IS_STM32(board) && version >= 218) ? 0 : 1) : (IS_2560(board) ? 2 : 0))
53 #define MAX_AUX_TRIMS(board) (IS_HORUS(board) ? 2 : 0)
55 #define IS_AFTER_RELEASE_21_MARCH_2013(board, version) (version >= 214 || (!IS_ARM(board) && version >= 213))
56 #define IS_AFTER_RELEASE_23_MARCH_2013(board, version) (version >= 214 || (board==BOARD_STOCK && version >= 213))
58 inline int switchIndex(int i, BoardEnum board, unsigned int version)
60 bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
61 if (!IS_HORUS_OR_TARANIS(board) && afterrelease21March2013)
62 return (i<=3 ? i+3 : (i<=6 ? i-3 : i));
63 else
64 return i;
67 class SwitchesConversionTable: public ConversionTable {
69 public:
70 SwitchesConversionTable(BoardEnum board, unsigned int version, bool timer=false)
72 int val=0;
73 int offset=0;
74 if (timer) {
75 offset = 4;
76 for (int i=0; i<5; i++) {
77 addConversion(RawSwitch(SWITCH_TYPE_TIMER_MODE, i), val++);
80 else {
81 addConversion(RawSwitch(SWITCH_TYPE_NONE), val++);
84 for (int i=1; i<=MAX_SWITCHES_POSITION(board, version); i++) {
85 int s = switchIndex(i, board, version);
86 if (IS_TARANIS(board) && version < 217) {
87 // SF positions 16 and 17 => 16 and 18
88 // SH positions 21 and 22 => 22 and 24
89 if (s == 17 || s == 23) {
90 continue;
92 if (s >= 22) {
93 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val);
94 addImportConversion(RawSwitch(SWITCH_TYPE_SWITCH, 21+22-s), -val+offset);
95 addExportConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val+offset);
96 val++;
97 continue;
100 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val);
101 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val+offset);
102 val++;
105 if (IS_HORUS_OR_TARANIS(board) && version >= 216) {
106 for (int i=1; i<=MAX_POTS(board, version)*6; i++) {
107 addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, -i), -val+offset);
108 addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, i), val++);
112 if (version >= 216) {
113 for (int i=1; i<=2*MAX_TRIMS(board); i++) {
114 addConversion(RawSwitch(SWITCH_TYPE_TRIM, -i), -val+offset);
115 addConversion(RawSwitch(SWITCH_TYPE_TRIM, i), val++);
119 if (version >= 216) {
120 for (int i=1; i<=MAX_ROTARY_ENCODERS(board); i++) {
121 addConversion(RawSwitch(SWITCH_TYPE_ROTARY_ENCODER, -i), -val+offset);
122 addConversion(RawSwitch(SWITCH_TYPE_ROTARY_ENCODER, i), val++);
126 for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) {
127 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, -i), -val+offset);
128 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++);
131 addConversion(RawSwitch(SWITCH_TYPE_OFF), -val+offset);
132 addConversion(RawSwitch(SWITCH_TYPE_ON), val++);
133 if (version >= 216) {
134 addConversion(RawSwitch(SWITCH_TYPE_ONE, -1), -val+offset);
135 addConversion(RawSwitch(SWITCH_TYPE_ONE, 1), val++);
136 if (IS_ARM(board)) {
137 for (int i=1; i<=MAX_FLIGHT_MODES(board, version); i++) {
138 addConversion(RawSwitch(SWITCH_TYPE_FLIGHT_MODE, -i), -val+offset);
139 addConversion(RawSwitch(SWITCH_TYPE_FLIGHT_MODE, i), val++);
144 if (version < 216) {
145 // previous "moment" switches
146 for (int i=1; i<=MAX_SWITCHES_POSITION(board, version); i++) {
147 int s = switchIndex(i, board, version);
148 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++);
151 for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) {
152 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++);
155 // previous "One" switch
156 addConversion(RawSwitch(SWITCH_TYPE_ON), val++);
160 protected:
162 void addConversion(const RawSwitch & sw, const int b)
164 ConversionTable::addConversion(sw.toValue(), b);
167 void addImportConversion(const RawSwitch & sw, const int b)
169 ConversionTable::addImportConversion(sw.toValue(), b);
172 void addExportConversion(const RawSwitch & sw, const int b)
174 ConversionTable::addExportConversion(sw.toValue(), b);
177 class Cache {
178 public:
179 Cache(BoardEnum board, unsigned int version, unsigned long flags, SwitchesConversionTable * table):
180 board(board),
181 version(version),
182 flags(flags),
183 table(table)
186 BoardEnum board;
187 unsigned int version;
188 unsigned long flags;
189 SwitchesConversionTable * table;
192 static std::list<Cache> internalCache;
194 public:
196 static SwitchesConversionTable * getInstance(BoardEnum board, unsigned int version, unsigned long flags=0)
198 for (std::list<Cache>::iterator it=internalCache.begin(); it!=internalCache.end(); it++) {
199 Cache element = *it;
200 if (element.board == board && element.version == version && element.flags == flags)
201 return element.table;
204 Cache element(board, version, flags, new SwitchesConversionTable(board, version, flags));
205 internalCache.push_back(element);
206 return element.table;
208 static void Cleanup()
210 for (std::list<Cache>::iterator it=internalCache.begin(); it!=internalCache.end(); it++) {
211 Cache element = *it;
212 delete element.table;
214 internalCache.clear();
218 std::list<SwitchesConversionTable::Cache> SwitchesConversionTable::internalCache;
220 #define FLAG_NONONE 0x01
221 #define FLAG_NOSWITCHES 0x02
222 #define FLAG_NOTELEMETRY 0x04
224 class SourcesConversionTable: public ConversionTable {
226 public:
227 SourcesConversionTable(BoardEnum board, unsigned int version, unsigned int variant, unsigned long flags=0)
229 bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
231 int val=0;
233 if (!(flags & FLAG_NONONE)) {
234 addConversion(RawSource(SOURCE_TYPE_NONE), val++);
237 if (IS_STM32(board) && version >= 216) {
238 for (int i=0; i<32; i++) {
239 addConversion(RawSource(SOURCE_TYPE_VIRTUAL_INPUT, i), val++);
241 for (int i=0; i<MAX_SCRIPTS(board); i++) {
242 for (int j=0; j<6; j++) {
243 addConversion(RawSource(SOURCE_TYPE_LUA_OUTPUT, i*16+j), val++);
248 for (int i=0; i<CPN_MAX_STICKS+MAX_POTS(board, version)+MAX_SLIDERS(board)+MAX_MOUSE_ANALOGS(board); i++) {
249 addConversion(RawSource(SOURCE_TYPE_STICK, i), val++);
252 for (int i=0; i<MAX_ROTARY_ENCODERS(board); i++) {
253 addConversion(RawSource(SOURCE_TYPE_ROTARY_ENCODER, 0), val++);
256 if (!afterrelease21March2013) {
257 for (int i=0; i<CPN_MAX_STICKS; i++) {
258 addConversion(RawSource(SOURCE_TYPE_TRIM, i), val++);
262 addConversion(RawSource(SOURCE_TYPE_MAX), val++);
264 if (afterrelease21March2013) {
265 for (int i=0; i<3; i++)
266 addConversion(RawSource(SOURCE_TYPE_CYC, i), val++);
269 if (afterrelease21March2013) {
270 for (int i=0; i<MAX_TRIMS(board); i++)
271 addConversion(RawSource(SOURCE_TYPE_TRIM, i), val++);
274 addConversion(RawSource(SOURCE_TYPE_SWITCH, 0), val++);
276 if (!(flags & FLAG_NOSWITCHES)) {
277 if (afterrelease21March2013) {
278 for (int i=1; i<MAX_SWITCHES(board, version); i++)
279 addConversion(RawSource(SOURCE_TYPE_SWITCH, i), val++);
281 else {
282 for (int i=1; i<=9; i++) {
283 if (i>=4 && i<=6)
284 addConversion(RawSource(SOURCE_TYPE_SWITCH, 0), val++);
285 else
286 addConversion(RawSource(SOURCE_TYPE_SWITCH, i), val++);
289 for (int i=0; i<MAX_LOGICAL_SWITCHES(board, version); i++) {
290 addConversion(RawSource(SOURCE_TYPE_CUSTOM_SWITCH, i), val++);
294 if (!afterrelease21March2013) {
295 for (int i=0; i<3; i++) {
296 addConversion(RawSource(SOURCE_TYPE_CYC, i), val++);
300 for (int i=0; i<NUM_PPM_INPUTS(board, version); i++) {
301 addConversion(RawSource(SOURCE_TYPE_PPM, i), val++);
304 for (int i=0; i<MAX_CHANNELS(board, version); i++) {
305 addConversion(RawSource(SOURCE_TYPE_CH, i), val++);
308 if (!(flags & FLAG_NOTELEMETRY)) {
309 if (IS_ARM(board) && version >= 217) {
310 for (int i=0; i<MAX_GVARS(board, version); i++)
311 addConversion(RawSource(SOURCE_TYPE_GVAR, i), val++);
312 addConversion(RawSource(SOURCE_TYPE_SPECIAL, 0), val++); // BATT
313 addConversion(RawSource(SOURCE_TYPE_SPECIAL, 1), val++); // TIME
314 val += 5;
315 addConversion(RawSource(SOURCE_TYPE_SPECIAL, 2), val++); // Timer1
316 addConversion(RawSource(SOURCE_TYPE_SPECIAL, 3), val++); // Timer2
317 addConversion(RawSource(SOURCE_TYPE_SPECIAL, 4), val++); // Timer3
318 for (int i=0; i<CPN_MAX_SENSORS*3; ++i) {
319 addConversion(RawSource(SOURCE_TYPE_TELEMETRY, i), val++);
322 else {
323 if (afterrelease21March2013) {
324 if ((board != BOARD_STOCK && (board!=BOARD_M128 || version<215)) || (variant & GVARS_VARIANT)) {
325 for (int i=0; i<MAX_GVARS(board, version); i++) {
326 addConversion(RawSource(SOURCE_TYPE_GVAR, i), val++);
331 for (int i=0; i<TELEMETRY_SOURCE_ACC; i++) {
332 if (version < 216) {
333 if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_SWR || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_ASPEED || i==TELEMETRY_SOURCE_DTE || i==TELEMETRY_SOURCE_CELL_MIN || i==TELEMETRY_SOURCE_CELLS_MIN || i==TELEMETRY_SOURCE_VFAS_MIN)
334 continue;
336 if (!IS_ARM(board)) {
337 if (i==TELEMETRY_SOURCE_TX_TIME || i==TELEMETRY_SOURCE_SWR || i==TELEMETRY_SOURCE_A3 || i==TELEMETRY_SOURCE_A4 || i==TELEMETRY_SOURCE_A3_MIN || i==TELEMETRY_SOURCE_A4_MIN)
338 continue;
340 addConversion(RawSource(SOURCE_TYPE_TELEMETRY, i), val++);
341 if (version >= 216 && IS_ARM(board)) {
342 if (i==TELEMETRY_SOURCE_RSSI_RX)
343 val += 1;
344 if (i==TELEMETRY_SOURCE_TX_TIME)
345 val += 5;
346 if (i==TELEMETRY_SOURCE_DTE)
347 val += 5;
348 if (i==TELEMETRY_SOURCE_POWER_MAX)
349 val += 5;
356 protected:
358 void addConversion(const RawSource & source, const int b)
360 ConversionTable::addConversion(source.toValue(), b);
363 class Cache {
364 public:
365 Cache(BoardEnum board, unsigned int version, unsigned int variant, unsigned long flags, SourcesConversionTable * table):
366 board(board),
367 version(version),
368 variant(variant),
369 flags(flags),
370 table(table)
373 BoardEnum board;
374 unsigned int version;
375 unsigned int variant;
376 unsigned long flags;
377 SourcesConversionTable * table;
379 static std::list<Cache> internalCache;
381 public:
383 static SourcesConversionTable * getInstance(BoardEnum board, unsigned int version, unsigned int variant, unsigned long flags=0)
385 for (std::list<Cache>::iterator it=internalCache.begin(); it!=internalCache.end(); it++) {
386 Cache element = *it;
387 if (element.board == board && element.version == version && element.variant == variant && element.flags == flags)
388 return element.table;
391 Cache element(board, version, variant, flags, new SourcesConversionTable(board, version, variant, flags));
392 internalCache.push_back(element);
393 return element.table;
395 static void Cleanup()
397 for (std::list<Cache>::iterator it=internalCache.begin(); it!=internalCache.end(); it++) {
398 Cache element = *it;
399 delete element.table;
401 internalCache.clear();
405 std::list<SourcesConversionTable::Cache> SourcesConversionTable::internalCache;
407 void OpenTxEepromCleanup(void)
409 SourcesConversionTable::Cleanup();
410 SwitchesConversionTable::Cleanup();
413 template <int N>
414 class SwitchField: public ConversionField< SignedField<N> > {
415 public:
416 SwitchField(RawSwitch & sw, BoardEnum board, unsigned int version, unsigned long flags=0):
417 ConversionField< SignedField<N> >(_switch, SwitchesConversionTable::getInstance(board, version, flags), QObject::tr("Switch").toLatin1(),
418 QObject::tr("Switch ").toLatin1()+ sw.toString()+ QObject::tr(" cannot be exported on this board!").toLatin1()),
419 sw(sw),
420 _switch(0)
424 virtual ~SwitchField()
428 virtual void beforeExport()
430 _switch = sw.toValue();
431 ConversionField< SignedField<N> >::beforeExport();
434 virtual void afterImport()
436 ConversionField< SignedField<N> >::afterImport();
437 sw = RawSwitch(_switch);
438 eepromImportDebug() << QString("imported %1: %2").arg(ConversionField< SignedField<N> >::internalField.getName()).arg(sw.toString());
441 protected:
442 RawSwitch & sw;
443 int _switch;
446 class TelemetrySourcesConversionTable: public ConversionTable {
448 public:
449 TelemetrySourcesConversionTable(BoardEnum board, unsigned int version)
451 int val = 0;
453 if (IS_AFTER_RELEASE_21_MARCH_2013(board, version)) {
454 addConversion(0, val++);
457 addConversion(1+TELEMETRY_SOURCE_TX_BATT, val++);
458 if (IS_ARM(board) && version >= 216) {
459 addConversion(1+TELEMETRY_SOURCE_TX_TIME, val++);
460 for (int i=0; i<5; i++)
461 addConversion(1+TELEMETRY_SOURCE_RESERVE, val++);
463 addConversion(1+TELEMETRY_SOURCE_TIMER1, val++);
464 addConversion(1+TELEMETRY_SOURCE_TIMER2, val++);
465 if (IS_ARM(board) && version >= 217)
466 addConversion(1+TELEMETRY_SOURCE_TIMER3, val++);
467 if (IS_ARM(board) && version >= 216)
468 addConversion(1+TELEMETRY_SOURCE_SWR, val++);
469 addConversion(1+TELEMETRY_SOURCE_RSSI_TX, val++);
470 addConversion(1+TELEMETRY_SOURCE_RSSI_RX, val++);
471 if (IS_ARM(board) && version >= 216)
472 addConversion(1+TELEMETRY_SOURCE_RESERVE, val++);
473 addConversion(1+TELEMETRY_SOURCE_A1, val++);
474 addConversion(1+TELEMETRY_SOURCE_A2, val++);
475 if (IS_ARM(board) && version >= 216) {
476 addConversion(1+TELEMETRY_SOURCE_A3, val++);
477 addConversion(1+TELEMETRY_SOURCE_A4, val++);
479 addConversion(1+TELEMETRY_SOURCE_ALT, val++);
480 addConversion(1+TELEMETRY_SOURCE_RPM, val++);
481 addConversion(1+TELEMETRY_SOURCE_FUEL, val++);
482 addConversion(1+TELEMETRY_SOURCE_T1, val++);
483 addConversion(1+TELEMETRY_SOURCE_T2, val++);
484 addConversion(1+TELEMETRY_SOURCE_SPEED, val++);
485 addConversion(1+TELEMETRY_SOURCE_DIST, val++);
486 addConversion(1+TELEMETRY_SOURCE_GPS_ALT, val++);
487 addConversion(1+TELEMETRY_SOURCE_CELL, val++);
488 addConversion(1+TELEMETRY_SOURCE_CELLS_SUM, val++);
489 addConversion(1+TELEMETRY_SOURCE_VFAS, val++);
490 addConversion(1+TELEMETRY_SOURCE_CURRENT, val++);
491 addConversion(1+TELEMETRY_SOURCE_CONSUMPTION, val++);
492 addConversion(1+TELEMETRY_SOURCE_POWER, val++);
493 addConversion(1+TELEMETRY_SOURCE_ACCX, val++);
494 addConversion(1+TELEMETRY_SOURCE_ACCY, val++);
495 addConversion(1+TELEMETRY_SOURCE_ACCZ, val++);
496 addConversion(1+TELEMETRY_SOURCE_HDG, val++);
497 addConversion(1+TELEMETRY_SOURCE_VERTICAL_SPEED, val++);
498 if (version >= 216) {
499 addConversion(1+TELEMETRY_SOURCE_ASPEED, val++);
500 addConversion(1+TELEMETRY_SOURCE_DTE, val++);
502 if (IS_ARM(board) && version >= 216) {
503 for (int i=0; i<5; i++)
504 addConversion(1+TELEMETRY_SOURCE_RESERVE, val++);
506 addConversion(1+TELEMETRY_SOURCE_A1_MIN, val++);
507 addConversion(1+TELEMETRY_SOURCE_A2_MIN, val++);
508 if (IS_ARM(board) && version >= 216) {
509 addConversion(1+TELEMETRY_SOURCE_A3_MIN, val++);
510 addConversion(1+TELEMETRY_SOURCE_A4_MIN, val++);
512 addConversion(1+TELEMETRY_SOURCE_ALT_MIN, val++);
513 addConversion(1+TELEMETRY_SOURCE_ALT_MAX, val++);
514 addConversion(1+TELEMETRY_SOURCE_RPM_MAX, val++);
515 addConversion(1+TELEMETRY_SOURCE_T1_MAX, val++);
516 addConversion(1+TELEMETRY_SOURCE_T2_MAX, val++);
517 addConversion(1+TELEMETRY_SOURCE_SPEED_MAX, val++);
518 addConversion(1+TELEMETRY_SOURCE_DIST_MAX, val++);
519 if (version >= 216) {
520 addConversion(1+TELEMETRY_SOURCE_ASPEED_MAX, val++);
521 addConversion(1+TELEMETRY_SOURCE_CELL_MIN, val++);
522 addConversion(1+TELEMETRY_SOURCE_CELLS_MIN, val++);
523 addConversion(1+TELEMETRY_SOURCE_VFAS_MIN, val++);
525 addConversion(1+TELEMETRY_SOURCE_CURRENT_MAX, val++);
526 addConversion(1+TELEMETRY_SOURCE_POWER_MAX, val++);
527 if (IS_ARM(board) && version >= 216) {
528 for (int i=0; i<5; i++)
529 addConversion(1+TELEMETRY_SOURCE_RESERVE, val++);
531 addConversion(1+TELEMETRY_SOURCE_ACC, val++);
532 addConversion(1+TELEMETRY_SOURCE_GPS_TIME, val++);
536 template <int N>
537 class TelemetrySourceField: public ConversionField< UnsignedField<N> > {
538 public:
539 TelemetrySourceField(RawSource & source, BoardEnum board, unsigned int version):
540 ConversionField< UnsignedField<N> >(_source, &conversionTable, "Telemetry source"),
541 conversionTable(board, version),
542 source(source),
543 board(board),
544 version(version),
545 _source(0)
549 virtual ~TelemetrySourceField()
553 virtual void beforeExport()
555 _source = (source.type == SOURCE_TYPE_TELEMETRY ? source.index+1 : 0);
556 ConversionField< UnsignedField<N> >::beforeExport();
559 virtual void afterImport()
561 ConversionField< UnsignedField<N> >::afterImport();
562 source = (_source == 0 ? RawSource(0) : RawSource(SOURCE_TYPE_TELEMETRY, _source-1));
563 eepromImportDebug() << QString("imported %1: %2").arg(ConversionField< UnsignedField<N> >::internalField.getName()).arg(source.toString());
566 protected:
567 TelemetrySourcesConversionTable conversionTable;
568 RawSource & source;
569 BoardEnum board;
570 unsigned int version;
571 unsigned int _source;
574 template <int N>
575 class SourceField: public ConversionField< UnsignedField<N> > {
576 public:
577 SourceField(RawSource & source, BoardEnum board, unsigned int version, unsigned int variant, unsigned long flags=0):
578 ConversionField< UnsignedField<N> >(_source, SourcesConversionTable::getInstance(board, version, variant, flags),
579 "Source", QObject::tr("Source %1 cannot be exported on this board!").arg(source.toString())),
580 source(source),
581 _source(0)
585 virtual ~SourceField()
589 virtual void beforeExport()
591 _source = source.toValue();
592 ConversionField< UnsignedField<N> >::beforeExport();
595 virtual void afterImport()
597 ConversionField< UnsignedField<N> >::afterImport();
598 source = RawSource(_source);
599 eepromImportDebug() << QString("imported %1: %2").arg(ConversionField< UnsignedField<N> >::internalField.getName()).arg(source.toString());
602 protected:
603 RawSource & source;
604 unsigned int _source;
608 int smallGvarToEEPROM(int gvar)
610 if (gvar < -10000) {
611 gvar = 128 + gvar + 10000;
613 else if (gvar > 10000) {
614 gvar = -128 +gvar - 10001;
616 return gvar;
619 int smallGvarToC9x(int gvar)
621 if (gvar > 110) {
622 gvar = gvar - 128 - 10000;
624 else if (gvar < -110) {
625 gvar = gvar + 128 + 10001;
627 return gvar;
630 void splitGvarParam(const int gvar, int & _gvar, unsigned int & _gvarParam, const BoardEnum board, const int version)
632 if (version >= 214 || (!IS_ARM(board) && version >= 213)) {
633 if (gvar < -10000) {
634 _gvarParam = 0;
635 _gvar = 256 + gvar + 10000;
637 else if (gvar > 10000) {
638 _gvarParam = 1;
639 _gvar = gvar - 10001;
641 else {
642 if (gvar < 0) _gvarParam = 1;
643 else _gvarParam = 0;
644 _gvar = gvar; // save routine throws away all unused bits; therefore no 2er complement compensation needed here
647 else {
648 if (gvar < -10000) {
649 _gvarParam = 1;
650 _gvar = gvar + 10000;
652 else if (gvar > 10000) {
653 _gvarParam = 1;
654 _gvar = gvar - 10001;
656 else {
657 _gvarParam = 0;
658 _gvar = gvar;
663 void concatGvarParam(int & gvar, const int _gvar, const unsigned int _gvarParam, const BoardEnum board, const int version)
665 if (version >= 214 || (!IS_ARM(board) && version >= 213)) {
666 gvar = _gvar;
667 if (gvar<0) gvar+=256; // remove 2er complement, because 8bit part is in this case unsigned
668 if (_gvarParam) { // here is the real sign bit
669 gvar|=-256; // set all higher bits to simulate negative value
672 if (gvar>245) {
673 gvar = gvar-256 - 10000;
674 } else if (gvar<-245) {
675 gvar = gvar+256 + 10001;
678 else {
679 if (_gvarParam == 0) {
680 gvar = _gvar;
682 else if (_gvar >= 0) {
683 gvar = 10001 + _gvar;
685 else {
686 gvar = -10000 + _gvar;
691 void exportGvarParam(const int gvar, int & _gvar, int version)
693 int GV1 = (version >= 217 ? 1024 : (version >= 216 ? 4096 : 512));
695 if (gvar < -10000) {
696 _gvar = GV1 + gvar + 10000;
698 else if (gvar > 10000) {
699 _gvar = GV1 + gvar - 10001;
701 else {
702 _gvar = gvar;
706 void importGvarParam(int & gvar, const int _gvar, int version)
708 int GV1 = (version >= 217 ? 1024 : (version >= 216 ? 4096 : 512));
710 if (_gvar >= GV1) {
711 gvar = 10001 + _gvar - GV1;
713 else if (_gvar >= GV1-9) {
714 gvar = -10000 + _gvar - GV1;
716 else if (_gvar < -GV1) {
717 gvar = -10000 + _gvar + GV1 + 1;
719 else if (_gvar < -GV1+9) {
720 gvar = 10000 + _gvar + GV1 + 1;
722 else {
723 gvar = _gvar;
726 // qDebug() << QString("import") << _gvar << gvar;
729 class CurveReferenceField: public TransformedField {
730 public:
731 CurveReferenceField(CurveReference & curve, BoardEnum board, unsigned int version):
732 TransformedField(internalField),
733 curve(curve),
734 _curve_type(0),
735 _curve_value(0)
737 internalField.Append(new UnsignedField<8>(_curve_type));
738 internalField.Append(new SignedField<8>(_curve_value));
741 virtual void beforeExport()
743 if (curve.value != 0) {
744 _curve_type = (unsigned int)curve.type;
745 _curve_value = smallGvarToEEPROM(curve.value);
747 else {
748 _curve_type = 0;
749 _curve_value = 0;
753 virtual void afterImport()
755 curve.type = (CurveReference::CurveRefType)_curve_type;
756 curve.value = smallGvarToC9x(_curve_value);
757 eepromImportDebug() << QString("imported CurveReference(%1)").arg(curve.toString());
760 protected:
761 StructField internalField;
762 CurveReference & curve;
763 unsigned int _curve_type;
764 int _curve_value;
767 static int exportHeliInversionWeight(int source) {
768 return (source < 0) ? 1 : 0;
771 static int importHeliInversionWeight(int source) {
772 return source ? -100: 100;
775 class HeliField: public StructField {
776 public:
777 HeliField(SwashRingData & heli, BoardEnum board, unsigned int version, unsigned int variant)
779 if (IS_STM32(board) && version >= 217) {
780 Append(new UnsignedField<8>(heli.type));
781 Append(new UnsignedField<8>(heli.value));
782 Append(new SourceField<8>(heli.collectiveSource, board, version, variant));
783 Append(new SourceField<8>(heli.aileronSource, board, version, variant));
784 Append(new SourceField<8>(heli.elevatorSource, board, version, variant));
785 Append(new SignedField<8>(heli.collectiveWeight));
786 Append(new SignedField<8>(heli.aileronWeight));
787 Append(new SignedField<8>(heli.elevatorWeight));
789 else {
790 Append(new ConversionField< SignedField<1> >(heli.elevatorWeight, exportHeliInversionWeight, importHeliInversionWeight));
791 Append(new ConversionField< SignedField<1> >(heli.aileronWeight, exportHeliInversionWeight, importHeliInversionWeight));
792 Append(new ConversionField< SignedField<1> >(heli.collectiveWeight, exportHeliInversionWeight, importHeliInversionWeight));
793 Append(new UnsignedField<5>(heli.type));
794 Append(new SourceField<8>(heli.collectiveSource, board, version, variant));
795 //, FLAG_NOSWITCHES)); Fix shift in collective
796 Append(new UnsignedField<8>(heli.value));
801 class FlightModeField: public TransformedField {
802 public:
803 FlightModeField(FlightModeData & phase, int index, BoardEnum board, unsigned int version):
804 TransformedField(internalField),
805 internalField("FlightMode"),
806 phase(phase),
807 index(index),
808 board(board),
809 version(version),
810 rotencCount(ROTENC_COUNT(board, version))
812 if (board == BOARD_STOCK || (board==BOARD_M128 && version>=215)) {
813 // On stock we use 10bits per trim
814 for (int i=0; i<CPN_MAX_STICKS; i++)
815 internalField.Append(new SignedField<8>(trimBase[i]));
816 for (int i=0; i<CPN_MAX_STICKS; i++)
817 internalField.Append(new SignedField<2>(trimExt[i]));
819 else if (IS_ARM(board) && version >= 218) {
820 for (int i=0; i<CPN_MAX_STICKS+MAX_AUX_TRIMS(board); i++) {
821 internalField.Append(new SignedField<11>(phase.trim[i]));
822 internalField.Append(new UnsignedField<5>(trimMode[i]));
825 else if (IS_TARANIS(board) && version >= 216) {
826 for (int i=0; i<CPN_MAX_STICKS; i++) {
827 internalField.Append(new SignedField<11>(phase.trim[i]));
828 internalField.Append(new UnsignedField<5>(trimMode[i]));
831 else {
832 for (int i=0; i<CPN_MAX_STICKS; i++) {
833 internalField.Append(new SignedField<16>(trimBase[i]));
836 if (IS_ARM(board) && version >= 218) {
837 if (HAS_LARGE_LCD(board))
838 internalField.Append(new ZCharField<10>(phase.name, "Flight mode name"));
839 else
840 internalField.Append(new ZCharField<6>(phase.name, "Flight mode name"));
841 internalField.Append(new SwitchField<9>(phase.swtch, board, version));
842 internalField.Append(new SpareBitsField<7>());
844 else {
845 internalField.Append(new SwitchField<8>(phase.swtch, board, version));
846 if (HAS_LARGE_LCD(board))
847 internalField.Append(new ZCharField<10>(phase.name));
848 else
849 internalField.Append(new ZCharField<6>(phase.name));
851 if (IS_ARM(board) && version >= 214) {
852 internalField.Append(new UnsignedField<8>(phase.fadeIn));
853 internalField.Append(new UnsignedField<8>(phase.fadeOut));
855 else {
856 internalField.Append(new UnsignedField<4>(phase.fadeIn));
857 internalField.Append(new UnsignedField<4>(phase.fadeOut));
860 for (int i=0; i<rotencCount; i++) {
861 internalField.Append(new SignedField<16>(phase.rotaryEncoders[i]));
864 if (board != BOARD_STOCK && (board != BOARD_M128 || version < 215)) {
865 for (int i=0; i<MAX_GVARS(board, version); i++) {
866 internalField.Append(new SignedField<16>(phase.gvars[i]));
871 virtual void beforeExport()
873 for (int i=0; i<CPN_MAX_STICKS+MAX_AUX_TRIMS(board); i++) {
874 if (IS_HORUS_OR_TARANIS(board) && version >= 216) {
875 if (phase.trimMode[i] < 0)
876 trimMode[i] = TRIM_MODE_NONE;
877 else
878 trimMode[i] = 2*phase.trimRef[i] + phase.trimMode[i];
880 else {
881 int trim;
882 if (phase.trimMode[i] < 0)
883 trim = 0;
884 else if (phase.trimRef[i] != index)
885 trim = 501 + phase.trimRef[i] - (phase.trimRef[i] > index ? 1 : 0);
886 else
887 trim = std::max(-500, std::min(500, phase.trim[i]));
888 if (board == BOARD_STOCK || (board == BOARD_M128 && version >= 215)) {
889 trimBase[i] = trim >> 2;
890 trimExt[i] = (trim & 0x03);
892 else {
893 trimBase[i] = trim;
899 virtual void afterImport()
901 for (int i=0; i<CPN_MAX_STICKS+MAX_AUX_TRIMS(board); i++) {
902 if (IS_HORUS_OR_TARANIS(board) && version >= 216) {
903 if (trimMode[i] == TRIM_MODE_NONE) {
904 phase.trimMode[i] = -1;
906 else {
907 phase.trimMode[i] = trimMode[i] % 2;
908 phase.trimRef[i] = trimMode[i] / 2;
911 else {
912 if (phase.swtch == RawSwitch(SWITCH_TYPE_NONE) && index > 0) {
913 phase.trimRef[i] = 0;
914 phase.trimMode[i] = 0;
915 phase.trim[i] = 0;
917 else {
918 int trim;
919 if (board == BOARD_STOCK || (board == BOARD_M128 && version >= 215))
920 trim = ((trimBase[i]) << 2) + (trimExt[i] & 0x03);
921 else
922 trim = trimBase[i];
923 if (trim > 500) {
924 phase.trimRef[i] = trim - 501;
925 if (phase.trimRef[i] >= index)
926 phase.trimRef[i] += 1;
927 phase.trimMode[i] = 0;
928 phase.trim[i] = 0;
930 else {
931 phase.trimRef[i] = index/*own trim*/;
932 phase.trimMode[i] = 0;
933 phase.trim[i] = trim;
938 eepromImportDebug() << QString("imported %1: '%2'").arg(internalField.getName()).arg(phase.name);
941 protected:
942 StructField internalField;
943 FlightModeData & phase;
944 int index;
945 BoardEnum board;
946 unsigned int version;
947 int rotencCount;
948 int trimBase[CPN_MAX_STICKS+CPN_MAX_AUX_TRIMS];
949 int trimExt[CPN_MAX_STICKS+CPN_MAX_AUX_TRIMS];
950 unsigned int trimMode[CPN_MAX_STICKS+CPN_MAX_AUX_TRIMS];
953 class MixField: public TransformedField {
954 public:
955 MixField(MixData & mix, BoardEnum board, unsigned int version, ModelData * model):
956 TransformedField(internalField),
957 internalField("Mix"),
958 mix(mix),
959 board(board),
960 version(version),
961 model(model)
963 if (IS_ARM(board) && version >= 218) {
964 internalField.Append(new SignedField<11>(_weight));
965 internalField.Append(new UnsignedField<5>(_destCh));
966 internalField.Append(new SourceField<10>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
967 internalField.Append(new UnsignedField<1>((unsigned int &)mix.carryTrim));
968 internalField.Append(new UnsignedField<2>(mix.mixWarn));
969 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
970 internalField.Append(new SpareBitsField<1>());
971 internalField.Append(new SignedField<14>(_offset));
972 internalField.Append(new SwitchField<9>(mix.swtch, board, version));
973 internalField.Append(new UnsignedField<9>(mix.flightModes));
974 internalField.Append(new CurveReferenceField(mix.curve, board, version));
975 internalField.Append(new UnsignedField<8>(mix.delayUp));
976 internalField.Append(new UnsignedField<8>(mix.delayDown));
977 internalField.Append(new UnsignedField<8>(mix.speedUp));
978 internalField.Append(new UnsignedField<8>(mix.speedDown));
979 if (IS_HORUS(board))
980 internalField.Append(new ZCharField<6>(mix.name));
981 else if (HAS_LARGE_LCD(board))
982 internalField.Append(new ZCharField<8>(mix.name));
983 else
984 internalField.Append(new ZCharField<6>(mix.name));
986 else if (IS_TARANIS(board) && version >= 217) {
987 internalField.Append(new UnsignedField<8>(_destCh));
988 internalField.Append(new UnsignedField<9>(mix.flightModes));
989 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
990 internalField.Append(new UnsignedField<1>((unsigned int &)mix.carryTrim));
991 internalField.Append(new UnsignedField<4>(mix.mixWarn));
992 internalField.Append(new SignedField<16>(_weight));
993 internalField.Append(new SourceField<10>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
994 internalField.Append(new SignedField<14>(_offset));
995 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
996 internalField.Append(new CurveReferenceField(mix.curve, board, version));
997 internalField.Append(new UnsignedField<8>(mix.delayUp));
998 internalField.Append(new UnsignedField<8>(mix.delayDown));
999 internalField.Append(new UnsignedField<8>(mix.speedUp));
1000 internalField.Append(new UnsignedField<8>(mix.speedDown));
1001 internalField.Append(new ZCharField<8>(mix.name));
1003 else if (IS_ARM(board) && version >= 217) {
1004 internalField.Append(new UnsignedField<5>(_destCh));
1005 internalField.Append(new UnsignedField<3>(mix.mixWarn));
1006 internalField.Append(new UnsignedField<9>(mix.flightModes));
1007 internalField.Append(new BoolField<1>(_curveMode));
1008 internalField.Append(new BoolField<1>(mix.noExpo));
1009 internalField.Append(new SignedField<3>(mix.carryTrim));
1010 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1011 internalField.Append(new SignedField<16>(_weight));
1012 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
1013 internalField.Append(new SignedField<8>(_curveParam));
1014 internalField.Append(new UnsignedField<8>(mix.delayUp));
1015 internalField.Append(new UnsignedField<8>(mix.delayDown));
1016 internalField.Append(new UnsignedField<8>(mix.speedUp));
1017 internalField.Append(new UnsignedField<8>(mix.speedDown));
1018 internalField.Append(new SourceField<8>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1019 internalField.Append(new SignedField<16>(_offset));
1020 internalField.Append(new ZCharField<6>(mix.name));
1022 else if (IS_TARANIS(board) && version == 216) {
1023 internalField.Append(new UnsignedField<8>(_destCh));
1024 internalField.Append(new UnsignedField<16>(mix.flightModes));
1025 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1026 internalField.Append(new UnsignedField<1>((unsigned int &)mix.carryTrim));
1027 internalField.Append(new SpareBitsField<5>());
1028 internalField.Append(new SignedField<16>(_weight));
1029 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
1030 internalField.Append(new CurveReferenceField(mix.curve, board, version));
1031 internalField.Append(new UnsignedField<4>(mix.mixWarn));
1032 internalField.Append(new SpareBitsField<4>());
1033 internalField.Append(new UnsignedField<8>(mix.delayUp));
1034 internalField.Append(new UnsignedField<8>(mix.delayDown));
1035 internalField.Append(new UnsignedField<8>(mix.speedUp));
1036 internalField.Append(new UnsignedField<8>(mix.speedDown));
1037 internalField.Append(new SourceField<8>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1038 internalField.Append(new SignedField<16>(_offset));
1039 internalField.Append(new ZCharField<8>(mix.name));
1040 internalField.Append(new SpareBitsField<8>());
1042 else if (IS_ARM(board) && version == 216) {
1043 internalField.Append(new UnsignedField<5>(_destCh));
1044 internalField.Append(new UnsignedField<3>(mix.mixWarn));
1045 internalField.Append(new UnsignedField<16>(mix.flightModes));
1046 internalField.Append(new BoolField<1>(_curveMode));
1047 internalField.Append(new BoolField<1>(mix.noExpo));
1048 internalField.Append(new SignedField<3>(mix.carryTrim));
1049 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1050 internalField.Append(new SpareBitsField<1>());
1051 internalField.Append(new SignedField<16>(_weight));
1052 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
1053 internalField.Append(new SignedField<8>(_curveParam));
1054 internalField.Append(new UnsignedField<8>(mix.delayUp));
1055 internalField.Append(new UnsignedField<8>(mix.delayDown));
1056 internalField.Append(new UnsignedField<8>(mix.speedUp));
1057 internalField.Append(new UnsignedField<8>(mix.speedDown));
1058 internalField.Append(new SourceField<8>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1059 internalField.Append(new SignedField<16>(_offset));
1060 internalField.Append(new ZCharField<6>(mix.name));
1062 else if (IS_ARM(board)) {
1063 internalField.Append(new UnsignedField<8>(_destCh));
1064 internalField.Append(new UnsignedField<16>(mix.flightModes));
1065 internalField.Append(new BoolField<1>(_curveMode));
1066 internalField.Append(new BoolField<1>(mix.noExpo));
1067 internalField.Append(new SignedField<3>(mix.carryTrim));
1068 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1069 if (version >= 214)
1070 internalField.Append(new SpareBitsField<1>());
1071 else
1072 internalField.Append(new UnsignedField<1>(_offsetMode));
1073 internalField.Append(new SignedField<16>(_weight));
1074 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
1075 internalField.Append(new SignedField<8>(_curveParam));
1076 if (version >= 214) {
1077 internalField.Append(new UnsignedField<4>(mix.mixWarn));
1078 internalField.Append(new SpareBitsField<4>());
1080 else {
1081 internalField.Append(new UnsignedField<8>(mix.mixWarn));
1083 internalField.Append(new UnsignedField<8>(mix.delayUp));
1084 internalField.Append(new UnsignedField<8>(mix.delayDown));
1085 internalField.Append(new UnsignedField<8>(mix.speedUp));
1086 internalField.Append(new UnsignedField<8>(mix.speedDown));
1087 internalField.Append(new SourceField<8>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1088 if (version >= 214)
1089 internalField.Append(new SignedField<16>(_offset));
1090 else
1091 internalField.Append(new SignedField<8>(_offset));
1092 if (HAS_LARGE_LCD(board)) {
1093 internalField.Append(new ZCharField<8>(mix.name));
1094 internalField.Append(new SpareBitsField<16>());
1096 else {
1097 internalField.Append(new ZCharField<6>(mix.name));
1100 else if (IS_DBLRAM(board, version) && IS_AFTER_RELEASE_23_MARCH_2013(board, version)) {
1101 internalField.Append(new UnsignedField<4>(_destCh));
1102 internalField.Append(new BoolField<1>(_curveMode));
1103 internalField.Append(new BoolField<1>(mix.noExpo));
1104 internalField.Append(new UnsignedField<1>(_weightMode));
1105 internalField.Append(new UnsignedField<1>(_offsetMode));
1106 internalField.Append(new SourceField<8>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1107 internalField.Append(new SignedField<8>(_weight));
1108 internalField.Append(new SwitchField<8>(mix.swtch, board, version));
1109 internalField.Append(new UnsignedField<8>(mix.flightModes));
1110 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1111 internalField.Append(new SignedField<3>(mix.carryTrim));
1112 internalField.Append(new UnsignedField<2>(mix.mixWarn));
1113 internalField.Append(new SpareBitsField<1>());
1114 internalField.Append(new UnsignedField<4>(mix.delayUp));
1115 internalField.Append(new UnsignedField<4>(mix.delayDown));
1116 internalField.Append(new UnsignedField<4>(mix.speedUp));
1117 internalField.Append(new UnsignedField<4>(mix.speedDown));
1118 internalField.Append(new SignedField<8>(_curveParam));
1119 internalField.Append(new SignedField<8>(_offset));
1121 else {
1122 internalField.Append(new UnsignedField<4>(_destCh));
1123 internalField.Append(new BoolField<1>(_curveMode));
1124 internalField.Append(new BoolField<1>(mix.noExpo));
1125 internalField.Append(new UnsignedField<1>(_weightMode));
1126 internalField.Append(new UnsignedField<1>(_offsetMode));
1127 internalField.Append(new SignedField<8>(_weight));
1128 internalField.Append(new SwitchField<6>(mix.swtch, board, version));
1129 internalField.Append(new UnsignedField<2>((unsigned int &)mix.mltpx));
1130 internalField.Append(new UnsignedField<5>(mix.flightModes));
1131 internalField.Append(new SignedField<3>(mix.carryTrim));
1132 internalField.Append(new SourceField<6>(mix.srcRaw, board, version, FLAG_NOTELEMETRY));
1133 internalField.Append(new UnsignedField<2>(mix.mixWarn));
1134 internalField.Append(new UnsignedField<4>(mix.delayUp));
1135 internalField.Append(new UnsignedField<4>(mix.delayDown));
1136 internalField.Append(new UnsignedField<4>(mix.speedUp));
1137 internalField.Append(new UnsignedField<4>(mix.speedDown));
1138 internalField.Append(new SignedField<8>(_curveParam));
1139 internalField.Append(new SignedField<8>(_offset));
1143 virtual void beforeExport()
1145 if (mix.destCh && mix.srcRaw.type != SOURCE_TYPE_NONE) {
1146 _destCh = mix.destCh - 1;
1147 if (mix.curve.type == CurveReference::CURVE_REF_CUSTOM) {
1148 _curveMode = true;
1149 if (mix.curve.value > 0) {
1150 _curveParam = 6 + mix.curve.value;
1152 else {
1153 _curveParam = mix.curve.value;
1156 else if (mix.curve.type == CurveReference::CURVE_REF_FUNC) {
1157 _curveMode = true;
1158 _curveParam = mix.curve.value;
1160 else if (mix.curve.type == CurveReference::CURVE_REF_DIFF) {
1161 _curveMode = 0;
1162 _curveParam = smallGvarToEEPROM(mix.curve.value);
1165 else {
1166 mix.clear();
1167 _destCh = 0;
1168 _curveMode = 0;
1169 _curveParam = 0;
1172 if (IS_ARM(board)) {
1173 exportGvarParam(mix.weight, _weight, version);
1174 if (version >= 214)
1175 exportGvarParam(mix.sOffset, _offset, version);
1176 else
1177 splitGvarParam(mix.sOffset, _offset, _offsetMode, board, version);
1179 else {
1180 splitGvarParam(mix.weight, _weight, _weightMode, board, version);
1181 splitGvarParam(mix.sOffset, _offset, _offsetMode, board, version);
1185 virtual void afterImport()
1187 if (IS_TARANIS(board) && version < 216) {
1188 if (mix.srcRaw.type == SOURCE_TYPE_STICK && mix.srcRaw.index < CPN_MAX_STICKS) {
1189 if (!mix.noExpo) {
1190 mix.srcRaw = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, mix.srcRaw.index);
1195 if (mix.srcRaw.type != SOURCE_TYPE_NONE) {
1196 mix.destCh = _destCh + 1;
1197 if (!IS_STM32(board) || version < 216) {
1198 if (!_curveMode)
1199 mix.curve = CurveReference(CurveReference::CURVE_REF_DIFF, smallGvarToC9x(_curveParam));
1200 else if (_curveParam > 6)
1201 mix.curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, _curveParam-6);
1202 else if (_curveParam < 0)
1203 mix.curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, _curveParam);
1204 else
1205 mix.curve = CurveReference(CurveReference::CURVE_REF_FUNC, _curveParam);
1209 if (IS_ARM(board)) {
1210 importGvarParam(mix.weight, _weight, version);
1211 if (version >= 214)
1212 importGvarParam(mix.sOffset, _offset, version);
1213 else
1214 concatGvarParam(mix.sOffset, _offset, _offsetMode, board, version);
1216 else {
1217 concatGvarParam(mix.weight, _weight, _weightMode, board, version);
1218 concatGvarParam(mix.sOffset, _offset, _offsetMode, board, version);
1221 if (IS_TARANIS(board) && version < 216) {
1222 if (mix.sOffset >= -500 && mix.sOffset <= 500 && mix.weight >= -500 && mix.weight <= 500) {
1223 mix.sOffset = divRoundClosest(mix.sOffset * mix.weight, 100);
1225 if (mix.carryTrim < 0) mix.carryTrim = 0;
1227 eepromImportDebug() << QString("imported %1: ch %2, name '%3'").arg(internalField.getName()).arg(mix.destCh).arg(mix.name);
1230 protected:
1231 StructField internalField;
1232 MixData & mix;
1233 BoardEnum board;
1234 unsigned int version;
1235 ModelData * model;
1236 unsigned int _destCh;
1237 bool _curveMode;
1238 int _curveParam;
1239 int _weight;
1240 int _offset;
1241 unsigned int _weightMode;
1242 unsigned int _offsetMode;
1245 class InputField: public TransformedField {
1246 public:
1247 InputField(ExpoData & expo, BoardEnum board, unsigned int version):
1248 TransformedField(internalField),
1249 internalField("Input"),
1250 expo(expo),
1251 board(board),
1252 version(version)
1254 if (IS_ARM(board) && version >= 218) {
1255 internalField.Append(new UnsignedField<2>(expo.mode, "Mode"));
1256 internalField.Append(new UnsignedField<14>(expo.scale, "Scale"));
1257 internalField.Append(new SourceField<10>(expo.srcRaw, board, version, 0));
1258 internalField.Append(new SignedField<6>(expo.carryTrim, "CarryTrim"));
1259 internalField.Append(new UnsignedField<5>(expo.chn, "Channel"));
1260 internalField.Append(new SwitchField<9>(expo.swtch, board, version));
1261 internalField.Append(new UnsignedField<9>(expo.flightModes));
1262 internalField.Append(new SignedField<8>(_weight, "Weight"));
1263 internalField.Append(new SpareBitsField<1>());
1264 if (IS_HORUS(board))
1265 internalField.Append(new ZCharField<6>(expo.name));
1266 else if (HAS_LARGE_LCD(board))
1267 internalField.Append(new ZCharField<8>(expo.name));
1268 else
1269 internalField.Append(new ZCharField<6>(expo.name));
1270 internalField.Append(new SignedField<8>(_offset, "Offset"));
1271 internalField.Append(new CurveReferenceField(expo.curve, board, version));
1273 else if (IS_TARANIS(board) && version >= 217) {
1274 internalField.Append(new SourceField<10>(expo.srcRaw, board, version, 0));
1275 internalField.Append(new UnsignedField<14>(expo.scale, "Scale"));
1276 internalField.Append(new UnsignedField<8>(expo.chn, "Channel"));
1277 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1278 internalField.Append(new UnsignedField<16>(expo.flightModes));
1279 internalField.Append(new SignedField<8>(_weight, "Weight"));
1280 internalField.Append(new SignedField<6>(expo.carryTrim, "CarryTrim"));
1281 internalField.Append(new UnsignedField<2>(expo.mode, "Mode"));
1282 internalField.Append(new ZCharField<8>(expo.name));
1283 internalField.Append(new SignedField<8>(_offset, "Offset"));
1284 internalField.Append(new CurveReferenceField(expo.curve, board, version));
1286 else if (IS_ARM(board) && version >= 217) {
1287 internalField.Append(new UnsignedField<2>(expo.mode, "Mode"));
1288 internalField.Append(new UnsignedField<3>(expo.chn, "Channel"));
1289 internalField.Append(new BoolField<2>(_curveMode));
1290 internalField.Append(new UnsignedField<9>(expo.flightModes, "Phases"));
1291 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1292 internalField.Append(new SignedField<8>(_weight, "Weight"));
1293 internalField.Append(new ZCharField<6>(expo.name));
1294 internalField.Append(new SignedField<8>(_curveParam));
1296 else if (IS_TARANIS(board) && version >= 216) {
1297 internalField.Append(new SourceField<8>(expo.srcRaw, board, version, 0));
1298 internalField.Append(new UnsignedField<16>(expo.scale, "Scale"));
1299 internalField.Append(new UnsignedField<8>(expo.chn, "Channel"));
1300 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1301 internalField.Append(new UnsignedField<16>(expo.flightModes));
1302 internalField.Append(new SignedField<8>(_weight, "Weight"));
1303 internalField.Append(new SignedField<6>(expo.carryTrim, "CarryTrim"));
1304 internalField.Append(new UnsignedField<2>(expo.mode, "Mode"));
1305 internalField.Append(new ZCharField<8>(expo.name));
1306 internalField.Append(new SignedField<8>(_offset, "Offset"));
1307 internalField.Append(new CurveReferenceField(expo.curve, board, version));
1308 internalField.Append(new SpareBitsField<8>());
1310 else if (IS_ARM(board) && version >= 216) {
1311 internalField.Append(new UnsignedField<2>(expo.mode, "Mode"));
1312 internalField.Append(new UnsignedField<4>(expo.chn, "Channel"));
1313 internalField.Append(new BoolField<2>(_curveMode));
1314 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1315 internalField.Append(new UnsignedField<16>(expo.flightModes, "Phases"));
1316 internalField.Append(new SignedField<8>(_weight, "Weight"));
1317 internalField.Append(new ZCharField<6>(expo.name));
1318 internalField.Append(new SignedField<8>(_curveParam));
1320 else if (IS_ARM(board)) {
1321 internalField.Append(new UnsignedField<8>(expo.mode, "Mode"));
1322 internalField.Append(new UnsignedField<8>(expo.chn, "Channel"));
1323 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1324 internalField.Append(new UnsignedField<16>(expo.flightModes, "Phases"));
1325 internalField.Append(new SignedField<8>(_weight, "Weight"));
1326 internalField.Append(new BoolField<8>(_curveMode));
1327 if (HAS_LARGE_LCD(board)) {
1328 internalField.Append(new ZCharField<8>(expo.name));
1329 internalField.Append(new SpareBitsField<16>());
1331 else {
1332 internalField.Append(new ZCharField<6>(expo.name));
1334 internalField.Append(new SignedField<8>(_curveParam));
1336 else if (IS_DBLRAM(board, version) && IS_AFTER_RELEASE_23_MARCH_2013(board, version)) {
1337 internalField.Append(new UnsignedField<2>(expo.mode));
1338 internalField.Append(new UnsignedField<2>(expo.chn));
1339 internalField.Append(new BoolField<1>(_curveMode));
1340 internalField.Append(new SpareBitsField<3>());
1341 internalField.Append(new UnsignedField<8>(expo.flightModes));
1342 internalField.Append(new SwitchField<8>(expo.swtch, board, version));
1343 internalField.Append(new SignedField<8>(_weight));
1344 internalField.Append(new SignedField<8>(_curveParam));
1346 else {
1347 internalField.Append(new UnsignedField<2>(expo.mode));
1348 internalField.Append(new SwitchField<6>(expo.swtch, board, version));
1349 internalField.Append(new UnsignedField<2>(expo.chn));
1350 internalField.Append(new UnsignedField<5>(expo.flightModes));
1351 internalField.Append(new BoolField<1>(_curveMode));
1352 internalField.Append(new SignedField<8>(_weight));
1353 internalField.Append(new SignedField<8>(_curveParam));
1357 virtual void beforeExport()
1359 _weight = smallGvarToEEPROM(expo.weight);
1361 if (IS_TARANIS(board) && version >= 216) {
1362 _offset = smallGvarToEEPROM(expo.offset);
1365 if (!IS_TARANIS(board) || version < 216) {
1366 if (expo.curve.type==CurveReference::CURVE_REF_FUNC && expo.curve.value) {
1367 _curveMode = true;
1368 _curveParam = expo.curve.value;
1370 else if (expo.curve.type==CurveReference::CURVE_REF_CUSTOM && expo.curve.value) {
1371 _curveMode = true;
1372 _curveParam = expo.curve.value+6;
1374 else {
1375 _curveMode = false;
1376 _curveParam = smallGvarToEEPROM(expo.curve.value);
1381 virtual void afterImport()
1383 if (IS_STM32(board)) {
1384 if (version < 216) {
1385 if (expo.mode) {
1386 expo.srcRaw = RawSource(SOURCE_TYPE_STICK, expo.chn);
1390 else if (expo.mode) {
1391 expo.srcRaw = RawSource(SOURCE_TYPE_STICK, expo.chn);
1394 expo.weight = smallGvarToC9x(_weight);
1396 if (IS_STM32(board) && version >= 216) {
1397 expo.offset = smallGvarToC9x(_offset);
1400 if (!IS_STM32(board) || version < 216) {
1401 if (!_curveMode)
1402 expo.curve = CurveReference(CurveReference::CURVE_REF_EXPO, smallGvarToC9x(_curveParam));
1403 else if (_curveParam > 6)
1404 expo.curve = CurveReference(CurveReference::CURVE_REF_CUSTOM, _curveParam-6);
1405 else
1406 expo.curve = CurveReference(CurveReference::CURVE_REF_FUNC, _curveParam);
1408 eepromImportDebug() << QString("imported %1: ch %2 name '%3'").arg(internalField.getName()).arg(expo.chn).arg(expo.name);
1411 protected:
1412 StructField internalField;
1413 ExpoData & expo;
1414 BoardEnum board;
1415 unsigned int version;
1416 bool _curveMode;
1417 int _weight;
1418 int _offset;
1419 int _curveParam;
1422 class LimitField: public StructField {
1423 public:
1424 template <int shift, int GV1>
1425 static int exportLimitValue(int value)
1427 if (value > 10000) {
1428 return -GV1 + value - 10001;
1430 if (value < -10000) {
1431 return GV1 + value + 10000;
1433 return value + shift;
1436 template <int shift, int GV1>
1437 static int importLimitValue(int value)
1439 if (value >= GV1) {
1440 return 10001 + value - GV1;
1442 if (value >= GV1-9) {
1443 return -10000 + value - GV1;
1445 if (value < -GV1) {
1446 return -10000 + value + GV1 + 1;
1448 if (value < -GV1+9) {
1449 return 10000 + value + GV1 + 1;
1451 return value - shift;
1454 LimitField(LimitData & limit, BoardEnum board, unsigned int version):
1455 StructField("Limit")
1457 if (IS_ARM(board) && version >= 218) {
1458 if (HAS_LARGE_LCD(board)) {
1459 Append(new ConversionField< SignedField<11> >(limit.min, exportLimitValue<1000, 1024>, importLimitValue<1000, 1024>));
1460 Append(new ConversionField< SignedField<11> >(limit.max, exportLimitValue<-1000, 1024>, importLimitValue<-1000, 1024>));
1462 else {
1463 Append(new ConversionField< SignedField<11> >(limit.min, +100, 10));
1464 Append(new ConversionField< SignedField<11> >(limit.max, -100, 10));
1466 Append(new SignedField<10>(limit.ppmCenter));
1467 Append(new ConversionField< SignedField<11> >(limit.offset, exportLimitValue<0, 1024>, importLimitValue<0, 1024>));
1468 Append(new BoolField<1>(limit.symetrical));
1469 Append(new BoolField<1>(limit.revert));
1470 Append(new SpareBitsField<3>());
1471 Append(new SignedField<8>(limit.curve.value));
1472 if (HAS_LARGE_LCD(board))
1473 Append(new ZCharField<6>(limit.name));
1474 else
1475 Append(new ZCharField<4>(limit.name));
1477 else if (IS_TARANIS(board) && version >= 217) {
1478 Append(new ConversionField< SignedField<11> >(limit.min, exportLimitValue<1000, 1024>, importLimitValue<1000, 1024>));
1479 Append(new ConversionField< SignedField<11> >(limit.max, exportLimitValue<-1000, 1024>, importLimitValue<-1000, 1024>));
1480 Append(new SignedField<10>(limit.ppmCenter));
1481 Append(new ConversionField< SignedField<11> >(limit.offset, exportLimitValue<0, 1024>, importLimitValue<0, 1024>));
1482 Append(new BoolField<1>(limit.symetrical));
1483 Append(new BoolField<1>(limit.revert));
1484 Append(new SpareBitsField<3>());
1485 Append(new SignedField<8>(limit.curve.value));
1486 Append(new ZCharField<6>(limit.name));
1488 else {
1489 if (IS_TARANIS(board) && version >= 216) {
1490 Append(new ConversionField< SignedField<16> >(limit.min, exportLimitValue<1000, 4096>, importLimitValue<1000, 4096>));
1491 Append(new ConversionField< SignedField<16> >(limit.max, exportLimitValue<-1000, 4096>, importLimitValue<-1000, 4096>));
1492 Append(new SignedField<8>(limit.ppmCenter));
1493 Append(new ConversionField< SignedField<14> >(limit.offset, exportLimitValue<0, 4096>, importLimitValue<0, 4096>));
1495 else {
1496 Append(new ConversionField< SignedField<8> >(limit.min, +100, 10));
1497 Append(new ConversionField< SignedField<8> >(limit.max, -100, 10));
1498 Append(new SignedField<8>(limit.ppmCenter));
1499 Append(new SignedField<14>(limit.offset));
1501 Append(new BoolField<1>(limit.symetrical));
1502 Append(new BoolField<1>(limit.revert));
1503 if (HAS_LARGE_LCD(board)) {
1504 Append(new ZCharField<6>(limit.name));
1506 if (IS_TARANIS(board) && version >= 216) {
1507 Append(new SignedField<8>(limit.curve.value));
1513 class CurvesField: public TransformedField {
1514 public:
1515 CurvesField(CurveData * curves, BoardEnum board, unsigned int version):
1516 TransformedField(internalField),
1517 internalField("Curves"),
1518 curves(curves),
1519 board(board),
1520 version(version),
1521 maxCurves(MAX_CURVES(board, version)),
1522 maxPoints(IS_ARM(board) ? 512 : 112-8)
1524 for (int i=0; i<maxCurves; i++) {
1525 if (IS_ARM(board) && version >= 218) {
1526 internalField.Append(new UnsignedField<1>((unsigned int &)curves[i].type));
1527 internalField.Append(new BoolField<1>(curves[i].smooth));
1528 internalField.Append(new ConversionField< SignedField<6> >(curves[i].count, -5));
1529 internalField.Append(new ZCharField<3>(curves[i].name));
1531 else if (IS_TARANIS(board) && version >= 216) {
1532 internalField.Append(new UnsignedField<3>((unsigned int &)curves[i].type));
1533 internalField.Append(new BoolField<1>(curves[i].smooth));
1534 internalField.Append(new SpareBitsField<4>());
1535 internalField.Append(new ConversionField< SignedField<8> >(curves[i].count, -5));
1537 else if (IS_ARM(board)) {
1538 internalField.Append(new SignedField<16>(_curves[i]));
1540 else {
1541 internalField.Append(new SignedField<8>(_curves[i]));
1545 for (int i=0; i<maxPoints; i++) {
1546 internalField.Append(new SignedField<8>(_points[i]));
1550 virtual void beforeExport()
1552 memset(_points, 0, sizeof(_points));
1554 int * cur = &_points[0];
1555 int offset = 0;
1557 for (int i=0; i<maxCurves; i++) {
1558 CurveData *curve = &curves[i];
1559 if (IS_STM32(board) && version >= 216) {
1560 offset += (curve->type == CurveData::CURVE_TYPE_CUSTOM ? curve->count * 2 - 2 : curve->count);
1561 if (offset > maxPoints) {
1562 EEPROMWarnings.push_back(::QObject::tr("OpenTX only accepts %1 points in all curves").arg(maxPoints));
1563 break;
1566 else {
1567 offset += (curve->type == CurveData::CURVE_TYPE_CUSTOM ? curve->count * 2 - 2 : curve->count) - 5;
1568 if (offset > maxPoints - 5 * maxCurves) {
1569 EEPROMWarnings.push_back(::QObject::tr("OpenTx only accepts %1 points in all curves").arg(maxPoints));
1570 break;
1572 _curves[i] = offset;
1574 for (int j=0; j<curve->count; j++) {
1575 *cur++ = curve->points[j].y;
1577 if (curve->type == CurveData::CURVE_TYPE_CUSTOM) {
1578 for (int j=1; j<curve->count-1; j++) {
1579 *cur++ = curve->points[j].x;
1585 virtual void afterImport()
1587 int * cur = &_points[0];
1589 for (int i=0; i<maxCurves; i++) {
1590 CurveData * curve = &curves[i];
1591 if (!IS_STM32(board) || version < 216) {
1592 int * next = &_points[5*(i+1) + _curves[i]];
1593 int size = next - cur;
1594 if (size % 2 == 0) {
1595 curve->count = (size / 2) + 1;
1596 curve->type = CurveData::CURVE_TYPE_CUSTOM;
1598 else {
1599 curve->count = size;
1600 curve->type = CurveData::CURVE_TYPE_STANDARD;
1604 if (curve->count > 17) {
1605 qDebug() << "Wrong points count" << curve->count;
1606 curve->count = 0;
1607 for (int j=0; j<maxCurves; j++) {
1608 CurveData *curve = &curves[j];
1609 curve->clear(5);
1611 return;
1614 for (int j=0; j<curve->count; j++) {
1615 curve->points[j].y = *cur++;
1618 if (curve->type == CurveData::CURVE_TYPE_CUSTOM) {
1619 curve->points[0].x = -100;
1620 for (int j=1; j<curve->count-1; j++)
1621 curve->points[j].x = *cur++;
1622 curve->points[curve->count-1].x = +100;
1624 else {
1625 for (int j=0; j<curve->count; j++)
1626 curve->points[j].x = -100 + (200*i) / (curve->count-1);
1628 eepromImportDebug() << QString("imported curve: %3 points").arg(curve->count);
1632 protected:
1633 StructField internalField;
1634 CurveData * curves;
1635 BoardEnum board;
1636 unsigned int version;
1637 int maxCurves;
1638 int maxPoints;
1639 int _curves[CPN_MAX_CURVES];
1640 int _points[CPN_MAX_CURVES*CPN_MAX_POINTS*2];
1643 class LogicalSwitchesFunctionsTable: public ConversionTable {
1645 public:
1646 LogicalSwitchesFunctionsTable(BoardEnum board, unsigned int version)
1648 int val=0;
1649 bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
1650 addConversion(LS_FN_OFF, val++);
1651 if (IS_ARM(board) && version >= 216)
1652 addConversion(LS_FN_VEQUAL, val++);
1653 if (afterrelease21March2013)
1654 addConversion(LS_FN_VALMOSTEQUAL, val++);
1655 addConversion(LS_FN_VPOS, val++);
1656 addConversion(LS_FN_VNEG, val++);
1657 if (IS_ARM(board) && version >= 216) val++; // later RANGE
1658 addConversion(LS_FN_APOS, val++);
1659 addConversion(LS_FN_ANEG, val++);
1660 addConversion(LS_FN_AND, val++);
1661 addConversion(LS_FN_OR, val++);
1662 addConversion(LS_FN_XOR, val++);
1663 if (IS_ARM(board) && version >= 216) addConversion(LS_FN_EDGE, val++);
1664 addConversion(LS_FN_EQUAL, val++);
1665 if (!afterrelease21March2013)
1666 addConversion(LS_FN_NEQUAL, val++);
1667 addConversion(LS_FN_GREATER, val++);
1668 addConversion(LS_FN_LESS, val++);
1669 if (!afterrelease21March2013) {
1670 addConversion(LS_FN_EGREATER, val++);
1671 addConversion(LS_FN_ELESS, val++);
1673 addConversion(LS_FN_DPOS, val++);
1674 addConversion(LS_FN_DAPOS, val++);
1675 addConversion(LS_FN_TIMER, val++);
1676 if (version >= 216)
1677 addConversion(LS_FN_STICKY, val++);
1681 class AndSwitchesConversionTable: public ConversionTable {
1683 public:
1684 AndSwitchesConversionTable(BoardEnum board, unsigned int version)
1686 int val=0;
1687 addConversion(RawSwitch(SWITCH_TYPE_NONE), val++);
1689 if (IS_STM32(board)) {
1690 for (int i=1; i<=MAX_SWITCHES_POSITION(board, version); i++) {
1691 int s = switchIndex(i, board, version);
1692 if (IS_TARANIS(board) && version < 217) {
1693 // SF positions 16 and 17 => 16 and 18
1694 // SH positions 21 and 22 => 22 and 24
1695 if (s == 17 || s == 23) {
1696 continue;
1699 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val);
1700 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++);
1702 for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) {
1703 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, -i), -val);
1704 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++);
1707 else if (IS_SKY9X(board)) {
1708 for (int i=1; i<=8; i++) {
1709 int s = switchIndex(i, board, version);
1710 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, -s), -val);
1711 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++);
1713 for (int i=1; i<=MAX_LOGICAL_SWITCHES(board, version); i++) {
1714 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, -i), -val);
1715 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++);
1718 else {
1719 for (int i=1; i<=9; i++) {
1720 int s = switchIndex(i, board, version);
1721 addConversion(RawSwitch(SWITCH_TYPE_SWITCH, s), val++);
1723 for (int i=1; i<=7; i++) {
1724 addConversion(RawSwitch(SWITCH_TYPE_VIRTUAL, i), val++);
1729 static ConversionTable * getInstance(BoardEnum board, unsigned int version)
1731 if (IS_ARM(board) && version >= 216)
1732 return new SwitchesConversionTable(board, version);
1733 else
1734 return new AndSwitchesConversionTable(board, version);
1736 #if 0
1737 static std::list<Cache> internalCache;
1739 for (std::list<Cache>::iterator it=internalCache.begin(); it!=internalCache.end(); it++) {
1740 Cache element = *it;
1741 if (element.board == board && element.version == version && element.flags == flags)
1742 return element.table;
1745 Cache element(board, version, flags, new SwitchesConversionTable(board, version, flags));
1746 internalCache.push_back(element);
1747 return element.table;
1748 #endif
1752 protected:
1754 void addConversion(const RawSwitch & sw, const int b)
1756 ConversionTable::addConversion(sw.toValue(), b);
1760 class LogicalSwitchField: public TransformedField {
1761 public:
1762 LogicalSwitchField(LogicalSwitchData & csw, BoardEnum board, unsigned int version, unsigned int variant, ModelData * model=NULL):
1763 TransformedField(internalField),
1764 internalField("LogicalSwitch"),
1765 csw(csw),
1766 board(board),
1767 version(version),
1768 variant(variant),
1769 model(model),
1770 functionsConversionTable(board, version),
1771 sourcesConversionTable(SourcesConversionTable::getInstance(board, version, variant, (version >= 214 || (!IS_ARM(board) && version >= 213)) ? 0 : FLAG_NOSWITCHES)),
1772 switchesConversionTable(SwitchesConversionTable::getInstance(board, version)),
1773 andswitchesConversionTable(AndSwitchesConversionTable::getInstance(board, version)),
1774 v1(0),
1775 v2(0),
1776 v3(0)
1778 if (IS_ARM(board) && version >= 218) {
1779 internalField.Append(new ConversionField< UnsignedField<8> >(csw.func, &functionsConversionTable, "Function"));
1780 internalField.Append(new SignedField<10>(v1));
1781 internalField.Append(new SignedField<10>(v3));
1782 internalField.Append(new ConversionField< SignedField<9> >((int &)csw.andsw, andswitchesConversionTable, "AND switch"));
1783 internalField.Append(new SpareBitsField<1>()); // TODO extra switch mode
1784 internalField.Append(new SpareBitsField<2>());
1785 internalField.Append(new SignedField<16>(v2));
1787 else if (IS_ARM(board) && version >= 217) {
1788 internalField.Append(new ConversionField< UnsignedField<6> >(csw.func, &functionsConversionTable, "Function"));
1789 internalField.Append(new SignedField<10>(v1));
1790 internalField.Append(new SignedField<16>(v2));
1791 internalField.Append(new SignedField<16>(v3));
1793 else if (IS_ARM(board) && version >= 216) {
1794 internalField.Append(new SignedField<8>(v1));
1795 internalField.Append(new SignedField<16>(v2));
1796 internalField.Append(new SignedField<16>(v3));
1797 internalField.Append(new ConversionField< UnsignedField<8> >(csw.func, &functionsConversionTable, "Function"));
1799 else if (IS_ARM(board) && version >= 215) {
1800 internalField.Append(new SignedField<16>(v1));
1801 internalField.Append(new SignedField<16>(v2));
1802 internalField.Append(new ConversionField< UnsignedField<8> >(csw.func, &functionsConversionTable, "Function"));
1804 else if (IS_ARM(board)) {
1805 internalField.Append(new SignedField<8>(v1));
1806 internalField.Append(new SignedField<8>(v2));
1807 internalField.Append(new ConversionField< UnsignedField<8> >(csw.func, &functionsConversionTable, "Function"));
1809 else {
1810 internalField.Append(new SignedField<8>(v1));
1811 internalField.Append(new SignedField<8>(v2));
1812 if (version >= 213)
1813 internalField.Append(new ConversionField< UnsignedField<4> >(csw.func, &functionsConversionTable, "Function"));
1814 else
1815 internalField.Append(new ConversionField< UnsignedField<8> >(csw.func, &functionsConversionTable, "Function"));
1818 if (IS_ARM(board)) {
1819 int scale = (version >= 216 ? 0 : 5);
1820 internalField.Append(new ConversionField< UnsignedField<8> >(csw.delay, 0, scale));
1821 internalField.Append(new ConversionField< UnsignedField<8> >(csw.duration, 0, scale));
1822 if (version >= 214 && version <= 217) {
1823 internalField.Append(new ConversionField< SignedField<8> >((int &)csw.andsw, andswitchesConversionTable, "AND switch"));
1826 else {
1827 if (version >= 213) {
1828 internalField.Append(new ConversionField< UnsignedField<4> >((unsigned int &)csw.andsw, andswitchesConversionTable, "AND switch"));
1833 ~LogicalSwitchField()
1835 delete andswitchesConversionTable;
1838 virtual void beforeExport()
1840 if (csw.func == LS_FN_TIMER) {
1841 v1 = csw.val1;
1842 v2 = csw.val2;
1844 else if (csw.func == LS_FN_EDGE) {
1845 switchesConversionTable->exportValue(csw.val1, v1);
1846 v2 = csw.val2;
1847 v3 = csw.val3;
1849 else if ((csw.func >= LS_FN_AND && csw.func <= LS_FN_XOR) || csw.func == LS_FN_STICKY) {
1850 switchesConversionTable->exportValue(csw.val1, v1);
1851 switchesConversionTable->exportValue(csw.val2, v2);
1853 else if (csw.func >= LS_FN_EQUAL && csw.func <= LS_FN_ELESS) {
1854 sourcesConversionTable->exportValue(csw.val1, v1);
1855 sourcesConversionTable->exportValue(csw.val2, v2);
1857 else if (csw.func != LS_FN_OFF) {
1858 sourcesConversionTable->exportValue(csw.val1, v1);
1859 v2 = csw.val2;
1863 virtual void afterImport()
1865 if (csw.func == LS_FN_TIMER) {
1866 csw.val1 = v1;
1867 csw.val2 = v2;
1869 else if (csw.func == LS_FN_EDGE) {
1870 switchesConversionTable->importValue(v1, csw.val1);
1871 csw.val2 = v2;
1872 csw.val3 = v3;
1874 else if ((csw.func >= LS_FN_AND && csw.func <= LS_FN_XOR) || csw.func == LS_FN_STICKY) {
1875 switchesConversionTable->importValue(v1, csw.val1);
1876 switchesConversionTable->importValue(v2, csw.val2);
1878 else if (csw.func >= LS_FN_EQUAL && csw.func <= LS_FN_ELESS) {
1879 if (IS_ARM(board)) {
1880 sourcesConversionTable->importValue((uint32_t)v1, csw.val1);
1881 sourcesConversionTable->importValue((uint32_t)v2, csw.val2);
1883 else {
1884 sourcesConversionTable->importValue((uint8_t)v1, csw.val1);
1885 sourcesConversionTable->importValue((uint8_t)v2, csw.val2);
1887 if (IS_TARANIS(board) && version < 216) {
1888 RawSource val1(csw.val1);
1889 if (val1.type == SOURCE_TYPE_STICK && val1.index < CPN_MAX_STICKS) {
1890 csw.val1 = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, val1.index).toValue();
1892 RawSource val2(csw.val2);
1893 if (val2.type == SOURCE_TYPE_STICK && val2.index < CPN_MAX_STICKS) {
1894 csw.val2 = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, val2.index).toValue();
1898 else if (csw.func != LS_FN_OFF) {
1899 if (IS_ARM(board) && version >= 217) {
1900 sourcesConversionTable->importValue((uint32_t)v1, csw.val1);
1902 else {
1903 sourcesConversionTable->importValue((uint8_t)v1, csw.val1);
1905 if (IS_TARANIS(board) && version < 216) {
1906 RawSource val1(csw.val1);
1907 if (val1.type == SOURCE_TYPE_STICK && val1.index < CPN_MAX_STICKS) {
1908 csw.val1 = RawSource(SOURCE_TYPE_VIRTUAL_INPUT, val1.index).toValue();
1911 csw.val2 = v2;
1912 RawSource val1(csw.val1);
1913 if (IS_ARM(board) && version < 216 && val1.type == SOURCE_TYPE_TELEMETRY) {
1914 switch (val1.index) {
1915 case TELEMETRY_SOURCE_TIMER1:
1916 case TELEMETRY_SOURCE_TIMER2:
1917 case TELEMETRY_SOURCE_TIMER3:
1918 csw.val2 = (csw.val2 + 128) * 3;
1919 break;
1920 case TELEMETRY_SOURCE_ALT:
1921 case TELEMETRY_SOURCE_GPS_ALT:
1922 case TELEMETRY_SOURCE_ALT_MIN:
1923 case TELEMETRY_SOURCE_ALT_MAX:
1924 csw.val2 = (csw.val2 + 128) * 8 - 500;
1925 break;
1926 case TELEMETRY_SOURCE_RPM:
1927 case TELEMETRY_SOURCE_RPM_MAX:
1928 csw.val2 = (csw.val2 + 128) * 50;
1929 break;
1930 case TELEMETRY_SOURCE_T1:
1931 case TELEMETRY_SOURCE_T2:
1932 case TELEMETRY_SOURCE_T1_MAX:
1933 case TELEMETRY_SOURCE_T2_MAX:
1934 csw.val2 = (csw.val2 + 128) + 30;
1935 break;
1936 case TELEMETRY_SOURCE_CELL:
1937 case TELEMETRY_SOURCE_HDG:
1938 csw.val2 = (csw.val2 + 128) * 2;
1939 break;
1940 case TELEMETRY_SOURCE_DIST:
1941 case TELEMETRY_SOURCE_DIST_MAX:
1942 csw.val2 = (csw.val2 + 128) * 8;
1943 break;
1944 case TELEMETRY_SOURCE_CURRENT:
1945 case TELEMETRY_SOURCE_POWER:
1946 csw.val2 = (csw.val2 + 128) * 5;
1947 break;
1948 case TELEMETRY_SOURCE_CONSUMPTION:
1949 csw.val2 = (csw.val2 + 128) * 20;
1950 break;
1951 default:
1952 csw.val2 += 128;
1953 break;
1957 eepromImportDebug() << QString("imported %1: %2").arg(internalField.getName()).arg(csw.funcToString());
1960 protected:
1961 StructField internalField;
1962 LogicalSwitchData & csw;
1963 BoardEnum board;
1964 unsigned int version;
1965 unsigned int variant;
1966 ModelData * model;
1967 LogicalSwitchesFunctionsTable functionsConversionTable;
1968 SourcesConversionTable * sourcesConversionTable;
1969 SwitchesConversionTable * switchesConversionTable;
1970 ConversionTable * andswitchesConversionTable;
1971 int v1;
1972 int v2;
1973 int v3;
1976 class CustomFunctionsConversionTable: public ConversionTable {
1978 public:
1979 CustomFunctionsConversionTable(BoardEnum board, unsigned int version)
1981 int val=0;
1983 if (version >= 216) {
1984 for (int i=0; i<MAX_CHANNELS(board, version); i++) {
1985 addConversion(i, val);
1987 val++;
1989 else if (IS_ARM(board) || version < 213) {
1990 for (int i=0; i<16; i++) {
1991 addConversion(val, val);
1992 val++;
1995 else {
1996 for (int i=0; i<16; i++) {
1997 addConversion(i, i / 4);
1999 val+=4;
2002 if (version >= 216) {
2003 addConversion(FuncTrainer, val);
2004 addConversion(FuncTrainerRUD, val);
2005 addConversion(FuncTrainerELE, val);
2006 addConversion(FuncTrainerTHR, val);
2007 addConversion(FuncTrainerAIL, val);
2008 val++;
2010 else {
2011 addConversion(FuncTrainer, val++);
2012 addConversion(FuncTrainerRUD, val++);
2013 addConversion(FuncTrainerELE, val++);
2014 addConversion(FuncTrainerTHR, val++);
2015 addConversion(FuncTrainerAIL, val++);
2018 addConversion(FuncInstantTrim, val++);
2020 if (version >= 216) {
2021 addConversion(FuncReset, val++);
2022 if (IS_ARM(board)) {
2023 addConversion(FuncSetTimer1, val);
2024 addConversion(FuncSetTimer2, val);
2025 addConversion(FuncSetTimer3, val);
2026 val++;
2028 for (int i=0; i<MAX_GVARS(board, version); i++)
2029 addConversion(FuncAdjustGV1+i, val);
2030 val++;
2031 if (IS_ARM(board)) {
2032 addConversion(FuncVolume, val++);
2033 addConversion(FuncSetFailsafeInternalModule, val);
2034 addConversion(FuncSetFailsafeExternalModule, val++);
2035 addConversion(FuncRangeCheckInternalModule, val);
2036 addConversion(FuncRangeCheckExternalModule, val++);
2037 addConversion(FuncBindInternalModule, val);
2038 addConversion(FuncBindExternalModule, val++);
2040 addConversion(FuncPlaySound, val++);
2041 addConversion(FuncPlayPrompt, val++);
2042 if (version >= 213 && !IS_ARM(board))
2043 addConversion(FuncPlayBoth, val++);
2044 addConversion(FuncPlayValue, val++);
2045 if (IS_ARM(board)) {
2046 addConversion(FuncReserve, val++);
2047 if (IS_STM32(board))
2048 addConversion(FuncPlayScript, val++);
2049 else
2050 addConversion(FuncReserve, val++);
2051 addConversion(FuncReserve, val++);
2052 addConversion(FuncBackgroundMusic, val++);
2053 addConversion(FuncBackgroundMusicPause, val++);
2055 addConversion(FuncVario, val++);
2056 addConversion(FuncPlayHaptic, val++);
2057 if (IS_2560(board) || IS_ARM(board) )
2058 addConversion(FuncLogs, val++);
2059 addConversion(FuncBacklight, val++);
2060 if (IS_STM32(board))
2061 addConversion(FuncScreenshot, val++);
2063 else {
2064 addConversion(FuncPlaySound, val++);
2065 if (!IS_TARANIS(board))
2066 addConversion(FuncPlayHaptic, val++);
2067 addConversion(FuncReset, val++);
2068 addConversion(FuncVario, val++);
2069 addConversion(FuncPlayPrompt, val++);
2070 if (version >= 213 && !IS_ARM(board))
2071 addConversion(FuncPlayBoth, val++);
2072 addConversion(FuncPlayValue, val++);
2073 if (IS_2560(board) || IS_ARM(board) )
2074 addConversion(FuncLogs, val++);
2075 if (IS_ARM(board))
2076 addConversion(FuncVolume, val++);
2077 addConversion(FuncBacklight, val++);
2078 if (IS_ARM(board)) {
2079 addConversion(FuncBackgroundMusic, val++);
2080 addConversion(FuncBackgroundMusicPause, val++);
2082 for (int i=0; i<5; i++)
2083 addConversion(FuncAdjustGV1+i, val++);
2088 template <int N>
2089 class SwitchesWarningField: public TransformedField {
2090 public:
2091 SwitchesWarningField(uint64_t & sw, BoardEnum board, unsigned int version):
2092 TransformedField(internalField),
2093 internalField(_sw, "SwitchesWarning"),
2094 sw(sw),
2095 board(board),
2096 version(version)
2100 virtual void beforeExport()
2102 _sw = sw;
2105 virtual void afterImport()
2107 bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
2108 if (afterrelease21March2013 && version < 216) {
2109 sw = _sw >> 1;
2111 else if (!afterrelease21March2013) {
2112 sw = ((_sw & 0x30) >> 4) + ((_sw & 0x0E) << 1) + ((_sw & 0xC0) >> 1);
2114 else {
2115 sw = _sw;
2117 eepromImportDebug() << QString("imported %1").arg(internalField.getName());
2120 protected:
2121 BaseUnsignedField<uint64_t, N> internalField;
2122 uint64_t & sw;
2123 uint64_t _sw;
2124 BoardEnum board;
2125 unsigned int version;
2128 class ArmCustomFunctionField: public TransformedField {
2129 public:
2130 ArmCustomFunctionField(CustomFunctionData & fn, BoardEnum board, unsigned int version, unsigned int variant):
2131 TransformedField(internalField),
2132 internalField("CustomFunction"),
2133 fn(fn),
2134 board(board),
2135 version(version),
2136 variant(variant),
2137 functionsConversionTable(board, version),
2138 sourcesConversionTable(SourcesConversionTable::getInstance(board, version, variant, version >= 216 ? 0 : FLAG_NONONE)),
2139 _func(0),
2140 _active(0),
2141 _mode(0)
2143 memset(_param, 0, sizeof(_param));
2145 if (version >= 218) {
2146 internalField.Append(new SwitchField<9>(fn.swtch, board, version));
2147 internalField.Append(new ConversionField< UnsignedField<7> >(_func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2149 else {
2150 internalField.Append(new SwitchField<8>(fn.swtch, board, version));
2151 internalField.Append(new ConversionField< UnsignedField<8> >(_func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2154 if (IS_TARANIS(board) && version >= 216)
2155 internalField.Append(new CharField<8>(_param, false));
2156 else if (IS_TARANIS(board))
2157 internalField.Append(new CharField<10>(_param, false));
2158 else
2159 internalField.Append(new CharField<6>(_param, false));
2161 if (version >= 216) {
2162 internalField.Append(new SignedField<8>(_active));
2164 else if (version >= 214) {
2165 internalField.Append(new UnsignedField<2>(_mode));
2166 internalField.Append(new UnsignedField<6>((unsigned int &)_active));
2168 else {
2169 internalField.Append(new UnsignedField<8>((unsigned int &)_active));
2170 internalField.Append(new SpareBitsField<8>());
2174 static bool hasRepeatParam(const CustomFunctionData & fn)
2176 return (fn.func == FuncPlaySound || fn.func == FuncPlayPrompt || fn.func == FuncPlayValue || fn.func == FuncPlayHaptic);
2179 virtual void beforeExport()
2181 if (fn.swtch.type != SWITCH_TYPE_NONE) {
2182 _func = fn.func;
2184 if (hasRepeatParam(fn))
2185 _active = (version >= 216 ? fn.repeatParam : (fn.repeatParam/5));
2186 else
2187 _active = (fn.enabled ? 1 : 0);
2189 if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) {
2190 if (version >= 216) {
2191 *((uint16_t *)_param) = fn.param;
2192 *((uint8_t *)(_param+3)) = fn.func - FuncOverrideCH1;
2194 else {
2195 *((uint32_t *)_param) = fn.param;
2198 else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) {
2199 if (version >= 216)
2200 *((uint8_t *)(_param+3)) = fn.func - FuncTrainer;
2202 else if (fn.func >= FuncSetTimer1 && fn.func <= FuncSetTimer3) {
2203 if (version >= 216) {
2204 *((uint16_t *)_param) = fn.param;
2205 *((uint8_t *)(_param+3)) = fn.func - FuncSetTimer1;
2208 else if (fn.func >= FuncSetFailsafeInternalModule && fn.func <= FuncSetFailsafeExternalModule) {
2209 if (version >= 216) {
2210 *((uint16_t *)_param) = fn.func - FuncSetFailsafeInternalModule;
2213 else if (fn.func >= FuncRangeCheckInternalModule && fn.func <= FuncRangeCheckExternalModule) {
2214 if (version >= 216) {
2215 *((uint16_t *)_param) = fn.func - FuncRangeCheckInternalModule;
2218 else if (fn.func >= FuncBindInternalModule && fn.func <= FuncBindExternalModule) {
2219 if (version >= 216) {
2220 *((uint16_t *)_param) = fn.func - FuncBindInternalModule;
2223 else if (fn.func == FuncPlayPrompt || fn.func == FuncBackgroundMusic || fn.func == FuncPlayScript) {
2224 memcpy(_param, fn.paramarm, sizeof(_param));
2226 else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) {
2227 if (version >= 216) {
2228 *((uint8_t *)(_param+2)) = fn.adjustMode;
2229 *((uint8_t *)(_param+3)) = fn.func - FuncAdjustGV1;
2230 unsigned int value;
2231 if (fn.adjustMode == 1)
2232 sourcesConversionTable->exportValue(fn.param, (int &)value);
2233 else if (fn.adjustMode == 2)
2234 value = RawSource(fn.param).index;
2235 else
2236 value = fn.param;
2237 *((uint16_t *)_param) = value;
2239 else if (version >= 214) {
2240 unsigned int value;
2241 _mode = fn.adjustMode;
2242 if (fn.adjustMode == 1)
2243 sourcesConversionTable->exportValue(fn.param, (int &)value);
2244 else if (fn.adjustMode == 2)
2245 value = RawSource(fn.param).index;
2246 else
2247 value = fn.param;
2248 *((uint32_t *)_param) = value;
2250 else {
2251 unsigned int value;
2252 sourcesConversionTable->exportValue(fn.param, (int &)value);
2253 *((uint32_t *)_param) = value;
2256 else if (fn.func == FuncPlayValue || fn.func == FuncVolume) {
2257 unsigned int value;
2258 sourcesConversionTable->exportValue(fn.param, (int &)value);
2259 if (version >= 216)
2260 *((uint16_t *)_param) = value;
2261 else
2262 *((uint32_t *)_param) = value;
2264 else if (fn.func == FuncReset) {
2265 if (version >= 217)
2266 *((uint32_t *)_param) = fn.param;
2267 else
2268 *((uint32_t *)_param) = (fn.param < 2 ? fn.param : fn.param-1);
2270 else {
2271 *((uint32_t *)_param) = fn.param;
2276 virtual void afterImport()
2278 fn.func = (AssignFunc)_func;
2280 if (hasRepeatParam(fn))
2281 fn.repeatParam = (version >= 216 ? _active : (_active*5));
2282 else
2283 fn.enabled = (_active & 0x01);
2285 unsigned int value=0, mode=0, index=0;
2286 if (version >= 216) {
2287 value = *((uint16_t *)_param);
2288 mode = *((uint8_t *)(_param+2));
2289 index = *((uint8_t *)(_param+3));
2291 else {
2292 value = *((uint32_t *)_param);
2295 if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) {
2296 fn.func = AssignFunc(fn.func + index);
2297 fn.param = (int16_t)(uint16_t)value;
2299 else if (fn.func >= FuncSetTimer1 && fn.func <= FuncSetTimer3) {
2300 fn.func = AssignFunc(fn.func + index);
2301 fn.param = (int)value;
2303 else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) {
2304 fn.func = AssignFunc(fn.func + index);
2305 fn.param = value;
2307 else if (fn.func == FuncPlayPrompt || fn.func == FuncBackgroundMusic || fn.func == FuncPlayScript) {
2308 memcpy(fn.paramarm, _param, sizeof(fn.paramarm));
2310 else if (fn.func == FuncVolume) {
2311 sourcesConversionTable->importValue(value, (int &)fn.param);
2313 else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) {
2314 if (version >= 216) {
2315 fn.func = AssignFunc(fn.func + index);
2316 fn.adjustMode = mode;
2317 if (fn.adjustMode == 1)
2318 sourcesConversionTable->importValue(value, (int &)fn.param);
2319 else if (fn.adjustMode == 2)
2320 fn.param = RawSource(SOURCE_TYPE_GVAR, value).toValue();
2321 else
2322 fn.param = (int16_t)value;
2324 else if (version >= 214) {
2325 fn.adjustMode = _mode;
2326 if (fn.adjustMode == 1)
2327 sourcesConversionTable->importValue(value, (int &)fn.param);
2328 else if (fn.adjustMode == 2)
2329 fn.param = RawSource(SOURCE_TYPE_GVAR, value).toValue();
2330 else
2331 fn.param = (int8_t)value;
2333 else {
2334 sourcesConversionTable->importValue(value, (int &)fn.param);
2337 else if (fn.func == FuncPlayValue) {
2338 if (version >= 213)
2339 sourcesConversionTable->importValue(value, (int &)fn.param);
2340 else
2341 SourcesConversionTable::getInstance(board, version, variant, FLAG_NONONE|FLAG_NOSWITCHES)->importValue(value, (int &)fn.param);
2343 else if (fn.func == FuncReset) {
2344 if (version >= 217)
2345 fn.param = value;
2346 else
2347 fn.param = (value < 2 ? value : value+1);
2349 else {
2350 fn.param = value;
2352 eepromImportDebug() << QString("imported %1").arg(internalField.getName());
2355 protected:
2356 StructField internalField;
2357 CustomFunctionData & fn;
2358 BoardEnum board;
2359 unsigned int version;
2360 unsigned int variant;
2361 CustomFunctionsConversionTable functionsConversionTable;
2362 SourcesConversionTable * sourcesConversionTable;
2363 unsigned int _func;
2364 char _param[10];
2365 int _active;
2366 unsigned int _mode;
2369 class AvrCustomFunctionField: public TransformedField {
2370 public:
2371 AvrCustomFunctionField(CustomFunctionData & fn, BoardEnum board, unsigned int version, unsigned int variant):
2372 TransformedField(internalField),
2373 internalField("CustomFunction"),
2374 fn(fn),
2375 board(board),
2376 version(version),
2377 variant(variant),
2378 functionsConversionTable(board, version),
2379 sourcesConversionTable(SourcesConversionTable::getInstance(board, version, variant, version >= 216 ? 0 : FLAG_NONONE)),
2380 _param(0),
2381 _mode(0),
2382 _union_param(0),
2383 _active(0)
2385 if (version >= 217 && IS_2560(board)) {
2386 internalField.Append(new SwitchField<8>(fn.swtch, board, version));
2387 internalField.Append(new ConversionField< UnsignedField<8> >((unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2388 internalField.Append(new UnsignedField<2>(fn.adjustMode));
2389 internalField.Append(new UnsignedField<4>(_union_param));
2390 internalField.Append(new UnsignedField<1>(_active));
2391 internalField.Append(new SpareBitsField<1>());
2393 else if (version >= 216) {
2394 internalField.Append(new SwitchField<6>(fn.swtch, board, version));
2395 internalField.Append(new ConversionField< UnsignedField<4> >((unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2396 internalField.Append(new UnsignedField<5>(_union_param));
2397 internalField.Append(new UnsignedField<1>(_active));
2399 else if (version >= 213) {
2400 internalField.Append(new SwitchField<8>(fn.swtch, board, version));
2401 internalField.Append(new UnsignedField<3>(_union_param));
2402 internalField.Append(new ConversionField< UnsignedField<5> >((unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2404 else {
2405 internalField.Append(new SwitchField<8>(fn.swtch, board, version));
2406 internalField.Append(new ConversionField< UnsignedField<7> >((unsigned int &)fn.func, &functionsConversionTable, "Function", ::QObject::tr("OpenTX on this board doesn't accept this function")));
2407 internalField.Append(new BoolField<1>((bool &)fn.enabled));
2409 internalField.Append(new UnsignedField<8>(_param));
2412 virtual void beforeExport()
2414 _param = fn.param;
2415 _active = (fn.enabled ? 1 : 0);
2417 if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) {
2418 if (version >= 216)
2419 _union_param = fn.func - FuncOverrideCH1;
2420 else if (version >= 213)
2421 _active += ((fn.func % 4) << 1);
2423 else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) {
2424 if (version >= 216)
2425 _union_param = fn.func - FuncTrainer;
2427 else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) {
2428 if (version >= 217 && IS_2560(board)) {
2429 _union_param = (fn.func - FuncAdjustGV1);
2430 if (fn.adjustMode == 1)
2431 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2432 else if (fn.adjustMode == 2)
2433 _param = RawSource(fn.param).index;
2435 else if (version >= 216) {
2436 _union_param = fn.adjustMode;
2437 _union_param += (fn.func - FuncAdjustGV1) << 2;
2438 if (fn.adjustMode == 1)
2439 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2440 else if (fn.adjustMode == 2)
2441 _param = RawSource(fn.param).index;
2443 else if (version >= 213) {
2444 _active += (fn.adjustMode << 1);
2445 if (fn.adjustMode == 1)
2446 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2447 else if (fn.adjustMode == 2)
2448 _param = RawSource(fn.param).index;
2450 else {
2451 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2454 else if (fn.func == FuncPlayValue) {
2455 if (version >= 216) {
2456 _union_param = fn.repeatParam / 10;
2457 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2459 else if (version >= 213) {
2460 _active = fn.repeatParam / 10;
2461 sourcesConversionTable->exportValue(fn.param, (int &)_param);
2463 else {
2464 SourcesConversionTable::getInstance(board, version, variant, FLAG_NONONE|FLAG_NOSWITCHES)->exportValue(fn.param, (int &)_param);
2467 else if (fn.func == FuncPlaySound || fn.func == FuncPlayPrompt || fn.func == FuncPlayBoth) {
2468 if (version >= 216) {
2469 _union_param = fn.repeatParam / 10;
2471 else if (version >= 213) {
2472 _active = fn.repeatParam / 10;
2477 virtual void afterImport()
2479 fn.param = _param;
2480 if (version >= 213) {
2481 fn.enabled = (_active & 0x01);
2484 if (fn.func >= FuncOverrideCH1 && fn.func <= FuncOverrideCH32) {
2485 if (version >= 216)
2486 fn.func = AssignFunc(fn.func + _union_param);
2487 else if (version >= 213)
2488 fn.func = AssignFunc(((fn.func >> 2) << 2) + ((_active >> 1) & 0x03));
2489 fn.param = (int8_t)fn.param;
2491 else if (fn.func >= FuncTrainer && fn.func <= FuncTrainerAIL) {
2492 if (version >= 216)
2493 fn.func = AssignFunc(fn.func + _union_param);
2495 else if (fn.func >= FuncAdjustGV1 && fn.func <= FuncAdjustGVLast) {
2496 if (version >= 217 && IS_2560(board)) {
2497 fn.func = AssignFunc(fn.func + _union_param);
2498 if (fn.adjustMode == 1)
2499 sourcesConversionTable->importValue(_param, (int &)fn.param);
2500 else if (fn.adjustMode == 2)
2501 fn.param = RawSource(SOURCE_TYPE_GVAR, _param).toValue();
2503 else if (version >= 216) {
2504 fn.func = AssignFunc(fn.func + (_union_param >> 2));
2505 fn.adjustMode = (_union_param & 0x03);
2506 if (fn.adjustMode == 1)
2507 sourcesConversionTable->importValue(_param, (int &)fn.param);
2508 else if (fn.adjustMode == 2)
2509 fn.param = RawSource(SOURCE_TYPE_GVAR, _param).toValue();
2511 else if (version >= 213) {
2512 fn.adjustMode = ((_active >> 1) & 0x03);
2513 if (fn.adjustMode == 1)
2514 sourcesConversionTable->importValue(_param, (int &)fn.param);
2515 else if (fn.adjustMode == 2)
2516 fn.param = RawSource(SOURCE_TYPE_GVAR, _param).toValue();
2518 else {
2519 sourcesConversionTable->importValue(_param, (int &)fn.param);
2522 else if (fn.func == FuncPlayValue) {
2523 if (version >= 216) {
2524 fn.repeatParam = _union_param * 10;
2525 sourcesConversionTable->importValue(_param, (int &)fn.param);
2527 else if (version >= 213) {
2528 fn.repeatParam = _active * 10;
2529 sourcesConversionTable->importValue(_param, (int &)fn.param);
2531 else {
2532 SourcesConversionTable::getInstance(board, version, variant, FLAG_NONONE|FLAG_NOSWITCHES)->importValue(_param, (int &)fn.param);
2535 else if (fn.func == FuncPlaySound || fn.func == FuncPlayPrompt || fn.func == FuncPlayBoth) {
2536 if (version >= 216)
2537 fn.repeatParam = _union_param * 10;
2538 else if (version >= 213)
2539 fn.repeatParam = _active * 10;
2541 eepromImportDebug() << QString("imported %1").arg(internalField.getName());
2544 protected:
2545 StructField internalField;
2546 CustomFunctionData & fn;
2547 BoardEnum board;
2548 unsigned int version;
2549 unsigned int variant;
2550 CustomFunctionsConversionTable functionsConversionTable;
2551 SourcesConversionTable * sourcesConversionTable;
2552 unsigned int _param;
2553 unsigned int _mode;
2554 unsigned int _union_param;
2555 unsigned int _active;
2558 class FrskyScreenField: public DataField {
2559 public:
2560 FrskyScreenField(FrSkyScreenData & screen, BoardEnum board, unsigned int version, unsigned int variant):
2561 DataField("Frsky Screen"),
2562 screen(screen),
2563 board(board),
2564 version(version)
2566 for (int i=0; i<4; i++) {
2567 if (IS_ARM(board) && version >= 217) {
2568 if (IS_TARANIS(board))
2569 bars.Append(new SourceField<16>(screen.body.bars[i].source, board, version, variant));
2570 else
2571 bars.Append(new SourceField<8>(screen.body.bars[i].source, board, version, variant));
2572 bars.Append(new UnsignedField<16>(screen.body.bars[i].barMin));
2573 bars.Append(new UnsignedField<16>(screen.body.bars[i].barMax));
2575 else {
2576 bars.Append(new TelemetrySourceField<8>(screen.body.bars[i].source, board, version));
2577 bars.Append(new UnsignedField<8>(screen.body.bars[i].barMin));
2578 bars.Append(new UnsignedField<8>(screen.body.bars[i].barMax));
2582 int columns = (HAS_LARGE_LCD(board) ? 3 : 2);
2583 for (int i=0; i<4; i++) {
2584 for (int j=0; j<columns; j++) {
2585 if (IS_TARANIS(board) && version >= 217)
2586 numbers.Append(new SourceField<16>(screen.body.lines[i].source[j], board, version, variant));
2587 else if (IS_ARM(board) && version >= 217)
2588 numbers.Append(new SourceField<8>(screen.body.lines[i].source[j], board, version, variant));
2589 else
2590 numbers.Append(new TelemetrySourceField<8>(screen.body.lines[i].source[j], board, version));
2594 if (!IS_TARANIS(board)) {
2595 if (IS_ARM(board))
2596 numbers.Append(new SpareBitsField<12*8>());
2597 else
2598 numbers.Append(new SpareBitsField<4*8>());
2601 if (IS_TARANIS(board) && version >= 217) {
2602 script.Append(new CharField<8>(screen.body.script.filename, true, "Script name"));
2603 script.Append(new SpareBitsField<16*8>());
2606 if (IS_ARM(board) && version >= 217) {
2607 if (IS_TARANIS(board))
2608 none.Append(new SpareBitsField<24*8>());
2609 else
2610 none.Append(new SpareBitsField<20*8>());
2614 virtual void ExportBits(QBitArray & output)
2616 if (IS_ARM(board) && version >= 217) {
2617 if (screen.type == TELEMETRY_SCREEN_SCRIPT)
2618 script.ExportBits(output);
2619 else if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2620 numbers.ExportBits(output);
2621 else if (screen.type == TELEMETRY_SCREEN_BARS)
2622 bars.ExportBits(output);
2623 else
2624 none.ExportBits(output);
2626 else {
2627 if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2628 numbers.ExportBits(output);
2629 else
2630 bars.ExportBits(output);
2634 virtual void ImportBits(const QBitArray & input)
2636 eepromImportDebug() << QString("importing %1: type: %2").arg(name).arg(screen.type);
2638 // NOTA: screen.type should have been imported first!
2639 if (IS_ARM(board) && version >= 217) {
2640 if (screen.type == TELEMETRY_SCREEN_SCRIPT)
2641 script.ImportBits(input);
2642 else if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2643 numbers.ImportBits(input);
2644 else if (screen.type == TELEMETRY_SCREEN_BARS)
2645 bars.ImportBits(input);
2646 else
2647 none.ImportBits(input);
2649 else {
2650 if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2651 numbers.ImportBits(input);
2652 else
2653 bars.ImportBits(input);
2657 virtual unsigned int size()
2659 // NOTA: screen.type should have been imported first!
2660 if (IS_ARM(board) && version >= 217) {
2661 if (screen.type == TELEMETRY_SCREEN_SCRIPT)
2662 return script.size();
2663 else if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2664 return numbers.size();
2665 else if (screen.type == TELEMETRY_SCREEN_BARS)
2666 return bars.size();
2667 else
2668 return none.size();
2670 else {
2671 if (screen.type == TELEMETRY_SCREEN_NUMBERS)
2672 return numbers.size();
2673 else
2674 return bars.size();
2678 protected:
2679 FrSkyScreenData & screen;
2680 BoardEnum board;
2681 unsigned int version;
2682 StructField none;
2683 StructField bars;
2684 StructField numbers;
2685 StructField script;
2688 class RSSIConversionTable: public ConversionTable
2690 public:
2691 RSSIConversionTable(int index)
2693 addConversion(0, 2-index);
2694 addConversion(1, 3-index);
2695 addConversion(2, index ? 3 : 0);
2696 addConversion(3, 1-index);
2699 RSSIConversionTable()
2704 class TelemetryVarioSourceConversionTable: public ConversionTable
2706 public:
2707 TelemetryVarioSourceConversionTable(BoardEnum board, unsigned int version)
2709 int val = 0;
2710 if (!IS_TARANIS(board)) {
2711 addConversion(TELEMETRY_VARIO_SOURCE_ALTI, val++);
2712 addConversion(TELEMETRY_VARIO_SOURCE_ALTI_PLUS, val++);
2714 addConversion(TELEMETRY_VARIO_SOURCE_VSPEED, val++);
2715 addConversion(TELEMETRY_VARIO_SOURCE_A1, val++);
2716 addConversion(TELEMETRY_VARIO_SOURCE_A2, val++);
2717 if (IS_TARANIS(board)) {
2718 addConversion(TELEMETRY_VARIO_SOURCE_DTE, val++);
2723 class TelemetryVoltsSourceConversionTable: public ConversionTable
2725 public:
2726 TelemetryVoltsSourceConversionTable(BoardEnum board, unsigned int version)
2728 int val = 0;
2729 addConversion(TELEMETRY_VOLTS_SOURCE_A1, val++);
2730 addConversion(TELEMETRY_VOLTS_SOURCE_A2, val++);
2731 if (IS_ARM(board) && version >= 216) {
2732 addConversion(TELEMETRY_VOLTS_SOURCE_A3, val++);
2733 addConversion(TELEMETRY_VOLTS_SOURCE_A4, val++);
2735 addConversion(TELEMETRY_VOLTS_SOURCE_FAS, val++);
2736 addConversion(TELEMETRY_VOLTS_SOURCE_CELLS, val++);
2740 class ScreenTypesConversionTable: public ConversionTable
2742 public:
2743 ScreenTypesConversionTable(BoardEnum board, unsigned int version)
2745 int val = 0;
2746 if (IS_ARM(board)) {
2747 addConversion(TELEMETRY_SCREEN_NONE, val++);
2749 addConversion(TELEMETRY_SCREEN_NUMBERS, val++);
2750 addConversion(TELEMETRY_SCREEN_BARS, val++);
2754 class TelemetryCurrentSourceConversionTable: public ConversionTable
2756 public:
2757 TelemetryCurrentSourceConversionTable(BoardEnum board, unsigned int version)
2759 int val = 0;
2760 addConversion(TELEMETRY_CURRENT_SOURCE_NONE, val++);
2761 addConversion(TELEMETRY_CURRENT_SOURCE_A1, val++);
2762 addConversion(TELEMETRY_CURRENT_SOURCE_A2, val++);
2763 if (IS_ARM(board) && version >= 216) {
2764 addConversion(TELEMETRY_CURRENT_SOURCE_A3, val++);
2765 addConversion(TELEMETRY_CURRENT_SOURCE_A4, val++);
2767 addConversion(TELEMETRY_CURRENT_SOURCE_FAS, val++);
2771 class FrskyField: public StructField {
2772 public:
2773 FrskyField(FrSkyData & frsky, BoardEnum board, unsigned int version, unsigned int variant):
2774 StructField("FrSky"),
2775 telemetryVarioSourceConversionTable(board, version),
2776 screenTypesConversionTable(board, version),
2777 telemetryVoltsSourceConversionTable(board, version),
2778 telemetryCurrentSourceConversionTable(board, version)
2780 rssiConversionTable[0] = RSSIConversionTable(0);
2781 rssiConversionTable[1] = RSSIConversionTable(1);
2783 if (IS_ARM(board)) {
2784 if (!IS_HORUS(board)) {
2785 if (version >= 217) {
2786 Append(new UnsignedField<8>(frsky.voltsSource, "Volts Source"));
2787 Append(new UnsignedField<8>(frsky.altitudeSource, "Altitude Source"));
2789 else {
2790 for (int i = 0; i < (version >= 216 ? 4 : 2); i++) {
2791 Append(new UnsignedField<8>(frsky.channels[i].ratio, "Ratio"));
2792 Append(new SignedField<12>(frsky.channels[i].offset, "Offset"));
2793 Append(new UnsignedField<4>(frsky.channels[i].type, "Type"));
2794 for (int j = 0; j < 2; j++)
2795 Append(new UnsignedField<8>(frsky.channels[i].alarms[j].value, "Alarm value"));
2796 for (int j = 0; j < 2; j++)
2797 Append(new UnsignedField<2>(frsky.channels[i].alarms[j].level));
2798 for (int j = 0; j < 2; j++)
2799 Append(new UnsignedField<1>(frsky.channels[i].alarms[j].greater));
2800 Append(new SpareBitsField<2>());
2801 Append(new UnsignedField<8>(frsky.channels[i].multiplier, 0, 5, "Multiplier"));
2803 Append(new UnsignedField<8>(frsky.usrProto));
2804 if (version >= 216) {
2805 Append(new ConversionField<UnsignedField<7> >(frsky.voltsSource, &telemetryVoltsSourceConversionTable, "Volts Source"));
2806 Append(new SpareBitsField<1>());
2808 else {
2809 Append(new ConversionField<UnsignedField<8> >(frsky.voltsSource, &telemetryVoltsSourceConversionTable, "Volts Source"));
2811 Append(new ConversionField<SignedField<8> >(frsky.blades, -2));
2812 Append(new ConversionField<UnsignedField<8> >(frsky.currentSource, &telemetryCurrentSourceConversionTable, "Current Source"));
2815 if (version >= 217) {
2816 for (int i = 0; i < 4; i++) {
2817 Append(new UnsignedField<2>(frsky.screens[i].type));
2819 for (int i = 0; i < 4; i++) {
2820 Append(new FrskyScreenField(frsky.screens[i], board, version, variant));
2823 else {
2824 Append(new UnsignedField<1>(frsky.screens[0].type));
2825 Append(new UnsignedField<1>(frsky.screens[1].type));
2826 Append(new UnsignedField<1>(frsky.screens[2].type));
2827 Append(new SpareBitsField<5>());
2828 for (int i = 0; i < 3; i++) {
2829 Append(new FrskyScreenField(frsky.screens[i], board, version, variant));
2834 if (version >= 217) {
2835 Append(new UnsignedField<7>(frsky.varioSource, "Vario Source"));
2836 Append(new BoolField<1>(frsky.varioCenterSilent));
2838 else {
2839 Append(new ConversionField< UnsignedField<8> >(frsky.varioSource, &telemetryVarioSourceConversionTable, "Vario Source"));
2841 Append(new SignedField<8>(frsky.varioCenterMax));
2842 Append(new SignedField<8>(frsky.varioCenterMin));
2843 Append(new SignedField<8>(frsky.varioMin));
2844 Append(new SignedField<8>(frsky.varioMax));
2845 for (int i=0; i<2; i++) {
2846 Append(new ConversionField< UnsignedField<2> >(frsky.rssiAlarms[i].level, &rssiConversionTable[i], "RSSI"));
2847 Append(new ConversionField< SignedField<6> >(frsky.rssiAlarms[i].value, -45+i*3));
2849 if (version == 216) {
2850 Append(new BoolField<1>(frsky.mAhPersistent));
2851 Append(new UnsignedField<15>(frsky.storedMah));
2852 Append(new SignedField<8>(frsky.fasOffset));
2855 else {
2856 for (int i=0; i<2; i++) {
2857 Append(new UnsignedField<8>(frsky.channels[i].ratio, "Ratio"));
2858 Append(new SignedField<12>(frsky.channels[i].offset, "Offset"));
2859 Append(new UnsignedField<4>(frsky.channels[i].type, "Type"));
2860 for (int j=0; j<2; j++)
2861 Append(new UnsignedField<8>(frsky.channels[i].alarms[j].value, "Alarm value"));
2862 for (int j=0; j<2; j++)
2863 Append(new UnsignedField<2>(frsky.channels[i].alarms[j].level));
2864 for (int j=0; j<2; j++)
2865 Append(new UnsignedField<1>(frsky.channels[i].alarms[j].greater));
2866 Append(new UnsignedField<2>(frsky.channels[i].multiplier, 0, 3, "Multiplier"));
2868 Append(new UnsignedField<2>(frsky.usrProto, "USR Proto"));
2869 Append(new ConversionField< UnsignedField<2> >((unsigned int &)frsky.blades, -2));
2870 for (int i=0; i<2; i++) {
2871 Append(new ConversionField< UnsignedField<1> >(frsky.screens[i].type, &screenTypesConversionTable, "Screen Type"));
2873 Append(new ConversionField< UnsignedField<2> >(frsky.voltsSource, &telemetryVoltsSourceConversionTable, "Volts Source"));
2874 Append(new SignedField<4>(frsky.varioMin, "Vario Min"));
2875 Append(new SignedField<4>(frsky.varioMax));
2876 for (int i=0; i<2; i++) {
2877 Append(new ConversionField< UnsignedField<2> >(frsky.rssiAlarms[i].level, &rssiConversionTable[i], "RSSI level"));
2878 Append(new ConversionField< SignedField<6> >(frsky.rssiAlarms[i].value, -45+i*3, 0, 0, 100, "RSSI value"));
2880 for (int i=0; i<2; i++) {
2881 Append(new FrskyScreenField(frsky.screens[i], board, version, variant));
2883 Append(new UnsignedField<3>(frsky.varioSource));
2884 Append(new SignedField<5>(frsky.varioCenterMin));
2885 Append(new ConversionField< UnsignedField<3> >(frsky.currentSource, &telemetryCurrentSourceConversionTable, "Current Source"));
2886 Append(new SignedField<5>(frsky.varioCenterMax));
2887 if (version >= 216) {
2888 Append(new SignedField<8>(frsky.fasOffset));
2893 protected:
2894 RSSIConversionTable rssiConversionTable[2];
2895 TelemetryVarioSourceConversionTable telemetryVarioSourceConversionTable;
2896 ScreenTypesConversionTable screenTypesConversionTable;
2897 TelemetryVoltsSourceConversionTable telemetryVoltsSourceConversionTable;
2898 TelemetryCurrentSourceConversionTable telemetryCurrentSourceConversionTable;
2901 class MavlinkField: public StructField {
2902 public:
2903 MavlinkField(MavlinkData & mavlink, BoardEnum board, unsigned int version):
2904 StructField("MavLink")
2906 Append(new UnsignedField<4>(mavlink.rc_rssi_scale, "Rc_rssi_scale"));
2907 Append(new UnsignedField<1>(mavlink.pc_rssi_en, "Pc_rssi_en"));
2908 Append(new SpareBitsField<3>());
2909 Append(new SpareBitsField<8>());
2910 Append(new SpareBitsField<8>());
2911 Append(new SpareBitsField<8>());
2916 * TODO
2918 #if 0
2919 class CustomScreenField: public StructField {
2920 public:
2921 CustomScreenField(CustomScreenData & customScreen):
2922 StructField("Custom Screen"),
2923 customScreen(customScreen)
2927 protected:
2928 CustomScreenData & customScreen;
2930 #endif
2932 class SensorField: public TransformedField {
2933 public:
2934 SensorField(SensorData & sensor, BoardEnum board, unsigned int version):
2935 TransformedField(internalField),
2936 internalField("Sensor"),
2937 sensor(sensor),
2938 version(version),
2939 _param(0)
2941 internalField.Append(new UnsignedField<16>(_id, "id/persistentValue"));
2942 internalField.Append(new UnsignedField<8>(_instance, "instance/formula"));
2943 internalField.Append(new ZCharField<4>(sensor.label));
2944 internalField.Append(new UnsignedField<1>(sensor.type, "type"));
2945 internalField.Append(new UnsignedField<5>(sensor.unit, "unit"));
2946 internalField.Append(new UnsignedField<2>(sensor.prec, "prec"));
2947 internalField.Append(new BoolField<1>(sensor.autoOffset));
2948 internalField.Append(new BoolField<1>(sensor.filter));
2949 internalField.Append(new BoolField<1>(sensor.logs));
2950 internalField.Append(new BoolField<1>(sensor.persistent));
2951 internalField.Append(new BoolField<1>(sensor.onlyPositive));
2952 internalField.Append(new UnsignedField<3>(_subid, "subid"));
2953 internalField.Append(new UnsignedField<32>(_param, "param"));
2956 virtual void beforeExport()
2958 if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) {
2959 _id = sensor.id;
2960 _subid = sensor.subid;
2961 _instance = sensor.instance;
2962 _ratio = sensor.ratio;
2963 _offset = sensor.offset;
2965 else {
2966 _id = sensor.persistentValue;
2967 _instance = sensor.formula;
2968 if (sensor.formula == SensorData::TELEM_FORMULA_CELL)
2969 _param = (sensor.source) + (sensor.index << 8);
2970 else if (sensor.formula == SensorData::TELEM_FORMULA_ADD || sensor.formula == SensorData::TELEM_FORMULA_AVERAGE || sensor.formula == SensorData::TELEM_FORMULA_MULTIPLY || sensor.formula == SensorData::TELEM_FORMULA_MIN || sensor.formula == SensorData::TELEM_FORMULA_MAX)
2971 _param = ((uint8_t)sensor.sources[0]) + ((uint8_t)sensor.sources[1] << 8) + ((uint8_t)sensor.sources[2] << 16) + ((uint8_t)sensor.sources[3] << 24);
2972 else if (sensor.formula == SensorData::TELEM_FORMULA_DIST)
2973 _param = (sensor.gps) + (sensor.alt << 8);
2974 else if (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION || sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE)
2975 _param = (sensor.amps);
2979 virtual void afterImport()
2981 if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) {
2982 sensor.id = _id;
2983 sensor.subid = _subid;
2984 sensor.instance = _instance;
2985 sensor.ratio = _ratio;
2986 sensor.offset = _offset;
2988 else {
2989 sensor.persistentValue = _id;
2990 sensor.formula = _instance;
2991 if (sensor.formula == SensorData::TELEM_FORMULA_CELL)
2992 (sensor.source = _sources[0], sensor.index = _sources[1]);
2993 else if (sensor.formula == SensorData::TELEM_FORMULA_ADD || sensor.formula == SensorData::TELEM_FORMULA_AVERAGE || sensor.formula == SensorData::TELEM_FORMULA_MULTIPLY || sensor.formula == SensorData::TELEM_FORMULA_MIN || sensor.formula == SensorData::TELEM_FORMULA_MAX)
2994 for (int i=0; i<4; ++i)
2995 sensor.sources[i] = _sources[i];
2996 else if (sensor.formula == SensorData::TELEM_FORMULA_DIST)
2997 (sensor.gps = _sources[0], sensor.alt = _sources[1]);
2998 else if (sensor.formula == SensorData::TELEM_FORMULA_CONSUMPTION || sensor.formula == SensorData::TELEM_FORMULA_TOTALIZE)
2999 sensor.amps = _sources[0];
3002 if (version < 218) {
3003 if (sensor.unit > SensorData::UNIT_WATTS)
3004 sensor.unit++;
3005 if (sensor.unit > SensorData::UNIT_DEGREE)
3006 sensor.unit++;
3009 eepromImportDebug() << QString("imported %1").arg(internalField.getName());
3012 protected:
3013 StructField internalField;
3014 SensorData & sensor;
3015 unsigned int version;
3016 unsigned int _id;
3017 unsigned int _subid;
3018 unsigned int _instance;
3019 union {
3020 unsigned int _param;
3021 uint8_t _sources[4];
3022 struct {
3023 uint16_t _ratio;
3024 int16_t _offset;
3029 int exportPpmDelay(int delay) { return (delay - 300) / 50; }
3030 int importPpmDelay(int delay) { return 300 + 50 * delay; }
3032 OpenTxModelData::OpenTxModelData(ModelData & modelData, BoardEnum board, unsigned int version, unsigned int variant):
3033 TransformedField(internalField),
3034 internalField("ModelData"),
3035 modelData(modelData),
3036 board(board),
3037 version(version),
3038 variant(variant),
3039 protocolsConversionTable(board)
3041 sprintf(name, "Model %s", modelData.name);
3043 eepromImportDebug() << QString("OpenTxModelData::OpenTxModelData(name: %1, board: %2, ver: %3, var: %4)").arg(name).arg(board).arg(version).arg(variant);
3045 if (board == BOARD_HORUS)
3046 internalField.Append(new ZCharField<15>(modelData.name, "Model name"));
3047 else if (HAS_LARGE_LCD(board))
3048 internalField.Append(new ZCharField<12>(modelData.name, "Model name"));
3049 else
3050 internalField.Append(new ZCharField<10>(modelData.name, "Model name"));
3052 bool afterrelease21March2013 = IS_AFTER_RELEASE_21_MARCH_2013(board, version);
3054 if (afterrelease21March2013) {
3055 internalField.Append(new UnsignedField<8>(modelData.moduleData[0].modelId));
3057 if (IS_ARM(board) && version >= 217) {
3058 internalField.Append(new UnsignedField<8>(modelData.moduleData[1].modelId));
3061 if (HAS_LARGE_LCD(board) && version >= 215) {
3062 internalField.Append(new CharField<10>(modelData.bitmap, true, "Model bitmap"));
3065 for (int i=0; i<MAX_TIMERS(board, version); i++) {
3066 if (IS_ARM(board) && version >= 218) {
3067 internalField.Append(new SwitchField<9>(modelData.timers[i].mode, board, version, true));
3068 internalField.Append(new UnsignedField<23>(modelData.timers[i].val));
3069 internalField.Append(new SignedField<24>(modelData.timers[i].pvalue));
3070 internalField.Append(new UnsignedField<2>(modelData.timers[i].countdownBeep));
3071 internalField.Append(new BoolField<1>(modelData.timers[i].minuteBeep));
3072 internalField.Append(new UnsignedField<2>(modelData.timers[i].persistent));
3073 internalField.Append(new SpareBitsField<3>());
3074 if (HAS_LARGE_LCD(board))
3075 internalField.Append(new ZCharField<8>(modelData.timers[i].name, "Timer name"));
3076 else
3077 internalField.Append(new ZCharField<3>(modelData.timers[i].name, "Timer name"));
3079 else if (IS_ARM(board) && version >= 217) {
3080 internalField.Append(new SwitchField<8>(modelData.timers[i].mode, board, version, true));
3081 internalField.Append(new UnsignedField<24>(modelData.timers[i].val));
3082 internalField.Append(new SignedField<24>(modelData.timers[i].pvalue));
3083 internalField.Append(new UnsignedField<2>(modelData.timers[i].countdownBeep));
3084 internalField.Append(new BoolField<1>(modelData.timers[i].minuteBeep));
3085 internalField.Append(new UnsignedField<2>(modelData.timers[i].persistent));
3086 internalField.Append(new SpareBitsField<3>());
3087 if (IS_TARANIS(board))
3088 internalField.Append(new ZCharField<8>(modelData.timers[i].name, "Timer name"));
3089 else
3090 internalField.Append(new ZCharField<3>(modelData.timers[i].name, "Timer name"));
3092 else if ((IS_ARM(board) || IS_2560(board)) && version >= 216) {
3093 internalField.Append(new SwitchField<8>(modelData.timers[i].mode, board, version, true));
3094 internalField.Append(new UnsignedField<16>(modelData.timers[i].val));
3095 internalField.Append(new UnsignedField<2>(modelData.timers[i].countdownBeep));
3096 internalField.Append(new BoolField<1>(modelData.timers[i].minuteBeep));
3097 internalField.Append(new UnsignedField<2>(modelData.timers[i].persistent));
3098 internalField.Append(new SpareBitsField<3>());
3099 internalField.Append(new SignedField<16>(modelData.timers[i].pvalue));
3101 else if (afterrelease21March2013) {
3102 internalField.Append(new SwitchField<8>(modelData.timers[i].mode, board, version, true));
3103 internalField.Append(new UnsignedField<12>(modelData.timers[i].val));
3104 internalField.Append(new BoolField<1>((bool &)modelData.timers[i].countdownBeep));
3105 internalField.Append(new BoolField<1>(modelData.timers[i].minuteBeep));
3106 if (HAS_PERSISTENT_TIMERS(board)) {
3107 internalField.Append(new UnsignedField<1>(modelData.timers[i].persistent));
3108 internalField.Append(new SpareBitsField<1>());
3109 internalField.Append(new SignedField<16>(modelData.timers[i].pvalue));
3111 else {
3112 internalField.Append(new SpareBitsField<2>());
3115 else {
3116 internalField.Append(new SwitchField<8>(modelData.timers[i].mode, board, version, true));
3117 internalField.Append(new UnsignedField<16>(modelData.timers[i].val));
3118 if (HAS_PERSISTENT_TIMERS(board)) {
3119 internalField.Append(new UnsignedField<1>(modelData.timers[i].persistent));
3120 internalField.Append(new SpareBitsField<15>());
3125 if (IS_ARM(board))
3126 internalField.Append(new UnsignedField<3>(modelData.telemetryProtocol));
3127 else
3128 internalField.Append(new ConversionField< UnsignedField<3> >((unsigned int &)modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this telemetry protocol")));
3130 internalField.Append(new BoolField<1>(modelData.thrTrim));
3132 if (IS_ARM(board) && version >= 217) {
3133 internalField.Append(new BoolField<1>(modelData.noGlobalFunctions));
3134 internalField.Append(new UnsignedField<2>(modelData.trimsDisplay));
3135 internalField.Append(new BoolField<1>(modelData.frsky.ignoreSensorIds));
3137 else if (IS_TARANIS(board) || (IS_ARM(board) && version >= 216)) {
3138 internalField.Append(new SpareBitsField<4>());
3140 else {
3141 internalField.Append(new ConversionField< SignedField<4> >(modelData.moduleData[0].channelsCount, &channelsConversionTable, "Channels number", ::QObject::tr("OpenTX doesn't allow this number of channels")));
3144 if (version >= 216)
3145 internalField.Append(new SignedField<3>(modelData.trimInc));
3146 else
3147 internalField.Append(new ConversionField< SignedField<3> >(modelData.trimInc, +2));
3149 internalField.Append(new BoolField<1>(modelData.disableThrottleWarning));
3151 if (IS_TARANIS(board) || (IS_ARM(board) && version >= 216))
3152 internalField.Append(new BoolField<1>(modelData.displayChecklist));
3153 else
3154 internalField.Append(new BoolField<1>(modelData.moduleData[0].ppm.pulsePol));
3156 internalField.Append(new BoolField<1>(modelData.extendedLimits));
3157 internalField.Append(new BoolField<1>(modelData.extendedTrims));
3158 internalField.Append(new BoolField<1>(modelData.throttleReversed));
3160 if (!IS_ARM(board) || version < 216) {
3161 internalField.Append(new ConversionField< SignedField<8> >(modelData.moduleData[0].ppm.delay, exportPpmDelay, importPpmDelay));
3164 if (IS_ARM(board) || IS_2560(board))
3165 internalField.Append(new UnsignedField<16>(modelData.beepANACenter));
3166 else
3167 internalField.Append(new UnsignedField<8>(modelData.beepANACenter));
3169 for (int i=0; i<MAX_MIXERS(board, version); i++)
3170 internalField.Append(new MixField(modelData.mixData[i], board, version, &modelData));
3171 for (int i=0; i<MAX_CHANNELS(board, version); i++)
3172 internalField.Append(new LimitField(modelData.limitData[i], board, version));
3173 for (int i=0; i<MAX_EXPOS(board, version); i++)
3174 internalField.Append(new InputField(modelData.expoData[i], board, version));
3175 internalField.Append(new CurvesField(modelData.curves, board, version));
3176 for (int i=0; i<MAX_LOGICAL_SWITCHES(board, version); i++)
3177 internalField.Append(new LogicalSwitchField(modelData.logicalSw[i], board, version, variant, &modelData));
3178 for (int i=0; i<MAX_CUSTOM_FUNCTIONS(board, version); i++) {
3179 if (IS_ARM(board))
3180 internalField.Append(new ArmCustomFunctionField(modelData.customFn[i], board, version, variant));
3181 else
3182 internalField.Append(new AvrCustomFunctionField(modelData.customFn[i], board, version, variant));
3184 internalField.Append(new HeliField(modelData.swashRingData, board, version, variant));
3185 for (int i=0; i<MAX_FLIGHT_MODES(board, version); i++) {
3186 internalField.Append(new FlightModeField(modelData.flightModeData[i], i, board, version));
3189 if (!IS_ARM(board) || version < 216) {
3190 internalField.Append(new SignedField<8>(modelData.moduleData[0].ppm.frameLength));
3193 internalField.Append(new UnsignedField<8>(modelData.thrTraceSrc, "Throttle Source"));
3195 if (!afterrelease21March2013) {
3196 internalField.Append(new UnsignedField<8>(modelData.moduleData[0].modelId));
3199 if (IS_HORUS(board))
3200 internalField.Append(new SwitchesWarningField<32>(modelData.switchWarningStates, board, version));
3201 else if (IS_TARANIS_X9E(board))
3202 internalField.Append(new SwitchesWarningField<64>(modelData.switchWarningStates, board, version));
3203 else if (IS_TARANIS(board))
3204 internalField.Append(new SwitchesWarningField<16>(modelData.switchWarningStates, board, version));
3205 else
3206 internalField.Append(new SwitchesWarningField<8>(modelData.switchWarningStates, board, version));
3209 if (IS_TARANIS_X9E(board))
3210 internalField.Append(new UnsignedField<32>(modelData.switchWarningEnable));
3211 else if (!IS_HORUS(board) && version >= 216)
3212 internalField.Append(new UnsignedField<8>(modelData.switchWarningEnable));
3214 if (board != BOARD_STOCK && (board != BOARD_M128 || version < 215)) {
3215 for (int i=0; i<MAX_GVARS(board, version); i++) {
3216 if (version >= 218) {
3217 internalField.Append(new ZCharField<3>(modelData.gvars_names[i], "GVar name"));
3218 internalField.Append(new SpareBitsField<12>()); // TODO min
3219 internalField.Append(new SpareBitsField<12>()); // TODO max
3220 internalField.Append(new BoolField<1>(modelData.gvars_popups[i]));
3221 internalField.Append(new SpareBitsField<1>());
3222 internalField.Append(new SpareBitsField<2>());
3223 internalField.Append(new SpareBitsField<4>());
3225 else {
3226 internalField.Append(new ZCharField<6>(modelData.gvars_names[i], "GVar name"));
3227 if (version >= 216) {
3228 internalField.Append(new BoolField<1>(modelData.gvars_popups[i]));
3229 internalField.Append(new SpareBitsField<7>());
3234 else if (variant & GVARS_VARIANT) {
3235 for (int i=0; i<MAX_GVARS(board, version); i++) {
3236 // on M64 GVARS are common to all flight modes, and there is no name
3237 internalField.Append(new SignedField<16>(modelData.flightModeData[0].gvars[i]));
3241 if ((board != BOARD_STOCK && (board != BOARD_M128 || version < 215)) || (variant & FRSKY_VARIANT)) {
3242 internalField.Append(new FrskyField(modelData.frsky, board, version, variant));
3244 else if ((board == BOARD_STOCK || board == BOARD_M128) && (variant & MAVLINK_VARIANT)) {
3245 internalField.Append(new MavlinkField(modelData.mavlink, board, version));
3248 if (IS_TARANIS(board) && version < 215) {
3249 internalField.Append(new CharField<10>(modelData.bitmap, true, "Model bitmap"));
3252 int modulesCount = 2;
3254 if (IS_STM32(board)) {
3255 modulesCount = 3;
3256 if (version >= 217) {
3257 internalField.Append(new SpareBitsField<3>());
3258 internalField.Append(new UnsignedField<3>(modelData.trainerMode));
3259 internalField.Append(new UnsignedField<2>(modelData.potsWarningMode));
3261 else {
3262 internalField.Append(new ConversionField< SignedField<8> >(modelData.moduleData[1].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
3263 internalField.Append(new UnsignedField<8>(modelData.trainerMode));
3266 else if (IS_ARM(board)) {
3267 if (version >= 217) {
3268 modulesCount = 3;
3269 internalField.Append(new SpareBitsField<6>());
3270 internalField.Append(new UnsignedField<2>(modelData.potsWarningMode));
3272 else if (version >= 216) {
3273 modulesCount = 3;
3274 internalField.Append(new ConversionField< SignedField<8> >(modelData.moduleData[0].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
3278 if (IS_ARM(board) && version >= 215) {
3279 for (int module=0; module<modulesCount; module++) {
3280 if (version >= 217) {
3281 internalField.Append(new ConversionField<SignedField<4> >(modelData.moduleData[module].protocol, &protocolsConversionTable, "Protocol", ::QObject::tr("OpenTX doesn't accept this radio protocol")));
3282 internalField.Append(new SignedField<4>(subprotocols[module]));
3284 else {
3285 internalField.Append(new SignedField<8>(subprotocols[module]));
3287 internalField.Append(new UnsignedField<8>(modelData.moduleData[module].channelsStart));
3288 internalField.Append(new ConversionField<SignedField<8> >(modelData.moduleData[module].channelsCount, -8));
3289 if (version >= 217) {
3290 internalField.Append(new UnsignedField<4>(modelData.moduleData[module].failsafeMode));
3291 internalField.Append(new UnsignedField<3>(modelData.moduleData[module].subType));
3292 internalField.Append(new BoolField<1>(modelData.moduleData[module].invertedSerial));
3294 else {
3295 internalField.Append(new ConversionField<UnsignedField<8> >(modelData.moduleData[module].failsafeMode, -1));
3297 for (int i=0; i<32; i++) {
3298 internalField.Append(new SignedField<16>(modelData.moduleData[module].failsafeChannels[i]));
3300 if (version >= 217) {
3301 internalField.Append(new ConversionField< SignedField<6> >(modelData.moduleData[module].ppm.delay, exportPpmDelay, importPpmDelay));
3302 internalField.Append(new BoolField<1>(modelData.moduleData[module].ppm.pulsePol));
3303 internalField.Append(new BoolField<1>(modelData.moduleData[module].ppm.outputType));
3304 internalField.Append(new SignedField<8>(modelData.moduleData[module].ppm.frameLength));
3306 else {
3307 internalField.Append(new ConversionField< SignedField<8> >(modelData.moduleData[module].ppm.delay, exportPpmDelay, importPpmDelay));
3308 internalField.Append(new SignedField<8>(modelData.moduleData[module].ppm.frameLength));
3309 internalField.Append(new BoolField<8>(modelData.moduleData[module].ppm.pulsePol));
3314 if (IS_TARANIS(board) && version < 218) {
3315 for (int i=0; i<MAX_CURVES(board, version); i++) {
3316 internalField.Append(new ZCharField<6>(modelData.curves[i].name, "Curve name"));
3320 if (IS_STM32(board)) {
3321 if (version >= 218) {
3322 for (int i=0; i<MAX_SCRIPTS(board); i++) {
3323 ScriptData & script = modelData.scriptData[i];
3324 internalField.Append(new CharField<6>(script.filename, true, "Script filename"));
3325 internalField.Append(new ZCharField<6>(script.name, "Script name"));
3326 for (int j=0; j<6; j++) {
3327 internalField.Append(new SignedField<16>(script.inputs[j]));
3331 else if (version >= 217) {
3332 for (int i=0; i<7; i++) {
3333 ScriptData & script = modelData.scriptData[i];
3334 internalField.Append(new CharField<8>(script.filename, true, "Script filename"));
3335 internalField.Append(new ZCharField<8>(script.name, "Script name"));
3336 for (int j=0; j<8; j++) {
3337 internalField.Append(new SignedField<8>(script.inputs[j]));
3341 else if (version >= 216) {
3342 for (int i=0; i<7; i++) {
3343 ScriptData & script = modelData.scriptData[i];
3344 internalField.Append(new CharField<10>(script.filename, true, "Script filename"));
3345 internalField.Append(new ZCharField<10>(script.name, "Script name"));
3346 for (int j=0; j<10; j++) {
3347 internalField.Append(new SignedField<8>(script.inputs[j]));
3353 if (IS_ARM(board) && version >= 216) {
3354 for (int i=0; i<32; i++) {
3355 if (HAS_LARGE_LCD(board))
3356 internalField.Append(new ZCharField<4>(modelData.inputNames[i], "Input name"));
3357 else
3358 internalField.Append(new ZCharField<3>(modelData.inputNames[i], "Input name"));
3362 if (IS_ARM(board) && version >= 217) {
3363 for (int i=0; i<8; i++) {
3364 if (i < MAX_POTS(board, version)+MAX_SLIDERS(board))
3365 internalField.Append(new BoolField<1>(modelData.potsWarningEnabled[i]));
3366 else
3367 internalField.Append(new SpareBitsField<1>());
3370 else if (IS_ARM(board) && version >= 216) {
3371 for (int i=0; i<6; i++) {
3372 if (i < MAX_POTS(board, version)+MAX_SLIDERS(board))
3373 internalField.Append(new BoolField<1>(modelData.potsWarningEnabled[i]));
3374 else
3375 internalField.Append(new SpareBitsField<1>());
3377 internalField.Append(new UnsignedField<2>(modelData.potsWarningMode));
3380 if (IS_ARM(board) && version >= 216) {
3381 for (int i=0; i < MAX_POTS(board, version)+MAX_SLIDERS(board); i++) {
3382 internalField.Append(new SignedField<8>(modelData.potPosition[i]));
3386 if (IS_ARM(board) && version == 216) {
3387 internalField.Append(new SpareBitsField<16>());
3390 if (IS_SKY9X(board) && version >= 217) {
3391 internalField.Append(new SpareBitsField<8>());
3392 internalField.Append(new SpareBitsField<8>());
3395 if (IS_ARM(board) && version >= 217) {
3396 for (int i=0; i<MAX_TELEMETRY_SENSORS(board, version); ++i) {
3397 internalField.Append(new SensorField(modelData.sensorData[i], board, version));
3401 if (IS_TARANIS_X9E(board)) {
3402 internalField.Append(new UnsignedField<8>(modelData.toplcdTimer));
3405 if (IS_HORUS(board)) {
3406 for (int i = 0; i < 5; i++) {
3407 internalField.Append(new CharField<610>(modelData.customScreenData[i], false, "Custom screen blob"));
3409 internalField.Append(new CharField<216>(modelData.topbarData, false, "Top bar blob"));
3410 internalField.Append(new SpareBitsField<8>()); // current view
3414 void OpenTxModelData::beforeExport()
3416 // qDebug() << QString("before export model") << modelData.name;
3418 for (int module=0; module<3; module++) {
3419 if (modelData.moduleData[module].protocol >= PULSES_PXX_XJT_X16 && modelData.moduleData[module].protocol <= PULSES_PXX_XJT_LR12) {
3420 subprotocols[module] = modelData.moduleData[module].protocol - PULSES_PXX_XJT_X16;
3422 else if (modelData.moduleData[module].protocol >= PULSES_LP45 && modelData.moduleData[module].protocol <= PULSES_DSMX) {
3423 subprotocols[module] = modelData.moduleData[module].protocol - PULSES_LP45;
3425 else if (modelData.moduleData[module].protocol == PULSES_MULTIMODULE) {
3426 // copy multi settings to ppm settings to get them written to the eeprom
3427 // (reverse the int => ms logic of the ppm delay) since only ppm is written
3428 subprotocols[module] = modelData.moduleData[module].multi.rfProtocol & (0x1f);
3429 int multiByte = ((modelData.moduleData[module].multi.rfProtocol >> 4) & 0x03) | (modelData.moduleData[module].multi.customProto << 7);
3430 modelData.moduleData[module].ppm.delay = 300 + 50 * multiByte;
3431 modelData.moduleData[module].ppm.frameLength = modelData.moduleData[module].multi.optionValue;
3432 modelData.moduleData[module].ppm.outputType = modelData.moduleData[module].multi.lowPowerMode;
3433 modelData.moduleData[module].ppm.pulsePol = modelData.moduleData[module].multi.autoBindMode;
3435 else {
3436 subprotocols[module] = (module == 0 ? -1 : 0);
3440 if (IS_HORUS(board)) {
3441 uint32_t newSwitchWarningStates = 0;
3442 for (int i = 0; i < MAX_SWITCHES(board, version); i++) {
3443 uint8_t value = (modelData.switchWarningStates >> (2*i)) & 0x03;
3444 if (!(modelData.switchWarningEnable & (1 << i))) {
3445 newSwitchWarningStates |= (value + 1) << (3*i);
3448 modelData.switchWarningStates = newSwitchWarningStates;
3452 void OpenTxModelData::afterImport()
3454 eepromImportDebug() << QString("OpenTxModelData::afterImport()") << modelData.name;
3456 if (IS_TARANIS(board) && version < 216) {
3457 for (unsigned int i=0; i<CPN_MAX_STICKS; i++) {
3458 for (int j=0; j<64; j++) {
3459 ExpoData * expo = &modelData.expoData[j];
3460 if (expo->mode == INPUT_MODE_BOTH && expo->chn == i && expo->flightModes == 0 && expo->swtch.type == SWITCH_TYPE_NONE)
3461 break;
3462 if (expo->mode == 0 || expo->chn > i) {
3463 ExpoData * newExpo = modelData.insertInput(j);
3464 newExpo->mode = INPUT_MODE_BOTH;
3465 newExpo->srcRaw = RawSource(SOURCE_TYPE_STICK, i);
3466 newExpo->chn = i;
3467 newExpo->weight = 100;
3468 break;
3471 strncpy(modelData.inputNames[i], GetCurrentFirmware()->getAnalogInputName(i).toLatin1().constData(), sizeof(modelData.inputNames[i])-1);
3475 for (int module=0; module<3; module++) {
3476 if (modelData.moduleData[module].protocol == PULSES_PXX_XJT_X16 || modelData.moduleData[module].protocol == PULSES_LP45) {
3477 if (subprotocols[module] >= 0)
3478 modelData.moduleData[module].protocol += subprotocols[module];
3479 else
3480 modelData.moduleData[module].protocol = PULSES_OFF;
3482 else if (modelData.moduleData[module].protocol == PULSES_MULTIMODULE) {
3483 // Copy data from ppm struct to multi struct
3484 unsigned int multiByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50);
3485 modelData.moduleData[module].multi.rfProtocol = subprotocols[module] | ((multiByte & 0x3) << 4);
3486 modelData.moduleData[module].multi.customProto = (multiByte & 0x80) == 0x80;
3487 modelData.moduleData[module].multi.optionValue = modelData.moduleData[module].ppm.frameLength;
3488 modelData.moduleData[module].multi.lowPowerMode = modelData.moduleData[module].ppm.outputType;
3489 modelData.moduleData[module].multi.autoBindMode = modelData.moduleData[module].ppm.pulsePol;
3493 if (IS_TARANIS(board) && version < 217 && modelData.moduleData[1].protocol != PULSES_OFF) {
3494 modelData.moduleData[1].modelId = modelData.moduleData[0].modelId;
3497 if (IS_HORUS(board)) {
3498 uint32_t newSwitchWarningStates = 0;
3499 for (int i = 0; i < MAX_SWITCHES(board, version); i++) {
3500 uint8_t value = (modelData.switchWarningStates >> (3*i)) & 0x07;
3501 if (value == 0)
3502 modelData.switchWarningEnable |= (1 << i);
3503 else
3504 newSwitchWarningStates |= ((value & 0x03) - 1) << (2*i);
3506 modelData.switchWarningStates = newSwitchWarningStates;
3510 OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, BoardEnum board, unsigned int version, unsigned int variant):
3511 TransformedField(internalField),
3512 internalField("General Settings"),
3513 generalData(generalData),
3514 board(board),
3515 version(version),
3516 inputsCount(CPN_MAX_STICKS+MAX_POTS(board, version)+MAX_SLIDERS(board)+MAX_MOUSE_ANALOGS(board))
3518 eepromImportDebug() << QString("OpenTxGeneralData::OpenTxGeneralData(board: %1, version:%2, variant:%3)").arg(board).arg(version).arg(variant);
3520 generalData.version = version;
3521 generalData.variant = variant;
3523 internalField.Append(new UnsignedField<8>(generalData.version));
3524 if (version >= 213 || (!IS_ARM(board) && version >= 212))
3525 internalField.Append(new UnsignedField<16>(generalData.variant));
3527 if (version >= 216) {
3528 for (int i=0; i<inputsCount; i++) {
3529 internalField.Append(new SignedField<16>(generalData.calibMid[i]));
3530 internalField.Append(new SignedField<16>(generalData.calibSpanNeg[i]));
3531 internalField.Append(new SignedField<16>(generalData.calibSpanPos[i]));
3534 else {
3535 for (int i=0; i<inputsCount; i++) {
3536 if (!IS_TARANIS(board) || i!=6)
3537 internalField.Append(new SignedField<16>(generalData.calibMid[i]));
3539 for (int i=0; i<inputsCount; i++) {
3540 if (!IS_TARANIS(board) || i!=6)
3541 internalField.Append(new SignedField<16>(generalData.calibSpanNeg[i]));
3543 for (int i=0; i<inputsCount; i++) {
3544 if (!IS_TARANIS(board) || i!=6)
3545 internalField.Append(new SignedField<16>(generalData.calibSpanPos[i]));
3549 internalField.Append(new UnsignedField<16>(chkSum));
3550 if (!IS_HORUS(board)) {
3551 internalField.Append(new UnsignedField<8>(generalData.currModelIndex));
3552 internalField.Append(new UnsignedField<8>(generalData.contrast));
3554 internalField.Append(new UnsignedField<8>(generalData.vBatWarn));
3555 internalField.Append(new SignedField<8>(generalData.txVoltageCalibration));
3556 internalField.Append(new SignedField<8>(generalData.backlightMode));
3558 for (int i=0; i<CPN_MAX_STICKS; i++) {
3559 internalField.Append(new SignedField<16>(generalData.trainer.calib[i]));
3561 for (int i=0; i<CPN_MAX_STICKS; i++) {
3562 internalField.Append(new UnsignedField<6>(generalData.trainer.mix[i].src));
3563 internalField.Append(new UnsignedField<2>(generalData.trainer.mix[i].mode));
3564 internalField.Append(new SignedField<8>(generalData.trainer.mix[i].weight));
3567 internalField.Append(new UnsignedField<8>(generalData.view, 0, MAX_VIEWS(board)-1));
3569 internalField.Append(new SpareBitsField<2>()); // TODO buzzerMode?
3570 internalField.Append(new BoolField<1>(generalData.fai));
3571 internalField.Append(new SignedField<2>((int &)generalData.beeperMode));
3572 internalField.Append(new BoolField<1>(generalData.flashBeep));
3573 internalField.Append(new BoolField<1>(generalData.disableMemoryWarning));
3574 internalField.Append(new BoolField<1>(generalData.disableAlarmWarning));
3576 internalField.Append(new UnsignedField<2>(generalData.stickMode));
3577 internalField.Append(new SignedField<5>(generalData.timezone));
3578 if (version >= 217 && IS_TARANIS(board)) {
3579 internalField.Append(new BoolField<1>(generalData.adjustRTC));
3581 else {
3582 internalField.Append(new SpareBitsField<1>());
3585 internalField.Append(new UnsignedField<8>(generalData.inactivityTimer));
3586 if (IS_9X(board)) {
3587 if (version >= 215) {
3588 internalField.Append(new UnsignedField<3>(generalData.mavbaud));
3590 else {
3591 internalField.Append(new SpareBitsField<1>());
3592 internalField.Append(new BoolField<1>(generalData.minuteBeep));
3593 internalField.Append(new BoolField<1>(generalData.preBeep));
3596 else {
3597 internalField.Append(new SpareBitsField<3>());
3599 if (version >= 216 && IS_TARANIS(board))
3600 internalField.Append(new SignedField<3>(generalData.splashDuration));
3601 else if (version >= 213 || (!IS_ARM(board) && version >= 212))
3602 internalField.Append(new UnsignedField<3>(generalData.splashMode)); // TODO
3603 else
3604 internalField.Append(new SpareBitsField<3>());
3605 internalField.Append(new SignedField<2>((int &)generalData.hapticMode));
3607 if (IS_ARM(board))
3608 internalField.Append(new SignedField<8>(generalData.switchesDelay));
3609 else
3610 internalField.Append(new SpareBitsField<8>()); // TODO blOffBright + blOnBright
3612 internalField.Append(new UnsignedField<8>(generalData.backlightDelay));
3613 internalField.Append(new UnsignedField<8>(generalData.templateSetup));
3614 internalField.Append(new SignedField<8>(generalData.PPM_Multiplier));
3615 internalField.Append(new SignedField<8>(generalData.hapticLength));
3617 if (version < 216 || (version < 218 && !IS_9X(board)) || (!IS_9X(board) && !IS_TARANIS(board) && !IS_HORUS(board))) {
3618 internalField.Append(new UnsignedField<8>(generalData.reNavigation));
3621 if (version >= 216 && !IS_TARANIS(board) && !IS_HORUS(board)) {
3622 internalField.Append(new UnsignedField<8>(generalData.stickReverse));
3625 internalField.Append(new SignedField<3>(generalData.beeperLength));
3626 internalField.Append(new SignedField<3>(generalData.hapticStrength));
3627 internalField.Append(new UnsignedField<1>(generalData.gpsFormat));
3628 internalField.Append(new SpareBitsField<1>()); // unexpectedShutdown
3630 internalField.Append(new UnsignedField<8>(generalData.speakerPitch));
3632 if (IS_ARM(board))
3633 internalField.Append(new ConversionField< SignedField<8> >(generalData.speakerVolume, -12, 0, 0, 23, "Volume"));
3634 else
3635 internalField.Append(new ConversionField< SignedField<8> >(generalData.speakerVolume, -7, 0, 0, 7, "Volume"));
3637 if (version >= 214 || (!IS_ARM(board) && version >= 213)) {
3638 internalField.Append(new SignedField<8>(generalData.vBatMin));
3639 internalField.Append(new SignedField<8>(generalData.vBatMax));
3642 if (IS_ARM(board)) {
3643 internalField.Append(new UnsignedField<8>(generalData.backlightBright));
3644 if (version < 218) internalField.Append(new SignedField<8>(generalData.txCurrentCalibration));
3645 if (version >= 213) {
3646 if (version < 218) internalField.Append(new SignedField<8>(generalData.temperatureWarn)); // TODO
3647 if (version < 218) internalField.Append(new UnsignedField<8>(generalData.mAhWarn));
3648 if (version < 218) internalField.Append(new UnsignedField<16>(generalData.mAhUsed));
3649 internalField.Append(new UnsignedField<32>(generalData.globalTimer));
3650 if (version < 218) internalField.Append(new SignedField<8>(generalData.temperatureCalib)); // TODO
3651 internalField.Append(new UnsignedField<8>(generalData.btBaudrate)); // TODO
3652 if (version < 218) internalField.Append(new BoolField<8>(generalData.optrexDisplay)); //TODO
3653 if (version < 218) internalField.Append(new UnsignedField<8>(generalData.sticksGain)); // TODO
3655 if (version >= 214) {
3656 if (version < 218) internalField.Append(new UnsignedField<8>(generalData.rotarySteps)); // TODO
3657 internalField.Append(new UnsignedField<8>(generalData.countryCode));
3658 internalField.Append(new UnsignedField<1>(generalData.imperial));
3659 if (version >= 218) {
3660 internalField.Append(new BoolField<1>(generalData.jitterFilter));
3661 internalField.Append(new SpareBitsField<6>());
3663 else {
3664 internalField.Append(new SpareBitsField<7>());
3667 if (version >= 215) {
3668 internalField.Append(new CharField<2>(generalData.ttsLanguage, true, "TTS language"));
3669 if (version >= 218) {
3670 internalField.Append(new SignedField<4>(generalData.beepVolume));
3671 internalField.Append(new SignedField<4>(generalData.wavVolume));
3672 internalField.Append(new SignedField<4>(generalData.varioVolume));
3673 internalField.Append(new SignedField<4>(generalData.backgroundVolume));
3675 else {
3676 internalField.Append(new SignedField<8>(generalData.beepVolume));
3677 internalField.Append(new SignedField<8>(generalData.wavVolume));
3678 internalField.Append(new SignedField<8>(generalData.varioVolume));
3680 if (version >= 216) {
3681 internalField.Append(new SignedField<8>(generalData.varioPitch));
3682 internalField.Append(new SignedField<8>(generalData.varioRange));
3683 internalField.Append(new SignedField<8>(generalData.varioRepeat));
3685 if (version < 218) internalField.Append(new SignedField<8>(generalData.backgroundVolume));
3687 if (version >= 218) {
3688 for (int i=0; i<MAX_CUSTOM_FUNCTIONS(board, version); i++) {
3689 internalField.Append(new ArmCustomFunctionField(generalData.customFn[i], board, version, variant));
3693 if (IS_STM32(board) && version >= 216) {
3694 if (version >= 218) {
3695 internalField.Append(new UnsignedField<4>(generalData.hw_uartMode));
3696 for (uint8_t i=0; i<4; i++) {
3697 internalField.Append(new UnsignedField<1>(generalData.sliderConfig[i]));
3700 else if (version >= 217) {
3701 internalField.Append(new UnsignedField<6>(generalData.hw_uartMode));
3702 if (IS_TARANIS_X9E(board)) {
3703 internalField.Append(new UnsignedField<1>(generalData.sliderConfig[2]));
3704 internalField.Append(new UnsignedField<1>(generalData.sliderConfig[3]));
3706 else {
3707 internalField.Append(new SpareBitsField<2>());
3710 else {
3711 internalField.Append(new UnsignedField<8>(generalData.hw_uartMode));
3713 if (IS_HORUS(board)) {
3714 for (int i=0; i<16; i++) {
3715 if (i < MAX_SWITCHES(board, version))
3716 internalField.Append(new UnsignedField<2>(generalData.switchConfig[i]));
3717 else
3718 internalField.Append(new SpareBitsField<2>());
3721 for (int i=0; i<4; i++) {
3722 if (i < MAX_POTS(board, version))
3723 internalField.Append(new UnsignedField<2>(generalData.potConfig[i]));
3724 else
3725 internalField.Append(new SpareBitsField<2>());
3727 if (!IS_HORUS(board))
3728 internalField.Append(new UnsignedField<8>(generalData.backlightColor));
3731 if (IS_TARANIS_X9E(board))
3732 internalField.Append(new SpareBitsField<64>()); // switchUnlockStates
3733 else if (IS_TARANIS(board))
3734 internalField.Append(new SpareBitsField<16>()); // switchUnlockStates
3736 if (version == 217) {
3737 for (int i=0; i<MAX_CUSTOM_FUNCTIONS(board, version); i++) {
3738 internalField.Append(new ArmCustomFunctionField(generalData.customFn[i], board, version, variant));
3742 if (IS_HORUS(board)) {
3743 for (int i=0; i<MAX_SWITCHES(board, version); ++i) {
3744 internalField.Append(new ZCharField<3>(generalData.switchName[i], "Switch name"));
3746 for (int i=0; i<CPN_MAX_STICKS; ++i) {
3747 internalField.Append(new ZCharField<3>(generalData.stickName[i], "Stick name"));
3749 for (int i=0; i<MAX_POTS(board, version); ++i) {
3750 internalField.Append(new ZCharField<3>(generalData.potName[i], "Pot name"));
3752 for (int i=0; i<MAX_SLIDERS(board); ++i) {
3753 internalField.Append(new ZCharField<3>(generalData.sliderName[i], "Slider name"));
3755 internalField.Append(new CharField<17>(generalData.currModelFilename, true, "Current model filename"));
3757 else if (IS_TARANIS(board) && version >= 217) {
3758 for (int i=0; i<MAX_SWITCHES(board, version); i++) {
3759 internalField.Append(new UnsignedField<2>(generalData.switchConfig[i]));
3761 if (IS_TARANIS_X9E(board)) {
3762 internalField.Append(new SpareBitsField<64-2*18>());
3764 for (int i=0; i<MAX_SWITCHES(board, version); ++i) {
3765 internalField.Append(new ZCharField<3>(generalData.switchName[i], "Switch name"));
3767 for (int i=0; i<CPN_MAX_STICKS; ++i) {
3768 internalField.Append(new ZCharField<3>(generalData.stickName[i], "Stick name"));
3770 for (int i=0; i<MAX_POTS(board, version); ++i) {
3771 internalField.Append(new ZCharField<3>(generalData.potName[i], "Pot name"));
3773 for (int i=0; i<MAX_SLIDERS(board); ++i) {
3774 internalField.Append(new ZCharField<3>(generalData.sliderName[i], "Slider name"));
3778 if (IS_HORUS(board)) {
3779 internalField.Append(new BoolField<1>(generalData.bluetoothEnable));
3780 internalField.Append(new UnsignedField<7>(generalData.backlightOffBright));
3781 internalField.Append(new ZCharField<10>(generalData.bluetoothName, "Bluetooth name"));
3783 else if (IS_TARANIS_X9E(board) && version >= 217) {
3784 internalField.Append(new BoolField<8>(generalData.bluetoothEnable));
3785 internalField.Append(new ZCharField<10>(generalData.bluetoothName, "Bluetooth name"));
3788 if (IS_HORUS(board)) {
3789 internalField.Append(new CharField<8>(generalData.themeName, true, "Theme name"));
3790 for (int i=0; i<5; i++) {
3791 internalField.Append(new CharField<8>((char *)generalData.themeOptionValue[i], true, "Theme blob"));
3797 void OpenTxGeneralData::beforeExport()
3799 uint16_t sum = 0;
3800 if (version >= 216) {
3801 int count = 0;
3802 for (int i=0; i<inputsCount; i++) {
3803 sum += generalData.calibMid[i];
3804 if (++count == 12) break;
3805 sum += generalData.calibSpanNeg[i];
3806 if (++count == 12) break;
3807 sum += generalData.calibSpanPos[i];
3808 if (++count == 12) break;
3811 else {
3812 for (int i=0; i<inputsCount; i++)
3813 sum += generalData.calibMid[i];
3814 for (int i=0; i<5; i++)
3815 sum += generalData.calibSpanNeg[i];
3817 chkSum = sum;
3820 void OpenTxGeneralData::afterImport()
3822 if (IS_TARANIS(board) && version < 217) {
3823 generalData.potConfig[0] = GeneralSettings::POT_WITH_DETENT;
3824 generalData.potConfig[1] = GeneralSettings::POT_WITH_DETENT;