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.
25 #elif defined __GNUC__
28 #if defined(WIN32) && defined(WIN_USE_CONSOLE_STDIO)
34 #include "simulatordialog.h"
35 #include "simulatorinterface.h"
36 #include "firmwareinterface.h"
37 #include "storage/storage_sdcard.h"
39 Stopwatch
gStopwatch("global");
41 const QColor colors
[CPN_MAX_CURVES
] = {
76 void populateGvSourceCB(QComboBox
*b
, int value
)
78 QString strings
[] = { QObject::tr("---"), QObject::tr("Rud Trim"), QObject::tr("Ele Trim"), QObject::tr("Thr Trim"), QObject::tr("Ail Trim"), QObject::tr("Rot Enc"), QObject::tr("Rud"), QObject::tr("Ele"), QObject::tr("Thr"), QObject::tr("Ail"), QObject::tr("P1"), QObject::tr("P2"), QObject::tr("P3")};
80 for (int i
=0; i
<= 12; i
++) {
81 b
->addItem(strings
[i
]);
83 b
->setCurrentIndex(value
);
86 void populateFileComboBox(QComboBox
* b
, const QSet
<QString
> & set
, const QString
& current
)
92 // Convert set into list and sort it alphabetically case insensitive
93 QStringList list
= QStringList::fromSet(set
);
94 qSort(list
.begin(), list
.end(), caseInsensitiveLessThan
);
95 foreach (QString entry
, list
) {
97 if (entry
== current
) {
98 b
->setCurrentIndex(b
->count()-1);
103 if (!added
&& !current
.isEmpty()) {
105 b
->setCurrentIndex(b
->count()-1);
109 void getFileComboBoxValue(QComboBox
* b
, char * dest
, int length
)
111 memset(dest
, 0, length
+1);
112 if (b
->currentText() != "----") {
113 strncpy(dest
, b
->currentText().toLatin1(), length
);
117 void populatePhasesCB(QComboBox
*b
, int value
)
119 for (int i
=-GetCurrentFirmware()->getCapability(FlightModes
); i
<=GetCurrentFirmware()->getCapability(FlightModes
); i
++) {
121 b
->addItem(QObject::tr("!Flight mode %1").arg(-i
-1), i
);
123 b
->addItem(QObject::tr("Flight mode %1").arg(i
-1), i
);
125 b
->addItem(QObject::tr("----"), 0);
127 b
->setCurrentIndex(value
+ GetCurrentFirmware()->getCapability(FlightModes
));
130 GVarGroup::GVarGroup(QCheckBox
* weightGV
, QAbstractSpinBox
* weightSB
, QComboBox
* weightCB
, int & weight
, const ModelData
& model
, const int deflt
, const int mini
, const int maxi
, const double step
, bool allowGvars
):
134 sb(dynamic_cast<QSpinBox
*>(weightSB
)),
135 dsb(dynamic_cast<QDoubleSpinBox
*>(weightSB
)),
141 if (allowGvars
&& GetCurrentFirmware()->getCapability(Gvars
)) {
142 populateGVCB(*weightCB
, weight
, model
);
143 connect(weightGV
, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
144 connect(weightCB
, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
148 if (weight
> maxi
|| weight
< mini
) {
155 if (weight
>maxi
|| weight
<mini
) {
157 weightGV
->setChecked(true);
163 weightGV
->setChecked(false);
169 sb
->setMinimum(mini
);
170 sb
->setMaximum(maxi
);
174 dsb
->setMinimum(mini
*step
);
175 dsb
->setMaximum(maxi
*step
);
176 dsb
->setValue(val
*step
);
179 connect(weightSB
, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
184 void GVarGroup::gvarCBChanged(int state
)
186 weightCB
->setVisible(state
);
188 weightSB
->setVisible(!state
);
190 weightSB
->setVisible(!state
);
194 void GVarGroup::valuesChanged()
197 if (weightGV
->isChecked())
198 weight
= weightCB
->itemData(weightCB
->currentIndex()).toInt();
200 weight
= sb
->value();
202 weight
= round(dsb
->value()/step
);
206 CurveGroup::CurveGroup(QComboBox
* curveTypeCB
, QCheckBox
* curveGVarCB
, QComboBox
* curveValueCB
, QSpinBox
* curveValueSB
, CurveReference
& curve
, const ModelData
& model
, unsigned int flags
):
208 curveTypeCB(curveTypeCB
),
209 curveGVarCB(curveGVarCB
),
210 curveValueCB(curveValueCB
),
211 curveValueSB(curveValueSB
),
218 if (!(flags
& HIDE_DIFF
)) curveTypeCB
->addItem(tr("Diff"), 0);
219 if (!(flags
& HIDE_EXPO
)) curveTypeCB
->addItem(tr("Expo"), 1);
220 curveTypeCB
->addItem(tr("Func"), 2);
221 curveTypeCB
->addItem(tr("Curve"), 3);
223 curveValueCB
->setMaxVisibleItems(10);
225 connect(curveTypeCB
, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
226 connect(curveGVarCB
, SIGNAL(stateChanged(int)), this, SLOT(gvarCBChanged(int)));
227 connect(curveValueCB
, SIGNAL(currentIndexChanged(int)), this, SLOT(valuesChanged()));
228 connect(curveValueSB
, SIGNAL(editingFinished()), this, SLOT(valuesChanged()));
233 void CurveGroup::update()
237 int found
= curveTypeCB
->findData(curve
.type
);
238 if (found
< 0) found
= 0;
239 curveTypeCB
->setCurrentIndex(found
);
241 if (curve
.type
== CurveReference::CURVE_REF_DIFF
|| curve
.type
== CurveReference::CURVE_REF_EXPO
) {
242 curveGVarCB
->setVisible(GetCurrentFirmware()->getCapability(Gvars
));
243 if (curve
.value
> 100 || curve
.value
< -100) {
244 curveGVarCB
->setChecked(true);
245 if (lastType
!= CurveReference::CURVE_REF_DIFF
&& lastType
!= CurveReference::CURVE_REF_EXPO
) {
246 lastType
= curve
.type
;
247 populateGVCB(*curveValueCB
, curve
.value
, model
);
249 curveValueCB
->show();
250 curveValueSB
->hide();
253 curveGVarCB
->setChecked(false);
254 curveValueSB
->setMinimum(-100);
255 curveValueSB
->setMaximum(100);
256 curveValueSB
->setValue(curve
.value
);
257 curveValueSB
->show();
258 curveValueCB
->hide();
263 curveValueSB
->hide();
264 curveValueCB
->show();
265 switch (curve
.type
) {
266 case CurveReference::CURVE_REF_FUNC
:
267 if (lastType
!= curve
.type
) {
268 lastType
= curve
.type
;
269 curveValueCB
->clear();
270 for (int i
=0; i
<=6/*TODO constant*/; i
++) {
271 curveValueCB
->addItem(CurveReference(CurveReference::CURVE_REF_FUNC
, i
).toString());
274 curveValueCB
->setCurrentIndex(curve
.value
);
276 case CurveReference::CURVE_REF_CUSTOM
:
278 int numcurves
= GetCurrentFirmware()->getCapability(NumCurves
);
279 if (lastType
!= curve
.type
) {
280 lastType
= curve
.type
;
281 curveValueCB
->clear();
282 for (int i
= ((flags
& HIDE_NEGATIVE_CURVES
) ? 0 : -numcurves
); i
<=numcurves
; i
++) {
283 curveValueCB
->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM
, i
).toString(), i
);
284 if (i
== curve
.value
) {
285 curveValueCB
->setCurrentIndex(curveValueCB
->count() - 1);
299 void CurveGroup::gvarCBChanged(int state
)
303 curve
.value
= 10000+1; // TODO constant in EEpromInterface ...
304 lastType
= -1; // quickfix for issue #3518: force refresh of curveValueCB at next update() to set current index to GV1
307 curve
.value
= 0; // TODO could be better
314 void CurveGroup::typeChanged(int value
)
317 int type
= curveTypeCB
->itemData(curveTypeCB
->currentIndex()).toInt();
320 curve
= CurveReference(CurveReference::CURVE_REF_DIFF
, 0);
323 curve
= CurveReference(CurveReference::CURVE_REF_EXPO
, 0);
326 curve
= CurveReference(CurveReference::CURVE_REF_FUNC
, 0);
329 curve
= CurveReference(CurveReference::CURVE_REF_CUSTOM
, 0);
337 void CurveGroup::valuesChanged()
340 switch (curveTypeCB
->itemData(curveTypeCB
->currentIndex()).toInt()) {
345 if (curveGVarCB
->isChecked())
346 value
= curveValueCB
->itemData(curveValueCB
->currentIndex()).toInt();
348 value
= curveValueSB
->value();
349 curve
= CurveReference(curveTypeCB
->itemData(curveTypeCB
->currentIndex()).toInt() == 0 ? CurveReference::CURVE_REF_DIFF
: CurveReference::CURVE_REF_EXPO
, value
);
353 curve
= CurveReference(CurveReference::CURVE_REF_FUNC
, curveValueCB
->currentIndex());
356 curve
= CurveReference(CurveReference::CURVE_REF_CUSTOM
, curveValueCB
->itemData(curveValueCB
->currentIndex()).toInt());
364 void populateGvarUseCB(QComboBox
*b
, unsigned int phase
)
366 b
->addItem(QObject::tr("Own value"));
367 for (int i
=0; i
<GetCurrentFirmware()->getCapability(FlightModes
); i
++) {
368 if (i
!= (int)phase
) {
369 b
->addItem(QObject::tr("Flight mode %1 value").arg(i
));
374 void populateSwitchCB(QComboBox
*b
, const RawSwitch
& value
, const GeneralSettings
& generalSettings
, SwitchContext context
)
380 if (context
!= MixesContext
&& context
!= GlobalFunctionsContext
) {
382 if (IS_ARM(GetCurrentFirmware()->getBoard())) {
383 for (int i
=-GetCurrentFirmware()->getCapability(FlightModes
); i
<0; i
++) {
384 item
= RawSwitch(SWITCH_TYPE_FLIGHT_MODE
, i
);
385 b
->addItem(item
.toString(), item
.toValue());
386 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
391 if (context
!= GlobalFunctionsContext
) {
392 for (int i
=-GetCurrentFirmware()->getCapability(LogicalSwitches
); i
<0; i
++) {
393 item
= RawSwitch(SWITCH_TYPE_VIRTUAL
, i
);
394 b
->addItem(item
.toString(), item
.toValue());
395 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
399 for (int i
=-GetCurrentFirmware()->getCapability(RotaryEncoders
); i
<0; i
++) {
400 item
= RawSwitch(SWITCH_TYPE_ROTARY_ENCODER
, i
);
401 b
->addItem(item
.toString(), item
.toValue());
402 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
405 for (int i
=-8; i
<0; i
++) {
406 item
= RawSwitch(SWITCH_TYPE_TRIM
, i
);
407 b
->addItem(item
.toString(), item
.toValue());
408 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
411 for (int i
=GetCurrentFirmware()->getCapability(MultiposPots
)-1; i
>=0; i
--) {
412 if (generalSettings
.potConfig
[i
] == GeneralSettings::POT_MULTIPOS_SWITCH
) {
413 for (int j
=-GetCurrentFirmware()->getCapability(MultiposPotsPositions
); j
<0; j
++) {
414 item
= RawSwitch(SWITCH_TYPE_MULTIPOS_POT
, -i
*GetCurrentFirmware()->getCapability(MultiposPotsPositions
)+j
);
415 b
->addItem(item
.toString(), item
.toValue());
416 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
421 for (int i
=-GetCurrentFirmware()->getCapability(SwitchesPositions
); i
<0; i
++) {
422 item
= RawSwitch(SWITCH_TYPE_SWITCH
, i
);
423 if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings
.switchPositionAllowedTaranis(i
)){
426 b
->addItem(item
.toString(), item
.toValue());
427 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
430 if (context
== TimersContext
) {
431 for (int i
=0; i
<5; i
++) {
432 item
= RawSwitch(SWITCH_TYPE_TIMER_MODE
, i
);
433 b
->addItem(item
.toString(), item
.toValue());
434 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
438 item
= RawSwitch(SWITCH_TYPE_NONE
);
439 b
->addItem(item
.toString(), item
.toValue());
440 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
443 for (int i
=1; i
<=GetCurrentFirmware()->getCapability(SwitchesPositions
); i
++) {
444 item
= RawSwitch(SWITCH_TYPE_SWITCH
, i
);
445 if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings
.switchPositionAllowedTaranis(i
)){
448 b
->addItem(item
.toString(), item
.toValue());
449 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
452 for (int i
=0; i
<GetCurrentFirmware()->getCapability(MultiposPots
); i
++) {
453 if (generalSettings
.potConfig
[i
] == GeneralSettings::POT_MULTIPOS_SWITCH
) {
454 for (int j
=1; j
<=GetCurrentFirmware()->getCapability(MultiposPotsPositions
); j
++) {
455 item
= RawSwitch(SWITCH_TYPE_MULTIPOS_POT
, i
*GetCurrentFirmware()->getCapability(MultiposPotsPositions
)+j
);
456 b
->addItem(item
.toString(), item
.toValue());
457 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
462 for (int i
=1; i
<=8; i
++) {
463 item
= RawSwitch(SWITCH_TYPE_TRIM
, i
);
464 b
->addItem(item
.toString(), item
.toValue());
465 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
468 for (int i
=1; i
<=GetCurrentFirmware()->getCapability(RotaryEncoders
); i
++) {
469 item
= RawSwitch(SWITCH_TYPE_ROTARY_ENCODER
, i
);
470 b
->addItem(item
.toString(), item
.toValue());
471 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
474 if (context
!= GlobalFunctionsContext
) {
475 for (int i
=1; i
<=GetCurrentFirmware()->getCapability(LogicalSwitches
); i
++) {
476 item
= RawSwitch(SWITCH_TYPE_VIRTUAL
, i
);
477 b
->addItem(item
.toString(), item
.toValue());
478 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
482 if (context
== SpecialFunctionsContext
|| context
== GlobalFunctionsContext
) {
484 item
= RawSwitch(SWITCH_TYPE_ON
);
485 b
->addItem(item
.toString(), item
.toValue());
486 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
488 item
= RawSwitch(SWITCH_TYPE_ONE
, 1);
489 b
->addItem(item
.toString(), item
.toValue());
490 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
494 if (context
!= MixesContext
&& context
!= GlobalFunctionsContext
) {
495 if (IS_ARM(GetCurrentFirmware()->getBoard())) {
496 for (int i
=1; i
<=GetCurrentFirmware()->getCapability(FlightModes
); i
++) {
497 item
= RawSwitch(SWITCH_TYPE_FLIGHT_MODE
, i
);
498 b
->addItem(item
.toString(), item
.toValue());
499 if (item
== value
) b
->setCurrentIndex(b
->count()-1);
504 b
->setMaxVisibleItems(10);
507 void populateGVCB(QComboBox
& b
, int value
, const ModelData
& model
)
509 bool selected
= false;
513 int count
= GetCurrentFirmware()->getCapability(Gvars
);
514 for (int i
=-count
; i
<=-1; i
++) {
515 int16_t gval
= (int16_t)(-10000+i
);
516 if (strlen(model
.gvars_names
[-i
-1]) > 0)
517 b
.addItem(QObject::tr("-GV%1 (%2)").arg(-i
).arg(model
.gvars_names
[-i
-1]), gval
);
519 b
.addItem(QObject::tr("-GV%1").arg(-i
), gval
);
521 b
.setCurrentIndex(b
.count()-1);
526 for (int i
=1; i
<=count
; i
++) {
527 int16_t gval
= (int16_t)(10000+i
);
528 if (strlen(model
.gvars_names
[i
-1]) > 0)
529 b
.addItem(QObject::tr("GV%1 (%2)").arg(i
).arg(model
.gvars_names
[i
-1]), gval
);
531 b
.addItem(QObject::tr("GV%1").arg(i
), gval
);
533 b
.setCurrentIndex(b
.count()-1);
539 b
.setCurrentIndex(count
);
543 void populateSourceCB(QComboBox
*b
, const RawSource
& source
, const GeneralSettings generalSettings
, const ModelData
* model
, unsigned int flags
)
545 BoardEnum board
= GetCurrentFirmware()->getBoard();
550 if (flags
& POPULATE_NONE
) {
551 item
= RawSource(SOURCE_TYPE_NONE
);
552 b
->addItem(item
.toString(model
), item
.toValue());
553 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
556 if (flags
& POPULATE_SCRIPT_OUTPUTS
) {
557 for (int i
=0; i
<GetCurrentFirmware()->getCapability(LuaScripts
); i
++) {
558 for (int j
=0; j
<GetCurrentFirmware()->getCapability(LuaOutputsPerScript
); j
++) {
559 item
= RawSource(SOURCE_TYPE_LUA_OUTPUT
, i
*16+j
);
560 b
->addItem(item
.toString(model
), item
.toValue());
561 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
566 if (model
&& (flags
& POPULATE_VIRTUAL_INPUTS
)) {
567 int virtualInputs
= GetCurrentFirmware()->getCapability(VirtualInputs
);
568 for (int i
=0; i
<virtualInputs
; i
++) {
569 if (model
->isInputValid(i
)) {
570 item
= RawSource(SOURCE_TYPE_VIRTUAL_INPUT
, i
);
571 b
->addItem(item
.toString(model
), item
.toValue());
572 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
577 if (flags
& POPULATE_SOURCES
) {
578 for (int i
=0; i
<CPN_MAX_STICKS
+GetCurrentFirmware()->getCapability(Pots
)+GetCurrentFirmware()->getCapability(Sliders
); i
++) {
579 item
= RawSource(SOURCE_TYPE_STICK
, i
);
580 // skip unavailable pots and sliders
581 if (item
.isPot() && !generalSettings
.isPotAvailable(i
-CPN_MAX_STICKS
)) continue;
582 if (item
.isSlider() && !generalSettings
.isSliderAvailable(i
-CPN_MAX_STICKS
-GetCurrentFirmware()->getCapability(Pots
))) continue;
583 b
->addItem(item
.toString(model
), item
.toValue());
584 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
586 for (int i
=0; i
<GetCurrentFirmware()->getCapability(RotaryEncoders
); i
++) {
587 item
= RawSource(SOURCE_TYPE_ROTARY_ENCODER
, i
);
588 b
->addItem(item
.toString(model
), item
.toValue());
589 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
593 if (flags
& POPULATE_TRIMS
) {
594 for (int i
=0; i
<4; i
++) {
595 item
= RawSource(SOURCE_TYPE_TRIM
, i
);
596 b
->addItem(item
.toString(model
), item
.toValue());
597 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
601 if (flags
& POPULATE_SOURCES
) {
602 item
= RawSource(SOURCE_TYPE_MAX
);
603 b
->addItem(item
.toString(model
), item
.toValue());
604 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
607 if (flags
& POPULATE_SWITCHES
) {
608 for (int i
=0; i
<GetCurrentFirmware()->getCapability(Switches
); i
++) {
609 item
= RawSource(SOURCE_TYPE_SWITCH
, i
);
610 b
->addItem(item
.toString(model
), item
.toValue());
611 if (IS_TARANIS(GetCurrentFirmware()->getBoard()) && !generalSettings
.switchSourceAllowedTaranis(i
)) {
612 QModelIndex index
= b
->model()->index(b
->count()-1, 0);
614 b
->model()->setData(index
, v
, Qt::UserRole
- 1);
616 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
619 for (int i
=0; i
<GetCurrentFirmware()->getCapability(LogicalSwitches
); i
++) {
620 item
= RawSource(SOURCE_TYPE_CUSTOM_SWITCH
, i
);
621 b
->addItem(item
.toString(model
), item
.toValue());
622 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
626 if (flags
& POPULATE_SOURCES
) {
627 for (int i
=0; i
<CPN_MAX_CYC
; i
++) {
628 item
= RawSource(SOURCE_TYPE_CYC
, i
);
629 b
->addItem(item
.toString(model
), item
.toValue());
630 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
633 for (int i
=0; i
<GetCurrentFirmware()->getCapability(TrainerInputs
); i
++) {
634 item
= RawSource(SOURCE_TYPE_PPM
, i
);
635 b
->addItem(item
.toString(model
), item
.toValue());
636 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
639 for (int i
=0; i
<GetCurrentFirmware()->getCapability(Outputs
); i
++) {
640 item
= RawSource(SOURCE_TYPE_CH
, i
);
641 b
->addItem(item
.toString(model
), item
.toValue());
642 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
646 if (flags
& POPULATE_TELEMETRY
) {
647 if (IS_ARM(GetCurrentFirmware()->getBoard())) {
648 for (int i
=0; i
<5; ++i
) {
649 item
= RawSource(SOURCE_TYPE_SPECIAL
, i
);
650 b
->addItem(item
.toString(model
), item
.toValue());
651 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
653 for (int i
=0; i
<CPN_MAX_SENSORS
; ++i
) {
654 if (model
&& model
->sensorData
[i
].isAvailable()) { //this conditon must be false if we populate Global Functions where model = 0
655 for (int j
=0; j
<3; ++j
) {
656 item
= RawSource(SOURCE_TYPE_TELEMETRY
, 3*i
+j
);
657 b
->addItem(item
.toString(model
), item
.toValue());
658 // qDebug() << item.toString(model) << source.toString(model);
659 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
665 for (int i
=0; i
<(flags
& POPULATE_TELEMETRYEXT
? TELEMETRY_SOURCES_STATUS_COUNT
: TELEMETRY_SOURCES_COUNT
); i
++) {
666 if (i
==TELEMETRY_SOURCE_TX_TIME
&& !GetCurrentFirmware()->getCapability(RtcTime
))
668 if (i
==TELEMETRY_SOURCE_SWR
&& !GetCurrentFirmware()->getCapability(SportTelemetry
))
670 if (i
==TELEMETRY_SOURCE_TIMER3
&& !IS_ARM(board
))
672 item
= RawSource(SOURCE_TYPE_TELEMETRY
, i
);
673 b
->addItem(item
.toString(model
), item
.toValue());
674 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
679 if (flags
& POPULATE_GVARS
) {
680 for (int i
=0; i
<GetCurrentFirmware()->getCapability(Gvars
); i
++) {
681 item
= RawSource(SOURCE_TYPE_GVAR
, i
);
682 b
->addItem(item
.toString(model
), item
.toValue());
683 if (item
== source
) b
->setCurrentIndex(b
->count()-1);
687 b
->setMaxVisibleItems(10);
690 QString
image2qstring(QImage image
)
695 image
.save(&buffer
, "PNG");
698 int size
=buffer
.data().size();
699 for (int j
= 0; j
< size
; j
++) {
700 b
=buffer
.data().at(j
);
701 ImageStr
+= QString("%1").arg(b
&0xff, 2, 16, QChar('0'));
706 int findmult(float value
, float base
)
708 int vvalue
= value
*10;
713 for (int i
=8; i
>=0; i
--) {
714 if (vvalue
/vbase
>= (1<<i
)) {
723 QString
getFrSkyAlarmType(int alarm
)
727 return QObject::tr("Yellow");
729 return QObject::tr("Orange");
731 return QObject::tr("Red");
737 QString
getFrSkyUnits(int units
)
741 return QObject::tr("---");
747 QString
getFrSkyProtocol(int protocol
)
751 if ((GetCurrentFirmware()->getCapability(Telemetry
) & TM_HASWSHH
))
752 return QObject::tr("Winged Shadow How High");
754 return QObject::tr("Winged Shadow How High (not supported)");
756 return QObject::tr("FrSky Sensor Hub");
758 return QObject::tr("None");
762 QString
getFrSkyMeasure(int units
)
766 return QObject::tr("Imperial");
768 return QObject::tr("Metric");
772 QString
getFrSkySrc(int index
)
774 return RawSource(SOURCE_TYPE_TELEMETRY
, index
-1).toString();
779 int theme_set
= g
.theme();
801 CompanionIcon::CompanionIcon(const QString
&baseimage
)
803 static QString theme
= getTheme();
804 addFile(":/themes/"+theme
+"/16/"+baseimage
, QSize(16,16));
805 addFile(":/themes/"+theme
+"/24/"+baseimage
, QSize(24,24));
806 addFile(":/themes/"+theme
+"/32/"+baseimage
, QSize(32,32));
807 addFile(":/themes/"+theme
+"/48/"+baseimage
, QSize(48,48));
810 void startSimulation(QWidget
* parent
, RadioData
& radioData
, int modelIdx
)
812 Firmware
* firmware
= GetCurrentFirmware();
813 SimulatorInterface
* simulator
= GetCurrentFirmwareSimulator();
815 #if defined(WIN32) && defined(WIN_USE_CONSOLE_STDIO)
817 SetConsoleTitle("Companion Console");
818 freopen("conin$", "r", stdin
);
819 freopen("conout$", "w", stdout
);
820 freopen("conout$", "w", stderr
);
822 RadioData
* simuData
= new RadioData(radioData
);
823 unsigned int flags
= 0;
825 flags
|= SIMULATOR_FLAGS_NOTX
;
826 simuData
->setCurrentModel(modelIdx
);
828 if (radioData
.generalSettings
.stickMode
& 1) {
829 flags
|= SIMULATOR_FLAGS_STICK_MODE_LEFT
;
831 BoardEnum board
= GetCurrentFirmware()->getBoard();
832 SimulatorDialog
* dialog
;
834 if (board
== BOARD_HORUS
&& HORUS_READY_FOR_RELEASE()) {
835 dialog
= new SimulatorDialogHorus(parent
, simulator
, flags
);
836 GetEepromInterface()->saveFile(*simuData
, g
.profile
[g
.id()].sdPath());
839 else if (board
== BOARD_FLAMENCO
) {
840 dialog
= new SimulatorDialogFlamenco(parent
, simulator
, flags
);
841 QByteArray
eeprom(GetEepromInterface()->getEEpromSize(), 0);
842 firmware
->saveEEPROM((uint8_t *)eeprom
.data(), *simuData
);
843 dialog
->start(eeprom
);
845 else if (board
== BOARD_TARANIS_X9D
|| board
== BOARD_TARANIS_X9DP
|| board
== BOARD_TARANIS_X9E
) {
846 for (int i
=0; i
<GetCurrentFirmware()->getCapability(Pots
); i
++) {
847 if (radioData
.generalSettings
.isPotAvailable(i
)) {
848 flags
|= (SIMULATOR_FLAGS_S1
<< i
);
849 if (radioData
.generalSettings
.potConfig
[1] == GeneralSettings::POT_MULTIPOS_SWITCH
) {
850 flags
|= (SIMULATOR_FLAGS_S1_MULTI
<< i
);
854 dialog
= new SimulatorDialogTaranis(parent
, simulator
, flags
);
855 QByteArray
eeprom(GetEepromInterface()->getEEpromSize(), 0);
856 firmware
->saveEEPROM((uint8_t *)eeprom
.data(), *simuData
);
857 dialog
->start(eeprom
);
860 dialog
= new SimulatorDialog9X(parent
, simulator
, flags
);
861 QByteArray
eeprom(GetEepromInterface()->getEEpromSize(), 0);
862 firmware
->saveEEPROM((uint8_t *)eeprom
.data(), *simuData
, 0, firmware
->getCapability(SimulatorVariant
));
863 dialog
->start(eeprom
);
869 #if defined(WIN32) && defined(WIN_USE_CONSOLE_STDIO)
874 QMessageBox::warning(NULL
,
875 QObject::tr("Warning"),
876 QObject::tr("Simulator for this firmware is not yet available"));
880 QPixmap
makePixMap(const QImage
& image
)
882 Firmware
* firmware
= GetCurrentFirmware();
883 QImage result
= image
.scaled(firmware
->getCapability(LcdWidth
), firmware
->getCapability(LcdHeight
));
884 if (firmware
->getCapability(LcdDepth
) == 4) {
885 result
= result
.convertToFormat(QImage::Format_RGB32
);
886 for (int i
= 0; i
< image
.width(); ++i
) {
887 for (int j
= 0; j
< image
.height(); ++j
) {
888 QRgb col
= result
.pixel(i
, j
);
889 int gray
= qGray(col
);
890 result
.setPixel(i
, j
, qRgb(gray
, gray
, gray
));
895 result
= result
.convertToFormat(QImage::Format_Mono
);
898 return QPixmap::fromImage(result
);
901 int version2index(const QString
& version
)
904 QStringList parts
= version
.split("N");
905 if (parts
.size() > 1)
906 result
= parts
[1].toInt(); // nightly build
907 parts
= parts
[0].split('.');
908 if (parts
.size() > 2)
909 result
+= 1000 * parts
[2].toInt();
910 if (parts
.size() > 1)
911 result
+= 100000 * parts
[1].toInt();
912 if (parts
.size() > 0)
913 result
+= 10000000 * parts
[0].toInt();
917 QString
index2version(int index
)
919 if (index
>= 19900000) {
920 int nightly
= index
% 1000;
922 int revision
= index
% 100;
924 int minor
= index
% 100;
925 int major
= index
/ 100;
926 QString result
= QString("%1.%2.%3").arg(major
).arg(minor
).arg(revision
);
927 if (nightly
> 0 && nightly
< 999) {
928 result
+= QString("N%1").arg(nightly
);
932 else if (index
>= 19900) {
933 int revision
= index
% 100;
935 int minor
= index
% 100;
936 int major
= index
/ 100;
937 return QString("%1.%2.%3").arg(major
).arg(minor
).arg(revision
);
944 int qunlink(const QString
& fileName
)
946 QByteArray ba
= fileName
.toLatin1();
947 return unlink(ba
.constData());
950 QString
generateProcessUniqueTempFileName(const QString
& fileName
)
952 QString sanitizedFileName
= fileName
;
953 sanitizedFileName
.remove('/');
954 return QDir::tempPath() + QString("/%1-").arg(QCoreApplication::applicationPid()) + sanitizedFileName
;
957 bool isTempFileName(const QString
& fileName
)
959 return fileName
.startsWith(QDir::tempPath());
962 QString
getSoundsPath(const GeneralSettings
&generalSettings
)
964 QString path
= g
.profile
[g
.id()].sdPath() + "/SOUNDS/";
965 QString lang
= generalSettings
.ttsLanguage
;
972 QSet
<QString
> getFilesSet(const QString
&path
, const QStringList
&filter
, int maxLen
)
974 QSet
<QString
> result
;
977 foreach (QString filename
, dir
.entryList(filter
, QDir::Files
)) {
978 QFileInfo
file(filename
);
979 QString name
= file
.completeBaseName();
980 if (name
.length() <= maxLen
) {
988 bool caseInsensitiveLessThan(const QString
&s1
, const QString
&s2
)
990 return s1
.toLower() < s2
.toLower();
993 bool GpsGlitchFilter::isGlitch(GpsCoord coord
)
995 if ((fabs(coord
.latitude
) < 0.1) && (fabs(coord
.longitude
) < 0.1)) {
1000 if (fabs(coord
.latitude
- lastLat
) > 0.01) {
1001 // qDebug() << "GpsGlitchFilter(): latitude glitch " << coord.latitude << lastLat;
1002 if ( ++glitchCount
< 10) {
1006 if (fabs(coord
.longitude
- lastLon
) > 0.01) {
1007 // qDebug() << "GpsGlitchFilter(): longitude glitch " << coord.longitude << lastLon;
1008 if ( ++glitchCount
< 10) {
1013 lastLat
= coord
.latitude
;
1014 lastLon
= coord
.longitude
;
1020 bool GpsLatLonFilter::isValid(GpsCoord coord
)
1022 if (lastLat
== coord
.latitude
) {
1025 if (lastLon
== coord
.longitude
) {
1028 lastLat
= coord
.latitude
;
1029 lastLon
= coord
.longitude
;
1033 double toDecimalCoordinate(const QString
& value
)
1035 if (value
.isEmpty()) return 0.0;
1036 double temp
= int(value
.left(value
.length()-1).toDouble() / 100);
1037 double result
= temp
+ (value
.left(value
.length() - 1).toDouble() - temp
* 100) / 60.0;
1038 QChar direction
= value
.at(value
.size()-1);
1039 if ((direction
== 'S') || (direction
== 'W')) {
1045 GpsCoord
extractGpsCoordinates(const QString
& position
)
1048 QStringList parts
= position
.split(' ');
1049 if (parts
.size() == 2) {
1050 QString value
= parts
.at(0).trimmed();
1051 QChar direction
= value
.at(value
.size()-1);
1052 if (direction
== 'E' || direction
== 'W') {
1053 // OpenTX 2.1 format: "NNN.MMM[E|W] NNN.MMM[N|S]" <longitude> <latitude>
1054 result
.latitude
= toDecimalCoordinate(parts
.at(1).trimmed());
1055 result
.longitude
= toDecimalCoordinate(parts
.at(0).trimmed());
1058 // OpenTX 2.2 format: "DD.DDDDDD DD.DDDDDD" <latitude> <longitude> both in Signed degrees format (DDD.dddd)
1059 // Precede South latitudes and West longitudes with a minus sign.
1060 // Latitudes range from -90 to 90.
1061 // Longitudes range from -180 to 180.
1062 result
.latitude
= parts
.at(0).trimmed().toDouble();
1063 result
.longitude
= parts
.at(1).trimmed().toDouble();
1069 TableLayout::TableLayout(QWidget
* parent
, int rowCount
, const QStringList
& headerLabels
)
1071 #if defined(TABLE_LAYOUT)
1072 tableWidget
= new QTableWidget(parent
);
1073 QVBoxLayout
* layout
= new QVBoxLayout();
1074 layout
->addWidget(tableWidget
);
1075 layout
->setContentsMargins(0, 0, 0, 0);
1076 parent
->setLayout(layout
);
1078 tableWidget
->setRowCount(rowCount
);
1079 tableWidget
->setColumnCount(headerLabels
.size());
1080 tableWidget
->setShowGrid(false);
1081 tableWidget
->verticalHeader()->setVisible(false);
1082 tableWidget
->setSelectionBehavior(QAbstractItemView::SelectRows
);
1083 tableWidget
->setSelectionMode(QAbstractItemView::NoSelection
);
1084 tableWidget
->setFrameStyle(QFrame::NoFrame
| QFrame::Plain
);
1085 tableWidget
->setStyleSheet("QTableWidget {background-color: transparent;}");
1086 tableWidget
->setHorizontalHeaderLabels(headerLabels
);
1088 gridWidget
= new QGridLayout(parent
);
1091 foreach(QString text
, headerLabels
) {
1092 QLabel
*label
= new QLabel();
1093 label
->setFrameShape(QFrame::Panel
);
1094 label
->setFrameShadow(QFrame::Raised
);
1095 label
->setMidLineWidth(0);
1096 label
->setAlignment(Qt::AlignCenter
);
1097 label
->setMargin(5);
1098 label
->setText(text
);
1100 // label->setMinimumWidth(100);
1101 gridWidget
->addWidget(label
, 0, col
++);
1106 void TableLayout::addWidget(int row
, int column
, QWidget
* widget
)
1108 #if defined(TABLE_LAYOUT)
1109 QHBoxLayout
* layout
= new QHBoxLayout(tableWidget
);
1110 layout
->addWidget(widget
);
1111 addLayout(row
, column
, layout
);
1113 gridWidget
->addWidget(widget
, row
+ 1, column
);
1117 void TableLayout::addLayout(int row
, int column
, QLayout
* layout
)
1119 #if defined(TABLE_LAYOUT)
1120 layout
->setContentsMargins(1, 3, 1, 3);
1121 QWidget
* containerWidget
= new QWidget(tableWidget
);
1122 containerWidget
->setLayout(layout
);
1123 tableWidget
->setCellWidget(row
, column
, containerWidget
);
1125 gridWidget
->addLayout(layout
, row
+ 1, column
);
1129 void TableLayout::resizeColumnsToContents()
1131 #if defined(TABLE_LAYOUT)
1132 tableWidget
->resizeColumnsToContents();
1137 void TableLayout::setColumnWidth(int col
, int width
)
1139 #if defined(TABLE_LAYOUT)
1140 tableWidget
->setColumnWidth(col
, width
);
1145 void TableLayout::pushRowsUp(int row
)
1147 #if defined(TABLE_LAYOUT)
1150 QSpacerItem
* spacer
= new QSpacerItem(0, 0, QSizePolicy::Minimum
, QSizePolicy::Expanding
);
1151 gridWidget
->addItem(spacer
, row
, 0);
1154 // addDoubleSpring(gridLayout, 5, num_fsw+1);