38 #include <QStringList>
41 #include <QVBoxLayout>
42 #include <QPushButton>
43 #include <QDesktopServices>
45 #include <QMessageBox>
50 #include "actuatorcommand.h"
51 #include "actuatorsettings.h"
52 #include "stabilizationsettings.h"
53 #include "systemsettings.h"
56 #define THROTTLE_NEUTRAL_FRACTION 0.02
57 #define ARMING_NEUTRAL_FRACTION 0.62
59 #define ACCESS_MIN_MOVE -3
60 #define ACCESS_MAX_MOVE 3
61 #define STICK_MIN_MOVE -8
62 #define STICK_MAX_MOVE 8
64 #define MIN_SANE_CHANNEL_VALUE 15
65 #define MAX_SANE_CHANNEL_VALUE 32768
66 #define MIN_SANE_RANGE 125
71 #define INITIAL_OFFSET 42
75 "always disarmed",
"Always Disarmed",
false,
false,
true },
79 "Roll Left+Throttle",
false,
true,
false },
81 "Roll Right+Throttle",
false,
true,
false },
87 "roll right and yaw left",
"Corners+Throttle",
false,
true,
false },
92 , wizardStep(wizardNone)
93 , transmitterType(heli)
96 , cbArmingOption(nullptr)
97 , lastArmingMethod(ARM_INVALID)
98 , armingConfigUpdating(false)
104 m_config =
new Ui_InputWidget();
105 m_config->setupUi(
this);
115 foreach (QString name, manualSettingsObj->getField(
"ChannelNumber")->getElementNames()) {
116 Q_ASSERT(index < static_cast<int>(ManualControlSettings::CHANNELGROUPS_NUMELEM));
118 m_config->channelSettings->layout()->addWidget(inpForm);
121 inpForm->ui->channelGroup, index);
123 inpForm->ui->channelNumber, index);
129 inpForm->ui->channelNeutral, index);
132 if (index == ManualControlSettings::CHANNELGROUPS_COLLECTIVE) {
134 this, &ConfigInputWidget::checkCollective);
137 int index2 = manualCommandObj->getField(
"Channel")->getElementNames().indexOf(name);
140 inpForm->ui->channelCurrent, index2);
142 inpForm->sbChannelCurrent, index2);
150 m_config->channelSettings->layout()->addWidget(inpForm);
151 QString name =
"RSSI";
155 inpForm->ui->channelNumber, 0);
160 connect(m_config->configurationWizard, &QAbstractButton::clicked,
this,
161 &ConfigInputWidget::goToWizard);
162 connect(m_config->runCalibration, &QAbstractButton::toggled,
this,
163 &ConfigInputWidget::simpleCalibration);
165 connect(m_config->wzNext, &QAbstractButton::clicked,
this, &ConfigInputWidget::wzNext);
166 connect(m_config->wzCancel, &QAbstractButton::clicked,
this, &ConfigInputWidget::wzCancel);
167 connect(m_config->wzBack, &QAbstractButton::clicked,
this, &ConfigInputWidget::wzBack);
169 m_config->stackedWidget->setCurrentIndex(0);
173 &ConfigInputWidget::moveFMSlider);
175 &ConfigInputWidget::updatePositionSlider);
178 const QStringList axes({
"Roll",
"Pitch",
"Yaw",
"Rep" });
179 for (
int i = 1;
i <= 3;
i++) {
180 foreach (
const QString &axis, axes) {
182 this->findChild<QComboBox *>(QString(
"fmsSsPos%1%2").arg(
i).arg(axis));
184 connect(child, &QComboBox::currentTextChanged,
this,
185 &ConfigInputWidget::checkReprojection);
190 fillArmingComboBox();
191 ActuatorSettings *actuatorSettings =
194 &ConfigInputWidget::checkArmingConfig);
195 connect(m_config->cbArmMethod, QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
196 &ConfigInputWidget::checkArmingConfig);
197 connect(m_config->cbThrottleCheck, &QCheckBox::stateChanged,
this,
198 &ConfigInputWidget::checkArmingConfig);
199 connect(m_config->sbThrottleTimeout, QOverload<int>::of(&QSpinBox::valueChanged),
this,
200 &ConfigInputWidget::checkArmingConfig);
201 connect(m_config->sbFailsafeTimeout, QOverload<int>::of(&QSpinBox::valueChanged),
this,
202 &ConfigInputWidget::checkArmingConfig);
203 connect(m_config->cbFailsafeTimeout, &QCheckBox::stateChanged,
this,
204 &ConfigInputWidget::timeoutCheckboxChanged);
205 connect(m_config->cbThrottleTimeout, &QCheckBox::stateChanged,
this,
206 &ConfigInputWidget::timeoutCheckboxChanged);
208 &ConfigInputWidget::updateArmingConfig);
211 cbArmingOption =
new QComboBox(
this);
212 cbArmingOption->setVisible(
false);
213 cbArmingOption->setProperty(
"objrelation",
214 QStringList{
"objname:ManualControlSettings",
"fieldname:Arming" });
215 m_config->gbArming->layout()->addWidget(cbArmingOption);
224 m_config->graphicsView->setScene(
new QGraphicsScene(
this));
225 m_config->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
226 m_renderer =
new QSvgRenderer();
227 QGraphicsScene *l_scene = m_config->graphicsView->scene();
228 if (QFile::exists(
":/configgadget/images/TX2.svg")
229 && m_renderer->load(QString(
":/configgadget/images/TX2.svg")) && m_renderer->isValid()) {
232 m_txBackground =
new QGraphicsSvgItem();
234 m_txBackground->setFlags(QGraphicsItem::ItemClipsChildrenToShape
235 | QGraphicsItem::ItemClipsToShape);
236 m_txBackground->setSharedRenderer(m_renderer);
237 m_txBackground->setElementId(
"background");
238 l_scene->addItem(m_txBackground);
240 m_txMainBody =
new QGraphicsSvgItem();
241 m_txMainBody->setParentItem(m_txBackground);
242 m_txMainBody->setSharedRenderer(m_renderer);
243 m_txMainBody->setElementId(
"body");
245 m_txLeftStick =
new QGraphicsSvgItem();
246 m_txLeftStick->setParentItem(m_txBackground);
247 m_txLeftStick->setSharedRenderer(m_renderer);
248 m_txLeftStick->setElementId(
"ljoy");
250 m_txRightStick =
new QGraphicsSvgItem();
251 m_txRightStick->setParentItem(m_txBackground);
252 m_txRightStick->setSharedRenderer(m_renderer);
253 m_txRightStick->setElementId(
"rjoy");
255 m_txAccess0 =
new QGraphicsSvgItem();
256 m_txAccess0->setParentItem(m_txBackground);
257 m_txAccess0->setSharedRenderer(m_renderer);
258 m_txAccess0->setElementId(
"access0");
260 m_txAccess1 =
new QGraphicsSvgItem();
261 m_txAccess1->setParentItem(m_txBackground);
262 m_txAccess1->setSharedRenderer(m_renderer);
263 m_txAccess1->setElementId(
"access1");
265 m_txAccess2 =
new QGraphicsSvgItem();
266 m_txAccess2->setParentItem(m_txBackground);
267 m_txAccess2->setSharedRenderer(m_renderer);
268 m_txAccess2->setElementId(
"access2");
270 m_txFlightMode =
new QGraphicsSvgItem();
271 m_txFlightMode->setParentItem(m_txBackground);
272 m_txFlightMode->setSharedRenderer(m_renderer);
273 m_txFlightMode->setElementId(
"flightModeCenter");
274 m_txFlightMode->setZValue(-10);
276 m_txArming =
new QGraphicsSvgItem();
277 m_txArming->setParentItem(m_txBackground);
278 m_txArming->setSharedRenderer(m_renderer);
279 m_txArming->setElementId(
"armedswitchleft");
280 m_txArming->setZValue(-10);
282 m_txArrows =
new QGraphicsSvgItem();
283 m_txArrows->setParentItem(m_txBackground);
284 m_txArrows->setSharedRenderer(m_renderer);
285 m_txArrows->setElementId(
"arrows");
286 m_txArrows->setVisible(
false);
288 QRectF orig = m_renderer->boundsOnElement(
"ljoy");
289 QMatrix Matrix = m_renderer->matrixForElement(
"ljoy");
290 orig = Matrix.mapRect(orig);
291 m_txLeftStickOrig.translate(orig.x(), orig.y());
292 m_txLeftStick->setTransform(m_txLeftStickOrig,
false);
294 orig = m_renderer->boundsOnElement(
"arrows");
295 Matrix = m_renderer->matrixForElement(
"arrows");
296 orig = Matrix.mapRect(orig);
297 m_txArrowsOrig.translate(orig.x(), orig.y());
298 m_txArrows->setTransform(m_txArrowsOrig,
false);
300 orig = m_renderer->boundsOnElement(
"body");
301 Matrix = m_renderer->matrixForElement(
"body");
302 orig = Matrix.mapRect(orig);
303 m_txMainBodyOrig.translate(orig.x(), orig.y());
304 m_txMainBody->setTransform(m_txMainBodyOrig,
false);
306 orig = m_renderer->boundsOnElement(
"flightModeCenter");
307 Matrix = m_renderer->matrixForElement(
"flightModeCenter");
308 orig = Matrix.mapRect(orig);
309 m_txFlightModeCOrig.translate(orig.x(), orig.y());
310 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
312 orig = m_renderer->boundsOnElement(
"flightModeLeft");
313 Matrix = m_renderer->matrixForElement(
"flightModeLeft");
314 orig = Matrix.mapRect(orig);
315 m_txFlightModeLOrig.translate(orig.x(), orig.y());
317 orig = m_renderer->boundsOnElement(
"flightModeRight");
318 Matrix = m_renderer->matrixForElement(
"flightModeRight");
319 orig = Matrix.mapRect(orig);
320 m_txFlightModeROrig.translate(orig.x(), orig.y());
322 orig = m_renderer->boundsOnElement(
"armedswitchright");
323 Matrix = m_renderer->matrixForElement(
"armedswitchright");
324 orig = Matrix.mapRect(orig);
325 m_txArmingSwitchOrigR.translate(orig.x(), orig.y());
327 orig = m_renderer->boundsOnElement(
"armedswitchleft");
328 Matrix = m_renderer->matrixForElement(
"armedswitchleft");
329 orig = Matrix.mapRect(orig);
330 m_txArmingSwitchOrigL.translate(orig.x(), orig.y());
332 orig = m_renderer->boundsOnElement(
"rjoy");
333 Matrix = m_renderer->matrixForElement(
"rjoy");
334 orig = Matrix.mapRect(orig);
335 m_txRightStickOrig.translate(orig.x(), orig.y());
336 m_txRightStick->setTransform(m_txRightStickOrig,
false);
338 orig = m_renderer->boundsOnElement(
"access0");
339 Matrix = m_renderer->matrixForElement(
"access0");
340 orig = Matrix.mapRect(orig);
341 m_txAccess0Orig.translate(orig.x(), orig.y());
342 m_txAccess0->setTransform(m_txAccess0Orig,
false);
344 orig = m_renderer->boundsOnElement(
"access1");
345 Matrix = m_renderer->matrixForElement(
"access1");
346 orig = Matrix.mapRect(orig);
347 m_txAccess1Orig.translate(orig.x(), orig.y());
348 m_txAccess1->setTransform(m_txAccess1Orig,
false);
350 orig = m_renderer->boundsOnElement(
"access2");
351 Matrix = m_renderer->matrixForElement(
"access2");
352 orig = Matrix.mapRect(orig);
353 m_txAccess2Orig.translate(orig.x(), orig.y());
354 m_txAccess2->setTransform(m_txAccess2Orig,
true);
356 m_config->graphicsView->fitInView(m_txMainBody, Qt::KeepAspectRatio);
357 m_config->graphicsView->setStyleSheet(
"background: transparent");
358 animate =
new QTimer(
this);
359 connect(animate, &QTimer::timeout,
this, &ConfigInputWidget::moveTxControls);
361 heliChannelOrder << ManualControlSettings::CHANNELGROUPS_COLLECTIVE
362 << ManualControlSettings::CHANNELGROUPS_THROTTLE
363 << ManualControlSettings::CHANNELGROUPS_ROLL
364 << ManualControlSettings::CHANNELGROUPS_PITCH
365 << ManualControlSettings::CHANNELGROUPS_YAW
366 << ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
367 << ManualControlSettings::CHANNELGROUPS_ACCESSORY0
368 << ManualControlSettings::CHANNELGROUPS_ACCESSORY1
369 << ManualControlSettings::CHANNELGROUPS_ACCESSORY2
370 << ManualControlSettings::CHANNELGROUPS_ARMING;
372 acroChannelOrder << ManualControlSettings::CHANNELGROUPS_THROTTLE
373 << ManualControlSettings::CHANNELGROUPS_ROLL
374 << ManualControlSettings::CHANNELGROUPS_PITCH
375 << ManualControlSettings::CHANNELGROUPS_YAW
376 << ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
377 << ManualControlSettings::CHANNELGROUPS_ACCESSORY0
378 << ManualControlSettings::CHANNELGROUPS_ACCESSORY1
379 << ManualControlSettings::CHANNELGROUPS_ACCESSORY2
380 << ManualControlSettings::CHANNELGROUPS_ARMING;
383 m_config->tabWidget->setCurrentIndex(0);
385 void ConfigInputWidget::resetTxControls()
388 m_txLeftStick->setTransform(m_txLeftStickOrig,
false);
389 m_txRightStick->setTransform(m_txRightStickOrig,
false);
390 m_txAccess0->setTransform(m_txAccess0Orig,
false);
391 m_txAccess1->setTransform(m_txAccess1Orig,
false);
392 m_txAccess2->setTransform(m_txAccess2Orig,
false);
393 m_txFlightMode->setElementId(
"flightModeCenter");
394 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
395 m_txArming->setElementId(
"armedswitchleft");
396 m_txArming->setTransform(m_txArmingSwitchOrigL,
false);
397 m_txArrows->setVisible(
false);
404 QWidget::resizeEvent(event);
405 m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
408 void ConfigInputWidget::goToWizard()
413 QMessageBox msgBox(
this);
414 msgBox.setText(tr(
"Arming Settings will be set to Always Disarmed for your safety."));
415 msgBox.setDetailedText(tr(
"You will have to reconfigure the arming settings manually "
416 "when the wizard is finished. After the last step of the "
417 "wizard you will be taken to the Arming Settings screen."));
418 msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
419 msgBox.setDefaultButton(QMessageBox::Cancel);
420 int ret = msgBox.exec();
423 case QMessageBox::Ok:
425 if (m_config->tabWidget->currentIndex() != 0) {
426 m_config->tabWidget->setCurrentIndex(0);
429 m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
431 case QMessageBox::Cancel:
438 void ConfigInputWidget::wzCancel()
442 dimOtherControls(
false);
443 manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata());
444 m_config->stackedWidget->setCurrentIndex(0);
447 wizardTearDownStep(wizardStep);
449 m_config->stackedWidget->setCurrentIndex(0);
452 manualSettingsObj->setData(previousManualSettingsData);
458 void ConfigInputWidget::wzNext()
463 wizardTearDownStep(wizardStep);
466 switch (wizardStep) {
478 if (currentChannelNum == -1) {
499 m_config->stackedWidget->setCurrentIndex(0);
500 m_config->tabWidget->setCurrentIndex(2);
507 void ConfigInputWidget::wzBack()
510 wizardTearDownStep(wizardStep);
513 switch (wizardStep) {
522 if (currentChannelNum == -1) {
547 void ConfigInputWidget::wizardSetUpStep(
enum wizardSteps step)
551 foreach (QPointer<QWidget> wd, extraWidgets) {
555 extraWidgets.clear();
556 m_config->graphicsView->setVisible(
false);
560 manualSettingsData = manualSettingsObj->getData();
561 manualSettingsData.Arming = ManualControlSettings::ARMING_ALWAYSDISARMED;
562 previousManualSettingsData = manualSettingsData;
565 for (uint
i = 0;
i < ManualControlSettings::CHANNELNUMBER_NUMELEM;
i++) {
566 manualSettingsData.ChannelNumber[
i] = 0;
567 manualSettingsData.ChannelMin[
i] = 0;
568 manualSettingsData.ChannelNeutral[
i] = 0;
569 manualSettingsData.ChannelMax[
i] = 0;
570 manualSettingsData.ChannelGroups[
i] = ManualControlSettings::CHANNELGROUPS_NONE;
573 manualSettingsObj->setData(manualSettingsData);
574 m_config->wzText->setText(
575 tr(
"Welcome to the inputs configuration wizard.\n"
576 "Please follow the instructions on the screen and move controls when asked to.\n"
577 "Make sure you have already configured your hardware settings on the proper tab and "
578 "restarted your board.\n"
579 "Note: if you are using RSSI injection to S.Bus, HSUM or PPM, please configure that "
580 "on the input screen and save before proceeding with this wizard.\n"));
581 m_config->stackedWidget->setCurrentIndex(1);
582 m_config->wzBack->setEnabled(
false);
583 m_config->wzNext->setEnabled(
true);
584 m_config->bypassFailsafeGroup->setVisible(
false);
587 m_config->graphicsView->setVisible(
true);
588 m_config->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
590 m_config->wzText->setText(tr(
"Please choose your transmitter type.\n"
591 "Mode 1 means your throttle stick is on the right.\n"
592 "Mode 2 means your throttle stick is on the left.\n"));
593 m_config->wzBack->setEnabled(
true);
594 QRadioButton *
mode1 =
new QRadioButton(tr(
"Mode 1"),
this);
595 QRadioButton *
mode2 =
new QRadioButton(tr(
"Mode 2"),
this);
596 mode2->setChecked(
true);
597 extraWidgets.clear();
598 extraWidgets.append(mode1);
599 extraWidgets.append(mode2);
600 m_config->checkBoxesLayout->layout()->addWidget(mode1);
601 m_config->checkBoxesLayout->layout()->addWidget(mode2);
604 m_config->wzText->setText(
605 tr(
"Please choose your transmitter mode.\n"
606 "Acro means normal transmitter.\n"
607 "Heli means there is a collective pitch and throttle input.\n"
608 "If you are using a heli transmitter please engage throttle hold now.\n"));
609 m_config->wzBack->setEnabled(
true);
610 QRadioButton *typeAcro =
new QRadioButton(tr(
"Acro"),
this);
611 QRadioButton *typeHeli =
new QRadioButton(tr(
"Heli"),
this);
612 typeAcro->setChecked(
true);
613 typeHeli->setChecked(
false);
614 extraWidgets.clear();
615 extraWidgets.append(typeAcro);
616 extraWidgets.append(typeHeli);
617 m_config->checkBoxesLayout->layout()->addWidget(typeAcro);
618 m_config->checkBoxesLayout->layout()->addWidget(typeHeli);
622 usedChannels.clear();
623 currentChannelNum = -1;
625 manualSettingsData = manualSettingsObj->getData();
627 &ConfigInputWidget::identifyControls);
629 m_config->wzNext->setEnabled(
false);
633 m_config->wzText->setText(
634 QString(tr(
"Please center all controls and press next when ready (if your FlightMode "
635 "switch has only two positions, leave it in either position).")));
640 m_config->wzText->setText(QString(
641 tr(
"Please move all controls <b>(including switches)</b> to their maximum extents in "
642 "all directions. (You may continue when all controls have moved)")));
644 manualSettingsData = manualSettingsObj->getData();
645 for (quint8
i = 0;
i < ManualControlSettings::CHANNELMAX_NUMELEM; ++
i) {
647 if (manualSettingsData.ChannelMin[
i] <= manualSettingsData.ChannelMax[
i]) {
648 manualSettingsData.ChannelMin[
i] =
649 manualSettingsData.ChannelNeutral[
i] - INITIAL_OFFSET;
650 manualSettingsData.ChannelMax[
i] =
651 manualSettingsData.ChannelNeutral[
i] + INITIAL_OFFSET;
653 manualSettingsData.ChannelMin[
i] =
654 manualSettingsData.ChannelNeutral[
i] + INITIAL_OFFSET;
655 manualSettingsData.ChannelMax[
i] =
656 manualSettingsData.ChannelNeutral[
i] - INITIAL_OFFSET;
660 &ConfigInputWidget::identifyLimits);
664 m_config->wzNext->setEnabled(
false);
667 dimOtherControls(
false);
669 extraWidgets.clear();
672 index < manualSettingsObj->getField(
"ChannelMax")->getElementNames().length();
674 QString name = manualSettingsObj->getField(
"ChannelMax")->getElementNames().at(index);
675 if (!name.contains(
"Access") && !name.contains(
"Flight")) {
676 QCheckBox *cb =
new QCheckBox(name,
this);
678 cb->setChecked(manualSettingsData.ChannelMax[index]
679 < manualSettingsData.ChannelMin[index]);
681 extraWidgets.append(cb);
682 m_config->checkBoxesLayout->layout()->addWidget(cb);
684 connect(cb, &QAbstractButton::toggled,
this, &ConfigInputWidget::invertControls);
688 m_config->wzText->setText(
689 QString(tr(
"Please check the picture below and correct all the sticks which show an "
690 "inverted movement, press next when ready.")));
695 dimOtherControls(
false);
697 extraWidgets.clear();
698 flightStatusObj->requestUpdate();
702 &ConfigInputWidget::detectFailsafe);
703 m_config->wzNext->setEnabled(
false);
704 m_config->graphicsView->setVisible(
false);
705 m_config->bypassFailsafeGroup->setVisible(
true);
706 connect(m_config->cbBypassFailsafe, &QAbstractButton::toggled,
this,
707 &ConfigInputWidget::detectFailsafe);
710 dimOtherControls(
false);
712 m_config->wzText->setText(QString(tr(
713 "You have completed this wizard, please check below if the picture mimics your sticks "
715 "These new settings aren't saved to the board yet, after pressing next you will go to "
716 "the Arming Settings "
717 "screen where you can set your desired arming sequence and save the configuration.")));
720 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE] =
721 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]
722 + ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]
723 - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])
724 * THROTTLE_NEUTRAL_FRACTION);
726 if ((abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]
728 .ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])
730 || (abs(manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]
732 .ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])
734 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE] =
735 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]
736 + (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]
737 - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE])
741 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_ARMING] =
742 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_ARMING]
743 + ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_ARMING]
744 - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_ARMING])
745 * ARMING_NEUTRAL_FRACTION);
747 manualSettingsObj->setData(manualSettingsData);
755 void ConfigInputWidget::wizardTearDownStep(
enum wizardSteps step)
757 QRadioButton *mode, *type;
758 Q_ASSERT(step == wizardStep);
763 mode = qobject_cast<QRadioButton *>(extraWidgets.at(0));
764 if (mode->isChecked())
765 transmitterMode = mode1;
767 transmitterMode =
mode2;
768 delete extraWidgets.at(0);
769 delete extraWidgets.at(1);
770 extraWidgets.clear();
773 type = qobject_cast<QRadioButton *>(extraWidgets.at(0));
774 if (type->isChecked())
775 transmitterType =
acro;
777 transmitterType =
heli;
778 delete extraWidgets.at(0);
779 delete extraWidgets.at(1);
780 extraWidgets.clear();
784 &ConfigInputWidget::identifyControls);
785 m_config->wzNext->setEnabled(
true);
789 manualCommandData = manualCommandObj->getData();
790 manualSettingsData = manualSettingsObj->getData();
791 for (
unsigned int i = 0;
i < ManualControlCommand::CHANNEL_NUMELEM; ++
i) {
792 manualSettingsData.ChannelNeutral[
i] = manualCommandData.Channel[
i];
793 minSeen[
i] = manualCommandData.Channel[
i];
794 maxSeen[
i] = manualCommandData.Channel[
i];
799 if (manualSettingsData.ChannelGroups[ManualControlSettings::CHANNELMIN_FLIGHTMODE]
800 == ManualControlSettings::CHANNELGROUPS_NONE) {
801 manualSettingsData.FlightModeNumber = 1;
804 manualSettingsObj->setData(manualSettingsData);
809 &ConfigInputWidget::identifyLimits);
811 &ConfigInputWidget::moveSticks);
812 manualSettingsObj->setData(manualSettingsData);
816 dimOtherControls(
false);
817 foreach (QWidget *wd, extraWidgets) {
818 QCheckBox *cb = qobject_cast<QCheckBox *>(wd);
820 disconnect(cb, &QAbstractButton::toggled,
this, &ConfigInputWidget::invertControls);
824 extraWidgets.clear();
826 &ConfigInputWidget::moveSticks);
829 dimOtherControls(
false);
830 extraWidgets.clear();
832 &ConfigInputWidget::detectFailsafe);
833 m_config->graphicsView->setVisible(
true);
834 m_config->bypassFailsafeGroup->setVisible(
false);
835 disconnect(m_config->cbBypassFailsafe, &QAbstractButton::toggled,
this,
836 &ConfigInputWidget::detectFailsafe);
839 dimOtherControls(
false);
842 &ConfigInputWidget::moveSticks);
853 void ConfigInputWidget::fastMdata()
856 if (!originalMetaData.empty())
864 quint16 fastUpdate = 150;
869 foreach (QVector<UAVDataObject *> list, objList) {
876 case ReceiverActivity::OBJID:
877 case FlightStatus::OBJID:
880 case ManualControlCommand::OBJID:
882 mdata.flightTelemetryUpdatePeriod = fastUpdate;
898 void ConfigInputWidget::restoreMdata()
900 foreach (QString objName, originalMetaData.keys()) {
904 originalMetaData.clear();
910 void ConfigInputWidget::setChannel(
int newChan)
912 if (newChan == ManualControlSettings::CHANNELGROUPS_COLLECTIVE)
913 m_config->wzText->setText(QString(
914 tr(
"Please enable the throttle hold mode and move the collective pitch stick.")));
915 else if (newChan == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE)
916 m_config->wzText->setText(QString(tr(
"Please toggle the flight mode switch. For switches "
917 "you may have to repeat this rapidly.")));
918 else if (newChan == ManualControlSettings::CHANNELGROUPS_ARMING)
919 m_config->wzText->setText(QString(tr(
920 "Please toggle the arming switch. For switches you may have to repeat this rapidly.")));
921 else if ((transmitterType ==
heli)
922 && (newChan == ManualControlSettings::CHANNELGROUPS_THROTTLE))
923 m_config->wzText->setText(
924 QString(tr(
"Please disable throttle hold mode and move the throttle stick.")));
926 m_config->wzText->setText(
927 QString(tr(
"Please move each control once at a time according to the instructions and "
929 "Move the %1 stick"))
930 .arg(manualSettingsObj->getField(
"ChannelGroups")->getElementNames().at(newChan)));
932 if (manualSettingsObj->getField(
"ChannelGroups")
935 .contains(
"Accessory")
936 || manualSettingsObj->getField(
"ChannelGroups")
939 .contains(
"FlightMode")
940 || manualSettingsObj->getField(
"ChannelGroups")
943 .contains(
"Arming")) {
944 m_config->wzNext->setEnabled(
true);
945 m_config->wzText->setText(m_config->wzText->text()
946 + tr(
" or click next to skip this channel."));
948 m_config->wzNext->setEnabled(
false);
950 setMoveFromCommand(newChan);
952 currentChannelNum = newChan;
953 channelDetected =
false;
960 void ConfigInputWidget::nextChannel()
962 QList<int> order = (transmitterType ==
heli) ? heliChannelOrder : acroChannelOrder;
964 if (currentChannelNum == -1) {
965 setChannel(order[0]);
968 for (
int i = 0;
i < order.length() - 1;
i++) {
969 if (order[
i] == currentChannelNum) {
970 setChannel(order[
i + 1]);
974 currentChannelNum = -1;
981 void ConfigInputWidget::prevChannel()
983 QList<int> order = transmitterType ==
heli ? heliChannelOrder : acroChannelOrder;
986 if (currentChannelNum == -1)
989 for (
int i = 1;
i < order.length();
i++) {
990 if (order[
i] == currentChannelNum) {
991 setChannel(order[
i - 1]);
992 usedChannels.removeLast();
996 currentChannelNum = -1;
1005 void ConfigInputWidget::identifyControls()
1007 static int debounce = 0;
1009 receiverActivityData = receiverActivityObj->getData();
1010 if (receiverActivityData.ActiveChannel == 255)
1013 if (channelDetected)
1016 receiverActivityData = receiverActivityObj->getData();
1017 currentChannel.group = receiverActivityData.ActiveGroup;
1018 currentChannel.number = receiverActivityData.ActiveChannel;
1019 if (currentChannel == lastChannel)
1021 lastChannel.group = currentChannel.group;
1022 lastChannel.number = currentChannel.number;
1026 if (!usedChannels.contains(lastChannel) && debounce > DEBOUNCE_THRESHOLD_COUNT) {
1027 channelDetected =
true;
1029 usedChannels.append(lastChannel);
1030 manualSettingsData = manualSettingsObj->getData();
1031 manualSettingsData.ChannelGroups[currentChannelNum] = currentChannel.group;
1032 manualSettingsData.ChannelNumber[currentChannelNum] = currentChannel.number;
1033 manualSettingsObj->setData(manualSettingsData);
1039 m_config->wzText->clear();
1044 QTimer::singleShot(CHANNEL_IDENTIFICATION_WAIT_TIME_MS,
this, &ConfigInputWidget::wzNext);
1047 void ConfigInputWidget::identifyLimits()
1049 bool allSane =
true;
1051 manualCommandData = manualCommandObj->getData();
1053 for (quint8
i = 0;
i < ManualControlSettings::CHANNELMAX_NUMELEM; ++
i) {
1054 uint16_t channelVal = manualCommandData.Channel[
i];
1057 if ((channelVal > MIN_SANE_CHANNEL_VALUE) && (channelVal < MAX_SANE_CHANNEL_VALUE)) {
1058 if (channelVal < minSeen[
i]) {
1059 minSeen[
i] = channelVal;
1062 if (channelVal > maxSeen[i]) {
1063 maxSeen[
i] = channelVal;
1068 case ManualControlSettings::CHANNELNUMBER_THROTTLE:
1076 if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) {
1077 manualSettingsData.ChannelNeutral[
i] =
1078 minSeen[
i] + (maxSeen[
i] - minSeen[
i]) * THROTTLE_NEUTRAL_FRACTION;
1080 manualSettingsData.ChannelNeutral[
i] =
1081 minSeen[
i] + (maxSeen[
i] - minSeen[
i]) * (1.0f - THROTTLE_NEUTRAL_FRACTION);
1086 case ManualControlSettings::CHANNELNUMBER_ARMING:
1087 case ManualControlSettings::CHANNELGROUPS_FLIGHTMODE:
1089 manualSettingsData.ChannelNeutral[
i] = (maxSeen[
i] + minSeen[
i]) / 2;
1096 if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) {
1106 if ((i == ManualControlSettings::CHANNELNUMBER_THROTTLE)
1107 || ((manualSettingsData.ChannelNeutral[
i] - minSeen[
i]) > INITIAL_OFFSET)) {
1108 manualSettingsData.ChannelMin[
i] = minSeen[
i];
1111 if ((maxSeen[i] - manualSettingsData.ChannelNeutral[i]) > INITIAL_OFFSET) {
1112 manualSettingsData.ChannelMax[
i] = maxSeen[
i];
1117 if ((i == ManualControlSettings::CHANNELNUMBER_THROTTLE)
1118 || ((maxSeen[
i] - manualSettingsData.ChannelNeutral[
i]) > INITIAL_OFFSET)) {
1119 manualSettingsData.ChannelMin[
i] = maxSeen[
i];
1122 if ((manualSettingsData.ChannelNeutral[i] - minSeen[i]) > INITIAL_OFFSET) {
1123 manualSettingsData.ChannelMax[
i] = minSeen[
i];
1128 if (manualSettingsData.ChannelGroups[i] != ManualControlSettings::CHANNELGROUPS_NONE) {
1129 int diff = maxSeen[
i] - minSeen[
i];
1131 if (diff < MIN_SANE_RANGE) {
1137 manualSettingsObj->setData(manualSettingsData);
1140 m_config->wzText->setText(
1141 QString(tr(
"Please move all controls <b>(including switches)</b> to their maximum "
1142 "extents in all directions. You may press next when finished.")));
1143 m_config->wzNext->setEnabled(
true);
1146 void ConfigInputWidget::setMoveFromCommand(
int command)
1148 if (command == ManualControlSettings::CHANNELNUMBER_ROLL) {
1150 }
else if (command == ManualControlSettings::CHANNELNUMBER_PITCH) {
1151 if (transmitterMode == mode2)
1155 }
else if (command == ManualControlSettings::CHANNELNUMBER_YAW) {
1157 }
else if (command == ManualControlSettings::CHANNELNUMBER_THROTTLE) {
1158 if (transmitterMode == mode2)
1162 }
else if (command == ManualControlSettings::CHANNELNUMBER_COLLECTIVE) {
1163 if (transmitterMode == mode2)
1167 }
else if (command == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) {
1169 }
else if (command == ManualControlSettings::CHANNELNUMBER_ARMING) {
1171 }
else if (command == ManualControlSettings::CHANNELNUMBER_ACCESSORY0) {
1173 }
else if (command == ManualControlSettings::CHANNELNUMBER_ACCESSORY1) {
1175 }
else if (command == ManualControlSettings::CHANNELNUMBER_ACCESSORY2) {
1180 void ConfigInputWidget::setTxMovement(txMovements movement)
1188 animate->start(100);
1194 animate->start(100);
1200 animate->start(100);
1206 animate->start(100);
1212 animate->start(100);
1218 animate->start(100);
1224 animate->start(100);
1230 animate->start(1000);
1236 animate->start(1000);
1241 animate->start(1000);
1258 void ConfigInputWidget::moveTxControls()
1261 QGraphicsItem *item = NULL;
1265 static bool auxFlag =
false;
1266 switch (currentMovement) {
1268 item = m_txLeftStick;
1269 trans = m_txLeftStickOrig;
1270 limitMax = STICK_MAX_MOVE;
1271 limitMin = STICK_MIN_MOVE;
1275 item = m_txRightStick;
1276 trans = m_txRightStickOrig;
1277 limitMax = STICK_MAX_MOVE;
1278 limitMin = STICK_MIN_MOVE;
1282 item = m_txLeftStick;
1283 trans = m_txLeftStickOrig;
1284 limitMax = STICK_MAX_MOVE;
1285 limitMin = STICK_MIN_MOVE;
1289 item = m_txRightStick;
1290 trans = m_txRightStickOrig;
1291 limitMax = STICK_MAX_MOVE;
1292 limitMin = STICK_MIN_MOVE;
1297 trans = m_txAccess0Orig;
1298 limitMax = ACCESS_MAX_MOVE;
1299 limitMin = ACCESS_MIN_MOVE;
1304 trans = m_txAccess1Orig;
1305 limitMax = ACCESS_MAX_MOVE;
1306 limitMin = ACCESS_MIN_MOVE;
1311 trans = m_txAccess2Orig;
1312 limitMax = ACCESS_MAX_MOVE;
1313 limitMin = ACCESS_MIN_MOVE;
1317 item = m_txFlightMode;
1329 limitMax = STICK_MAX_MOVE;
1330 limitMin = STICK_MIN_MOVE;
1337 item->setTransform(trans.translate(0, movePos * 10),
false);
1339 item->setTransform(trans.translate(movePos * 10, 0),
false);
1340 else if (move ==
jump) {
1341 if (item == m_txArrows) {
1342 m_txArrows->setVisible(!m_txArrows->isVisible());
1343 }
else if (item == m_txFlightMode) {
1344 QGraphicsSvgItem *svg;
1345 svg =
static_cast<QGraphicsSvgItem *
>(item);
1347 if (svg->elementId() ==
"flightModeCenter") {
1349 svg->setElementId(
"flightModeRight");
1350 m_txFlightMode->setTransform(m_txFlightModeROrig,
false);
1352 svg->setElementId(
"flightModeLeft");
1353 m_txFlightMode->setTransform(m_txFlightModeLOrig,
false);
1355 }
else if (svg->elementId() ==
"flightModeRight") {
1357 svg->setElementId(
"flightModeCenter");
1358 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
1359 }
else if (svg->elementId() ==
"flightModeLeft") {
1361 svg->setElementId(
"flightModeCenter");
1362 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
1365 }
else if (item == m_txArming) {
1366 QGraphicsSvgItem *svg;
1367 svg =
static_cast<QGraphicsSvgItem *
>(item);
1369 if (svg->elementId() ==
"armedswitchleft") {
1370 svg->setElementId(
"armedswitchright");
1371 m_txArming->setTransform(m_txArmingSwitchOrigR,
false);
1373 svg->setElementId(
"armedswitchleft");
1374 m_txArming->setTransform(m_txArmingSwitchOrigL,
false);
1378 }
else if (move ==
mix) {
1379 trans = m_txAccess0Orig;
1380 m_txAccess0->setTransform(
1381 trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0),
false);
1382 trans = m_txAccess1Orig;
1383 m_txAccess1->setTransform(
1384 trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0),
false);
1385 trans = m_txAccess2Orig;
1386 m_txAccess2->setTransform(
1387 trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0),
false);
1390 trans = m_txLeftStickOrig;
1391 m_txLeftStick->setTransform(trans.translate(0, movePos * 10),
false);
1392 trans = m_txRightStickOrig;
1393 m_txRightStick->setTransform(trans.translate(0, movePos * 10),
false);
1395 trans = m_txLeftStickOrig;
1396 m_txLeftStick->setTransform(trans.translate(movePos * 10, 0),
false);
1397 trans = m_txRightStickOrig;
1398 m_txRightStick->setTransform(trans.translate(movePos * 10, 0),
false);
1402 m_txFlightMode->setElementId(
"flightModeCenter");
1403 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
1404 }
else if (movePos == ACCESS_MAX_MOVE / 2) {
1405 m_txFlightMode->setElementId(
"flightModeRight");
1406 m_txFlightMode->setTransform(m_txFlightModeROrig,
false);
1407 }
else if (movePos == ACCESS_MIN_MOVE / 2) {
1408 m_txFlightMode->setElementId(
"flightModeLeft");
1409 m_txFlightMode->setTransform(m_txFlightModeLOrig,
false);
1413 if (movePos == 0 && growing)
1419 if (movePos > limitMax) {
1420 movePos = movePos - 2;
1423 if (movePos < limitMin) {
1424 movePos = movePos + 2;
1434 void ConfigInputWidget::detectFailsafe()
1436 FlightStatus::DataFields flightStatusData = flightStatusObj->getData();
1439 if (flightStatusData.ControlSource == FlightStatus::CONTROLSOURCE_TRANSMITTER) {
1440 m_config->wzText->setText(
1441 QString(tr(
"To verify that the failsafe mode on your receiver is safe, please turn "
1442 "off your transmitter now.\n")));
1445 m_config->wzText->setText(QString(tr(
"Unable to detect transmitter to verify failsafe. "
1446 "Please ensure it is turned on.\n")));
1450 if (flightStatusData.ControlSource == FlightStatus::CONTROLSOURCE_FAILSAFE) {
1451 m_config->wzText->setText(
1452 QString(tr(
"Failsafe mode detected. Please turn on your transmitter again.\n")));
1457 if (flightStatusData.ControlSource == FlightStatus::CONTROLSOURCE_TRANSMITTER) {
1458 m_config->wzText->setText(QString(
1459 tr(
"Congratulations. Failsafe detection appears to be working reliably.\n")));
1460 m_config->wzNext->setEnabled(
true);
1464 if (m_config->cbBypassFailsafe->checkState()) {
1465 m_config->wzText->setText(
1466 QString(tr(
"You are selecting to bypass failsafe detection. If this is not working, "
1467 "then the flight controller is likely to fly away. Please check on the "
1468 "forums how to configure this properly.\n")));
1469 m_config->wzNext->setEnabled(
true);
1473 void ConfigInputWidget::moveSticks()
1476 manualCommandData = manualCommandObj->getData();
1480 double throttlePosition = manualCommandData.Throttle < 0
1481 ? 0 + THROTTLE_NEUTRAL_FRACTION * (1 - manualCommandData.Throttle)
1482 : THROTTLE_NEUTRAL_FRACTION + manualCommandData.Throttle * (1 - THROTTLE_NEUTRAL_FRACTION);
1484 throttlePosition = 2 * throttlePosition - 1;
1485 if (transmitterMode == mode2) {
1486 trans = m_txLeftStickOrig;
1487 m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10,
1488 -throttlePosition * STICK_MAX_MOVE * 10),
1490 trans = m_txRightStickOrig;
1491 m_txRightStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10,
1492 manualCommandData.Pitch * STICK_MAX_MOVE * 10),
1495 trans = m_txRightStickOrig;
1496 m_txRightStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10,
1497 -throttlePosition * STICK_MAX_MOVE * 10),
1499 trans = m_txLeftStickOrig;
1500 m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10,
1501 manualCommandData.Pitch * STICK_MAX_MOVE * 10),
1504 switch (scaleSwitchChannel(ManualControlSettings::CHANNELMIN_FLIGHTMODE,
1505 manualSettingsObj->getData().FlightModeNumber)) {
1507 m_txFlightMode->setElementId(
"flightModeLeft");
1508 m_txFlightMode->setTransform(m_txFlightModeLOrig,
false);
1511 m_txFlightMode->setElementId(
"flightModeCenter");
1512 m_txFlightMode->setTransform(m_txFlightModeCOrig,
false);
1516 m_txFlightMode->setElementId(
"flightModeRight");
1517 m_txFlightMode->setTransform(m_txFlightModeROrig,
false);
1520 switch (scaleSwitchChannel(ManualControlSettings::CHANNELMIN_ARMING, 2)) {
1522 m_txArming->setElementId(
"armedswitchleft");
1523 m_txArming->setTransform(m_txArmingSwitchOrigL,
false);
1526 m_txArming->setElementId(
"armedswitchright");
1527 m_txArming->setTransform(m_txArmingSwitchOrigR,
false);
1532 m_txAccess0->setTransform(
1533 QTransform(m_txAccess0Orig)
1534 .translate(manualCommandData.Accessory[0] * ACCESS_MAX_MOVE * 10, 0),
1536 m_txAccess1->setTransform(
1537 QTransform(m_txAccess1Orig)
1538 .translate(manualCommandData.Accessory[1] * ACCESS_MAX_MOVE * 10, 0),
1540 m_txAccess2->setTransform(
1541 QTransform(m_txAccess2Orig)
1542 .translate(manualCommandData.Accessory[2] * ACCESS_MAX_MOVE * 10, 0),
1546 void ConfigInputWidget::dimOtherControls(
bool value)
1553 m_txAccess0->setOpacity(opac);
1554 m_txAccess1->setOpacity(opac);
1555 m_txAccess2->setOpacity(opac);
1556 m_txFlightMode->setOpacity(opac);
1557 m_txArming->setOpacity(opac);
1562 m_config->configurationWizard->setEnabled(enable);
1563 m_config->runCalibration->setEnabled(enable);
1568 void ConfigInputWidget::invertControls()
1570 manualSettingsData = manualSettingsObj->getData();
1571 foreach (QWidget *wd, extraWidgets) {
1572 QCheckBox *cb = qobject_cast<QCheckBox *>(wd);
1575 manualSettingsObj->getField(
"ChannelNumber")->getElementNames().indexOf(cb->text());
1576 if ((cb->isChecked()
1577 && (manualSettingsData.ChannelMax[index] > manualSettingsData.ChannelMin[index]))
1578 || (!cb->isChecked()
1579 && (manualSettingsData.ChannelMax[index]
1580 < manualSettingsData.ChannelMin[index]))) {
1582 aux = manualSettingsData.ChannelMax[index];
1583 manualSettingsData.ChannelMax[index] = manualSettingsData.ChannelMin[index];
1584 manualSettingsData.ChannelMin[index] = aux;
1585 if (index == ManualControlSettings::CHANNELNEUTRAL_THROTTLE) {
1589 manualSettingsData.ChannelNeutral[index] = manualSettingsData.ChannelMin[index]
1590 + (manualSettingsData.ChannelMax[index]
1591 - manualSettingsData.ChannelMin[index])
1592 * THROTTLE_NEUTRAL_FRACTION;
1597 manualSettingsObj->setData(manualSettingsData);
1605 quint8 ConfigInputWidget::scaleSwitchChannel(quint8 channelNumber, quint8 switchPositions)
1607 if (channelNumber > (ManualControlSettings::CHANNELMIN_NUMELEM - 1))
1609 ManualControlSettings::DataFields manualSettingsDataPriv = manualSettingsObj->getData();
1610 ManualControlCommand::DataFields manualCommandDataPriv = manualCommandObj->getData();
1613 int chMin = manualSettingsDataPriv.ChannelMin[channelNumber];
1614 int chMax = manualSettingsDataPriv.ChannelMax[channelNumber];
1615 int chNeutral = manualSettingsDataPriv.ChannelNeutral[channelNumber];
1617 int value = manualCommandDataPriv.Channel[channelNumber];
1618 if ((chMax > chMin && value >= chNeutral) || (chMin > chMax && value <= chNeutral)) {
1619 if (chMax != chNeutral)
1620 valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral);
1624 if (chMin != chNeutral)
1625 valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin);
1630 if (valueScaled < -1.0)
1632 else if (valueScaled > 1.0)
1637 quint8 pos = ((qint16)(valueScaled * 256) + 256) * switchPositions >> 9;
1638 if (pos >= switchPositions)
1639 pos = switchPositions - 1;
1643 void ConfigInputWidget::moveFMSlider()
1645 m_config->fmsSlider->setValue(
1646 scaleSwitchChannel(ManualControlSettings::CHANNELMIN_FLIGHTMODE,
1647 manualSettingsObj->getData().FlightModeNumber));
1650 void ConfigInputWidget::updatePositionSlider()
1652 ManualControlSettings::DataFields manualSettingsDataPriv = manualSettingsObj->getData();
1654 switch (manualSettingsDataPriv.FlightModeNumber) {
1657 m_config->fmsModePos6->setEnabled(
true);
1660 m_config->fmsModePos5->setEnabled(
true);
1663 m_config->fmsModePos4->setEnabled(
true);
1666 m_config->fmsModePos3->setEnabled(
true);
1669 m_config->fmsModePos2->setEnabled(
true);
1672 m_config->fmsModePos1->setEnabled(
true);
1678 switch (manualSettingsDataPriv.FlightModeNumber) {
1680 m_config->fmsModePos1->setEnabled(
false);
1683 m_config->fmsModePos2->setEnabled(
false);
1686 m_config->fmsModePos3->setEnabled(
false);
1689 m_config->fmsModePos4->setEnabled(
false);
1692 m_config->fmsModePos5->setEnabled(
false);
1695 m_config->fmsModePos6->setEnabled(
false);
1703 void ConfigInputWidget::updateCalibration()
1705 manualCommandData = manualCommandObj->getData();
1706 for (quint8 i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++
i) {
1707 if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i])
1708 || (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i]))
1709 manualSettingsData.ChannelMin[
i] = manualCommandData.Channel[
i];
1710 if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i])
1711 || (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i]))
1712 manualSettingsData.ChannelMax[
i] = manualCommandData.Channel[
i];
1713 manualSettingsData.ChannelNeutral[
i] = manualCommandData.Channel[
i];
1716 manualSettingsObj->setData(manualSettingsData);
1717 manualSettingsObj->updated();
1720 void ConfigInputWidget::simpleCalibration(
bool enable)
1723 m_config->configurationWizard->setEnabled(
false);
1726 msgBox.setText(tr(
"Arming Settings are now set to Always Disarmed for your safety."));
1727 msgBox.setDetailedText(tr(
"You will have to reconfigure the arming settings manually when "
1728 "the wizard is finished."));
1729 msgBox.setStandardButtons(QMessageBox::Ok);
1730 msgBox.setDefaultButton(QMessageBox::Ok);
1733 manualCommandData = manualCommandObj->getData();
1735 manualSettingsData = manualSettingsObj->getData();
1736 manualSettingsData.Arming = ManualControlSettings::ARMING_ALWAYSDISARMED;
1737 manualSettingsObj->setData(manualSettingsData);
1739 for (
unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) {
1740 reverse[
i] = manualSettingsData.ChannelMax[
i] < manualSettingsData.ChannelMin[
i];
1741 manualSettingsData.ChannelMin[
i] = manualCommandData.Channel[
i];
1742 manualSettingsData.ChannelNeutral[
i] = manualCommandData.Channel[
i];
1743 manualSettingsData.ChannelMax[
i] = manualCommandData.Channel[
i];
1749 &ConfigInputWidget::updateCalibration);
1751 m_config->configurationWizard->setEnabled(
true);
1753 manualCommandData = manualCommandObj->getData();
1754 manualSettingsData = manualSettingsObj->getData();
1758 for (
unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++)
1759 manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
1762 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE] =
1763 (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE]
1764 + manualSettingsData.ChannelMin[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE])
1767 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNUMBER_ARMING] =
1768 (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELNUMBER_ARMING]
1769 + manualSettingsData.ChannelMin[ManualControlSettings::CHANNELNUMBER_ARMING])
1773 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE] =
1774 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]
1775 + (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]
1776 - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])
1777 * THROTTLE_NEUTRAL_FRACTION;
1779 manualSettingsObj->setData(manualSettingsData);
1782 &ConfigInputWidget::updateCalibration);
1788 QLabel *lbl = findChild<QLabel *>(
"lblMessage" + type);
1790 widget->layout()->removeWidget(lbl);
1797 QLabel *lbl = findChild<QLabel *>(
"lblMessage" + type);
1799 lbl =
new QLabel(
this);
1800 lbl->setObjectName(
"lblMessage" + type);
1801 lbl->setWordWrap(
true);
1802 target->layout()->addWidget(lbl);
1805 lbl->setText(lbl->text() + msg +
"\n");
1810 cause->setProperty(
"hasWarning",
true);
1816 foreach (QWidget *wid, causesParent->findChildren<QFrame *>())
1817 wid->setProperty(
"hasWarning",
false);
1821 void ConfigInputWidget::checkReprojection()
1823 const QString prefix = sender()->objectName().left(9);
1824 QComboBox *rep = findChild<QComboBox *>(prefix +
"Rep");
1830 QStringList allowed_modes;
1831 if (rep->currentText() ==
"CameraAngle") {
1834 allowed_modes <<
"AxisLock"
1839 }
else if (rep->currentText() ==
"HeadFree") {
1842 allowed_modes <<
"AxisLock"
1854 QString selected_mode;
1855 foreach (
const QString axis_name, axes) {
1856 QComboBox *axis = findChild<QComboBox *>(prefix + axis_name);
1860 if (!allowed_modes.contains(axis->currentText()))
1862 QString(
"Stabilized%0: When using %1 reprojection, only the following "
1863 "stabilization modes are allowed on axes %2: %3")
1864 .arg(prefix.right(1))
1865 .arg(rep->currentText())
1866 .arg(axes.join(
", "))
1867 .arg(allowed_modes.join(
", ")));
1870 if (selected_mode.length() < 1)
1871 selected_mode = axis->currentText();
1872 if (selected_mode != axis->currentText())
1874 QString(
"Stabilized%0: When using %1 reprojection, stabilization modes must "
1875 "match for %2 axes!")
1876 .arg(prefix.right(1))
1877 .arg(rep->currentText())
1878 .arg(axes.join(
", ")));
1883 ConfigInputWidget::armingMethodFromArmName(
const QString &name)
1886 if (method.armName == name)
1895 ConfigInputWidget::armingMethodFromUavoOption(
const QString &option)
1898 QString opt = option.split(
'+', QString::SkipEmptyParts).at(0);
1900 if (method.uavoOption.split(
'+', QString::SkipEmptyParts).at(0) == opt)
1908 void ConfigInputWidget::checkArmingConfig()
1910 if (armingConfigUpdating)
1914 clearWarnings(m_config->gbWarnings, m_config->saArmingSettings);
1916 SystemSettings *sys =
1919 const quint8 vehicle = sys->getAirframeType();
1921 const ArmingMethod arming = armingMethodFromArmName(m_config->cbArmMethod->currentText());
1922 m_config->lblDisarmMethod->setText((arming.isStick ? tr(
"throttle low and ") :
"")
1923 + arming.disarmName);
1925 if (lastArmingMethod != arming.method && lastArmingMethod !=
ARM_INVALID) {
1927 m_config->cbThrottleCheck->setChecked(
true);
1930 lastArmingMethod = arming.method;
1932 m_config->frStickArmTime->setVisible(arming.isStick);
1933 m_config->frSwitchArmTime->setVisible(arming.isSwitch);
1934 m_config->cbSwitchArmTime->setEnabled(
true);
1936 m_config->frThrottleCheck->setVisible(arming.isSwitch);
1938 m_config->frStickDisarmTime->setVisible(arming.isStick);
1939 m_config->frThrottleTimeout->setVisible(!arming.isFixed);
1940 m_config->frAutoDisarm->setVisible(!arming.isFixed);
1942 m_config->gbDisarming->setVisible(!arming.isFixed);
1945 bool hangtime =
false;
1946 StabilizationSettings *stabilizationSettings = qobject_cast<StabilizationSettings *>(
1948 Q_ASSERT(stabilizationSettings);
1949 if (stabilizationSettings)
1950 hangtime = stabilizationSettings->getLowPowerStabilizationMaxTime() > 0;
1953 m_config->lblRecommendedArm->setText(tr(
"Switch"));
1955 addWarning(m_config->gbWarnings, m_config->frArmMethod,
1956 tr(
"Switch arming is recommended when hangtime is enabled."));
1959 case SystemSettings::AIRFRAMETYPE_HELICP:
1960 m_config->lblRecommendedArm->setText(tr(
"Switch"));
1962 case SystemSettings::AIRFRAMETYPE_HEXA:
1963 case SystemSettings::AIRFRAMETYPE_HEXACOAX:
1964 case SystemSettings::AIRFRAMETYPE_HEXAX:
1965 case SystemSettings::AIRFRAMETYPE_OCTO:
1966 case SystemSettings::AIRFRAMETYPE_OCTOCOAXP:
1967 case SystemSettings::AIRFRAMETYPE_OCTOCOAXX:
1968 case SystemSettings::AIRFRAMETYPE_OCTOV:
1969 case SystemSettings::AIRFRAMETYPE_QUADP:
1970 case SystemSettings::AIRFRAMETYPE_QUADX:
1971 case SystemSettings::AIRFRAMETYPE_TRI:
1972 case SystemSettings::AIRFRAMETYPE_VTOL:
1973 m_config->lblRecommendedArm->setText(tr(
"Switch, roll or yaw"));
1976 m_config->lblRecommendedArm->setText(tr(
"Any"));
1980 if (!m_config->frThrottleCheck->isHidden() && !m_config->cbThrottleCheck->isChecked())
1981 addWarning(m_config->gbWarnings, m_config->frThrottleCheck,
1982 tr(
"Your vehicle can be armed while throttle is not low, be careful!"));
1984 if (!m_config->frFailsafeTimeout->isHidden() && !m_config->frAutoDisarm->isHidden()
1985 && !m_config->sbFailsafeTimeout->value())
1987 m_config->gbWarnings, m_config->frFailsafeTimeout,
1988 tr(
"Your vehicle will remain armed indefinitely when receiver is disconnected!"));
1990 if (!m_config->frThrottleTimeout->isHidden() && !m_config->sbThrottleTimeout->value())
1992 m_config->gbWarnings, m_config->frThrottleTimeout,
1993 tr(
"Your vehicle will remain armed indefinitely while throttle is low, be careful!"));
1996 m_config->saArmingSettings->setStyleSheet(m_config->saArmingSettings->styleSheet());
1998 QString armOption = arming.uavoOption;
1999 switch (arming.method) {
2001 if (m_config->cbThrottleCheck->isChecked())
2002 armOption +=
"+Throttle";
2007 if (cbArmingOption->currentText() != armOption)
2008 cbArmingOption->setCurrentText(armOption);
2011 void ConfigInputWidget::timeoutCheckboxChanged()
2013 m_config->sbThrottleTimeout->setEnabled(m_config->cbThrottleTimeout->isChecked());
2014 if (!m_config->cbThrottleTimeout->isChecked())
2015 m_config->sbThrottleTimeout->setValue(0);
2016 else if (!m_config->sbThrottleTimeout->value())
2019 m_config->sbFailsafeTimeout->setEnabled(m_config->cbFailsafeTimeout->isChecked());
2020 if (!m_config->cbFailsafeTimeout->isChecked())
2021 m_config->sbFailsafeTimeout->setValue(0);
2022 else if (!m_config->sbFailsafeTimeout->value())
2025 checkArmingConfig();
2028 void ConfigInputWidget::updateArmingConfig(
UAVObject *obj)
2030 armingConfigUpdating =
true;
2032 ManualControlSettings *man = qobject_cast<ManualControlSettings *>(obj);
2040 m_config->saArmingSettings->setEnabled(man->getIsPresentOnHardware());
2041 m_config->cbThrottleTimeout->setChecked(man->getArmedTimeout() > 0);
2042 m_config->cbFailsafeTimeout->setChecked(man->getInvalidRXArmedTimeout() > 0);
2044 const QString &armingOption = man->getField(
"Arming")->getValue().toString();
2045 ArmingMethod arming = armingMethodFromUavoOption(armingOption);
2046 if (m_config->cbArmMethod->currentText() != arming.armName)
2047 m_config->cbArmMethod->setCurrentText(arming.armName);
2048 m_config->cbThrottleCheck->setChecked(armingOption.contains(
"Throttle"));
2052 armingConfigUpdating =
false;
2054 checkArmingConfig();
2057 void ConfigInputWidget::fillArmingComboBox()
2059 m_config->cbArmMethod->clear();
2061 m_config->cbArmMethod->addItem(method.armName, method.method);
2064 void ConfigInputWidget::checkCollective()
2068 qWarning() <<
"invalid sender";
2075 if (!inputForm->assigned())
2078 SystemSettings *sys =
2081 const quint8 vehicle = sys->getAirframeType();
2083 if (vehicle != SystemSettings::AIRFRAMETYPE_HELICP) {
2084 addWarning(m_config->gbChannelWarnings, inputForm,
2085 tr(
"Collective is normally not used for this vehicle type, are you sure?"));
virtual void setMetadata(const Metadata &mdata)=0
void clearMessages(QWidget *widget, const QString type)
void resizeEvent(QResizeEvent *event)
void setMetadata(const Metadata &mdata)
static void SetFlightAccess(Metadata &meta, AccessMode mode)
Core plugin system that manages the plugins, their life cycle and their registered objects...
void objectUnpacked(UAVObject *obj)
objectUnpacked: triggered whenever an object is unpacked (i.e. arrives from the telemetry link) ...
void clearWarnings(QWidget *target, QWidget *causesParent)
void objectUpdated(UAVObject *obj)
Signal sent whenever any field of the object is updated.
QMap< QString, UAVObject::Metadata > readAllNonSettingsMetadata()
UAVObjectUtilManager::readAllNonSettingsMetadata Convenience function for calling readMetadata...
static void SetFlightTelemetryUpdateMode(Metadata &meta, UpdateMode val)
void addMessage(QWidget *target, const QString type, const QString msg)
void addWarning(QWidget *target, QWidget *cause, const QString msg)
virtual void enableControls(bool enable)
static const QVector< ArmingMethod > armingMethods
UAVObject * getObject(const QString &name, quint32 instId=0)
QVector< QVector< UAVDataObject * > > getDataObjectsVector()
ConfigInputWidget(QWidget *parent=nullptr)