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.
23 #include "ui_setup_timer.h"
24 #include "ui_setup_module.h"
25 #include "switchitemmodel.h"
28 #include "modelprinter.h"
29 #include "multiprotocols.h"
30 #include "checklistdialog.h"
32 TimerPanel::TimerPanel(QWidget
*parent
, ModelData
& model
, TimerData
& timer
, GeneralSettings
& generalSettings
, Firmware
* firmware
, QWidget
* prevFocus
):
33 ModelPanel(parent
, model
, generalSettings
, firmware
),
37 Board::Type board
= firmware
->getBoard();
44 int length
= firmware
->getCapability(TimersName
);
49 ui
->name
->setMaxLength(length
);
50 ui
->name
->setText(timer
.name
);
54 rawSwitchItemModel
= new RawSwitchFilterItemModel(&generalSettings
, &model
, TimersContext
);
55 ui
->mode
->setModel(rawSwitchItemModel
);
56 ui
->mode
->setCurrentIndex(ui
->mode
->findData(timer
.mode
.toValue()));
58 if (!firmware
->getCapability(PermTimers
)) {
59 ui
->persistent
->hide();
60 ui
->persistentValue
->hide();
63 ui
->countdownBeep
->setField(timer
.countdownBeep
, this);
64 ui
->countdownBeep
->addItem(tr("Silent"), TimerData::COUNTDOWN_SILENT
);
65 ui
->countdownBeep
->addItem(tr("Beeps"), TimerData::COUNTDOWN_BEEPS
);
66 if (IS_ARM(board
) || IS_2560(board
)) {
67 ui
->countdownBeep
->addItem(tr("Voice"), TimerData::COUNTDOWN_VOICE
);
68 ui
->countdownBeep
->addItem(tr("Haptic"), TimerData::COUNTDOWN_HAPTIC
);
71 ui
->value
->setMaximumTime(firmware
->getMaxTimerStart());
73 ui
->persistent
->setField(timer
.persistent
, this);
74 ui
->persistent
->addItem(tr("Not persistent"), 0);
75 ui
->persistent
->addItem(tr("Persistent (flight)"), 1);
76 ui
->persistent
->addItem(tr("Persistent (manual reset)"), 2);
78 disableMouseScrolling();
79 QWidget::setTabOrder(prevFocus
, ui
->name
);
80 QWidget::setTabOrder(ui
->name
, ui
->value
);
81 QWidget::setTabOrder(ui
->value
, ui
->mode
);
82 QWidget::setTabOrder(ui
->mode
, ui
->countdownBeep
);
83 QWidget::setTabOrder(ui
->countdownBeep
, ui
->minuteBeep
);
84 QWidget::setTabOrder(ui
->minuteBeep
, ui
->persistent
);
89 TimerPanel::~TimerPanel()
94 void TimerPanel::update()
96 rawSwitchItemModel
->update();
98 int hour
= timer
.val
/ 3600;
99 int min
= (timer
.val
- (hour
* 3600)) / 60;
100 int sec
= (timer
.val
- (hour
* 3600)) % 60;
102 ui
->value
->setTime(QTime(hour
, min
, sec
));
104 if (firmware
->getCapability(PermTimers
)) {
106 int pvalue
= timer
.pvalue
;
111 int hours
= pvalue
/ 3600;
112 pvalue
-= hours
* 3600;
113 int minutes
= pvalue
/ 60;
114 int seconds
= pvalue
% 60;
115 ui
->persistentValue
->setText(QString(" %1(%2:%3:%4)").arg(sign
<0 ? "-" :" ").arg(hours
, 2, 10, QLatin1Char('0')).arg(minutes
, 2, 10, QLatin1Char('0')).arg(seconds
, 2, 10, QLatin1Char('0')));
118 ui
->minuteBeep
->setChecked(timer
.minuteBeep
);
121 QWidget
* TimerPanel::getLastFocus()
123 return ui
->persistent
;
126 void TimerPanel::on_value_editingFinished()
128 unsigned val
= ui
->value
->time().hour()*3600 + ui
->value
->time().minute()*60 + ui
->value
->time().second();
129 if (timer
.val
!= val
) {
135 void TimerPanel::on_mode_currentIndexChanged(int index
)
138 timer
.mode
= RawSwitch(ui
->mode
->itemData(index
).toInt());
143 void TimerPanel::on_minuteBeep_toggled(bool checked
)
145 timer
.minuteBeep
= checked
;
149 void TimerPanel::on_name_editingFinished()
151 if (QString(timer
.name
) != ui
->name
->text()) {
152 int length
= ui
->name
->maxLength();
153 strncpy(timer
.name
, ui
->name
->text().toLatin1(), length
);
158 /******************************************************************************/
160 #define FAILSAFE_CHANNEL_HOLD 2000
161 #define FAILSAFE_CHANNEL_NOPULSE 2001
163 #define MASK_PROTOCOL 1
164 #define MASK_CHANNELS_COUNT 2
165 #define MASK_RX_NUMBER 4
166 #define MASK_CHANNELS_RANGE 8
167 #define MASK_PPM_FIELDS 16
168 #define MASK_FAILSAFES 32
169 #define MASK_OPEN_DRAIN 64
170 #define MASK_MULTIMODULE 128
171 #define MASK_ANTENNA 256
172 #define MASK_MULTIOPTION 512
173 #define MASK_R9M 1024
175 quint8
ModulePanel::failsafesValueDisplayType
= ModulePanel::FAILSAFE_DISPLAY_PERCENT
;
177 ModulePanel::ModulePanel(QWidget
* parent
, ModelData
& model
, ModuleData
& module
, GeneralSettings
& generalSettings
, Firmware
* firmware
, int moduleIdx
):
178 ModelPanel(parent
, model
, generalSettings
, firmware
),
180 moduleIdx(moduleIdx
),
189 label
= tr("Trainer Port");
190 if (IS_HORUS(firmware
->getBoard())) {
191 ui
->trainerMode
->setItemData(TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
, 0, Qt::UserRole
- 1);
192 ui
->trainerMode
->setItemData(TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE
, 0, Qt::UserRole
- 1);
194 if (generalSettings
.hw_uartMode
!= UART_MODE_SBUS_TRAINER
) {
195 ui
->trainerMode
->setItemData(TRAINER_MODE_MASTER_BATTERY_COMPARTMENT
, 0, Qt::UserRole
- 1);
197 ui
->trainerMode
->setCurrentIndex(model
.trainerMode
);
198 if (!IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
199 ui
->label_trainerMode
->hide();
200 ui
->trainerMode
->hide();
202 ui
->formLayout_col1
->setSpacing(0);
205 ui
->label_trainerMode
->hide();
206 ui
->trainerMode
->hide();
207 if (firmware
->getCapability(NumModules
) > 1) {
208 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
210 label
= tr("Internal Radio System");
212 label
= tr("External Radio Module");
216 label
= tr("Radio System");
218 label
= tr("Extra Radio System");
222 label
= tr("Radio System");
225 ui
->label_module
->setText(label
);
227 // The protocols available on this board
228 for (int i
=0; i
<PULSES_PROTOCOL_LAST
; i
++) {
229 if (firmware
->isAvailable((PulsesProtocol
)i
, moduleIdx
)) {
230 ui
->protocol
->addItem(ModelPrinter::printModuleProtocol(i
), (QVariant
)i
);
231 if (i
== module
.protocol
)
232 ui
->protocol
->setCurrentIndex(ui
->protocol
->count()-1);
235 for (int i
=0; i
<=MM_RF_PROTO_LAST
; i
++) {
236 ui
->multiProtocol
->addItem(ModelPrinter::printMultiRfProtocol(i
, false), (QVariant
) i
);
239 ui
->btnGrpValueType
->setId(ui
->optPercent
, FAILSAFE_DISPLAY_PERCENT
);
240 ui
->btnGrpValueType
->setId(ui
->optUs
, FAILSAFE_DISPLAY_USEC
);
241 ui
->btnGrpValueType
->button(failsafesValueDisplayType
)->setChecked(true);
245 disableMouseScrolling();
249 connect(ui
->protocol
, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged
), this, &ModulePanel::onProtocolChanged
);
250 connect(ui
->multiProtocol
, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged
), this, &ModulePanel::onMultiProtocolChanged
);
251 connect(this, &ModulePanel::channelsRangeChanged
, this, &ModulePanel::setupFailsafes
);
252 connect(ui
->btnGrpValueType
, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked
), this, &ModulePanel::onFailsafesDisplayValueTypeChanged
);
258 ModulePanel::~ModulePanel()
263 bool ModulePanel::moduleHasFailsafes()
265 return (((PulsesProtocol
)module
.protocol
== PulsesProtocol::PULSES_PXX_XJT_X16
|| (PulsesProtocol
)module
.protocol
== PulsesProtocol::PULSES_PXX_R9M
)
266 && firmware
->getCapability(HasFailsafe
));;
269 void ModulePanel::setupFailsafes()
271 ChannelFailsafeWidgetsGroup grp
;
272 const int start
= module
.channelsStart
;
273 const int end
= start
+ module
.channelsCount
;
274 const bool hasFailsafe
= moduleHasFailsafes();
278 QMutableMapIterator
<int, ChannelFailsafeWidgetsGroup
> i(failsafeGroupsMap
);
279 while (i
.hasNext()) {
282 ui
->failsafesLayout
->removeWidget(grp
.label
);
283 ui
->failsafesLayout
->removeWidget(grp
.combo
);
284 ui
->failsafesLayout
->removeWidget(grp
.sbPercent
);
285 ui
->failsafesLayout
->removeWidget(grp
.sbUsec
);
286 if (i
.key() < start
|| i
.key() >= end
|| !hasFailsafe
) {
287 grp
.label
->deleteLater();
288 grp
.combo
->deleteLater();
289 grp
.sbPercent
->deleteLater();
290 grp
.sbUsec
->deleteLater();
300 int channelMax
= model
->getChannelsMax();
301 int channelMaxUs
= 512 * channelMax
/ 100 * 2;
303 for (int i
= start
; i
< end
; ++i
) {
304 if (failsafeGroupsMap
.contains(i
)) {
305 grp
= failsafeGroupsMap
.value(i
);
308 QLabel
* label
= new QLabel(this);
309 label
->setProperty("index", i
);
310 label
->setText(QString::number(i
+1));
312 QComboBox
* combo
= new QComboBox(this);
313 combo
->setProperty("index", i
);
314 combo
->addItem(tr("Value"), 0);
315 combo
->addItem(tr("Hold"), FAILSAFE_CHANNEL_HOLD
);
316 combo
->addItem(tr("No Pulse"), FAILSAFE_CHANNEL_NOPULSE
);
318 QDoubleSpinBox
* sbDbl
= new QDoubleSpinBox(this);
319 sbDbl
->setProperty("index", i
);
320 sbDbl
->setMinimumSize(QSize(20, 0));
321 sbDbl
->setRange(-channelMax
, channelMax
);
322 sbDbl
->setSingleStep(0.1);
323 sbDbl
->setDecimals(1);
325 QSpinBox
* sbInt
= new QSpinBox(this);
326 sbInt
->setProperty("index", i
);
327 sbInt
->setMinimumSize(QSize(20, 0));
328 sbInt
->setRange(-channelMaxUs
, channelMaxUs
);
329 sbInt
->setSingleStep(1);
331 grp
= ChannelFailsafeWidgetsGroup();
333 grp
.sbPercent
= sbDbl
;
336 failsafeGroupsMap
.insert(i
, grp
);
338 connect(combo
, SIGNAL(currentIndexChanged(int)), this, SLOT(onFailsafeComboIndexChanged(int)));
339 connect(sbInt
, SIGNAL(valueChanged(int)), this, SLOT(onFailsafeUsecChanged(int)));
340 connect(sbDbl
, SIGNAL(valueChanged(double)), this, SLOT(onFailsafePercentChanged(double)));
343 ui
->failsafesLayout
->addWidget(grp
.label
, row
, col
, Qt::AlignHCenter
);
344 ui
->failsafesLayout
->addWidget(grp
.combo
, row
+ 1, col
, Qt::AlignHCenter
);
345 ui
->failsafesLayout
->addWidget(grp
.sbPercent
, row
+ 2, col
, Qt::AlignHCenter
);
346 ui
->failsafesLayout
->addWidget(grp
.sbUsec
, row
+ 3, col
, Qt::AlignHCenter
);
347 grp
.sbPercent
->setVisible(failsafesValueDisplayType
== FAILSAFE_DISPLAY_PERCENT
);
348 grp
.sbUsec
->setVisible(failsafesValueDisplayType
== FAILSAFE_DISPLAY_USEC
);
361 void ModulePanel::update()
363 unsigned int mask
= 0;
364 PulsesProtocol protocol
= (PulsesProtocol
)module
.protocol
;
365 unsigned int max_rx_num
= 63;
367 if (moduleIdx
>= 0) {
368 mask
|= MASK_PROTOCOL
;
372 case PULSES_PXX_XJT_X16
:
373 case PULSES_PXX_XJT_D8
:
374 case PULSES_PXX_XJT_LR12
:
376 mask
|= MASK_CHANNELS_RANGE
| MASK_CHANNELS_COUNT
;
377 if (protocol
==PULSES_PXX_XJT_X16
|| protocol
==PULSES_PXX_XJT_LR12
|| protocol
==PULSES_PXX_R9M
)
378 mask
|= MASK_RX_NUMBER
;
379 if (IS_HORUS(firmware
->getBoard()) && moduleIdx
==0)
380 mask
|= MASK_ANTENNA
;
385 mask
|= MASK_CHANNELS_RANGE
| MASK_RX_NUMBER
;
386 module
.channelsCount
= 6;
389 case PULSES_CROSSFIRE
:
390 mask
|= MASK_CHANNELS_RANGE
;
391 module
.channelsCount
= 16;
394 mask
|= MASK_PPM_FIELDS
| MASK_CHANNELS_RANGE
| MASK_CHANNELS_COUNT
;
395 if (IS_9XRPRO(firmware
->getBoard())) {
396 mask
|= MASK_OPEN_DRAIN
;
399 case PULSES_MULTIMODULE
:
400 mask
|= MASK_CHANNELS_RANGE
| MASK_RX_NUMBER
| MASK_MULTIMODULE
;
402 if (module
.multi
.rfProtocol
== MM_RF_PROTO_DSM2
)
403 mask
|= MASK_CHANNELS_COUNT
;
405 module
.channelsCount
= 16;
406 if (multiProtocols
.getProtocol(module
.multi
.rfProtocol
).optionsstr
!= nullptr)
407 mask
|= MASK_MULTIOPTION
;
415 else if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
416 if (model
->trainerMode
== TRAINER_SLAVE_JACK
) {
417 mask
|= MASK_PPM_FIELDS
| MASK_CHANNELS_RANGE
| MASK_CHANNELS_COUNT
;
420 else if (model
->trainerMode
!= TRAINER_MASTER_JACK
) {
421 mask
|= MASK_PPM_FIELDS
| MASK_CHANNELS_RANGE
| MASK_CHANNELS_COUNT
;
424 if (moduleHasFailsafes()) {
425 mask
|= MASK_FAILSAFES
;
428 ui
->label_protocol
->setVisible(mask
& MASK_PROTOCOL
);
429 ui
->protocol
->setVisible(mask
& MASK_PROTOCOL
);
430 ui
->label_rxNumber
->setVisible(mask
& MASK_RX_NUMBER
);
431 ui
->rxNumber
->setVisible(mask
& MASK_RX_NUMBER
);
432 ui
->rxNumber
->setMaximum(max_rx_num
);
433 ui
->rxNumber
->setValue(module
.modelId
);
434 ui
->label_channelsStart
->setVisible(mask
& MASK_CHANNELS_RANGE
);
435 ui
->channelsStart
->setVisible(mask
& MASK_CHANNELS_RANGE
);
436 ui
->channelsStart
->setValue(module
.channelsStart
+1);
437 ui
->label_channelsCount
->setVisible(mask
& MASK_CHANNELS_RANGE
);
438 ui
->channelsCount
->setVisible(mask
& MASK_CHANNELS_RANGE
);
439 ui
->channelsCount
->setEnabled(mask
& MASK_CHANNELS_COUNT
);
440 ui
->channelsCount
->setValue(module
.channelsCount
);
441 ui
->channelsCount
->setSingleStep(firmware
->getCapability(HasPPMStart
) ? 1 : 2);
443 // PPM settings fields
444 ui
->label_ppmPolarity
->setVisible(mask
& MASK_PPM_FIELDS
);
445 ui
->ppmPolarity
->setVisible(mask
& MASK_PPM_FIELDS
);
446 ui
->ppmPolarity
->setCurrentIndex(module
.ppm
.pulsePol
);
447 ui
->label_ppmOutputType
->setVisible(mask
& MASK_OPEN_DRAIN
);
448 ui
->ppmOutputType
->setVisible(mask
& MASK_OPEN_DRAIN
);
449 ui
->ppmOutputType
->setCurrentIndex(module
.ppm
.outputType
);
450 ui
->label_ppmDelay
->setVisible(mask
& MASK_PPM_FIELDS
);
451 ui
->ppmDelay
->setVisible(mask
& MASK_PPM_FIELDS
);
452 ui
->ppmDelay
->setValue(module
.ppm
.delay
);
453 ui
->label_ppmFrameLength
->setVisible(mask
& MASK_PPM_FIELDS
);
454 ui
->ppmFrameLength
->setVisible(mask
& MASK_PPM_FIELDS
);
455 ui
->ppmFrameLength
->setMinimum(module
.channelsCount
*(model
->extendedLimits
? 2.250 : 2)+3.5);
456 ui
->ppmFrameLength
->setMaximum(firmware
->getCapability(PPMFrameLength
));
457 ui
->ppmFrameLength
->setValue(22.5+((double)module
.ppm
.frameLength
)*0.5);
459 // Antenna slection on Horus
460 ui
->label_antenna
->setVisible(mask
& MASK_ANTENNA
);
461 ui
->antennaMode
->setVisible(mask
& MASK_ANTENNA
);
462 ui
->antennaMode
->setCurrentIndex(module
.pxx
.external_antenna
);
465 ui
->sportOut
->setVisible(mask
& MASK_R9M
);
466 ui
->label_sportOut
->setVisible(mask
& MASK_R9M
);
467 ui
->sportOut
->setCurrentIndex(module
.pxx
.sport_out
);
469 ui
->r9mPower
->setVisible(mask
& MASK_R9M
);
470 ui
->label_r9mPower
->setVisible(mask
& MASK_R9M
);
471 ui
->r9mPower
->setCurrentIndex(module
.pxx
.power
);
474 // Multi settings fields
475 ui
->label_multiProtocol
->setVisible(mask
& MASK_MULTIMODULE
);
476 ui
->multiProtocol
->setVisible(mask
& MASK_MULTIMODULE
);
477 ui
->multiProtocol
->setCurrentIndex(module
.multi
.rfProtocol
);
478 ui
->label_multiSubType
->setVisible(mask
& MASK_MULTIMODULE
);
479 ui
->multiSubType
->setVisible(mask
& MASK_MULTIMODULE
);
480 ui
->label_option
->setVisible(mask
& MASK_MULTIOPTION
);
481 ui
->optionValue
->setVisible(mask
& MASK_MULTIOPTION
);
483 if (mask
& MASK_MULTIMODULE
) {
484 int numEntries
= multiProtocols
.getProtocol(module
.multi
.rfProtocol
).numSubytes();
485 if (module
.multi
.customProto
)
487 // Removes extra items
488 ui
->multiSubType
->setMaxCount(numEntries
);
489 for (int i
=0; i
< numEntries
; i
++) {
490 if (i
< ui
->multiSubType
->count())
491 ui
->multiSubType
->setItemText(i
, ModelPrinter::printMultiSubType(module
.multi
.rfProtocol
, module
.multi
.customProto
, i
));
493 ui
->multiSubType
->addItem(ModelPrinter::printMultiSubType(module
.multi
.rfProtocol
, module
.multi
.customProto
, i
), (QVariant
) i
);
497 if (mask
& MASK_MULTIOPTION
) {
498 auto pdef
= multiProtocols
.getProtocol(module
.multi
.rfProtocol
);
499 ui
->optionValue
->setMinimum(pdef
.getOptionMin());
500 ui
->optionValue
->setMaximum(pdef
.getOptionMax());
501 ui
->optionValue
->setValue(module
.multi
.optionValue
);
502 ui
->label_option
->setText(qApp
->translate("Multiprotocols", qPrintable(pdef
.optionsstr
)));
504 ui
->multiSubType
->setCurrentIndex(module
.subType
);
506 ui
->autoBind
->setVisible(mask
& MASK_MULTIMODULE
);
507 ui
->autoBind
->setChecked(module
.multi
.autoBindMode
? Qt::Checked
: Qt::Unchecked
);
508 ui
->lowPower
->setVisible(mask
& MASK_MULTIMODULE
);
509 ui
->lowPower
->setChecked(module
.multi
.lowPowerMode
? Qt::Checked
: Qt::Unchecked
);
512 ui
->label_failsafeMode
->setVisible(mask
& MASK_FAILSAFES
);
513 ui
->failsafeMode
->setVisible(mask
& MASK_FAILSAFES
);
515 if ((mask
& MASK_FAILSAFES
) && module
.failsafeMode
== FAILSAFE_CUSTOM
) {
516 if (ui
->failsafesGroupBox
->isHidden()) {
518 ui
->failsafesGroupBox
->setVisible(true);
522 ui
->failsafesGroupBox
->setVisible(false);
525 if (mask
& MASK_FAILSAFES
) {
526 ui
->failsafeMode
->setCurrentIndex(module
.failsafeMode
);
528 if (firmware
->getCapability(ChannelsName
)) {
531 QMapIterator
<int, ChannelFailsafeWidgetsGroup
> i(failsafeGroupsMap
);
532 while (i
.hasNext()) {
535 name
= QString(model
->limitData
[chan
+ module
.channelsStart
].name
).trimmed();
537 i
.value().label
->setText(QString::number(chan
+ 1));
539 i
.value().label
->setText(name
);
544 if (mask
& MASK_CHANNELS_RANGE
) {
545 ui
->channelsStart
->setMaximum(33 - ui
->channelsCount
->value());
546 ui
->channelsCount
->setMaximum(qMin(16, 33-ui
->channelsStart
->value()));
550 void ModulePanel::on_trainerMode_currentIndexChanged(int index
)
553 model
->trainerMode
= index
;
559 void ModulePanel::onProtocolChanged(int index
)
562 module
.protocol
= ui
->protocol
->itemData(index
).toInt();
568 void ModulePanel::on_ppmPolarity_currentIndexChanged(int index
)
570 module
.ppm
.pulsePol
= index
;
574 void ModulePanel::on_antennaMode_currentIndexChanged(int index
)
576 module
.pxx
.external_antenna
= index
;
580 void ModulePanel::on_sportOut_currentIndexChanged(int index
)
582 module
.pxx
.sport_out
= index
;
586 void ModulePanel::on_r9mPower_currentIndexChanged(int index
)
588 module
.pxx
.power
= index
;
592 void ModulePanel::on_ppmOutputType_currentIndexChanged(int index
)
594 module
.ppm
.outputType
= index
;
598 void ModulePanel::on_channelsCount_editingFinished()
600 if (!lock
&& module
.channelsCount
!= ui
->channelsCount
->value()) {
601 module
.channelsCount
= ui
->channelsCount
->value();
603 emit
channelsRangeChanged();
608 void ModulePanel::on_channelsStart_editingFinished()
610 if (!lock
&& module
.channelsStart
!= (unsigned)ui
->channelsStart
->value() - 1) {
611 module
.channelsStart
= (unsigned)ui
->channelsStart
->value() - 1;
613 emit
channelsRangeChanged();
618 void ModulePanel::on_ppmDelay_editingFinished()
620 if (!lock
&& module
.ppm
.delay
!= ui
->ppmDelay
->value()) {
621 // TODO only accept valid values
622 module
.ppm
.delay
= ui
->ppmDelay
->value();
627 void ModulePanel::on_rxNumber_editingFinished()
629 if (module
.modelId
!= (unsigned)ui
->rxNumber
->value()) {
630 module
.modelId
= (unsigned)ui
->rxNumber
->value();
635 void ModulePanel::on_ppmFrameLength_editingFinished()
637 int val
= (ui
->ppmFrameLength
->value()-22.5) / 0.5;
638 if (module
.ppm
.frameLength
!= val
) {
639 module
.ppm
.frameLength
= val
;
644 void ModulePanel::on_failsafeMode_currentIndexChanged(int value
)
647 module
.failsafeMode
= value
;
653 void ModulePanel::onMultiProtocolChanged(int index
)
657 module
.multi
.rfProtocol
= (unsigned int) index
;
658 unsigned int maxSubTypes
= multiProtocols
.getProtocol(index
).numSubytes();
659 if (module
.multi
.customProto
)
661 module
.subType
= std::min(module
.subType
, maxSubTypes
-1);
668 void ModulePanel::on_optionValue_editingFinished()
670 if (module
.multi
.optionValue
!= ui
->optionValue
->value()) {
671 module
.multi
.optionValue
= ui
->optionValue
->value();
676 void ModulePanel::on_multiSubType_currentIndexChanged(int index
)
680 module
.subType
= index
;
687 void ModulePanel::on_autoBind_stateChanged(int state
)
689 module
.multi
.autoBindMode
= (state
== Qt::Checked
);
691 void ModulePanel::on_lowPower_stateChanged(int state
)
693 module
.multi
.lowPowerMode
= (state
== Qt::Checked
);
696 // updtSb (update spin box(es)): 0=none or bitmask of FailsafeValueDisplayTypes
697 void ModulePanel::setChannelFailsafeValue(const int channel
, const int value
, quint8 updtSb
)
699 if (channel
< 0 || channel
>= CPN_MAX_CHNOUT
)
702 module
.failsafeChannels
[channel
] = value
;
703 double pctVal
= divRoundClosest(value
* 1000, 1024) / 10.0;
704 // qDebug() << value << pctVal;
706 if (failsafeGroupsMap
.contains(channel
)) {
707 const ChannelFailsafeWidgetsGroup
& grp
= failsafeGroupsMap
.value(channel
);
708 if ((updtSb
& FAILSAFE_DISPLAY_PERCENT
) && grp
.sbPercent
) {
709 grp
.sbPercent
->blockSignals(true);
710 grp
.sbPercent
->setValue(pctVal
);
711 grp
.sbPercent
->blockSignals(false);
713 if ((updtSb
& FAILSAFE_DISPLAY_USEC
) && grp
.sbUsec
) {
714 grp
.sbUsec
->blockSignals(true);
715 grp
.sbUsec
->setValue(value
);
716 grp
.sbUsec
->blockSignals(false);
723 void ModulePanel::onFailsafeUsecChanged(int value
)
729 int channel
= sender()->property("index").toInt(&ok
);
731 setChannelFailsafeValue(channel
, value
, FAILSAFE_DISPLAY_PERCENT
);
734 void ModulePanel::onFailsafePercentChanged(double value
)
740 int channel
= sender()->property("index").toInt(&ok
);
742 setChannelFailsafeValue(channel
, divRoundClosest(int(value
* 1024), 100), FAILSAFE_DISPLAY_USEC
);
745 void ModulePanel::onFailsafeComboIndexChanged(int index
)
750 QComboBox
* cb
= qobject_cast
<QComboBox
*>(sender());
755 int channel
= sender()->property("index").toInt(&ok
);
757 module
.failsafeChannels
[channel
] = cb
->itemData(index
).toInt();
758 updateFailsafe(channel
);
765 void ModulePanel::onFailsafesDisplayValueTypeChanged(int type
)
767 if (failsafesValueDisplayType
!= type
) {
768 failsafesValueDisplayType
= type
;
769 foreach (ChannelFailsafeWidgetsGroup grp
, failsafeGroupsMap
) {
771 grp
.sbPercent
->setVisible(type
== FAILSAFE_DISPLAY_PERCENT
);
773 grp
.sbUsec
->setVisible(type
== FAILSAFE_DISPLAY_USEC
);
778 void ModulePanel::onExtendedLimitsToggled()
780 double channelMaxPct
= double(model
->getChannelsMax());
781 int channelMaxUs
= 512 * channelMaxPct
/ 100 * 2;
782 foreach (ChannelFailsafeWidgetsGroup grp
, failsafeGroupsMap
) {
784 grp
.sbPercent
->setRange(-channelMaxPct
, channelMaxPct
);
786 grp
.sbUsec
->setRange(-channelMaxUs
, channelMaxUs
);
790 void ModulePanel::updateFailsafe(int channel
)
792 if (channel
>= CPN_MAX_CHNOUT
|| !failsafeGroupsMap
.contains(channel
))
795 const int failsafeValue
= module
.failsafeChannels
[channel
];
796 const ChannelFailsafeWidgetsGroup
& grp
= failsafeGroupsMap
.value(channel
);
797 const bool valDisable
= (failsafeValue
== FAILSAFE_CHANNEL_HOLD
|| failsafeValue
== FAILSAFE_CHANNEL_NOPULSE
);
800 grp
.combo
->setCurrentIndex(grp
.combo
->findData(valDisable
? failsafeValue
: 0));
802 grp
.sbPercent
->setDisabled(valDisable
);
804 grp
.sbUsec
->setDisabled(valDisable
);
807 setChannelFailsafeValue(channel
, failsafeValue
, (FAILSAFE_DISPLAY_PERCENT
| FAILSAFE_DISPLAY_USEC
));
810 /******************************************************************************/
812 SetupPanel::SetupPanel(QWidget
* parent
, ModelData
& model
, GeneralSettings
& generalSettings
, Firmware
* firmware
):
813 ModelPanel(parent
, model
, generalSettings
, firmware
),
816 Board::Type board
= firmware
->getBoard();
820 memset(modules
, 0, sizeof(modules
));
824 QRegExp
rx(CHAR_FOR_NAMES_REGEX
);
825 ui
->name
->setValidator(new QRegExpValidator(rx
, this));
826 ui
->name
->setMaxLength(firmware
->getCapability(ModelName
));
828 if (firmware
->getCapability(ModelImage
)) {
831 QString path
= g
.profile
[g
.id()].sdPath();
832 path
.append("/IMAGES/");
836 if(IS_HORUS(board
)) {
837 filters
<< "*.bmp" << "*.jpg" << "*.png";
838 foreach ( QString file
, qd
.entryList(filters
, QDir::Files
) ) {
840 QString temp
= fi
.fileName();
841 if (!items
.contains(temp
) && temp
.length() <= 6+4) {
848 foreach (QString file
, qd
.entryList(filters
, QDir::Files
)) {
850 QString temp
= fi
.completeBaseName();
851 if (!items
.contains(temp
) && temp
.length() <= 10+4) {
857 if (!items
.contains(model
.bitmap
)) {
858 items
.append(model
.bitmap
);
861 foreach (QString file
, items
) {
862 ui
->image
->addItem(file
);
863 if (file
== model
.bitmap
) {
864 ui
->image
->setCurrentIndex(ui
->image
->count()-1);
865 QString fileName
= path
;
866 fileName
.append(model
.bitmap
);
867 if (!IS_HORUS(board
))
868 fileName
.append(".bmp");
869 QImage
image(fileName
);
870 if (image
.isNull() && !IS_HORUS(board
)) {
872 fileName
.append(model
.bitmap
);
873 fileName
.append(".BMP");
874 image
.load(fileName
);
876 if (!image
.isNull()) {
877 if (IS_HORUS(board
)) {
878 ui
->imagePreview
->setFixedSize(QSize(192, 114));
879 ui
->imagePreview
->setPixmap(QPixmap::fromImage(image
.scaled(192, 114)));
882 ui
->imagePreview
->setFixedSize(QSize(64, 32));
883 ui
->imagePreview
->setPixmap(QPixmap::fromImage(image
.scaled(64, 32)));
891 ui
->modelImage_label
->hide();
892 ui
->imagePreview
->hide();
895 QWidget
* prevFocus
= ui
->image
;
896 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++) {
897 if (i
<firmware
->getCapability(Timers
)) {
898 timers
[i
] = new TimerPanel(this, model
, model
.timers
[i
], generalSettings
, firmware
, prevFocus
);
899 ui
->gridLayout
->addWidget(timers
[i
], 1+i
, 1);
900 connect(timers
[i
], &TimerPanel::modified
, this, &SetupPanel::modified
);
901 prevFocus
= timers
[i
]->getLastFocus();
904 foreach(QLabel
*label
, findChildren
<QLabel
*>(QRegExp(QString("label_timer%1").arg(i
+1)))) {
910 if (firmware
->getCapability(HasTopLcd
)) {
911 ui
->toplcdTimer
->setField(model
.toplcdTimer
, this);
912 for (int i
=0; i
<CPN_MAX_TIMERS
; i
++) {
913 if (i
<firmware
->getCapability(Timers
)) {
914 ui
->toplcdTimer
->addItem(tr("Timer %1").arg(i
+1), i
);
919 ui
->toplcdTimerLabel
->hide();
920 ui
->toplcdTimer
->hide();
923 if (!firmware
->getCapability(HasDisplayText
)) {
924 ui
->displayText
->hide();
925 ui
->editText
->hide();
928 if (!firmware
->getCapability(GlobalFunctions
)) {
929 ui
->gfEnabled
->hide();
932 // Beep Center checkboxes
933 prevFocus
= ui
->trimsDisplay
;
934 int analogs
= CPN_MAX_STICKS
+ getBoardCapability(board
, Board::Pots
) + getBoardCapability(board
, Board::Sliders
);
936 for (int i
=0; i
< analogs
+ firmware
->getCapability(RotaryEncoders
); i
++) {
937 RawSource
src((i
< analogs
) ? SOURCE_TYPE_STICK
: SOURCE_TYPE_ROTARY_ENCODER
, (i
< analogs
) ? i
: analogs
- i
);
938 QCheckBox
* checkbox
= new QCheckBox(this);
939 checkbox
->setProperty("index", i
);
940 checkbox
->setText(src
.toString(&model
, &generalSettings
));
941 ui
->centerBeepLayout
->addWidget(checkbox
, 0, i
+1);
942 connect(checkbox
, SIGNAL(toggled(bool)), this, SLOT(onBeepCenterToggled(bool)));
943 centerBeepCheckboxes
<< checkbox
;
944 if (IS_HORUS_OR_TARANIS(board
)) {
945 if (src
.isPot(&genAryIdx
) && !generalSettings
.isPotAvailable(genAryIdx
)) {
948 else if (src
.isSlider(&genAryIdx
) && !generalSettings
.isSliderAvailable(genAryIdx
)) {
952 QWidget::setTabOrder(prevFocus
, checkbox
);
953 prevFocus
= checkbox
;
956 // Startup switches warnings
957 for (int i
=0; i
<getBoardCapability(board
, Board::Switches
); i
++) {
958 Board::SwitchInfo switchInfo
= Boards::getSwitchInfo(board
, i
);
959 switchInfo
.config
= Board::SwitchType(generalSettings
.switchConfig
[i
]);
960 if (switchInfo
.config
== Board::SWITCH_NOT_AVAILABLE
|| switchInfo
.config
== Board::SWITCH_TOGGLE
) {
963 RawSource
src(RawSourceType::SOURCE_TYPE_SWITCH
, i
);
964 QLabel
* label
= new QLabel(this);
965 QSlider
* slider
= new QSlider(this);
966 QCheckBox
* cb
= new QCheckBox(this);
967 slider
->setProperty("index", i
);
968 slider
->setOrientation(Qt::Vertical
);
969 slider
->setMinimum(0);
970 slider
->setInvertedAppearance(true);
971 slider
->setInvertedControls(true);
972 slider
->setTickPosition(QSlider::TicksBothSides
);
973 slider
->setMinimumSize(QSize(30, 50));
974 slider
->setMaximumSize(QSize(50, 50));
975 slider
->setSingleStep(1);
976 slider
->setPageStep(1);
977 slider
->setTickInterval(1);
978 label
->setText(src
.toString(&model
, &generalSettings
));
979 slider
->setMaximum(switchInfo
.config
== Board::SWITCH_3POS
? 2 : 1);
980 cb
->setProperty("index", i
);
981 ui
->switchesStartupLayout
->addWidget(label
, 0, i
+1);
982 ui
->switchesStartupLayout
->setAlignment(label
, Qt::AlignCenter
);
983 ui
->switchesStartupLayout
->addWidget(slider
, 1, i
+1);
984 ui
->switchesStartupLayout
->setAlignment(slider
, Qt::AlignCenter
);
985 ui
->switchesStartupLayout
->addWidget(cb
, 2, i
+1);
986 ui
->switchesStartupLayout
->setAlignment(cb
, Qt::AlignCenter
);
987 connect(slider
, SIGNAL(valueChanged(int)), this, SLOT(startupSwitchEdited(int)));
988 connect(cb
, SIGNAL(toggled(bool)), this, SLOT(startupSwitchToggled(bool)));
989 startupSwitchesSliders
<< slider
;
990 startupSwitchesCheckboxes
<< cb
;
991 QWidget::setTabOrder(prevFocus
, slider
);
992 QWidget::setTabOrder(slider
, cb
);
997 prevFocus
= ui
->potWarningMode
;
998 if (IS_HORUS_OR_TARANIS(board
)) {
999 for (int i
=0; i
<getBoardCapability(board
, Board::Pots
)+getBoardCapability(board
, Board::Sliders
); i
++) {
1000 RawSource
src(SOURCE_TYPE_STICK
, CPN_MAX_STICKS
+ i
);
1001 QCheckBox
* cb
= new QCheckBox(this);
1002 cb
->setProperty("index", i
);
1003 cb
->setText(src
.toString(&model
, &generalSettings
));
1004 ui
->potWarningLayout
->addWidget(cb
, 0, i
+1);
1005 connect(cb
, SIGNAL(toggled(bool)), this, SLOT(potWarningToggled(bool)));
1006 potWarningCheckboxes
<< cb
;
1007 if (src
.isPot(&genAryIdx
) && !generalSettings
.isPotAvailable(genAryIdx
)) {
1010 else if (src
.isSlider(&genAryIdx
) && !generalSettings
.isSliderAvailable(genAryIdx
)) {
1013 QWidget::setTabOrder(prevFocus
, cb
);
1018 ui
->label_potWarning
->hide();
1019 ui
->potWarningMode
->hide();
1022 if (IS_ARM(board
)) {
1023 ui
->trimsDisplay
->setField(model
.trimsDisplay
, this);
1026 ui
->labelTrimsDisplay
->hide();
1027 ui
->trimsDisplay
->hide();
1030 for (int i
=0; i
<firmware
->getCapability(NumModules
); i
++) {
1031 modules
[i
] = new ModulePanel(this, model
, model
.moduleData
[i
], generalSettings
, firmware
, i
);
1032 ui
->modulesLayout
->addWidget(modules
[i
]);
1033 connect(modules
[i
], &ModulePanel::modified
, this, &SetupPanel::modified
);
1034 connect(this, &SetupPanel::extendedLimitsToggled
, modules
[i
], &ModulePanel::onExtendedLimitsToggled
);
1037 if (firmware
->getCapability(ModelTrainerEnable
)) {
1038 modules
[CPN_MAX_MODULES
] = new ModulePanel(this, model
, model
.moduleData
[CPN_MAX_MODULES
], generalSettings
, firmware
, -1);
1039 ui
->modulesLayout
->addWidget(modules
[CPN_MAX_MODULES
]);
1040 connect(modules
[CPN_MAX_MODULES
], &ModulePanel::modified
, this, &SetupPanel::modified
);
1043 disableMouseScrolling();
1048 SetupPanel::~SetupPanel()
1053 void SetupPanel::on_extendedLimits_toggled(bool checked
)
1055 model
->extendedLimits
= checked
;
1056 emit
extendedLimitsToggled();
1060 void SetupPanel::on_throttleWarning_toggled(bool checked
)
1062 model
->disableThrottleWarning
= !checked
;
1066 void SetupPanel::on_throttleReverse_toggled(bool checked
)
1068 model
->throttleReversed
= checked
;
1072 void SetupPanel::on_extendedTrims_toggled(bool checked
)
1074 model
->extendedTrims
= checked
;
1078 void SetupPanel::on_trimIncrement_currentIndexChanged(int index
)
1080 model
->trimInc
= index
-2;
1084 void SetupPanel::on_throttleSource_currentIndexChanged(int index
)
1087 model
->thrTraceSrc
= index
;
1092 void SetupPanel::on_name_editingFinished()
1094 if (QString(model
->name
) != ui
->name
->text()) {
1095 int length
= ui
->name
->maxLength();
1096 strncpy(model
->name
, ui
->name
->text().toLatin1(), length
);
1101 void SetupPanel::on_image_currentIndexChanged(int index
)
1104 Board::Type board
= firmware
->getBoard();
1105 strncpy(model
->bitmap
, ui
->image
->currentText().toLatin1(), 10);
1106 QString path
= g
.profile
[g
.id()].sdPath();
1107 path
.append("/IMAGES/");
1110 QString fileName
=path
;
1111 fileName
.append(model
->bitmap
);
1112 if (!IS_HORUS(board
))
1113 fileName
.append(".bmp");
1114 QImage
image(fileName
);
1115 if (image
.isNull() && !IS_HORUS(board
)) {
1117 fileName
.append(model
->bitmap
);
1118 fileName
.append(".BMP");
1119 image
.load(fileName
);
1121 if (!image
.isNull()) {
1122 if (IS_HORUS(board
)) {
1123 ui
->imagePreview
->setFixedSize(QSize(192, 114));
1124 ui
->imagePreview
->setPixmap(QPixmap::fromImage(image
.scaled(192, 114)));
1127 ui
->imagePreview
->setFixedSize(QSize(64, 32));
1128 ui
->imagePreview
->setPixmap(QPixmap::fromImage(image
.scaled(64, 32)));
1132 ui
->imagePreview
->clear();
1136 ui
->imagePreview
->clear();
1142 void SetupPanel::populateThrottleSourceCB()
1144 Board::Type board
= firmware
->getBoard();
1146 ui
->throttleSource
->clear();
1147 ui
->throttleSource
->addItem(QObject::tr("THR"));
1148 for (int i
=0; i
<getBoardCapability(board
, Board::Pots
)+getBoardCapability(board
, Board::Sliders
); i
++) {
1149 ui
->throttleSource
->addItem(firmware
->getAnalogInputName(4+i
), i
);
1151 for (int i
=0; i
<firmware
->getCapability(Outputs
); i
++) {
1152 ui
->throttleSource
->addItem(RawSource(SOURCE_TYPE_CH
, i
).toString(model
, &generalSettings
));
1154 ui
->throttleSource
->setCurrentIndex(model
->thrTraceSrc
);
1158 void SetupPanel::update()
1160 ui
->name
->setText(model
->name
);
1161 ui
->throttleReverse
->setChecked(model
->throttleReversed
);
1162 populateThrottleSourceCB();
1163 ui
->throttleWarning
->setChecked(!model
->disableThrottleWarning
);
1164 ui
->trimIncrement
->setCurrentIndex(model
->trimInc
+2);
1165 ui
->throttleTrim
->setChecked(model
->thrTrim
);
1166 ui
->extendedLimits
->setChecked(model
->extendedLimits
);
1167 ui
->extendedTrims
->setChecked(model
->extendedTrims
);
1168 ui
->displayText
->setChecked(model
->displayChecklist
);
1169 ui
->editText
->setEnabled(model
->displayChecklist
);
1170 ui
->gfEnabled
->setChecked(!model
->noGlobalFunctions
);
1173 updateStartupSwitches();
1175 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
1176 updatePotWarnings();
1179 for (int i
=0; i
<firmware
->getCapability(Timers
); i
++) {
1180 timers
[i
]->update();
1183 for (int i
=0; i
<CPN_MAX_MODULES
+1; i
++) {
1185 modules
[i
]->update();
1190 void SetupPanel::updateBeepCenter()
1192 for (int i
=0; i
<centerBeepCheckboxes
.size(); i
++) {
1193 centerBeepCheckboxes
[i
]->setChecked(model
->beepANACenter
& (0x01 << i
));
1197 void SetupPanel::updateStartupSwitches()
1201 uint64_t switchStates
= model
->switchWarningStates
;
1204 for (int i
=0; i
<startupSwitchesSliders
.size(); i
++) {
1205 QSlider
* slider
= startupSwitchesSliders
[i
];
1206 QCheckBox
* cb
= startupSwitchesCheckboxes
[i
];
1207 int index
= slider
->property("index").toInt();
1208 bool enabled
= !(model
->switchWarningEnable
& (1 << index
));
1209 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
1210 value
= (switchStates
>> (2*index
)) & 0x03;
1211 if (generalSettings
.switchConfig
[index
] != Board::SWITCH_3POS
&& value
== 2) {
1216 value
= (i
==0 ? switchStates
& 0x3 : switchStates
& 0x1);
1217 switchStates
>>= (i
==0 ? 2 : 1);
1219 slider
->setValue(value
);
1220 slider
->setEnabled(enabled
);
1221 cb
->setChecked(enabled
);
1227 void SetupPanel::startupSwitchEdited(int value
)
1232 int index
= sender()->property("index").toInt();
1234 if (IS_HORUS_OR_TARANIS(firmware
->getBoard())) {
1236 mask
= 0x03ull
<< shift
;
1244 mask
= 0x01ull
<< shift
;
1248 model
->switchWarningStates
&= ~mask
;
1250 if (IS_HORUS_OR_TARANIS(firmware
->getBoard()) && generalSettings
.switchConfig
[index
] != Board::SWITCH_3POS
) {
1257 model
->switchWarningStates
|= ((uint64_t)value
<< shift
);
1260 updateStartupSwitches();
1265 void SetupPanel::startupSwitchToggled(bool checked
)
1268 int index
= sender()->property("index").toInt();
1271 model
->switchWarningEnable
&= ~(1 << index
);
1273 model
->switchWarningEnable
|= (1 << index
);
1275 updateStartupSwitches();
1280 void SetupPanel::updatePotWarnings()
1283 ui
->potWarningMode
->setCurrentIndex(model
->potsWarningMode
);
1284 for (int i
=0; i
<potWarningCheckboxes
.size(); i
++) {
1285 QCheckBox
*checkbox
= potWarningCheckboxes
[i
];
1286 int index
= checkbox
->property("index").toInt();
1287 checkbox
->setChecked(!model
->potsWarningEnabled
[index
]);
1288 checkbox
->setDisabled(model
->potsWarningMode
== 0);
1293 void SetupPanel::potWarningToggled(bool checked
)
1296 int index
= sender()->property("index").toInt();
1297 model
->potsWarningEnabled
[index
] = !checked
;
1298 updatePotWarnings();
1303 void SetupPanel::on_potWarningMode_currentIndexChanged(int index
)
1306 model
->potsWarningMode
= index
;
1307 updatePotWarnings();
1312 void SetupPanel::on_displayText_toggled(bool checked
)
1314 model
->displayChecklist
= checked
;
1315 ui
->editText
->setEnabled(checked
);
1319 void SetupPanel::on_gfEnabled_toggled(bool checked
)
1321 model
->noGlobalFunctions
= !checked
;
1325 void SetupPanel::on_throttleTrim_toggled(bool checked
)
1327 model
->thrTrim
= checked
;
1331 void SetupPanel::onBeepCenterToggled(bool checked
)
1334 int index
= sender()->property("index").toInt();
1335 unsigned int mask
= (0x01 << index
);
1337 model
->beepANACenter
|= mask
;
1339 model
->beepANACenter
&= ~mask
;
1344 void SetupPanel::on_editText_clicked()
1346 ChecklistDialog
*g
= new ChecklistDialog(this, ui
->name
->text());