6 #include "eeprominterface.h"
7 #include "firmwares/er9x/er9xinterface.h"
8 #include "firmwares/th9x/th9xinterface.h"
9 #include "firmwares/gruvin9x/gruvin9xinterface.h"
10 #include "firmwares/opentx/opentxinterface.h"
11 #include "firmwares/opentx/opentxeeprom.h"
12 #include "firmwares/ersky9x/ersky9xinterface.h"
15 #include "wizarddata.h"
16 #include "firmwareinterface.h"
18 std::list
<QString
> EEPROMWarnings
;
20 const uint8_t chout_ar
[] = { // First number is 0..23 -> template setup, Second is relevant channel out
21 1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
22 2,1,3,4 , 2,1,4,3 , 2,3,1,4 , 2,3,4,1 , 2,4,1,3 , 2,4,3,1,
23 3,1,2,4 , 3,1,4,2 , 3,2,1,4 , 3,2,4,1 , 3,4,1,2 , 3,4,2,1,
24 4,1,2,3 , 4,1,3,2 , 4,2,1,3 , 4,2,3,1 , 4,3,1,2 , 4,3,2,1
27 void setEEPROMString(char *dst
, const char *src
, int size
)
29 memcpy(dst
, src
, size
);
30 for (int i
=size
-1; i
>=0; i
--) {
38 void getEEPROMString(char *dst
, const char *src
, int size
)
40 memcpy(dst
, src
, size
);
42 for (int i
=size
-1; i
>=0; i
--) {
50 float ValToTim(int value
)
52 return ((value
< -109 ? 129+value
: (value
< 7 ? (113+value
)*5 : (53+value
)*10))/10.0);
55 int TimToVal(float value
)
59 temp
=136+round((value
-60));
62 temp
=20+round((value
-2.0)*2.0);
65 temp
=round(value
*10.0);
70 QString
getSignedStr(int value
)
72 return value
> 0 ? QString("+%1").arg(value
) : QString("%1").arg(value
);
75 QString
getGVarString(int16_t val
, bool sign
)
77 if (val
>= -10000 && val
<= 10000) {
79 return QString("%1%").arg(getSignedStr(val
));
81 return QString("%1%").arg(val
);
85 return QObject::tr("-GV%1").arg(-val
-10000);
87 return QObject::tr("GV%1").arg(val
-10000);
91 void SensorData::updateUnit()
93 if (type
== TELEM_TYPE_CALCULATED
) {
94 if (formula
== TELEM_FORMULA_CONSUMPTION
)
99 QString
SensorData::unitString() const
103 return QObject::tr("V");
105 return QObject::tr("A");
107 return QObject::tr("mA");
109 return QObject::tr("kts");
110 case UNIT_METERS_PER_SECOND
:
111 return QObject::tr("m/s");
113 return QObject::tr("km/h");
115 return QObject::tr("mph");
117 return QObject::tr("m");
119 return QObject::tr("f");
121 return QObject::trUtf8("°C");
122 case UNIT_FAHRENHEIT
:
123 return QObject::trUtf8("°F");
125 return QObject::tr("%");
127 return QObject::tr("mAh");
129 return QObject::tr("W");
131 return QObject::tr("dB");
133 return QObject::tr("rpms");
135 return QObject::tr("g");
137 return QObject::trUtf8("°");
139 return QObject::tr("hours");
141 return QObject::tr("minutes");
143 return QObject::tr("seconds");
145 return QObject::tr("V");
151 bool RawSource::isTimeBased() const
153 if (IS_ARM(GetCurrentFirmware()->getBoard()))
154 return (type
== SOURCE_TYPE_SPECIAL
&& index
> 0);
156 return (type
==SOURCE_TYPE_TELEMETRY
&& (index
==TELEMETRY_SOURCE_TX_TIME
|| index
==TELEMETRY_SOURCE_TIMER1
|| index
==TELEMETRY_SOURCE_TIMER2
|| index
==TELEMETRY_SOURCE_TIMER3
));
159 float RawSourceRange::getValue(int value
)
161 if (IS_ARM(GetCurrentFirmware()->getBoard()))
162 return float(value
) * step
;
164 return min
+ float(value
) * step
;
167 RawSourceRange
RawSource::getRange(const ModelData
* model
, const GeneralSettings
& settings
, unsigned int flags
) const
169 RawSourceRange result
;
171 Firmware
* firmware
= GetCurrentFirmware();
172 int board
= firmware
->getBoard();
173 bool singleprec
= (flags
& RANGE_SINGLE_PRECISION
);
175 if (!singleprec
&& !IS_ARM(board
)) {
180 case SOURCE_TYPE_TELEMETRY
:
182 div_t qr
= div(index
, 3);
183 const SensorData
& sensor
= model
->sensorData
[qr
.quot
];
184 if (sensor
.prec
== 2)
186 else if (sensor
.prec
== 1)
190 result
.min
= -30000 * result
.step
;
191 result
.max
= +30000 * result
.step
;
192 result
.decimals
= sensor
.prec
;
193 result
.unit
= sensor
.unitString();
197 result
.offset
= -DBL_MAX
;
201 case TELEMETRY_SOURCE_TX_BATT
:
205 result
.unit
= QObject::tr("V");
207 case TELEMETRY_SOURCE_TX_TIME
:
209 result
.max
= 24*60 - 1;
211 case TELEMETRY_SOURCE_TIMER1
:
212 case TELEMETRY_SOURCE_TIMER2
:
213 case TELEMETRY_SOURCE_TIMER3
:
214 result
.step
= singleprec
? 5 : 1;
215 result
.max
= singleprec
? 255*5 : 60*60;
216 result
.unit
= QObject::tr("s");
218 case TELEMETRY_SOURCE_RSSI_TX
:
219 case TELEMETRY_SOURCE_RSSI_RX
:
221 if (singleprec
) result
.offset
= 128;
223 case TELEMETRY_SOURCE_A1_MIN
:
224 case TELEMETRY_SOURCE_A2_MIN
:
225 case TELEMETRY_SOURCE_A3_MIN
:
226 case TELEMETRY_SOURCE_A4_MIN
:
227 if (model
) result
= model
->frsky
.channels
[index
-TELEMETRY_SOURCE_A1_MIN
].getRange();
229 case TELEMETRY_SOURCE_A1
:
230 case TELEMETRY_SOURCE_A2
:
231 case TELEMETRY_SOURCE_A3
:
232 case TELEMETRY_SOURCE_A4
:
233 if (model
) result
= model
->frsky
.channels
[index
-TELEMETRY_SOURCE_A1
].getRange();
235 case TELEMETRY_SOURCE_ALT
:
236 case TELEMETRY_SOURCE_ALT_MIN
:
237 case TELEMETRY_SOURCE_ALT_MAX
:
238 case TELEMETRY_SOURCE_GPS_ALT
:
239 result
.step
= singleprec
? 8 : 1;
241 result
.max
= singleprec
? 1540 : 3000;
242 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
243 result
.step
= (result
.step
* 105) / 32;
244 result
.min
= (result
.min
* 105) / 32;
245 result
.max
= (result
.max
* 105) / 32;
246 result
.unit
= QObject::tr("ft");
249 result
.unit
= QObject::tr("m");
252 case TELEMETRY_SOURCE_T1
:
253 case TELEMETRY_SOURCE_T1_MAX
:
254 case TELEMETRY_SOURCE_T2
:
255 case TELEMETRY_SOURCE_T2_MAX
:
258 result
.unit
= QObject::trUtf8("°C");
260 case TELEMETRY_SOURCE_HDG
:
261 result
.step
= singleprec
? 2 : 1;
263 if (singleprec
) result
.offset
= 256;
264 result
.unit
= QObject::trUtf8("°");
266 case TELEMETRY_SOURCE_RPM
:
267 case TELEMETRY_SOURCE_RPM_MAX
:
268 result
.step
= singleprec
? 50 : 1;
269 result
.max
= singleprec
? 12750 : 30000;
271 case TELEMETRY_SOURCE_FUEL
:
273 result
.unit
= QObject::tr("%");
275 case TELEMETRY_SOURCE_ASPEED
:
276 case TELEMETRY_SOURCE_ASPEED_MAX
:
278 result
.step
= singleprec
? 2.0 : 0.1;
279 result
.max
= singleprec
? (2*255) : 2000;
280 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
281 result
.step
*= 1.150779;
282 result
.max
*= 1.150779;
283 result
.unit
= QObject::tr("mph");
286 result
.step
*= 1.852;
288 result
.unit
= QObject::tr("km/h");
291 case TELEMETRY_SOURCE_SPEED
:
292 case TELEMETRY_SOURCE_SPEED_MAX
:
293 result
.step
= singleprec
? 2 : 1;
294 result
.max
= singleprec
? (2*255) : 2000;
295 if (firmware
->getCapability(Imperial
) || settings
.imperial
) {
296 result
.step
*= 1.150779;
297 result
.max
*= 1.150779;
298 result
.unit
= QObject::tr("mph");
301 result
.step
*= 1.852;
303 result
.unit
= QObject::tr("km/h");
306 case TELEMETRY_SOURCE_VERTICAL_SPEED
:
308 result
.min
= singleprec
? -12.5 : -300.0;
309 result
.max
= singleprec
? 13.0 : 300.0;
311 result
.unit
= QObject::tr("m/s");
313 case TELEMETRY_SOURCE_DTE
:
316 case TELEMETRY_SOURCE_DIST
:
317 case TELEMETRY_SOURCE_DIST_MAX
:
318 result
.step
= singleprec
? 8 : 1;
319 result
.max
= singleprec
? 2040 : 10000;
320 result
.unit
= QObject::tr("m");
322 case TELEMETRY_SOURCE_CELL
:
323 case TELEMETRY_SOURCE_CELL_MIN
:
324 result
.step
= singleprec
? 0.02 : 0.01;
327 result
.unit
= QObject::tr("V");
329 case TELEMETRY_SOURCE_CELLS_SUM
:
330 case TELEMETRY_SOURCE_CELLS_MIN
:
331 case TELEMETRY_SOURCE_VFAS
:
332 case TELEMETRY_SOURCE_VFAS_MIN
:
334 result
.max
= singleprec
? 25.5 : 100.0;
336 result
.unit
= QObject::tr("V");
338 case TELEMETRY_SOURCE_CURRENT
:
339 case TELEMETRY_SOURCE_CURRENT_MAX
:
340 result
.step
= singleprec
? 0.5 : 0.1;
341 result
.max
= singleprec
? 127.5 : 200.0;
343 result
.unit
= QObject::tr("A");
345 case TELEMETRY_SOURCE_CONSUMPTION
:
346 result
.step
= singleprec
? 100 : 1;
347 result
.max
= singleprec
? 25500 : 30000;
348 result
.unit
= QObject::tr("mAh");
350 case TELEMETRY_SOURCE_POWER
:
351 case TELEMETRY_SOURCE_POWER_MAX
:
352 result
.step
= singleprec
? 5 : 1;
353 result
.max
= singleprec
? 1275 : 2000;
354 result
.unit
= QObject::tr("W");
356 case TELEMETRY_SOURCE_ACCX
:
357 case TELEMETRY_SOURCE_ACCY
:
358 case TELEMETRY_SOURCE_ACCZ
:
361 result
.max
= singleprec
? 2.55 : 10.00;
362 result
.min
= singleprec
? 0 : -10.00;
363 result
.unit
= QObject::tr("g");
370 if (singleprec
&& result
.offset
==-DBL_MAX
) {
371 result
.offset
= result
.max
- (127*result
.step
);
374 if (flags
& (RANGE_DELTA_FUNCTION
|RANGE_DELTA_ABS_FUNCTION
)) {
377 result
.min
= result
.step
* -127;
378 result
.max
= result
.step
* 127;
381 result
.min
= -result
.max
;
387 case SOURCE_TYPE_GVAR
:
389 result
.min
= -result
.max
;
392 case SOURCE_TYPE_SPECIAL
:
393 if (index
== 0) { //Batt
397 result
.unit
= QObject::tr("V");
399 else if (index
== 1) { //Time
401 result
.max
= 24*60 - 1;
402 result
.unit
= QObject::tr("h:m");
404 else { // Timers 1 - 3
405 result
.step
= singleprec
? 5 : 1;
406 result
.max
= singleprec
? 255*5 : 60*60;
407 result
.unit
= singleprec
? QObject::tr("m:s") : QObject::tr("h:m:s");
413 result
.max
= model
->getChannelsMax(true);
414 result
.min
= -result
.max
;
419 if (flags
& RANGE_DELTA_ABS_FUNCTION
) {
426 QString
AnalogString(int index
)
428 static const QString sticks
[] = { QObject::tr("Rud"), QObject::tr("Ele"), QObject::tr("Thr"), QObject::tr("Ail") };
429 static const QString pots9X
[] = { QObject::tr("P1"), QObject::tr("P2"), QObject::tr("P3") };
430 static const QString potsTaranisX9E
[] = { QObject::tr("F1"), QObject::tr("F2"), QObject::tr("F3"), QObject::tr("F4"), QObject::tr("S1"), QObject::tr("S2"), QObject::tr("LS"), QObject::tr("RS") };
431 static const QString potsTaranis
[] = { QObject::tr("S1"), QObject::tr("S2"), QObject::tr("S3"), QObject::tr("LS"), QObject::tr("RS") };
433 return CHECK_IN_ARRAY(sticks
, index
);
434 else if (IS_TARANIS_X9E(GetEepromInterface()->getBoard()))
435 return CHECK_IN_ARRAY(potsTaranisX9E
, index
-4);
436 else if (IS_TARANIS(GetEepromInterface()->getBoard()))
437 return CHECK_IN_ARRAY(potsTaranis
, index
-4);
439 return CHECK_IN_ARRAY(pots9X
, index
-4);
442 QString
RotaryEncoderString(int index
)
444 static const QString rotary
[] = { QObject::tr("REa"), QObject::tr("REb") };
445 return CHECK_IN_ARRAY(rotary
, index
);
448 QString
RawSource::toString(const ModelData
* model
) const
450 static const QString trims
[] = {
451 QObject::tr("TrmR"), QObject::tr("TrmE"), QObject::tr("TrmT"), QObject::tr("TrmA")
454 static const QString special
[] = {
455 QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
458 static const QString telemetry
[] = {
459 QObject::tr("Batt"), QObject::tr("Time"), QObject::tr("Timer1"), QObject::tr("Timer2"), QObject::tr("Timer3"),
460 QObject::tr("SWR"), QObject::tr("RSSI Tx"), QObject::tr("RSSI Rx"),
461 QObject::tr("A1"), QObject::tr("A2"), QObject::tr("A3"), QObject::tr("A4"),
462 QObject::tr("Alt"), QObject::tr("Rpm"), QObject::tr("Fuel"), QObject::tr("T1"), QObject::tr("T2"),
463 QObject::tr("Speed"), QObject::tr("Dist"), QObject::tr("GPS Alt"),
464 QObject::tr("Cell"), QObject::tr("Cells"), QObject::tr("Vfas"), QObject::tr("Curr"), QObject::tr("Cnsp"), QObject::tr("Powr"),
465 QObject::tr("AccX"), QObject::tr("AccY"), QObject::tr("AccZ"),
466 QObject::tr("Hdg "), QObject::tr("VSpd"), QObject::tr("AirSpeed"), QObject::tr("dTE"),
467 QObject::tr("A1-"), QObject::tr("A2-"), QObject::tr("A3-"), QObject::tr("A4-"),
468 QObject::tr("Alt-"), QObject::tr("Alt+"), QObject::tr("Rpm+"), QObject::tr("T1+"), QObject::tr("T2+"), QObject::tr("Speed+"), QObject::tr("Dist+"), QObject::tr("AirSpeed+"),
469 QObject::tr("Cell-"), QObject::tr("Cells-"), QObject::tr("Vfas-"), QObject::tr("Curr+"), QObject::tr("Powr+"),
470 QObject::tr("ACC"), QObject::tr("GPS Time"),
474 return QObject::tr("----");
478 case SOURCE_TYPE_VIRTUAL_INPUT
:
480 QString result
= QObject::tr("[I%1]").arg(index
+1);
481 if (model
&& strlen(model
->inputNames
[index
]) > 0) {
482 result
+= QString(model
->inputNames
[index
]);
486 case SOURCE_TYPE_LUA_OUTPUT
:
487 return QObject::tr("LUA%1%2").arg(index
/16+1).arg(QChar('a'+index
%16));
488 case SOURCE_TYPE_STICK
:
489 return AnalogString(index
);
490 case SOURCE_TYPE_TRIM
:
491 return CHECK_IN_ARRAY(trims
, index
);
492 case SOURCE_TYPE_ROTARY_ENCODER
:
493 return RotaryEncoderString(index
);
494 case SOURCE_TYPE_MAX
:
495 return QObject::tr("MAX");
496 case SOURCE_TYPE_SWITCH
:
497 return GetCurrentFirmware()->getSwitch(index
).name
;
498 case SOURCE_TYPE_CUSTOM_SWITCH
:
499 return QObject::tr("L%1").arg(index
+1);
500 case SOURCE_TYPE_CYC
:
501 return QObject::tr("CYC%1").arg(index
+1);
502 case SOURCE_TYPE_PPM
:
503 return QObject::tr("TR%1").arg(index
+1);
505 return QObject::tr("CH%1").arg(index
+1);
506 case SOURCE_TYPE_SPECIAL
:
507 return CHECK_IN_ARRAY(special
, index
);
508 case SOURCE_TYPE_TELEMETRY
:
509 if (IS_ARM(GetEepromInterface()->getBoard())) {
510 div_t qr
= div(index
, 3);
511 QString result
= QString(model
? model
->sensorData
[qr
.quot
].label
: QString("[T%1]").arg(qr
.quot
+1));
512 if (qr
.rem
) result
+= qr
.rem
== 1 ? "-" : "+";
516 return CHECK_IN_ARRAY(telemetry
, index
);
518 case SOURCE_TYPE_GVAR
:
519 return QObject::tr("GV%1").arg(index
+1);
521 return QObject::tr("----");
525 bool RawSource::isPot() const
527 return (type
== SOURCE_TYPE_STICK
&&
528 index
>= NUM_STICKS
&&
529 index
< NUM_STICKS
+GetCurrentFirmware()->getCapability(Pots
));
532 bool RawSource::isSlider() const
534 return (type
== SOURCE_TYPE_STICK
&&
535 index
>= NUM_STICKS
+GetCurrentFirmware()->getCapability(Pots
) &&
536 index
< NUM_STICKS
+GetCurrentFirmware()->getCapability(Pots
)+GetCurrentFirmware()->getCapability(Sliders
));
539 QString
RawSwitch::toString() const
541 static const QString switches9X
[] = {
542 QString("THR"), QString("RUD"), QString("ELE"),
543 QString("ID0"), QString("ID1"), QString("ID2"),
544 QString("AIL"), QString("GEA"), QString("TRN")
547 static const QString flightModes
[] = {
548 QObject::tr("FM0"), QObject::tr("FM1"), QObject::tr("FM2"), QObject::tr("FM3"), QObject::tr("FM4"), QObject::tr("FM5"), QObject::tr("FM6"), QObject::tr("FM7"), QObject::tr("FM8")
551 static const QString multiposPots
[] = {
552 QObject::tr("S11"), QObject::tr("S12"), QObject::tr("S13"), QObject::tr("S14"), QObject::tr("S15"), QObject::tr("S16"),
553 QObject::tr("S21"), QObject::tr("S22"), QObject::tr("S23"), QObject::tr("S24"), QObject::tr("S25"), QObject::tr("S26"),
554 QObject::tr("S31"), QObject::tr("S32"), QObject::tr("S33"), QObject::tr("S34"), QObject::tr("S35"), QObject::tr("S36")
557 static const QString trimsSwitches
[] = {
558 QObject::tr("RudTrim Left"), QObject::tr("RudTrim Right"),
559 QObject::tr("EleTrim Down"), QObject::tr("EleTrim Up"),
560 QObject::tr("ThrTrim Down"), QObject::tr("ThrTrim Up"),
561 QObject::tr("AilTrim Left"), QObject::tr("AilTrim Right")
564 static const QString rotaryEncoders
[] = {
565 QObject::tr("REa"), QObject::tr("REb")
568 static const QString timerModes
[] = {
569 QObject::tr("OFF"), QObject::tr("ON"),
570 QObject::tr("THs"), QObject::tr("TH%"), QObject::tr("THt")
574 return QString("!") + RawSwitch(type
, -index
).toString();
578 case SWITCH_TYPE_SWITCH
:
579 if (IS_TARANIS(GetEepromInterface()->getBoard())) {
580 div_t qr
= div(index
-1, 3);
581 Firmware::Switch sw
= GetCurrentFirmware()->getSwitch(qr
.quot
);
582 const char * positions
[] = { ARROW_UP
, "-", ARROW_DOWN
};
583 return QString(sw
.name
) + QString(positions
[qr
.rem
]);
586 return CHECK_IN_ARRAY(switches9X
, index
- 1);
588 case SWITCH_TYPE_VIRTUAL
:
589 return QObject::tr("L%1").arg(index
);
590 case SWITCH_TYPE_MULTIPOS_POT
:
591 return CHECK_IN_ARRAY(multiposPots
, index
-1);
592 case SWITCH_TYPE_TRIM
:
593 return CHECK_IN_ARRAY(trimsSwitches
, index
-1);
594 case SWITCH_TYPE_ROTARY_ENCODER
:
595 return CHECK_IN_ARRAY(rotaryEncoders
, index
-1);
597 return QObject::tr("ON");
598 case SWITCH_TYPE_OFF
:
599 return QObject::tr("OFF");
600 case SWITCH_TYPE_ONE
:
601 return QObject::tr("One");
602 case SWITCH_TYPE_FLIGHT_MODE
:
603 return CHECK_IN_ARRAY(flightModes
, index
-1);
604 case SWITCH_TYPE_NONE
:
605 return QObject::tr("----");
606 case SWITCH_TYPE_TIMER_MODE
:
607 return CHECK_IN_ARRAY(timerModes
, index
);
609 return QObject::tr("???");
614 QString
CurveReference::toString() const
622 return QObject::tr("Diff(%1)").arg(getGVarString(value
));
624 return QObject::tr("Expo(%1)").arg(getGVarString(value
));
626 return QObject::tr("Function(%1)").arg(QString("x>0" "x<0" "|x|" "f>0" "f<0" "|f|").mid(3*(value
-1), 3));
628 return QString(value
> 0 ? QObject::tr("Curve(%1)") : QObject::tr("!Curve(%1)")).arg(abs(value
));
633 CSFunctionFamily
LogicalSwitchData::getFunctionFamily() const
635 if (func
== LS_FN_EDGE
)
636 return LS_FAMILY_EDGE
;
637 else if (func
== LS_FN_TIMER
)
638 return LS_FAMILY_TIMER
;
639 else if (func
== LS_FN_STICKY
)
640 return LS_FAMILY_STICKY
;
641 else if (func
< LS_FN_AND
|| func
> LS_FN_ELESS
)
642 return LS_FAMILY_VOFS
;
643 else if (func
< LS_FN_EQUAL
)
644 return LS_FAMILY_VBOOL
;
646 return LS_FAMILY_VCOMP
;
649 unsigned int LogicalSwitchData::getRangeFlags() const
651 if (func
== LS_FN_DPOS
)
652 return RANGE_DELTA_FUNCTION
;
653 else if (func
== LS_FN_DAPOS
)
654 return RANGE_DELTA_ABS_FUNCTION
;
659 QString
LogicalSwitchData::funcToString() const
663 return QObject::tr("---");
665 return QObject::tr("a>x");
667 return QObject::tr("a<x");
669 return QObject::tr("|a|>x");
671 return QObject::tr("|a|<x");
673 return QObject::tr("AND");
675 return QObject::tr("OR");
677 return QObject::tr("XOR");
679 return QObject::tr("a=b");
681 return QObject::tr("a!=b");
683 return QObject::tr("a>b");
685 return QObject::tr("a<b");
687 return QObject::tr("a>=b");
689 return QObject::tr("a<=b");
691 return QObject::tr("d>=x");
693 return QObject::tr("|d|>=x");
695 return QObject::tr("a=x");
696 case LS_FN_VALMOSTEQUAL
:
697 return QObject::tr("a~x");
699 return QObject::tr("Timer");
701 return QObject::tr("Sticky");
703 return QObject::tr("Edge");
705 return QObject::tr("Unknown");
709 void CustomFunctionData::clear()
711 memset(this, 0, sizeof(CustomFunctionData
));
712 if (!GetCurrentFirmware()->getCapability(SafetyChannelCustomFunction
)) {
717 QString
CustomFunctionData::funcToString() const
719 if (func
>= FuncOverrideCH1
&& func
<= FuncOverrideCH32
)
720 return QObject::tr("Override %1").arg(RawSource(SOURCE_TYPE_CH
, func
).toString());
721 else if (func
== FuncTrainer
)
722 return QObject::tr("Trainer");
723 else if (func
== FuncTrainerRUD
)
724 return QObject::tr("Trainer RUD");
725 else if (func
== FuncTrainerELE
)
726 return QObject::tr("Trainer ELE");
727 else if (func
== FuncTrainerTHR
)
728 return QObject::tr("Trainer THR");
729 else if (func
== FuncTrainerAIL
)
730 return QObject::tr("Trainer AIL");
731 else if (func
== FuncInstantTrim
)
732 return QObject::tr("Instant Trim");
733 else if (func
== FuncPlaySound
)
734 return QObject::tr("Play Sound");
735 else if (func
== FuncPlayHaptic
)
736 return QObject::tr("Haptic");
737 else if (func
== FuncReset
)
738 return QObject::tr("Reset");
739 else if (func
>= FuncSetTimer1
&& func
<= FuncSetTimer3
)
740 return QObject::tr("Set Timer %1").arg(func
-FuncSetTimer1
+1);
741 else if (func
== FuncVario
)
742 return QObject::tr("Vario");
743 else if (func
== FuncPlayPrompt
)
744 return QObject::tr("Play Track");
745 else if (func
== FuncPlayBoth
)
746 return QObject::tr("Play Both");
747 else if (func
== FuncPlayValue
)
748 return QObject::tr("Play Value");
749 else if (func
== FuncPlayScript
)
750 return QObject::tr("Play Script");
751 else if (func
== FuncLogs
)
752 return QObject::tr("SD Logs");
753 else if (func
== FuncVolume
)
754 return QObject::tr("Volume");
755 else if (func
== FuncBacklight
)
756 return QObject::tr("Backlight");
757 else if (func
== FuncScreenshot
)
758 return QObject::tr("Screenshot");
759 else if (func
== FuncBackgroundMusic
)
760 return QObject::tr("Background Music");
761 else if (func
== FuncBackgroundMusicPause
)
762 return QObject::tr("Background Music Pause");
763 else if (func
>= FuncAdjustGV1
&& func
<= FuncAdjustGVLast
)
764 return QObject::tr("Adjust GV%1").arg(func
-FuncAdjustGV1
+1);
765 else if (func
== FuncSetFailsafeInternalModule
)
766 return QObject::tr("SetFailsafe Int. Module");
767 else if (func
== FuncSetFailsafeExternalModule
)
768 return QObject::tr("SetFailsafe Ext. Module");
769 else if (func
== FuncRangeCheckInternalModule
)
770 return QObject::tr("RangeCheck Int. Module");
771 else if (func
== FuncRangeCheckExternalModule
)
772 return QObject::tr("RangeCheck Ext. Module");
773 else if (func
== FuncBindInternalModule
)
774 return QObject::tr("Bind Int. Module");
775 else if (func
== FuncBindExternalModule
)
776 return QObject::tr("Bind Ext. Module");
778 return QString("???"); // Highlight unknown functions with output of question marks.(BTW should not happen that we do not know what a function is)
782 void CustomFunctionData::populateResetParams(const ModelData
* model
, QComboBox
* b
, unsigned int value
= 0)
785 Firmware
* firmware
= GetCurrentFirmware();
786 BoardEnum board
= GetEepromInterface()->getBoard();
788 b
->addItem(QObject::tr("Timer1"), val
++);
789 b
->addItem(QObject::tr("Timer2"), val
++);
791 b
->addItem( QObject::tr("Timer3"), val
++);
793 b
->addItem(QObject::tr("Flight"), val
++);
794 b
->addItem(QObject::tr("Telemetry"), val
++);
795 int reCount
= firmware
->getCapability(RotaryEncoders
);
797 b
->addItem(QObject::tr("Rotary Encoder"), val
++);
799 else if (reCount
== 2) {
800 b
->addItem(QObject::tr("REa"), val
++);
801 b
->addItem(QObject::tr("REb"), val
++);
803 if ((int)value
< b
->count()) {
804 b
->setCurrentIndex(value
);
806 if (model
&& IS_ARM(board
)) {
807 for (int i
=0; i
<C9X_MAX_SENSORS
; ++i
) {
808 if (model
->sensorData
[i
].isAvailable()) {
809 RawSource item
= RawSource(SOURCE_TYPE_TELEMETRY
, 3*i
);
810 b
->addItem(item
.toString(model
), val
+i
);
811 if ((int)value
== val
+i
) {
812 b
->setCurrentIndex(b
->count()-1);
819 void CustomFunctionData::populatePlaySoundParams(QStringList
& qs
)
821 qs
<<"Beep 1" << "Beep 2" << "Beep 3" << "Warn1" << "Warn2" << "Cheep" << "Ratata" << "Tick" << "Siren" << "Ring" ;
822 qs
<< "SciFi" << "Robot" << "Chirp" << "Tada" << "Crickt" << "AlmClk" ;
825 void CustomFunctionData::populateHapticParams(QStringList
& qs
)
827 qs
<< "0" << "1" << "2" << "3";
830 QString
CustomFunctionData::paramToString(const ModelData
* model
) const
833 if (func
<= FuncInstantTrim
) {
834 return QString("%1").arg(param
);
836 else if (func
==FuncLogs
) {
837 return QString("%1").arg(param
/10.0) + QObject::tr("s");
839 else if (func
==FuncPlaySound
) {
840 CustomFunctionData::populatePlaySoundParams(qs
);
841 if (param
>=0 && param
<(int)qs
.count())
844 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
846 else if (func
==FuncPlayHaptic
) {
847 CustomFunctionData::populateHapticParams(qs
);
848 if (param
>=0 && param
<(int)qs
.count())
851 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
853 else if (func
==FuncReset
) {
855 CustomFunctionData::populateResetParams(model
, &cb
);
856 int pos
= cb
.findData(param
);
858 return cb
.itemText(pos
);
860 return QObject::tr("<font color=red><b>Inconsistent parameter</b></font>");
862 else if ((func
==FuncVolume
)|| (func
==FuncPlayValue
)) {
863 RawSource
item(param
);
864 return item
.toString(model
);
866 else if ((func
==FuncPlayPrompt
) || (func
==FuncPlayBoth
)) {
867 if ( GetCurrentFirmware()->getCapability(VoicesAsNumbers
)) {
868 return QString("%1").arg(param
);
874 else if ((func
>=FuncAdjustGV1
) && (func
<FuncCount
)) {
875 switch (adjustMode
) {
876 case FUNC_ADJUST_GVAR_CONSTANT
:
877 return QObject::tr("Value ")+QString("%1").arg(param
);
878 case FUNC_ADJUST_GVAR_SOURCE
:
879 case FUNC_ADJUST_GVAR_GVAR
:
880 return RawSource(param
).toString();
881 case FUNC_ADJUST_GVAR_INCDEC
:
882 if (param
==0) return QObject::tr("Decr:") + " -1";
883 else return QObject::tr("Incr:") + " +1";
889 QString
CustomFunctionData::repeatToString() const
891 if (repeatParam
== -1) {
892 return QObject::tr("played once, not during startup");
894 else if (repeatParam
== 0) {
898 unsigned int step
= IS_ARM(GetEepromInterface()->getBoard()) ? 1 : 10;
899 return QObject::tr("repeat(%1s)").arg(step
*repeatParam
);
903 QString
CustomFunctionData::enabledToString() const
905 if ((func
>=FuncOverrideCH1
&& func
<=FuncOverrideCH32
) ||
906 (func
>=FuncAdjustGV1
&& func
<=FuncAdjustGVLast
) ||
908 (func
>=FuncSetTimer1
&& func
<=FuncSetTimer2
) ||
909 (func
==FuncVolume
) ||
910 (func
<= FuncInstantTrim
)) {
912 return QObject::tr("DISABLED");
918 CurveData::CurveData()
923 void CurveData::clear(int count
)
925 memset(this, 0, sizeof(CurveData
));
929 bool CurveData::isEmpty() const
931 for (int i
=0; i
<count
; i
++) {
932 if (points
[i
].y
!= 0) {
939 QString
LimitData::minToString() const
941 return QString::number((qreal
)min
/10);
944 QString
LimitData::maxToString() const
946 return QString::number((qreal
)max
/10);
949 QString
LimitData::revertToString() const
951 return revert
? QObject::tr("INV") : QObject::tr("NOR");
954 QString
LimitData::offsetToString() const
956 return QString::number((qreal
)offset
/10, 'f', 1);
959 void LimitData::clear()
961 memset(this, 0, sizeof(LimitData
));
966 GeneralSettings::SwitchInfo
GeneralSettings::switchInfoFromSwitchPositionTaranis(unsigned int index
)
968 return SwitchInfo((index
-1)/3, (index
-1)%3);
971 bool GeneralSettings::switchPositionAllowedTaranis(int index
) const
975 SwitchInfo info
= switchInfoFromSwitchPositionTaranis(abs(index
));
976 if (index
< 0 && switchConfig
[info
.index
] != Firmware::SWITCH_3POS
)
978 else if (info
.position
== 1)
979 return switchConfig
[info
.index
] == Firmware::SWITCH_3POS
;
981 return switchConfig
[info
.index
] != Firmware::SWITCH_NONE
;
984 bool GeneralSettings::switchSourceAllowedTaranis(int index
) const
986 return switchConfig
[index
] != Firmware::SWITCH_NONE
;
989 bool GeneralSettings::isPotAvailable(int index
) const
991 if (index
<0 || index
>GetCurrentFirmware()->getCapability(Pots
)) return false;
992 return potConfig
[index
] != POT_NONE
;
995 bool GeneralSettings::isSliderAvailable(int index
) const
997 if (index
<0 || index
>GetCurrentFirmware()->getCapability(Sliders
)) return false;
998 return sliderConfig
[index
] != SLIDER_NONE
;
1001 GeneralSettings::GeneralSettings()
1003 memset(this, 0, sizeof(GeneralSettings
));
1008 for (int i
=0; i
<NUM_STICKS
+C9X_NUM_POTS
; ++i
) {
1009 calibMid
[i
] = 0x200;
1010 calibSpanNeg
[i
] = 0x180;
1011 calibSpanPos
[i
] = 0x180;
1014 for (int i
=0; i
<GetCurrentFirmware()->getCapability(Switches
); i
++) {
1015 switchConfig
[i
] = GetCurrentFirmware()->getSwitch(i
).type
;
1018 BoardEnum board
= GetEepromInterface()->getBoard();
1019 if (IS_TARANIS(board
)) {
1020 potConfig
[0] = POT_WITH_DETENT
;
1021 potConfig
[1] = POT_WITH_DETENT
;
1022 sliderConfig
[0] = SLIDER_WITH_DETENT
;
1023 sliderConfig
[1] = SLIDER_WITH_DETENT
;
1026 for (int i
=0; i
<3; i
++) {
1027 potConfig
[i
] = POT_WITHOUT_DETENT
;
1031 if (IS_ARM(board
)) {
1035 if (IS_TARANIS_X9E(board
)) {
1036 strcpy(bluetoothName
, "Taranis");
1039 templateSetup
= g
.profile
[g
.id()].channelOrder();
1040 stickMode
= g
.profile
[g
.id()].defaultMode();
1042 QString t_calib
=g
.profile
[g
.id()].stickPotCalib();
1043 int potsnum
=GetCurrentFirmware()->getCapability(Pots
);
1044 if (t_calib
.isEmpty()) {
1048 QString t_trainercalib
=g
.profile
[g
.id()].trainerCalib();
1049 int8_t t_txVoltageCalibration
=(int8_t)g
.profile
[g
.id()].txVoltageCalibration();
1050 int8_t t_txCurrentCalibration
=(int8_t)g
.profile
[g
.id()].txCurrentCalibration();
1051 int8_t t_PPM_Multiplier
=(int8_t)g
.profile
[g
.id()].ppmMultiplier();
1052 uint8_t t_stickMode
=(uint8_t)g
.profile
[g
.id()].gsStickMode();
1053 uint8_t t_vBatWarn
=(uint8_t)g
.profile
[g
.id()].vBatWarn();
1054 QString t_DisplaySet
=g
.profile
[g
.id()].display();
1055 QString t_BeeperSet
=g
.profile
[g
.id()].beeper();
1056 QString t_HapticSet
=g
.profile
[g
.id()].haptic();
1057 QString t_SpeakerSet
=g
.profile
[g
.id()].speaker();
1058 QString t_CountrySet
=g
.profile
[g
.id()].countryCode();
1060 if ((t_calib
.length()==(NUM_STICKS
+potsnum
)*12) && (t_trainercalib
.length()==16)) {
1064 for (int i
=0; i
<(NUM_STICKS
+potsnum
); i
++) {
1065 Byte
=t_calib
.mid(i
*12,4);
1066 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1069 Byte
=t_calib
.mid(4+i
*12,4);
1070 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1072 calibSpanNeg
[i
]=byte16
;
1073 Byte
=t_calib
.mid(8+i
*12,4);
1074 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1076 calibSpanPos
[i
]=byte16
;
1078 for (int i
=0; i
<4; i
++) {
1079 Byte
=t_trainercalib
.mid(i
*4,4);
1080 byte16
=(int16_t)Byte
.toInt(&ok
,16);
1082 trainer
.calib
[i
]=byte16
;
1084 txCurrentCalibration
=t_txCurrentCalibration
;
1085 txVoltageCalibration
=t_txVoltageCalibration
;
1086 vBatWarn
=t_vBatWarn
;
1087 PPM_Multiplier
=t_PPM_Multiplier
;
1088 stickMode
= t_stickMode
;
1090 if ((t_DisplaySet
.length()==6) && (t_BeeperSet
.length()==4) && (t_HapticSet
.length()==6) && (t_SpeakerSet
.length()==6)) {
1094 byte8
=(int8_t)t_DisplaySet
.mid(0,2).toInt(&ok
,16);
1096 optrexDisplay
=(byte8
==1 ? true : false);
1097 byte8u
=(uint8_t)t_DisplaySet
.mid(2,2).toUInt(&ok
,16);
1100 byte8u
=(uint8_t)t_DisplaySet
.mid(4,2).toUInt(&ok
,16);
1102 backlightBright
=byte8u
;
1103 byte8
=(int8_t)t_BeeperSet
.mid(0,2).toUInt(&ok
,16);
1105 beeperMode
=(BeeperMode
)byte8
;
1106 byte8
=(int8_t)t_BeeperSet
.mid(2,2).toInt(&ok
,16);
1109 byte8
=(int8_t)t_HapticSet
.mid(0,2).toUInt(&ok
,16);
1111 hapticMode
=(BeeperMode
)byte8
;
1112 byte8
=(int8_t)t_HapticSet
.mid(2,2).toInt(&ok
,16);
1114 hapticStrength
=byte8
;
1115 byte8
=(int8_t)t_HapticSet
.mid(4,2).toInt(&ok
,16);
1118 byte8u
=(uint8_t)t_SpeakerSet
.mid(0,2).toUInt(&ok
,16);
1121 byte8u
=(uint8_t)t_SpeakerSet
.mid(2,2).toUInt(&ok
,16);
1123 speakerPitch
=byte8u
;
1124 byte8u
=(uint8_t)t_SpeakerSet
.mid(4,2).toUInt(&ok
,16);
1126 speakerVolume
=byte8u
;
1127 if (t_CountrySet
.length()==6) {
1128 byte8u
=(uint8_t)t_CountrySet
.mid(0,2).toUInt(&ok
,16);
1131 byte8u
=(uint8_t)t_CountrySet
.mid(2,2).toUInt(&ok
,16);
1134 QString chars
= t_CountrySet
.mid(4, 2);
1135 ttsLanguage
[0] = chars
[0].toLatin1();
1136 ttsLanguage
[1] = chars
[1].toLatin1();
1142 int GeneralSettings::getDefaultStick(unsigned int channel
) const
1144 if (channel
>= NUM_STICKS
)
1147 return chout_ar
[4*templateSetup
+ channel
] - 1;
1150 RawSource
GeneralSettings::getDefaultSource(unsigned int channel
) const
1152 int stick
= getDefaultStick(channel
);
1154 return RawSource(SOURCE_TYPE_STICK
, stick
);
1156 return RawSource(SOURCE_TYPE_NONE
);
1159 int GeneralSettings::getDefaultChannel(unsigned int stick
) const
1161 for (int i
=0; i
<4; i
++){
1162 if (getDefaultStick(i
) == (int)stick
)
1168 float FrSkyChannelData::getRatio() const
1170 if (type
==0 || type
==1 || type
==2)
1171 return float(ratio
<< multiplier
) / 10.0;
1173 return ratio
<< multiplier
;
1176 RawSourceRange
FrSkyChannelData::getRange() const
1178 RawSourceRange result
;
1179 float ratio
= getRatio();
1180 if (type
==0 || type
==1 || type
==2)
1181 result
.decimals
= 2;
1183 result
.decimals
= 0;
1184 result
.step
= ratio
/ 255;
1185 result
.min
= offset
* result
.step
;
1186 result
.max
= ratio
+ result
.min
;
1187 result
.unit
= QObject::tr("V");
1191 void FrSkyScreenData::clear()
1193 memset(this, 0, sizeof(FrSkyScreenData
));
1194 if (!IS_ARM(GetCurrentFirmware()->getBoard())) {
1195 type
= TELEMETRY_SCREEN_NUMBERS
;
1199 void FrSkyData::clear()
1206 varioCenterMin
= 0; // if increment in 0.2m/s = 3.0m/s max
1212 rssiAlarms
[0].clear(2, 45);
1213 rssiAlarms
[1].clear(3, 42);
1214 for (int i
=0; i
<4; i
++)
1216 varioSource
= 2/*VARIO*/;
1220 ModelData::ModelData()
1225 ModelData::ModelData(const ModelData
& src
)
1230 ModelData
& ModelData::operator = (const ModelData
& src
)
1232 memcpy(this, &src
, sizeof(ModelData
));
1236 ExpoData
* ModelData::insertInput(const int idx
)
1238 memmove(&expoData
[idx
+1], &expoData
[idx
], (C9X_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
1239 expoData
[idx
].clear();
1240 return &expoData
[idx
];
1243 bool ModelData::isInputValid(const unsigned int idx
) const
1245 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++) {
1246 const ExpoData
* expo
= &expoData
[i
];
1247 if (expo
->mode
== 0) break;
1248 if (expo
->chn
== idx
)
1254 bool ModelData::hasExpos(uint8_t inputIdx
) const
1256 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++) {
1257 const ExpoData
& expo
= expoData
[i
];
1258 if (expo
.chn
==inputIdx
&& expo
.mode
!=0) {
1265 bool ModelData::hasMixes(uint8_t channelIdx
) const
1268 for (int i
=0; i
<C9X_MAX_MIXERS
; i
++) {
1269 if (mixData
[i
].destCh
== channelIdx
) {
1276 QVector
<const ExpoData
*> ModelData::expos(int input
) const
1278 QVector
<const ExpoData
*> result
;
1279 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++) {
1280 const ExpoData
* ed
= &expoData
[i
];
1281 if ((int)ed
->chn
==input
&& ed
->mode
!=0) {
1288 QVector
<const MixData
*> ModelData::mixes(int channel
) const
1290 QVector
<const MixData
*> result
;
1291 for (int i
=0; i
<C9X_MAX_MIXERS
; i
++) {
1292 const MixData
* md
= &mixData
[i
];
1293 if ((int)md
->destCh
== channel
+1) {
1300 void ModelData::removeInput(const int idx
)
1302 unsigned int chn
= expoData
[idx
].chn
;
1304 memmove(&expoData
[idx
], &expoData
[idx
+1], (C9X_MAX_EXPOS
-(idx
+1))*sizeof(ExpoData
));
1305 expoData
[C9X_MAX_EXPOS
-1].clear();
1307 //also remove input name if removing last line for this input
1309 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++) {
1310 if (expoData
[i
].mode
==0) continue;
1311 if (expoData
[i
].chn
==chn
) {
1316 if (!found
) inputNames
[chn
][0] = 0;
1319 void ModelData::clearInputs()
1321 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++)
1322 expoData
[i
].clear();
1324 //clear all input names
1325 if (GetCurrentFirmware()->getCapability(VirtualInputs
)) {
1326 for (int i
=0; i
<C9X_MAX_INPUTS
; i
++) {
1327 inputNames
[i
][0] = 0;
1332 void ModelData::clearMixes()
1334 for (int i
=0; i
<C9X_MAX_MIXERS
; i
++)
1338 void ModelData::clear()
1340 memset(this, 0, sizeof(ModelData
));
1341 moduleData
[0].channelsCount
= 8;
1342 moduleData
[1].channelsStart
= 0;
1343 moduleData
[1].channelsCount
= 8;
1344 moduleData
[0].ppm
.delay
= 300;
1345 moduleData
[1].ppm
.delay
= 300;
1346 moduleData
[2].ppm
.delay
= 300;
1347 int board
= GetEepromInterface()->getBoard();
1348 if (IS_TARANIS(board
)) {
1349 moduleData
[0].protocol
= PULSES_PXX_XJT_X16
;
1350 moduleData
[1].protocol
= PULSES_OFF
;
1352 else if (IS_SKY9X(board
)) {
1353 moduleData
[0].protocol
= PULSES_PPM
;
1354 moduleData
[1].protocol
= PULSES_PPM
;
1357 moduleData
[0].protocol
= PULSES_PPM
;
1358 moduleData
[1].protocol
= PULSES_OFF
;
1360 for (int i
=0; i
<C9X_MAX_FLIGHT_MODES
; i
++) {
1361 flightModeData
[i
].clear(i
);
1365 for (int i
=0; i
<C9X_NUM_CHNOUT
; i
++)
1366 limitData
[i
].clear();
1367 for (int i
=0; i
<NUM_STICKS
; i
++)
1368 expoData
[i
].clear();
1369 for (int i
=0; i
<C9X_NUM_CSW
; i
++)
1370 logicalSw
[i
].clear();
1371 for (int i
=0; i
<C9X_MAX_CUSTOM_FUNCTIONS
; i
++)
1372 customFn
[i
].clear();
1373 for (int i
=0; i
<C9X_MAX_CURVES
; i
++)
1375 for (int i
=0; i
<C9X_MAX_TIMERS
; i
++)
1377 swashRingData
.clear();
1379 for (int i
=0; i
<C9X_MAX_SENSORS
; i
++)
1380 sensorData
[i
].clear();
1383 bool ModelData::isEmpty() const
1388 QString
removeAccents(const QString
& str
)
1390 QString result
= str
;
1392 // UTF-8 ASCII Table
1393 const QString tA
[] = { "á", "â", "ã", "à", "ä" };
1394 const QString tE
[] = { "é", "è", "ê", "ě" };
1395 const QString tI
[] = { "í" };
1396 const QString tO
[] = { "ó", "ô", "õ", "ö" };
1397 const QString tU
[] = { "ú", "ü" };
1398 const QString tC
[] = { "ç" };
1399 const QString tY
[] = { "ý" };
1400 const QString tS
[] = { "š" };
1401 const QString tR
[] = { "ř" };
1403 for (unsigned int i
= 0; i
< DIM(tA
); i
++) result
.replace(tA
[i
], "a");
1404 for (unsigned int i
= 0; i
< DIM(tE
); i
++) result
.replace(tE
[i
], "e");
1405 for (unsigned int i
= 0; i
< DIM(tI
); i
++) result
.replace(tI
[i
], "i");
1406 for (unsigned int i
= 0; i
< DIM(tO
); i
++) result
.replace(tO
[i
], "o");
1407 for (unsigned int i
= 0; i
< DIM(tU
); i
++) result
.replace(tU
[i
], "u");
1408 for (unsigned int i
= 0; i
< DIM(tC
); i
++) result
.replace(tC
[i
], "c");
1409 for (unsigned int i
= 0; i
< DIM(tY
); i
++) result
.replace(tY
[i
], "y");
1410 for (unsigned int i
= 0; i
< DIM(tS
); i
++) result
.replace(tS
[i
], "s");
1411 for (unsigned int i
= 0; i
< DIM(tR
); i
++) result
.replace(tR
[i
], "r");
1416 void ModelData::setDefaultInputs(const GeneralSettings
& settings
)
1418 if (IS_TARANIS(GetEepromInterface()->getBoard())) {
1419 for (int i
=0; i
<NUM_STICKS
; i
++) {
1420 ExpoData
* expo
= &expoData
[i
];
1422 expo
->mode
= INPUT_MODE_BOTH
;
1423 expo
->srcRaw
= settings
.getDefaultSource(i
);
1425 strncpy(inputNames
[i
], removeAccents(expo
->srcRaw
.toString(this)).toLatin1().constData(), sizeof(inputNames
[i
])-1);
1430 void ModelData::setDefaultMixes(const GeneralSettings
& settings
)
1432 if (IS_TARANIS(GetEepromInterface()->getBoard())) {
1433 setDefaultInputs(settings
);
1436 for (int i
=0; i
<NUM_STICKS
; i
++) {
1437 MixData
* mix
= &mixData
[i
];
1440 if (IS_TARANIS(GetEepromInterface()->getBoard())) {
1441 mix
->srcRaw
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
1444 mix
->srcRaw
= RawSource(SOURCE_TYPE_STICK
, i
);
1449 void ModelData::setDefaultValues(unsigned int id
, const GeneralSettings
& settings
)
1453 sprintf(name
, "MODEL%02d", id
+1);
1454 for (int i
=0; i
<C9X_NUM_MODULES
; i
++) {
1455 moduleData
[i
].modelId
= id
+1;
1457 setDefaultMixes(settings
);
1460 int ModelData::getTrimValue(int phaseIdx
, int trimIdx
)
1463 for (int i
=0; i
<C9X_MAX_FLIGHT_MODES
; i
++) {
1464 FlightModeData
& phase
= flightModeData
[phaseIdx
];
1465 if (phase
.trimMode
[trimIdx
] < 0) {
1469 if (phase
.trimRef
[trimIdx
] == phaseIdx
|| phaseIdx
== 0) {
1470 return result
+ phase
.trim
[trimIdx
];
1473 phaseIdx
= phase
.trimRef
[trimIdx
];
1474 if (phase
.trimMode
[trimIdx
] != 0)
1475 result
+= phase
.trim
[trimIdx
];
1482 bool ModelData::isGVarLinked(int phaseIdx
, int gvarIdx
)
1484 return flightModeData
[phaseIdx
].gvars
[gvarIdx
] > 1024;
1487 int ModelData::getGVarFieldValue(int phaseIdx
, int gvarIdx
)
1489 int idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
1490 for (int i
=0; idx
>1024 && i
<C9X_MAX_FLIGHT_MODES
; i
++) {
1491 int nextPhase
= idx
- 1025;
1492 if (nextPhase
>= phaseIdx
) nextPhase
+= 1;
1493 phaseIdx
= nextPhase
;
1494 idx
= flightModeData
[phaseIdx
].gvars
[gvarIdx
];
1499 void ModelData::setTrimValue(int phaseIdx
, int trimIdx
, int value
)
1501 for (uint8_t i
=0; i
<C9X_MAX_FLIGHT_MODES
; i
++) {
1502 FlightModeData
& phase
= flightModeData
[phaseIdx
];
1503 int mode
= phase
.trimMode
[trimIdx
];
1504 int p
= phase
.trimRef
[trimIdx
];
1505 int & trim
= phase
.trim
[trimIdx
];
1508 if (p
== phaseIdx
|| phaseIdx
== 0) {
1512 else if (mode
== 0) {
1516 trim
= value
- getTrimValue(p
, trimIdx
);
1526 void ModelData::removeGlobalVar(int & var
)
1528 if (var
>= 126 && var
<= 130)
1529 var
= flightModeData
[0].gvars
[var
-126];
1530 else if (var
<= -126 && var
>= -130)
1531 var
= - flightModeData
[0].gvars
[-126-var
];
1534 ModelData
ModelData::removeGlobalVars()
1536 ModelData result
= *this;
1538 for (int i
=0; i
<C9X_MAX_MIXERS
; i
++) {
1539 removeGlobalVar(mixData
[i
].weight
);
1540 removeGlobalVar(mixData
[i
].curve
.value
);
1541 removeGlobalVar(mixData
[i
].sOffset
);
1544 for (int i
=0; i
<C9X_MAX_EXPOS
; i
++) {
1545 removeGlobalVar(expoData
[i
].weight
);
1546 removeGlobalVar(expoData
[i
].curve
.value
);
1552 int ModelData::getChannelsMax(bool forceExtendedLimits
) const
1554 if (forceExtendedLimits
|| extendedLimits
)
1555 return IS_TARANIS(GetCurrentFirmware()->getBoard()) ? 150 : 125;
1560 QList
<EEPROMInterface
*> eepromInterfaces
;
1561 void registerEEpromInterfaces()
1563 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_STOCK
));
1564 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_M128
));
1565 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_GRUVIN9X
));
1566 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_SKY9X
));
1567 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_9XRPRO
));
1568 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9D
));
1569 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9DP
));
1570 eepromInterfaces
.push_back(new OpenTxEepromInterface(BOARD_TARANIS_X9E
));
1571 eepromInterfaces
.push_back(new Gruvin9xInterface(BOARD_STOCK
));
1572 eepromInterfaces
.push_back(new Gruvin9xInterface(BOARD_GRUVIN9X
));
1573 eepromInterfaces
.push_back(new Ersky9xInterface());
1574 eepromInterfaces
.push_back(new Th9xInterface());
1575 eepromInterfaces
.push_back(new Er9xInterface());
1578 void unregisterEEpromInterfaces()
1580 foreach(EEPROMInterface
* intf
, eepromInterfaces
) {
1581 // qDebug() << "UnregisterEepromInterfaces(): deleting " << QString::number( reinterpret_cast<uint64_t>(intf), 16 );
1584 OpenTxEepromCleanup();
1587 QList
<Firmware
*> firmwares
;
1588 Firmware
* default_firmware_variant
;
1589 Firmware
* current_firmware_variant
;
1591 void ShowEepromErrors(QWidget
*parent
, const QString
&title
, const QString
&mainMessage
, unsigned long errorsFound
)
1593 std::bitset
<NUM_ERRORS
> errors((unsigned long long)errorsFound
);
1594 QStringList errorsList
;
1596 errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "Possible causes for this:");
1598 if (errors
.test(UNSUPPORTED_NEWER_VERSION
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a newer version of OpenTX"); }
1599 if (errors
.test(NOT_OPENTX
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from OpenTX"); }
1600 if (errors
.test(NOT_TH9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Th9X"); }
1601 if (errors
.test(NOT_GRUVIN9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Gruvin9X"); }
1602 if (errors
.test(NOT_ERSKY9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from ErSky9X"); }
1603 if (errors
.test(NOT_ER9X
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is not from Er9X"); }
1604 if (errors
.test(WRONG_SIZE
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom size is invalid"); }
1605 if (errors
.test(WRONG_FILE_SYSTEM
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom file system is invalid"); }
1606 if (errors
.test(UNKNOWN_BOARD
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from a unknown board"); }
1607 if (errors
.test(WRONG_BOARD
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom is from the wrong board"); }
1608 if (errors
.test(BACKUP_NOT_SUPPORTED
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Eeprom backup not supported"); }
1610 if (errors
.test(UNKNOWN_ERROR
)) { errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Something that couldn't be guessed, sorry"); }
1612 if (errors
.test(HAS_WARNINGS
)) {
1613 errorsList
<< QT_TRANSLATE_NOOP("EepromInterface", "Warning:");
1614 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"); }
1617 QMessageBox
msgBox(parent
);
1618 msgBox
.setWindowTitle(title
);
1619 msgBox
.setIcon(QMessageBox::Critical
);
1620 msgBox
.setText(mainMessage
);
1621 msgBox
.setInformativeText(errorsList
.join("\n"));
1622 msgBox
.setStandardButtons(QMessageBox::Ok
);
1626 void ShowEepromWarnings(QWidget
*parent
, const QString
&title
, unsigned long errorsFound
)
1628 std::bitset
<NUM_ERRORS
> errors((unsigned long long)errorsFound
);
1629 QStringList warningsList
;
1630 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"); }
1631 if (errors
.test(OLD_VERSION
)) { warningsList
<< QT_TRANSLATE_NOOP("EepromInterface", "- Your eeprom is from an old version of OpenTX, upgrading!\n You should 'save as' to keep the old file as a backup."); }
1633 QMessageBox
msgBox(parent
);
1634 msgBox
.setWindowTitle(title
);
1635 msgBox
.setIcon(QMessageBox::Warning
);
1636 msgBox
.setText(QT_TRANSLATE_NOOP("EepromInterface", "Warnings!"));
1637 msgBox
.setInformativeText(warningsList
.join("\n"));
1638 msgBox
.setStandardButtons(QMessageBox::Ok
);
1642 unsigned long LoadEeprom(RadioData
&radioData
, const uint8_t *eeprom
, const int size
)
1644 std::bitset
<NUM_ERRORS
> errors
;
1646 foreach(EEPROMInterface
*eepromInterface
, eepromInterfaces
) {
1647 std::bitset
<NUM_ERRORS
> result((unsigned long long)eepromInterface
->load(radioData
, eeprom
, size
));
1648 if (result
.test(ALL_OK
)) {
1649 return result
.to_ulong();
1656 if (errors
.none()) {
1657 errors
.set(UNKNOWN_ERROR
);
1659 return errors
.to_ulong();
1662 unsigned long LoadBackup(RadioData
& radioData
, uint8_t * eeprom
, int size
, int index
)
1664 std::bitset
<NUM_ERRORS
> errors
;
1666 foreach(EEPROMInterface
*eepromInterface
, eepromInterfaces
) {
1667 std::bitset
<NUM_ERRORS
> result((unsigned long long)eepromInterface
->loadBackup(radioData
, eeprom
, size
, index
));
1668 if (result
.test(ALL_OK
)) {
1669 return result
.to_ulong();
1676 if (errors
.none()) {
1677 errors
.set(UNKNOWN_ERROR
);
1679 return errors
.to_ulong();
1683 unsigned long LoadEepromXml(RadioData
& radioData
, QDomDocument
& doc
)
1685 std::bitset
<NUM_ERRORS
> errors
;
1687 foreach(EEPROMInterface
* eepromInterface
, eepromInterfaces
) {
1688 std::bitset
<NUM_ERRORS
> result((unsigned long long)eepromInterface
->loadxml(radioData
, doc
));
1689 if (result
.test(ALL_OK
)) {
1690 return result
.to_ulong();
1697 if (errors
.none()) {
1698 errors
.set(UNKNOWN_ERROR
);
1700 return errors
.to_ulong();
1703 const int Firmware::getFlashSize()
1710 case BOARD_MEGA2560
:
1711 case BOARD_GRUVIN9X
:
1712 return FSIZE_GRUVIN9X
;
1717 return FSIZE_9XRPRO
;
1718 case BOARD_TARANIS_X9D
:
1719 case BOARD_TARANIS_X9DP
:
1720 case BOARD_TARANIS_X9E
:
1721 case BOARD_FLAMENCO
:
1722 return FSIZE_TARANIS
;
1730 Firmware
* GetFirmware(QString id
)
1732 foreach(Firmware
* firmware
, firmwares
) {
1733 Firmware
* result
= firmware
->getFirmwareVariant(id
);
1739 return default_firmware_variant
;
1742 void Firmware::addOption(const char *option
, QString tooltip
, uint32_t variant
)
1744 Option options
[] = { { option
, tooltip
, variant
}, { NULL
} };
1745 addOptions(options
);
1748 unsigned int Firmware::getVariantNumber()
1750 unsigned int result
= 0;
1751 const Firmware
* base
= getFirmwareBase();
1752 QStringList options
= id
.mid(base
->getId().length()+1).split("-", QString::SkipEmptyParts
);
1753 foreach(QString option
, options
) {
1754 foreach(QList
<Option
> group
, base
->opts
) {
1755 foreach(Option opt
, group
) {
1756 if (opt
.name
== option
) {
1757 result
+= opt
.variant
;
1765 void Firmware::addLanguage(const char *lang
)
1767 languages
.push_back(lang
);
1770 void Firmware::addTTSLanguage(const char *lang
)
1772 ttslanguages
.push_back(lang
);
1775 void Firmware::addOptions(Option options
[])
1778 for (int i
=0; options
[i
].name
; i
++) {
1779 opts
.push_back(options
[i
]);
1781 this->opts
.push_back(opts
);
1784 SimulatorInterface
*GetCurrentFirmwareSimulator()
1786 QString firmwareId
= GetCurrentFirmware()->getId();
1787 SimulatorFactory
*factory
= getSimulatorFactory(firmwareId
);
1789 return factory
->create();
1794 unsigned int getNumSubtypes(MultiModuleRFProtocols type
) {
1796 case MM_RF_PROTO_HISKY
:
1797 case MM_RF_PROTO_SYMAX
:
1798 case MM_RF_PROTO_KN
:
1801 case MM_RF_PROTO_CG023
:
1802 case MM_RF_PROTO_MT99XX
:
1805 case MM_RF_PROTO_FRSKY
:
1806 case MM_RF_PROTO_FLYSKY
:
1807 case MM_RF_PROTO_DSM2
:
1808 case MM_RF_PROTO_AFHDS2A
:
1811 case MM_RF_PROTO_MJXQ
:
1812 case MM_RF_PROTO_YD717
:
1815 case MM_RF_PROTO_CX10
:
1823 void FlightModeData::clear(const int phase
)
1825 memset(this, 0, sizeof(FlightModeData
));
1827 for (int idx
=0; idx
<C9X_MAX_GVARS
; idx
++) {
1830 for (int idx
=0; idx
<C9X_MAX_ENCODERS
; idx
++) {
1831 rotaryEncoders
[idx
] = 1025;