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 "eeprominterface.h"
22 #include "firmwares/er9x/er9xinterface.h"
23 #include "firmwares/ersky9x/ersky9xinterface.h"
24 #include "firmwares/opentx/opentxinterface.h"
25 #include "firmwares/opentx/opentxeeprom.h"
28 #include "wizarddata.h"
29 #include "firmwareinterface.h"
31 #include "multiprotocols.h"
39 const uint8_t chout_ar
[] = { // First number is 0..23 -> template setup, Second is relevant channel out
40 1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
41 2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1,
42 3,1,2,4 , 3,1,4,2 , 3,2,1,4 , 3,2,4,1 , 3,4,1,2 , 3,4,2,1,
43 4,1,2,3 , 4,1,3,2 , 4,2,1,3 , 4,2,3,1 , 4,3,1,2 , 4,3,2,1
46 static const char specialCharsTab
[] = "_-.,";
48 void setEEPROMString(char *dst
, const char *src
, int size
)
50 memcpy(dst
, src
, size
);
51 for (int i
=size
-1; i
>=0; i
--) {
59 void getEEPROMString(char *dst
, const char *src
, int size
)
61 memcpy(dst
, src
, size
);
63 for (int i
=size
-1; i
>=0; i
--) {
71 int8_t char2idx(char c
)
74 if (c
>='A' && c
<='Z') return 1+c
-'A';
75 if (c
>='a' && c
<='z') return -1-c
+'a';
76 if (c
>='0' && c
<='9') return 27+c
-'0';
77 for (int8_t i
=0;;i
++) {
78 char cc
= specialCharsTab
[i
];
80 if (cc
==c
) return 37+i
;
85 char idx2char(int8_t idx
)
87 if (idx
== 0) return ' ';
89 if (idx
> -27) return 'a' - idx
- 1;
92 if (idx
< 27) return 'A' + idx
- 1;
93 if (idx
< 37) return '0' + idx
- 27;
94 if (idx
<= ZCHAR_MAX
) return specialCharsTab
[idx
-37];
98 void setEEPROMZString(char *dst
, const char *src
, int size
)
100 for (int i
=size
-1; i
>=0; i
--)
101 dst
[i
] = char2idx(src
[i
]);
104 void getEEPROMZString(char *dst
, const char *src
, int size
)
106 for (int i
=size
-1; i
>=0; i
--)
107 dst
[i
] = idx2char(src
[i
]);
109 for (int i
=size
-1; i
>=0; i
--) {
117 QString
getElementName(const QString
& prefix
, unsigned int index
, const char * name
= NULL
, bool padding
= false)
119 QString result
= prefix
;
121 result
+= QString("%1").arg(index
, 2, 10, QChar('0'));
123 result
+= QString("%1").arg(index
);
125 QString trimmed
= QString(name
).trimmed();
126 if (trimmed
.length() > 0) {
127 result
+= ":" + QString(name
).trimmed();
134 float ValToTim(int value
)
136 return ((value
< -109 ? 129+value
: (value
< 7 ? (113+value
)*5 : (53+value
)*10))/10.0);
139 int TimToVal(float value
)
143 temp
=136+round((value
-60));
146 temp
=20+round((value
-2.0)*2.0);
149 temp
=round(value
*10.0);
154 void SensorData::updateUnit()
156 if (type
== TELEM_TYPE_CALCULATED
) {
157 if (formula
== TELEM_FORMULA_CONSUMPTION
)
162 QString
SensorData::unitString() const
166 return QObject::tr("V");
168 return QObject::tr("A");
170 return QObject::tr("mA");
172 return QObject::tr("kts");
173 case UNIT_METERS_PER_SECOND
:
174 return QObject::tr("m/s");
176 return QObject::tr("km/h");
178 return QObject::tr("mph");
180 return QObject::tr("m");
182 return QObject::tr("f");
184 return QObject::trUtf8("°C");
185 case UNIT_FAHRENHEIT
:
186 return QObject::trUtf8("°F");
188 return QObject::tr("%");
190 return QObject::tr("mAh");
192 return QObject::tr("W");
193 case UNIT_MILLIWATTS
:
194 return QObject::tr("mW");
196 return QObject::tr("dB");
198 return QObject::tr("rpms");
200 return QObject::tr("g");
202 return QObject::trUtf8("°");
204 return QObject::trUtf8("Rad");
206 return QObject::tr("hours");
208 return QObject::tr("minutes");
210 return QObject::tr("seconds");
212 return QObject::tr("V");
218 bool RawSource::isTimeBased() const
220 if (IS_ARM(getCurrentBoard()))
221 return (type
== SOURCE_TYPE_SPECIAL
&& index
> 0);
223 return (type
==SOURCE_TYPE_TELEMETRY
&& (index
==TELEMETRY_SOURCE_TX_TIME
|| index
==TELEMETRY_SOURCE_TIMER1
|| index
==TELEMETRY_SOURCE_TIMER2
|| index
==TELEMETRY_SOURCE_TIMER3
));
226 float RawSourceRange::getValue(int value
)
228 if (IS_ARM(getCurrentBoard()))
229 return float(value
) * step
;
231 return min
+ float(value
) * step
;
234 RawSourceRange
RawSource::getRange(const ModelData
* model
, const GeneralSettings
& settings
, unsigned int flags
) const
236 RawSourceRange result
;
238 Firmware
* firmware
= Firmware::getCurrentVariant();
239 int board
= firmware
->getBoard();
240 bool singleprec
= (flags
& RANGE_SINGLE_PRECISION
);
242 if (!singleprec
&& !IS_ARM(board
)) {
247 case SOURCE_TYPE_TELEMETRY
:
249 div_t qr
= div(index
, 3);
250 const SensorData
& sensor
= model
->sensorData
[qr
.quot
];
251 if (sensor
.prec
== 2)
253 else if (sensor
.prec
== 1)
257 result
.min
= -30000 * result
.step
;
258 result
.max
= +30000 * result
.step
;
259 result
.decimals
= sensor
.prec
;
260 result
.unit
= sensor
.unitString();
264 result
.offset
= -DBL_MAX
;
268 case TELEMETRY_SOURCE_TX_BATT
:
272 result
.unit
= QObject::tr("V");
274 case TELEMETRY_SOURCE_TX_TIME
:
276 result
.max
= 24*60 - 1;
278 case TELEMETRY_SOURCE_TIMER1
:
279 case TELEMETRY_SOURCE_TIMER2
:
280 case TELEMETRY_SOURCE_TIMER3
:
281 result
.step
= singleprec
? 5 : 1;
282 result
.max
= singleprec
? 255*5 : 60*60;
283 result
.unit
= QObject::tr("s");
285 case TELEMETRY_SOURCE_RSSI_TX
:
286 case TELEMETRY_SOURCE_RSSI_RX
:
288 if (singleprec
) result
.offset
= 128;
290 case TELEMETRY_SOURCE_A1_MIN
:
291 case TELEMETRY_SOURCE_A2_MIN
:
292 case TELEMETRY_SOURCE_A3_MIN
:
293 case TELEMETRY_SOURCE_A4_MIN
:
294 if (model
) result
= model
->frsky
.channels
[index
-TELEMETRY_SOURCE_A1_MIN
].getRange();
296 case TELEMETRY_SOURCE_A1
:
297 case TELEMETRY_SOURCE_A2
:
298 case TELEMETRY_SOURCE_A3
:
299 case TELEMETRY_SOURCE_A4
:
300 if (model
) result
= model
->frsky
.channels
[index
-TELEMETRY_SOURCE_A1
].getRange();
302 case TELEMETRY_SOURCE_ALT
:
303 case TELEMETRY_SOURCE_ALT_MIN
:
304 case TELEMETRY_SOURCE_ALT_MAX
:
305 case TELEMETRY_SOURCE_GPS_ALT
:
306 result
.step
= singleprec
? 8 : 1;
308 result
.max
= singleprec
? 1540 : 3000;
309 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
310 result
.step
= (result
.step
* 105) / 32;
311 result
.min
= (result
.min
* 105) / 32;
312 result
.max
= (result
.max
* 105) / 32;
313 result
.unit
= QObject::tr("ft");
316 result
.unit
= QObject::tr("m");
319 case TELEMETRY_SOURCE_T1
:
320 case TELEMETRY_SOURCE_T1_MAX
:
321 case TELEMETRY_SOURCE_T2
:
322 case TELEMETRY_SOURCE_T2_MAX
:
325 result
.unit
= QObject::trUtf8("°C");
327 case TELEMETRY_SOURCE_HDG
:
328 result
.step
= singleprec
? 2 : 1;
330 if (singleprec
) result
.offset
= 256;
331 result
.unit
= QObject::trUtf8("°");
333 case TELEMETRY_SOURCE_RPM
:
334 case TELEMETRY_SOURCE_RPM_MAX
:
335 result
.step
= singleprec
? 50 : 1;
336 result
.max
= singleprec
? 12750 : 30000;
338 case TELEMETRY_SOURCE_FUEL
:
340 result
.unit
= QObject::tr("%");
342 case TELEMETRY_SOURCE_ASPEED
:
343 case TELEMETRY_SOURCE_ASPEED_MAX
:
345 result
.step
= singleprec
? 2.0 : 0.1;
346 result
.max
= singleprec
? (2*255) : 2000;
347 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
348 result
.step
*= 1.150779;
349 result
.max
*= 1.150779;
350 result
.unit
= QObject::tr("mph");
353 result
.step
*= 1.852;
355 result
.unit
= QObject::tr("km/h");
358 case TELEMETRY_SOURCE_SPEED
:
359 case TELEMETRY_SOURCE_SPEED_MAX
:
360 result
.step
= singleprec
? 2 : 1;
361 result
.max
= singleprec
? (2*255) : 2000;
362 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
363 result
.step
*= 1.150779;
364 result
.max
*= 1.150779;
365 result
.unit
= QObject::tr("mph");
368 result
.step
*= 1.852;
370 result
.unit
= QObject::tr("km/h");
373 case TELEMETRY_SOURCE_VERTICAL_SPEED
:
375 result
.min
= singleprec
? -12.5 : -300.0;
376 result
.max
= singleprec
? 13.0 : 300.0;
378 result
.unit
= QObject::tr("m/s");
380 case TELEMETRY_SOURCE_DTE
:
383 case TELEMETRY_SOURCE_DIST
:
384 case TELEMETRY_SOURCE_DIST_MAX
:
385 result
.step
= singleprec
? 8 : 1;
386 result
.max
= singleprec
? 2040 : 10000;
387 result
.unit
= QObject::tr("m");
389 case TELEMETRY_SOURCE_CELL
:
390 case TELEMETRY_SOURCE_CELL_MIN
:
391 result
.step
= singleprec
? 0.02 : 0.01;
394 result
.unit
= QObject::tr("V");
396 case TELEMETRY_SOURCE_CELLS_SUM
:
397 case TELEMETRY_SOURCE_CELLS_MIN
:
398 case TELEMETRY_SOURCE_VFAS
:
399 case TELEMETRY_SOURCE_VFAS_MIN
:
401 result
.max
= singleprec
? 25.5 : 100.0;
403 result
.unit
= QObject::tr("V");
405 case TELEMETRY_SOURCE_CURRENT
:
406 case TELEMETRY_SOURCE_CURRENT_MAX
:
407 result
.step
= singleprec
? 0.5 : 0.1;
408 result
.max
= singleprec
? 127.5 : 200.0;
410 result
.unit
= QObject::tr("A");
412 case TELEMETRY_SOURCE_CONSUMPTION
:
413 result
.step
= singleprec
? 100 : 1;
414 result
.max
= singleprec
? 25500 : 30000;
415 result
.unit
= QObject::tr("mAh");
417 case TELEMETRY_SOURCE_POWER
:
418 case TELEMETRY_SOURCE_POWER_MAX
:
419 result
.step
= singleprec
? 5 : 1;
420 result
.max
= singleprec
? 1275 : 2000;
421 result
.unit
= QObject::tr("W");
423 case TELEMETRY_SOURCE_ACCX
:
424 case TELEMETRY_SOURCE_ACCY
:
425 case TELEMETRY_SOURCE_ACCZ
:
428 result
.max
= singleprec
? 2.55 : 10.00;
429 result
.min
= singleprec
? 0 : -10.00;
430 result
.unit
= QObject::tr("g");
437 if (singleprec
&& result
.offset
==-DBL_MAX
) {
438 result
.offset
= result
.max
- (127*result
.step
);
441 if (flags
& (RANGE_DELTA_FUNCTION
|RANGE_DELTA_ABS_FUNCTION
)) {
444 result
.min
= result
.step
* -127;
445 result
.max
= result
.step
* 127;
448 result
.min
= -result
.max
;
454 case SOURCE_TYPE_GVAR
:
456 result
.min
= -result
.max
;
459 case SOURCE_TYPE_SPECIAL
:
460 if (index
== 0) { //Batt
464 result
.unit
= QObject::tr("V");
466 else if (index
== 1) { //Time
468 result
.max
= 24*60 - 1;
469 result
.unit
= QObject::tr("h:m");
471 else { // Timers 1 - 3
472 result
.step
= singleprec
? 5 : 1;
473 result
.max
= singleprec
? 255*5 : 60*60;
474 result
.unit
= singleprec
? QObject::tr("m:s") : QObject::tr("h:m:s");
480 result
.max
= model
->getChannelsMax(true);
481 result
.min
= -result
.max
;
486 if (flags
& RANGE_DELTA_ABS_FUNCTION
) {
493 QString
RawSource::toString(const ModelData
* model
, const GeneralSettings
* const generalSettings
) const
495 static const QString trims
[] = {
496 QObject::tr("TrmR"), QObject::tr("TrmE"), QObject::tr("TrmT"), QObject::tr("TrmA"), QObject::tr("Trm5"), QObject::tr("Trm6")
499 static const QString special
[] = {
500 QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
503 static const QString telemetry
[] = {
504 QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
505 QObject::tr("SWR"), QObject::tr("RSSI Tx"), QObject::tr("RSSI Rx"),
506 QObject::tr("A1"), QObject::tr("A2"), QObject::tr("A3"), QObject::tr("A4"),
507 QObject::tr("Alt"), QObject::tr("Rpm"), QObject::tr("Fuel"), QObject::tr("T1"), QObject::tr("T2"),
508 QObject::tr("Speed"), QObject::tr("Dist"), QObject::tr("GPS Alt"),
509 QObject::tr("Cell"), QObject::tr("Cells"), QObject::tr("Vfas"), QObject::tr("Curr"), QObject::tr("Cnsp"), QObject::tr("Powr"),
510 QObject::tr("AccX"), QObject::tr("AccY"), QObject::tr("AccZ"),
511 QObject::tr("Hdg "), QObject::tr("VSpd"), QObject::tr("AirSpeed"), QObject::tr("dTE"),
512 QObject::tr("A1-"), QObject::tr("A2-"), QObject::tr("A3-"), QObject::tr("A4-"),
513 QObject::tr("Alt-"), QObject::tr("Alt+"), QObject::tr("Rpm+"), QObject::tr("T1+"), QObject::tr("T2+"), QObject::tr("Speed+"), QObject::tr("Dist+"), QObject::tr("AirSpeed+"),
514 QObject::tr("Cell-"), QObject::tr("Cells-"), QObject::tr("Vfas-"), QObject::tr("Curr+"), QObject::tr("Powr+"),
515 QObject::tr("ACC"), QObject::tr("GPS Time"),
518 static const QString rotary
[] = { QObject::tr("REa"), QObject::tr("REb") };
521 return QObject::tr("----");
527 case SOURCE_TYPE_VIRTUAL_INPUT
:
529 const char * name
= NULL
;
531 name
= model
->inputNames
[index
];
532 return getElementName(QCoreApplication::translate("Input", "I"), index
+ 1, name
);
535 case SOURCE_TYPE_LUA_OUTPUT
:
536 return QObject::tr("LUA%1%2").arg(index
/16+1).arg(QChar('a'+index
%16));
538 case SOURCE_TYPE_STICK
:
539 if (generalSettings
) {
540 if (isPot(&genAryIdx
))
541 result
= QString(generalSettings
->potName
[genAryIdx
]);
542 else if (isSlider(&genAryIdx
))
543 result
= QString(generalSettings
->sliderName
[genAryIdx
]);
544 else if (isStick(&genAryIdx
))
545 result
= QString(generalSettings
->stickName
[genAryIdx
]);
547 if (result
.isEmpty())
548 result
= getCurrentFirmware()->getAnalogInputName(index
);;
551 case SOURCE_TYPE_TRIM
:
552 return CHECK_IN_ARRAY(trims
, index
);
553 case SOURCE_TYPE_ROTARY_ENCODER
:
554 return CHECK_IN_ARRAY(rotary
, index
);
555 case SOURCE_TYPE_MAX
:
556 return QObject::tr("MAX");
558 case SOURCE_TYPE_SWITCH
:
560 result
= QString(generalSettings
->switchName
[index
]);
561 if (result
.isEmpty())
562 result
= getSwitchInfo(getCurrentBoard(), index
).name
;
565 case SOURCE_TYPE_CUSTOM_SWITCH
:
566 return RawSwitch(SWITCH_TYPE_VIRTUAL
, index
+1).toString();
568 case SOURCE_TYPE_CYC
:
569 return QObject::tr("CYC%1").arg(index
+1);
571 case SOURCE_TYPE_PPM
:
572 return getElementName(QCoreApplication::translate("Trainer", "TR"), index
+ 1);
576 const char * name
= NULL
;
577 if (getCurrentFirmware()->getCapability(ChannelsName
) && model
)
578 name
= model
->limitData
[index
].name
;
579 return getElementName(QCoreApplication::translate("Channel", "CH"), index
+ 1, name
);
582 case SOURCE_TYPE_SPECIAL
:
583 return CHECK_IN_ARRAY(special
, index
);
585 case SOURCE_TYPE_TELEMETRY
:
586 if (IS_ARM(getCurrentBoard())) {
587 div_t qr
= div(index
, 3);
588 result
= getElementName(QCoreApplication::translate("Telemetry", "TELE"), qr
.quot
+1, model
? model
->sensorData
[qr
.quot
].label
: NULL
);
590 result
+= (qr
.rem
== 1 ? "-" : "+");
594 return CHECK_IN_ARRAY(telemetry
, index
);
597 case SOURCE_TYPE_GVAR
:
599 const char * name
= NULL
;
600 if (getCurrentFirmware()->getCapability(GvarsName
) && model
)
601 name
= model
->gvars_names
[index
];
602 return getElementName(QCoreApplication::translate("Global Variable", "GV"), index
+ 1, name
);
606 return QObject::tr("----");
610 bool RawSource::isStick(int * stickIndex
) const
612 if (type
== SOURCE_TYPE_STICK
&& index
< getBoardCapability(getCurrentBoard(), Board::Sticks
)) {
620 bool RawSource::isPot(int * potsIndex
) const
622 if (type
== SOURCE_TYPE_STICK
&&
623 index
>= getBoardCapability(getCurrentBoard(), Board::Sticks
) &&
624 index
< getBoardCapability(getCurrentBoard(), Board::Sticks
) + getBoardCapability(getCurrentBoard(), Board::Pots
)) {
626 *potsIndex
= index
- getBoardCapability(getCurrentBoard(), Board::Sticks
);
632 bool RawSource::isSlider(int * sliderIndex
) const
634 if (type
== SOURCE_TYPE_STICK
&&
635 index
>= getBoardCapability(getCurrentBoard(), Board::Sticks
) + getBoardCapability(getCurrentBoard(), Board::Pots
) &&
636 index
< getBoardCapability(getCurrentBoard(), Board::Sticks
) + getBoardCapability(getCurrentBoard(), Board::Pots
) + getBoardCapability(getCurrentBoard(), Board::Sliders
)) {
638 *sliderIndex
= index
- getBoardCapability(getCurrentBoard(), Board::Sticks
) - getBoardCapability(getCurrentBoard(), Board::Pots
);
648 QString
RawSwitch::toString(Board::Type board
, const GeneralSettings
* const generalSettings
, const ModelData
* const modelData
) const
650 if (board
== Board::BOARD_UNKNOWN
) {
651 board
= getCurrentBoard();
654 static const QString switches9X
[] = {
655 QString("THR"), QString("RUD"), QString("ELE"),
656 QString("ID0"), QString("ID1"), QString("ID2"),
657 QString("AIL"), QString("GEA"), QString("TRN")
660 static const QString trimsSwitches
[] = {
661 QObject::tr("RudTrim Left"), QObject::tr("RudTrim Right"),
662 QObject::tr("EleTrim Down"), QObject::tr("EleTrim Up"),
663 QObject::tr("ThrTrim Down"), QObject::tr("ThrTrim Up"),
664 QObject::tr("AilTrim Left"), QObject::tr("AilTrim Right"),
665 QObject::tr("Trim 5 Down"), QObject::tr("Trim 5 Up"),
666 QObject::tr("Trim 6 Down"), QObject::tr("Trim 6 Up")
669 static const QString rotaryEncoders
[] = {
670 QObject::tr("REa"), QObject::tr("REb")
673 static const QString timerModes
[] = {
674 QObject::tr("OFF"), QObject::tr("ON"),
675 QObject::tr("THs"), QObject::tr("TH%"), QObject::tr("THt")
678 const QStringList directionIndicators
= QStringList()
679 << CPN_STR_SW_INDICATOR_UP
680 << CPN_STR_SW_INDICATOR_NEUT
681 << CPN_STR_SW_INDICATOR_DN
;
684 return CPN_STR_SW_INDICATOR_REV
% RawSwitch(type
, -index
).toString(board
, generalSettings
, modelData
);
690 case SWITCH_TYPE_SWITCH
:
691 if (IS_HORUS_OR_TARANIS(board
)) {
692 qr
= div(index
-1, 3);
694 swName
= QString(generalSettings
->switchName
[qr
.quot
]);
695 if (swName
.isEmpty())
696 swName
= getSwitchInfo(board
, qr
.quot
).name
;
697 return swName
+ directionIndicators
.at(qr
.rem
> -1 && qr
.rem
< directionIndicators
.size() ? qr
.rem
: 1);
700 return CHECK_IN_ARRAY(switches9X
, index
- 1);
703 case SWITCH_TYPE_VIRTUAL
:
704 return getElementName(QCoreApplication::translate("Logic Switch", "L"), index
, NULL
, true);
706 case SWITCH_TYPE_MULTIPOS_POT
:
707 if (!getCurrentFirmware()->getCapability(MultiposPotsPositions
))
708 return QObject::tr("???");
709 qr
= div(index
- 1, getCurrentFirmware()->getCapability(MultiposPotsPositions
));
710 if (generalSettings
&& qr
.quot
< (int)DIM(generalSettings
->potConfig
))
711 swName
= QString(generalSettings
->potName
[qr
.quot
]);
712 if (swName
.isEmpty())
713 swName
= getCurrentFirmware()->getAnalogInputName(qr
.quot
+ getBoardCapability(board
, Board::Sticks
));;
714 return swName
+ "_" + QString::number(qr
.rem
+ 1);
716 case SWITCH_TYPE_TRIM
:
717 return CHECK_IN_ARRAY(trimsSwitches
, index
-1);
719 case SWITCH_TYPE_ROTARY_ENCODER
:
720 return CHECK_IN_ARRAY(rotaryEncoders
, index
-1);
723 return QObject::tr("ON");
725 case SWITCH_TYPE_OFF
:
726 return QObject::tr("OFF");
728 case SWITCH_TYPE_ONE
:
729 return QObject::tr("One");
731 case SWITCH_TYPE_FLIGHT_MODE
:
732 return getElementName(QCoreApplication::translate("Flight mode", "FM"), index
- 1, modelData
? modelData
->flightModeData
[index
-1].name
: NULL
);
734 case SWITCH_TYPE_NONE
:
735 return QObject::tr("----");
737 case SWITCH_TYPE_TIMER_MODE
:
738 return CHECK_IN_ARRAY(timerModes
, index
);
740 case SWITCH_TYPE_SENSOR
:
741 return getElementName(QCoreApplication::translate("Telemetry", "TELE"), index
, modelData
? modelData
->sensorData
[index
-1].label
: NULL
);
743 case SWITCH_TYPE_TELEMETRY
:
744 return QObject::tr("Telemetry");
747 return QObject::tr("???");
757 QString
CurveReference::toString(const ModelData
* model
, bool verbose
) const
764 unsigned idx
= abs(value
) - 1;
768 ret
= QObject::tr("Diff(%1)").arg(Helpers::getAdjustmentString(value
, model
));
772 ret
= QObject::tr("Expo(%1)").arg(Helpers::getAdjustmentString(value
, model
));
776 ret
= QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value
-1), 3);
778 ret
= QObject::tr("Function(%1)").arg(ret
);
783 ret
= model
->curves
[idx
].nameToString(idx
);
785 ret
= CurveData().nameToString(idx
);
787 ret
= QObject::tr("Curve(%1)").arg(ret
);
789 ret
.prepend(CPN_STR_SW_INDICATOR_REV
);
796 bool LogicalSwitchData::isEmpty() const
801 CSFunctionFamily
LogicalSwitchData::getFunctionFamily() const
803 if (func
== LS_FN_EDGE
)
804 return LS_FAMILY_EDGE
;
805 else if (func
== LS_FN_TIMER
)
806 return LS_FAMILY_TIMER
;
807 else if (func
== LS_FN_STICKY
)
808 return LS_FAMILY_STICKY
;
809 else if (func
< LS_FN_AND
|| func
> LS_FN_ELESS
)
810 return LS_FAMILY_VOFS
;
811 else if (func
< LS_FN_EQUAL
)
812 return LS_FAMILY_VBOOL
;
814 return LS_FAMILY_VCOMP
;
817 unsigned int LogicalSwitchData::getRangeFlags() const
819 if (func
== LS_FN_DPOS
)
820 return RANGE_DELTA_FUNCTION
;
821 else if (func
== LS_FN_DAPOS
)
822 return RANGE_DELTA_ABS_FUNCTION
;
827 QString
LogicalSwitchData::funcToString() const
831 return QObject::tr("---");
833 return QObject::tr("a>x");
835 return QObject::tr("a<x");
837 return QObject::tr("|a|>x");
839 return QObject::tr("|a|<x");
841 return QObject::tr("AND");
843 return QObject::tr("OR");
845 return QObject::tr("XOR");
847 return QObject::tr("a=b");
849 return QObject::tr("a!=b");
851 return QObject::tr("a>b");
853 return QObject::tr("a<b");
855 return QObject::tr("a>=b");
857 return QObject::tr("a<=b");
859 return QObject::tr("d>=x");
861 return QObject::tr("|d|>=x");
863 return QObject::tr("a=x");
864 case LS_FN_VALMOSTEQUAL
:
865 return QObject::tr("a~x");
867 return QObject::tr("Timer");
869 return QObject::tr("Sticky");
871 return QObject::tr("Edge");
873 return QObject::tr("Unknown");
877 void CustomFunctionData::clear()
879 memset(this, 0, sizeof(CustomFunctionData
));
880 if (!getCurrentFirmware()->getCapability(SafetyChannelCustomFunction
)) {
885 bool CustomFunctionData::isEmpty() const
887 return (swtch
.type
== SWITCH_TYPE_NONE
);
890 QString
CustomFunctionData::funcToString(const ModelData
* model
) const
892 if (func
>= FuncOverrideCH1
&& func
<= FuncOverrideCH32
)
893 return QObject::tr("Override %1").arg(RawSource(SOURCE_TYPE_CH
, func
).toString(model
));
894 else if (func
== FuncTrainer
)
895 return QObject::tr("Trainer");
896 else if (func
== FuncTrainerRUD
)
897 return QObject::tr("Trainer RUD");
898 else if (func
== FuncTrainerELE
)
899 return QObject::tr("Trainer ELE");
900 else if (func
== FuncTrainerTHR
)
901 return QObject::tr("Trainer THR");
902 else if (func
== FuncTrainerAIL
)
903 return QObject::tr("Trainer AIL");
904 else if (func
== FuncInstantTrim
)
905 return QObject::tr("Instant Trim");
906 else if (func
== FuncPlaySound
)
907 return QObject::tr("Play Sound");
908 else if (func
== FuncPlayHaptic
)
909 return QObject::tr("Haptic");
910 else if (func
== FuncReset
)
911 return QObject::tr("Reset");
912 else if (func
>= FuncSetTimer1
&& func
<= FuncSetTimer3
)
913 return QObject::tr("Set Timer %1").arg(func
-FuncSetTimer1
+1);
914 else if (func
== FuncVario
)
915 return QObject::tr("Vario");
916 else if (func
== FuncPlayPrompt
)
917 return QObject::tr("Play Track");
918 else if (func
== FuncPlayBoth
)
919 return QObject::tr("Play Both");
920 else if (func
== FuncPlayValue
)
921 return QObject::tr("Play Value");
922 else if (func
== FuncPlayScript
)
923 return QObject::tr("Play Script");
924 else if (func
== FuncLogs
)
925 return QObject::tr("SD Logs");
926 else if (func
== FuncVolume
)
927 return QObject::tr("Volume");
928 else if (func
== FuncBacklight
)
929 return QObject::tr("Backlight");
930 else if (func
== FuncScreenshot
)
931 return QObject::tr("Screenshot");
932 else if (func
== FuncBackgroundMusic
)
933 return QObject::tr("Background Music");
934 else if (func
== FuncBackgroundMusicPause
)
935 return QObject::tr("Background Music Pause");
936 else if (func
>= FuncAdjustGV1
&& func
<= FuncAdjustGVLast
)
937 return QObject::tr("Adjust %1").arg(RawSource(SOURCE_TYPE_GVAR
, func
-FuncAdjustGV1
).toString(model
));
938 else if (func
== FuncSetFailsafeInternalModule
)
939 return QObject::tr("SetFailsafe Int. Module");
940 else if (func
== FuncSetFailsafeExternalModule
)
941 return QObject::tr("SetFailsafe Ext. Module");
942 else if (func
== FuncRangeCheckInternalModule
)
943 return QObject::tr("RangeCheck Int. Module");
944 else if (func
== FuncRangeCheckExternalModule
)
945 return QObject::tr("RangeCheck Ext. Module");
946 else if (func
== FuncBindInternalModule
)
947 return QObject::tr("Bind Int. Module");
948 else if (func
== FuncBindExternalModule
)
949 return QObject::tr("Bind Ext. Module");
951 return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is)
955 void CustomFunctionData::populateResetParams(const ModelData
* model
, QComboBox
* b
, unsigned int value
= 0)
958 Firmware
* firmware
= Firmware::getCurrentVariant();
959 Board::Type board
= firmware
->getBoard();
961 b
->addItem(QObject::tr("Timer1"), val
++);
962 b
->addItem(QObject::tr("Timer2"), val
++);
964 b
->addItem( QObject::tr("Timer3"), val
++);
966 b
->addItem(QObject::tr("Flight"), val
++);
967 b
->addItem(QObject::tr("Telemetry"), val
++);
968 int reCount
= firmware
->getCapability(RotaryEncoders
);
970 b
->addItem(QObject::tr("Rotary Encoder"), val
++);
972 else if (reCount
== 2) {
973 b
->addItem(QObject::tr("REa"), val
++);
974 b
->addItem(QObject::tr("REb"), val
++);
976 if ((int)value
< b
->count()) {
977 b
->setCurrentIndex(value
);
979 if (model
&& IS_ARM(board
)) {
980 for (int i
=0; i
<CPN_MAX_SENSORS
; ++i
) {
981 if (model
->sensorData
[i
].isAvailable()) {
982 RawSource item
= RawSource(SOURCE_TYPE_TELEMETRY
, 3*i
);
983 b
->addItem(item
.toString(model
), val
+i
);
984 if ((int)value
== val
+i
) {
985 b
->setCurrentIndex(b
->count()-1);
992 void CustomFunctionData::populatePlaySoundParams(QStringList
& qs
)
994 qs
<<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ;
995 qs
<< "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ;
998 void CustomFunctionData::populateHapticParams(QStringList
& qs
)
1000 qs
<< "0" << "1" << "2" << "3";
1003 QString
CustomFunctionData::paramToString(const ModelData
* model
) const
1006 if (func
<= FuncInstantTrim
) {
1007 return QString("%1").arg(param
);
1009 else if (func
==FuncLogs
) {
1010 return QString("%1").arg(param
/10.0) + QObject::tr("s");
1012 else if (func
==FuncPlaySound
) {
1013 CustomFunctionData::populatePlaySoundParams(qs
);
1014 if (param
>=0 && param
<(int)qs
.count())
1015 return qs
.at(param
);
1017 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
1019 else if (func
==FuncPlayHaptic
) {
1020 CustomFunctionData::populateHapticParams(qs
);
1021 if (param
>=0 && param
<(int)qs
.count())
1022 return qs
.at(param
);
1024 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
1026 else if (func
==FuncReset
) {
1028 CustomFunctionData::populateResetParams(model
, &cb
);
1029 int pos
= cb
.findData(param
);
1031 return cb
.itemText(pos
);
1033 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
1035 else if ((func
==FuncVolume
)|| (func
==FuncPlayValue
)) {
1036 RawSource
item(param
);
1037 return item
.toString(model
);
1039 else if ((func
==FuncPlayPrompt
) || (func
==FuncPlayBoth
)) {
1040 if ( getCurrentFirmware()->getCapability(VoicesAsNumbers
)) {
1041 return QString("%1").arg(param
);
1047 else if ((func
>=FuncAdjustGV1
) && (func
<FuncCount
)) {
1048 switch (adjustMode
) {
1049 case FUNC_ADJUST_GVAR_CONSTANT
:
1050 return QObject::tr("Value ")+QString("%1").arg(param
);
1051 case FUNC_ADJUST_GVAR_SOURCE
:
1052 case FUNC_ADJUST_GVAR_GVAR
:
1053 return RawSource(param
).toString();
1054 case FUNC_ADJUST_GVAR_INCDEC
:
1055 if (param
==0) return QObject::tr("Decr:") + " -1";
1056 else return QObject::tr("Incr:") + " +1";
1062 QString
CustomFunctionData::repeatToString() const
1064 if (repeatParam
== -1) {
1065 return QObject::tr("played once, not during startup");
1067 else if (repeatParam
== 0) {
1071 unsigned int step
= IS_ARM(getCurrentBoard()) ? 1 : 10;
1072 return QObject::tr("repeat(%1s)").arg(step
*repeatParam
);
1076 QString
CustomFunctionData::enabledToString() const
1078 if ((func
>=FuncOverrideCH1
&& func
<=FuncOverrideCH32
) ||
1079 (func
>=FuncAdjustGV1
&& func
<=FuncAdjustGVLast
) ||
1080 (func
==FuncReset
) ||
1081 (func
>=FuncSetTimer1
&& func
<=FuncSetTimer2
) ||
1082 (func
==FuncVolume
) ||
1083 (func
<= FuncInstantTrim
)) {
1085 return QObject::tr("DISABLED");
1091 CurveData::CurveData()
1096 void CurveData::clear(int count
)
1098 memset(this, 0, sizeof(CurveData
));
1099 this->count
= count
;
1102 bool CurveData::isEmpty() const
1104 for (int i
=0; i
<count
; i
++) {
1105 if (points
[i
].y
!= 0) {
1112 QString
CurveData::nameToString(const int idx
) const
1114 return getElementName(QCoreApplication::translate("Curve", "CV"), idx
+ 1, name
);
1117 QString
LimitData::minToString() const
1119 return QString::number((qreal
)min
/10);
1122 QString
LimitData::maxToString() const
1124 return QString::number((qreal
)max
/10);
1127 QString
LimitData::revertToString() const
1129 return revert
? QObject::tr("INV") : QObject::tr("NOR");
1132 QString
LimitData::offsetToString() const
1134 return QString::number((qreal
)offset
/10, 'f', 1);
1137 void LimitData::clear()
1139 memset(this, 0, sizeof(LimitData
));
1144 bool GeneralSettings::switchPositionAllowedTaranis(int index
) const
1149 div_t qr
= div(abs(index
)-1, 3);
1151 if (index
< 0 && switchConfig
[qr
.quot
] != Board::SWITCH_3POS
)
1153 else if (qr
.rem
== 1)
1154 return switchConfig
[qr
.quot
] == Board::SWITCH_3POS
;
1156 return switchConfig
[qr
.quot
] != Board::SWITCH_NOT_AVAILABLE
;
1159 bool GeneralSettings::switchSourceAllowedTaranis(int index
) const
1161 return switchConfig
[index
] != Board::SWITCH_NOT_AVAILABLE
;
1164 bool GeneralSettings::isPotAvailable(int index
) const
1166 if (index
<0 || index
>getBoardCapability(getCurrentBoard(), Board::Pots
)) return false;
1167 return potConfig
[index
] != Board::POT_NONE
;
1170 bool GeneralSettings::isSliderAvailable(int index
) const
1172 if (index
<0 || index
>getBoardCapability(getCurrentBoard(), Board::Sliders
)) return false;
1173 return sliderConfig
[index
] != Board::SLIDER_NONE
;
1176 GeneralSettings::GeneralSettings()
1178 memset(this, 0, sizeof(GeneralSettings
));
1183 for (int i
=0; i
< CPN_MAX_ANALOGS
; ++i
) {
1184 calibMid
[i
] = 0x200;
1185 calibSpanNeg
[i
] = 0x180;
1186 calibSpanPos
[i
] = 0x180;
1189 Firmware
* firmware
= Firmware::getCurrentVariant();
1190 Board::Type board
= firmware
->getBoard();
1192 for (int i
=0; i
<getBoardCapability(board
, Board::FactoryInstalledSwitches
); i
++) {
1193 switchConfig
[i
] = Boards::getSwitchInfo(board
, i
).config
;
1196 backlightMode
= 3; // keys and sticks
1197 // backlightBright = 0; // 0 = 100%
1199 if (IS_HORUS(board
)) {
1200 backlightOffBright
= 20;
1203 if (IS_HORUS(board
)) {
1204 potConfig
[0] = Board::POT_WITH_DETENT
;
1205 potConfig
[1] = Board::POT_MULTIPOS_SWITCH
;
1206 potConfig
[2] = Board::POT_WITH_DETENT
;
1208 else if (IS_TARANIS_X7(board
)) {
1209 potConfig
[0] = Board::POT_WITHOUT_DETENT
;
1210 potConfig
[1] = Board::POT_WITH_DETENT
;
1212 else if (IS_TARANIS(board
)) {
1213 potConfig
[0] = Board::POT_WITH_DETENT
;
1214 potConfig
[1] = Board::POT_WITH_DETENT
;
1217 potConfig
[0] = Board::POT_WITHOUT_DETENT
;
1218 potConfig
[1] = Board::POT_WITHOUT_DETENT
;
1219 potConfig
[2] = Board::POT_WITHOUT_DETENT
;
1222 if (IS_HORUS(board
) || IS_TARANIS_X9E(board
)) {
1223 sliderConfig
[0] = Board::SLIDER_WITH_DETENT
;
1224 sliderConfig
[1] = Board::SLIDER_WITH_DETENT
;
1225 sliderConfig
[2] = Board::SLIDER_WITH_DETENT
;
1226 sliderConfig
[3] = Board::SLIDER_WITH_DETENT
;
1228 else if (IS_TARANIS(board
) && !IS_TARANIS_X7(board
)) {
1229 sliderConfig
[0] = Board::SLIDER_WITH_DETENT
;
1230 sliderConfig
[1] = Board::SLIDER_WITH_DETENT
;
1233 if (IS_ARM(board
)) {
1237 if (IS_TARANIS_X9E(board
)) {
1238 strcpy(bluetoothName
, "Taranis");
1241 templateSetup
= g
.profile
[g
.sessionId()].channelOrder();
1242 stickMode
= g
.profile
[g
.sessionId()].defaultMode();
1244 QString t_calib
= g
.profile
[g
.sessionId()].stickPotCalib();
1245 int potsnum
= getBoardCapability(getCurrentBoard(), Board::Pots
);
1246 if (!t_calib
.isEmpty()) {
1247 QString t_trainercalib
=g
.profile
[g
.sessionId()].trainerCalib();
1248 int8_t t_txVoltageCalibration
=(int8_t)g
.profile
[g
.sessionId()].txVoltageCalibration();
1249 int8_t t_txCurrentCalibration
=(int8_t)g
.profile
[g
.sessionId()].txCurrentCalibration();
1250 int8_t t_PPM_Multiplier
=(int8_t)g
.profile
[g
.sessionId()].ppmMultiplier();
1251 uint8_t t_stickMode
=(uint8_t)g
.profile
[g
.sessionId()].gsStickMode();
1252 uint8_t t_vBatWarn
=(uint8_t)g
.profile
[g
.sessionId()].vBatWarn();
1253 QString t_DisplaySet
=g
.profile
[g
.sessionId()].display();
1254 QString t_BeeperSet
=g
.profile
[g
.sessionId()].beeper();
1255 QString t_HapticSet
=g
.profile
[g
.sessionId()].haptic();
1256 QString t_SpeakerSet
=g
.profile
[g
.sessionId()].speaker();
1257 QString t_CountrySet
=g
.profile
[g
.sessionId()].countryCode();
1259 if ((t_calib
.length()==(CPN_MAX_STICKS
+potsnum
)*12) && (t_trainercalib
.length()==16)) {
1263 for (int i
=0; i
<(CPN_MAX_STICKS
+potsnum
); i
++) {
1264 Byte
=t_calib
.mid(i
*12,4);
1265 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1268 Byte
=t_calib
.mid(4+i
*12,4);
1269 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1271 calibSpanNeg
[i
]=byte16
;
1272 Byte
=t_calib
.mid(8+i
*12,4);
1273 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1275 calibSpanPos
[i
]=byte16
;
1277 for (int i
=0; i
<4; i
++) {
1278 Byte
=t_trainercalib
.mid(i
*4,4);
1279 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1281 trainer
.calib
[i
]=byte16
;
1283 txCurrentCalibration
=t_txCurrentCalibration
;
1284 txVoltageCalibration
=t_txVoltageCalibration
;
1285 vBatWarn
=t_vBatWarn
;
1286 PPM_Multiplier
=t_PPM_Multiplier
;
1287 stickMode
= t_stickMode
;
1289 if ((t_DisplaySet
.length()==6) && (t_BeeperSet
.length()==4) && (t_HapticSet
.length()==6) && (t_SpeakerSet
.length()==6)) {
1293 byte8
=(int8_t)t_DisplaySet
.mid(0,2).toInt(&ok
,16);
1295 optrexDisplay
=(byte8
==1 ? true : false);
1296 byte8u
=(uint8_t)t_DisplaySet
.mid(2,2).toUInt(&ok
,16);
1299 byte8u
=(uint8_t)t_DisplaySet
.mid(4,2).toUInt(&ok
,16);
1301 backlightBright
=byte8u
;
1302 byte8
=(int8_t)t_BeeperSet
.mid(0,2).toUInt(&ok
,16);
1304 beeperMode
=(BeeperMode
)byte8
;
1305 byte8
=(int8_t)t_BeeperSet
.mid(2,2).toInt(&ok
,16);
1308 byte8
=(int8_t)t_HapticSet
.mid(0,2).toUInt(&ok
,16);
1310 hapticMode
=(BeeperMode
)byte8
;
1311 byte8
=(int8_t)t_HapticSet
.mid(2,2).toInt(&ok
,16);
1313 hapticStrength
=byte8
;
1314 byte8
=(int8_t)t_HapticSet
.mid(4,2).toInt(&ok
,16);
1317 byte8u
=(uint8_t)t_SpeakerSet
.mid(0,2).toUInt(&ok
,16);
1320 byte8u
=(uint8_t)t_SpeakerSet
.mid(2,2).toUInt(&ok
,16);
1322 speakerPitch
=byte8u
;
1323 byte8u
=(uint8_t)t_SpeakerSet
.mid(4,2).toUInt(&ok
,16);
1325 speakerVolume
=byte8u
;
1326 if (t_CountrySet
.length()==6) {
1327 byte8u
=(uint8_t)t_CountrySet
.mid(0,2).toUInt(&ok
,16);
1330 byte8u
=(uint8_t)t_CountrySet
.mid(2,2).toUInt(&ok
,16);
1333 QString chars
= t_CountrySet
.mid(4, 2);
1334 ttsLanguage
[0] = chars
[0].toLatin1();
1335 ttsLanguage
[1] = chars
[1].toLatin1();
1340 strcpy(themeName
, "default");
1341 ThemeOptionData option1
= { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
1342 memcpy(&themeOptionValue
[0], option1
, sizeof(ThemeOptionData
));
1343 ThemeOptionData option2
= { 0x03, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 };
1344 memcpy(&themeOptionValue
[1], option2
, sizeof(ThemeOptionData
));
1347 int GeneralSettings::getDefaultStick(unsigned int channel
) const
1349 if (channel
>= CPN_MAX_STICKS
)
1352 return chout_ar
[4*templateSetup
+ channel
] - 1;
1355 RawSource
GeneralSettings::getDefaultSource(unsigned int channel
) const
1357 int stick
= getDefaultStick(channel
);
1359 return RawSource(SOURCE_TYPE_STICK
, stick
);
1361 return RawSource(SOURCE_TYPE_NONE
);
1364 int GeneralSettings::getDefaultChannel(unsigned int stick
) const
1366 for (int i
=0; i
<4; i
++){
1367 if (getDefaultStick(i
) == (int)stick
)
1373 float FrSkyChannelData::getRatio() const
1375 if (type
==0 || type
==1 || type
==2)
1376 return float(ratio
<< multiplier
) / 10.0;
1378 return ratio
<< multiplier
;
1381 RawSourceRange
FrSkyChannelData::getRange() const
1383 RawSourceRange result
;
1384 float ratio
= getRatio();
1385 if (type
==0 || type
==1 || type
==2)
1386 result
.decimals
= 2;
1388 result
.decimals
= 0;
1389 result
.step
= ratio
/ 255;
1390 result
.min
= offset
* result
.step
;
1391 result
.max
= ratio
+ result
.min
;
1392 result
.unit
= QObject::tr("V");
1396 void FrSkyScreenData::clear()
1398 memset(this, 0, sizeof(FrSkyScreenData
));
1399 if (!IS_ARM(getCurrentBoard())) {
1400 type
= TELEMETRY_SCREEN_NUMBERS
;
1404 void FrSkyData::clear()
1411 varioCenterMin
= 0; // if increment in 0.2m/s = 3.0m/s max
1417 for (int i
=0; i
<4; i
++)
1419 varioSource
= 2/*VARIO*/;
1423 ModelData::ModelData()
1428 ModelData::ModelData(const ModelData
& src
)
1433 ModelData
& ModelData::operator = (const ModelData
& src
)
1435 memcpy(this, &src
, sizeof(ModelData
));
1439 ExpoData
* ModelData::insertInput(const int idx
)
1441 memmove(&expoData
[idx
+1], &expoData
[idx
], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
1442 expoData
[idx
].clear();
1443 return &expoData
[idx
];
1446 bool ModelData::isInputValid(const unsigned int idx
) const
1448 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
1449 const ExpoData
* expo
= &expoData
[i
];
1450 if (expo
->mode
== 0) break;
1451 if (expo
->chn
== idx
)
1457 bool ModelData::hasExpos(uint8_t inputIdx
) const
1459 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
1460 const ExpoData
& expo
= expoData
[i
];
1461 if (expo
.chn
==inputIdx
&& expo
.mode
!=0) {
1468 bool ModelData::hasMixes(uint8_t channelIdx
) const
1471 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
1472 if (mixData
[i
].destCh
== channelIdx
) {
1479 QVector
<const ExpoData
*> ModelData::expos(int input
) const
1481 QVector
<const ExpoData
*> result
;
1482 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
1483 const ExpoData
* ed
= &expoData
[i
];
1484 if ((int)ed
->chn
==input
&& ed
->mode
!=0) {
1491 QVector
<const MixData
*> ModelData::mixes(int channel
) const
1493 QVector
<const MixData
*> result
;
1494 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
1495 const MixData
* md
= &mixData
[i
];
1496 if ((int)md
->destCh
== channel
+1) {
1503 void ModelData::removeInput(const int idx
)
1505 unsigned int chn
= expoData
[idx
].chn
;
1507 memmove(&expoData
[idx
], &expoData
[idx
+1], (CPN_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
1508 expoData
[CPN_MAX_EXPOS
-1].clear();
1510 //also remove input name if removing last line for this input
1512 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
1513 if (expoData
[i
].mode
==0) continue;
1514 if (expoData
[i
].chn
==chn
) {
1519 if (!found
) inputNames
[chn
][0] = 0;
1522 void ModelData::clearInputs()
1524 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++)
1525 expoData
[i
].clear();
1527 //clear all input names
1528 if (getCurrentFirmware()->getCapability(VirtualInputs
)) {
1529 for (int i
=0; i
<CPN_MAX_INPUTS
; i
++) {
1530 inputNames
[i
][0] = 0;
1535 void ModelData::clearMixes()
1537 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++)
1541 void ModelData::clear()
1543 memset(this, 0, sizeof(ModelData
));
1544 modelIndex
= -1; // an invalid index, this is managed by the TreeView data model
1545 moduleData
[0].channelsCount
= 8;
1546 moduleData
[1].channelsStart
= 0;
1547 moduleData
[1].channelsCount
= 8;
1548 moduleData
[0].ppm
.delay
= 300;
1549 moduleData
[1].ppm
.delay
= 300;
1550 moduleData
[2].ppm
.delay
= 300;
1551 int board
= getCurrentBoard();
1552 if (IS_HORUS_OR_TARANIS(board
)) {
1553 moduleData
[0].protocol
= PULSES_PXX_XJT_X16
;
1554 moduleData
[1].protocol
= PULSES_OFF
;
1556 else if (IS_SKY9X(board
)) {
1557 moduleData
[0].protocol
= PULSES_PPM
;
1558 moduleData
[1].protocol
= PULSES_PPM
;
1561 moduleData
[0].protocol
= PULSES_PPM
;
1562 moduleData
[1].protocol
= PULSES_OFF
;
1564 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
1565 flightModeData
[i
].clear(i
);
1569 for (int i
=0; i
<CPN_MAX_CHNOUT
; i
++)
1570 limitData
[i
].clear();
1571 for (int i
=0; i
<CPN_MAX_STICKS
; i
++)
1572 expoData
[i
].clear();
1573 for (int i
=0; i
<CPN_MAX_LOGICAL_SWITCHES
; i
++)
1574 logicalSw
[i
].clear();
1575 for (int i
=0; i
<CPN_MAX_SPECIAL_FUNCTIONS
; i
++)
1576 customFn
[i
].clear();
1577 for (int i
=0; i
<CPN_MAX_CURVES
; i
++)
1579 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++)
1581 swashRingData
.clear();
1584 for (int i
=0; i
<CPN_MAX_SENSORS
; i
++)
1585 sensorData
[i
].clear();
1587 static const uint8_t blob
[] = { 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x32, 0x50, 0x31, 0x00, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x42, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
1588 memcpy(customScreenData
[0], blob
, sizeof(blob
));
1591 bool ModelData::isEmpty() const
1596 QString
removeAccents(const QString
& str
)
1598 QString result
= str
;
1600 // UTF-8 ASCII Table
1601 const QString tA
[] = { "á", "â", "ã", "à ", "ä" };
1602 const QString tE
[] = { "é", "è", "ê", "ě" };
1603 const QString tI
[] = { "Ã" };
1604 const QString tO
[] = { "ó", "ô", "õ", "ö" };
1605 const QString tU
[] = { "ú", "ü" };
1606 const QString tC
[] = { "ç" };
1607 const QString tY
[] = { "ý" };
1608 const QString tS
[] = { "Å¡" };
1609 const QString tR
[] = { "Å™" };
1611 for (unsigned int i
= 0; i
< DIM(tA
); i
++) result
.replace(tA
[i
], "a");
1612 for (unsigned int i
= 0; i
< DIM(tE
); i
++) result
.replace(tE
[i
], "e");
1613 for (unsigned int i
= 0; i
< DIM(tI
); i
++) result
.replace(tI
[i
], "i");
1614 for (unsigned int i
= 0; i
< DIM(tO
); i
++) result
.replace(tO
[i
], "o");
1615 for (unsigned int i
= 0; i
< DIM(tU
); i
++) result
.replace(tU
[i
], "u");
1616 for (unsigned int i
= 0; i
< DIM(tC
); i
++) result
.replace(tC
[i
], "c");
1617 for (unsigned int i
= 0; i
< DIM(tY
); i
++) result
.replace(tY
[i
], "y");
1618 for (unsigned int i
= 0; i
< DIM(tS
); i
++) result
.replace(tS
[i
], "s");
1619 for (unsigned int i
= 0; i
< DIM(tR
); i
++) result
.replace(tR
[i
], "r");
1624 void ModelData::setDefaultInputs(const GeneralSettings
& settings
)
1626 Board::Type board
= getCurrentBoard();
1627 if (IS_ARM(board
)) {
1628 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
1629 ExpoData
* expo
= &expoData
[i
];
1631 expo
->mode
= INPUT_MODE_BOTH
;
1632 expo
->srcRaw
= settings
.getDefaultSource(i
);
1634 strncpy(inputNames
[i
], removeAccents(expo
->srcRaw
.toString(this)).toLatin1().constData(), sizeof(inputNames
[i
])-1);
1639 void ModelData::setDefaultMixes(const GeneralSettings
& settings
)
1641 Board::Type board
= getCurrentBoard();
1642 if (IS_ARM(board
)) {
1643 setDefaultInputs(settings
);
1646 for (int i
=0; i
<CPN_MAX_STICKS
; i
++) {
1647 MixData
* mix
= &mixData
[i
];
1650 if (IS_ARM(board
)) {
1651 mix
->srcRaw
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
1654 mix
->srcRaw
= RawSource(SOURCE_TYPE_STICK
, i
);
1659 void ModelData::setDefaultValues(unsigned int id
, const GeneralSettings
& settings
)
1663 sprintf(name
, "MODEL%02d", id
+1);
1664 for (int i
=0; i
<CPN_MAX_MODULES
; i
++) {
1665 moduleData
[i
].modelId
= id
+1;
1667 setDefaultMixes(settings
);
1670 int ModelData::getTrimValue(int phaseIdx
, int trimIdx
)
1673 for (int i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
1674 FlightModeData
& phase
= flightModeData
[phaseIdx
];
1675 if (phase
.trimMode
[trimIdx
] < 0) {
1679 if (phase
.trimRef
[trimIdx
] == phaseIdx
|| phaseIdx
== 0) {
1680 return result
+ phase
.trim
[trimIdx
];
1683 phaseIdx
= phase
.trimRef
[trimIdx
];
1684 if (phase
.trimMode
[trimIdx
] != 0)
1685 result
+= phase
.trim
[trimIdx
];
1692 bool ModelData::isGVarLinked(int phaseIdx
, int gvarIdx
)
1694 return flightModeData
[phaseIdx
].gvars
[gvarIdx
] > 1024;
1697 int ModelData::getGVarFieldValue(int phaseIdx
, int gvarIdx
)
1699 int idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
1700 for (int i
=0; idx
>1024 && i
<CPN_MAX_FLIGHT_MODES
; i
++) {
1701 int nextPhase
= idx
- 1025;
1702 if (nextPhase
>= phaseIdx
) nextPhase
+= 1;
1703 phaseIdx
= nextPhase
;
1704 idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
1709 void ModelData::setTrimValue(int phaseIdx
, int trimIdx
, int value
)
1711 for (uint8_t i
=0; i
<CPN_MAX_FLIGHT_MODES
; i
++) {
1712 FlightModeData
& phase
= flightModeData
[phaseIdx
];
1713 int mode
= phase
.trimMode
[trimIdx
];
1714 int p
= phase
.trimRef
[trimIdx
];
1715 int & trim
= phase
.trim
[trimIdx
];
1718 if (p
== phaseIdx
|| phaseIdx
== 0) {
1722 else if (mode
== 0) {
1726 trim
= value
- getTrimValue(p
, trimIdx
);
1736 void ModelData::removeGlobalVar(int & var
)
1738 if (var
>= 126 && var
<= 130)
1739 var
= flightModeData
[0].gvars
[var
-126];
1740 else if (var
<= -126 && var
>= -130)
1741 var
= - flightModeData
[0].gvars
[-126-var
];
1744 ModelData
ModelData::removeGlobalVars()
1746 ModelData result
= *this;
1748 for (int i
=0; i
<CPN_MAX_MIXERS
; i
++) {
1749 removeGlobalVar(mixData
[i
].weight
);
1750 removeGlobalVar(mixData
[i
].curve
.value
);
1751 removeGlobalVar(mixData
[i
].sOffset
);
1754 for (int i
=0; i
<CPN_MAX_EXPOS
; i
++) {
1755 removeGlobalVar(expoData
[i
].weight
);
1756 removeGlobalVar(expoData
[i
].curve
.value
);
1762 int ModelData::getChannelsMax(bool forceExtendedLimits
) const
1764 if (forceExtendedLimits
|| extendedLimits
)
1765 return IS_HORUS_OR_TARANIS(getCurrentBoard()) ? 150 : 125;
1770 bool ModelData::isAvailable(const RawSwitch
& swtch
) const
1772 unsigned index
= abs(swtch
.index
) - 1;
1774 if (swtch
.type
== SWITCH_TYPE_VIRTUAL
) {
1775 return logicalSw
[index
].func
!= LS_FN_OFF
;
1777 else if (swtch
.type
== SWITCH_TYPE_FLIGHT_MODE
) {
1778 return index
== 0 || flightModeData
[index
].swtch
.type
!= SWITCH_TYPE_NONE
;
1780 else if (swtch
.type
== SWITCH_TYPE_SENSOR
) {
1781 return strlen(sensorData
[index
].label
) > 0;
1788 QList
<EEPROMInterface
*> eepromInterfaces
;
1790 void unregisterEEpromInterfaces()
1792 foreach(EEPROMInterface
* intf
, eepromInterfaces
) {
1793 // qDebug() << "UnregisterEepromInterfaces(): deleting " << QString::number( reinterpret_cast<uint64_t>(intf), 16 );
1796 OpenTxEepromCleanup();
1799 void ShowEepromErrors(QWidget
*parent
, const QString
&title
, const QString
&mainMessage
, unsigned long errorsFound
)
1801 std::bitset
<NUM_ERRORS
> errors((unsigned long long)errorsFound
);
1802 QStringList errorsList
;
1804 errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "Possible causes for this:");
1806 if (errors
.test(UNSUPPORTED_NEWER_VERSION
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a newer version of OpenTX"); }
1807 if (errors
.test(NOT_OPENTX
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from OpenTX"); }
1808 if (errors
.test(NOT_TH9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Th9X"); }
1809 if (errors
.test(NOT_GRUVIN9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Gruvin9X"); }
1810 if (errors
.test(NOT_ERSKY9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from ErSky9X"); }
1811 if (errors
.test(NOT_ER9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Er9X"); }
1812 if (errors
.test(WRONG_SIZE
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom size is invalid"); }
1813 if (errors
.test(WRONG_FILE_SYSTEM
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom file system is invalid"); }
1814 if (errors
.test(UNKNOWN_BOARD
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a unknown board"); }
1815 if (errors
.test(WRONG_BOARD
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from the wrong board"); }
1816 if (errors
.test(BACKUP_NOT_SUPPORTED
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom backup not supported"); }
1818 if (errors
.test(UNKNOWN_ERROR
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Something that couldn't be guessed, sorry"); }
1820 if (errors
.test(HAS_WARNINGS
)) {
1821 errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "Warning:");
1822 if (errors
.test(WARNING_WRONG_FIRMWARE
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
1825 QMessageBox
msgBox(parent
);
1826 msgBox
.setWindowTitle(title
);
1827 msgBox
.setIcon(QMessageBox::Critical
);
1828 msgBox
.setText(mainMessage
);
1829 msgBox
.setInformativeText(errorsList
.join("\n"));
1830 msgBox
.setStandardButtons(QMessageBox::Ok
);
1834 void ShowEepromWarnings(QWidget
*parent
, const QString
&title
, unsigned long errorsFound
)
1836 std::bitset
<NUM_ERRORS
> errors((unsigned long long)errorsFound
);
1837 QStringList warningsList
;
1838 if (errors
.test(WARNING_WRONG_FIRMWARE
)) { warningsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Your radio probably uses a wrong firmware,\n eeprom size is 4096 but only the first 2048 are used"); }
1839 if (errors
.test(OLD_VERSION
)) { warningsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Your eeprom is from an old version of OpenTX, upgrading!\n To keep your original file as a backup, please choose File -> Save As specifying a different name."); }
1841 QMessageBox
msgBox(parent
);
1842 msgBox
.setWindowTitle(title
);
1843 msgBox
.setIcon(QMessageBox::Warning
);
1844 msgBox
.setText(QT_TRANSLATE_NOOP("EepromInterface", "Warnings!"));
1845 msgBox
.setInformativeText(warningsList
.join("\n"));
1846 msgBox
.setStandardButtons(QMessageBox::Ok
);
1851 QVector
<Firmware
*> Firmware::registeredFirmwares
;
1852 Firmware
* Firmware::defaultVariant
= NULL
;
1853 Firmware
* Firmware::currentVariant
= NULL
;
1856 Firmware
* Firmware::getFirmwareForId(const QString
& id
)
1858 foreach(Firmware
* firmware
, registeredFirmwares
) {
1859 Firmware
* result
= firmware
->getFirmwareVariant(id
);
1865 return defaultVariant
;
1868 void Firmware::addOption(const char *option
, QString tooltip
, uint32_t variant
)
1870 Option options
[] = { { option
, tooltip
, variant
}, { NULL
} };
1871 addOptions(options
);
1874 unsigned int Firmware::getVariantNumber()
1876 unsigned int result
= 0;
1877 const Firmware
* base
= getFirmwareBase();
1878 QStringList options
= id
.mid(base
->getId().length()+1).split("-", QString::SkipEmptyParts
);
1879 foreach(QString option
, options
) {
1880 foreach(QList
<Option
> group
, base
->opts
) {
1881 foreach(Option opt
, group
) {
1882 if (opt
.name
== option
) {
1883 result
+= opt
.variant
;
1891 void Firmware::addLanguage(const char *lang
)
1893 languages
.push_back(lang
);
1896 void Firmware::addTTSLanguage(const char *lang
)
1898 ttslanguages
.push_back(lang
);
1901 void Firmware::addOptions(Option options
[])
1904 for (int i
=0; options
[i
].name
; i
++) {
1905 opts
.push_back(options
[i
]);
1907 this->opts
.push_back(opts
);
1910 void FlightModeData::clear(const int phase
)
1912 memset(this, 0, sizeof(FlightModeData
));
1914 for (int idx
=0; idx
<CPN_MAX_GVARS
; idx
++) {
1917 for (int idx
=0; idx
<CPN_MAX_ENCODERS
; idx
++) {
1918 rotaryEncoders
[idx
] = 1025;