2 ******************************************************************************
4 * @file configinputwidget.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup ConfigPlugin Config Plugin
11 * @brief Servo input/output configuration panel for the config gadget
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "configinputwidget.h"
31 #include <extensionsystem/pluginmanager.h>
32 #include <coreplugin/generalsettings.h>
33 #include <utils/stylehelper.h>
36 #include "ui_input_wizard.h"
38 #include "inputchannelform.h"
39 #include "ui_inputchannelform.h"
41 #include "failsafechannelform.h"
42 #include "ui_failsafechannelform.h"
44 #include <systemalarms.h>
47 #include <QStringList>
50 #include <QVBoxLayout>
51 #include <QPushButton>
52 #include <QDesktopServices>
54 #include <QMessageBox>
56 #include <QGraphicsSvgItem>
57 #include <QSvgRenderer>
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 CHANNEL_NUMBER_NONE 0
65 #define DEFAULT_FLIGHT_MODE_NUMBER 0
67 ConfigInputWidget::ConfigInputWidget(QWidget
*parent
) :
68 ConfigTaskWidget(parent
),
69 wizardStep(wizardNone
),
70 // not currently stored in the settings UAVO
71 transmitterMode(mode2
),
72 transmitterType(acro
),
78 nextDelayedLatestActivityTick(0),
79 accessoryDesiredObj0(NULL
),
80 accessoryDesiredObj1(NULL
),
81 accessoryDesiredObj2(NULL
),
82 accessoryDesiredObj3(NULL
)
84 manualCommandObj
= ManualControlCommand::GetInstance(getObjectManager());
85 manualSettingsObj
= ManualControlSettings::GetInstance(getObjectManager());
86 flightModeSettingsObj
= FlightModeSettings::GetInstance(getObjectManager());
87 flightStatusObj
= FlightStatus::GetInstance(getObjectManager());
88 receiverActivityObj
= ReceiverActivity::GetInstance(getObjectManager());
89 accessoryDesiredObj0
= AccessoryDesired::GetInstance(getObjectManager(), 0);
90 accessoryDesiredObj1
= AccessoryDesired::GetInstance(getObjectManager(), 1);
91 accessoryDesiredObj2
= AccessoryDesired::GetInstance(getObjectManager(), 2);
92 accessoryDesiredObj3
= AccessoryDesired::GetInstance(getObjectManager(), 3);
93 actuatorSettingsObj
= ActuatorSettings::GetInstance(getObjectManager());
94 systemSettingsObj
= SystemSettings::GetInstance(getObjectManager());
96 // Only instance 0 is present if the board is not connected.
97 // The other instances are populated lazily.
98 Q_ASSERT(accessoryDesiredObj0
);
100 ui
= new Ui_InputWidget();
103 wizardUi
= new Ui_InputWizardWidget();
104 wizardUi
->setupUi(ui
->wizard
);
106 addApplySaveButtons(ui
->saveRCInputToRAM
, ui
->saveRCInputToSD
);
108 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
109 Core::Internal::GeneralSettings
*settings
= pm
->getObject
<Core::Internal::GeneralSettings
>();
110 if (!settings
->useExpertMode()) {
111 ui
->saveRCInputToRAM
->setVisible(false);
114 addApplySaveButtons(ui
->saveRCInputToRAM
, ui
->saveRCInputToSD
);
116 // Generate the rows of buttons in the input channel form GUI
119 foreach(QString name
, manualSettingsObj
->getField("ChannelNumber")->getElementNames()) {
120 Q_ASSERT(index
< ManualControlSettings::CHANNELGROUPS_NUMELEM
);
122 // Input channel setup
123 InputChannelForm
*inputChannelForm
= new InputChannelForm(index
, this);
124 inputChannelForm
->setName(name
);
126 inputChannelForm
->moveTo(*(ui
->channelLayout
));
128 // The order of the following binding calls is important. Since the values will be populated
129 // in reverse order of the binding order otherwise the 'Reversed' logic will floor the neutral value
130 // to the max value ( which is smaller than the neutral value when reversed ) and the channel number
131 // will not be set correctly.
132 addWidgetBinding("ManualControlSettings", "ChannelNumber", inputChannelForm
->ui
->channelNumber
, index
);
133 addWidgetBinding("ManualControlSettings", "ChannelGroups", inputChannelForm
->ui
->channelGroup
, index
);
134 // Slider position based on real time Rcinput (allow monitoring)
135 addWidgetBinding("ManualControlCommand", "Channel", inputChannelForm
->ui
->channelNeutral
, index
);
136 // Neutral value stored on board (SpinBox)
137 addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm
->ui
->neutralValue
, index
);
138 addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm
->ui
->channelMax
, index
);
139 addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm
->ui
->channelMin
, index
);
140 addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm
->ui
->channelMax
, index
);
142 addWidget(inputChannelForm
->ui
->channelRev
);
144 // Reversing supported for some channels only
145 bool reversable
= ((index
== ManualControlSettings::CHANNELGROUPS_THROTTLE
) ||
146 (index
== ManualControlSettings::CHANNELGROUPS_ROLL
) ||
147 (index
== ManualControlSettings::CHANNELGROUPS_PITCH
) ||
148 (index
== ManualControlSettings::CHANNELGROUPS_YAW
));
149 inputChannelForm
->ui
->channelRev
->setVisible(reversable
);
151 // Input filter response time fields supported for some channels only
153 case ManualControlSettings::CHANNELGROUPS_ROLL
:
154 case ManualControlSettings::CHANNELGROUPS_PITCH
:
155 case ManualControlSettings::CHANNELGROUPS_YAW
:
156 case ManualControlSettings::CHANNELGROUPS_COLLECTIVE
:
157 case ManualControlSettings::CHANNELGROUPS_ACCESSORY0
:
158 case ManualControlSettings::CHANNELGROUPS_ACCESSORY1
:
159 case ManualControlSettings::CHANNELGROUPS_ACCESSORY2
:
160 case ManualControlSettings::CHANNELGROUPS_ACCESSORY3
:
161 addWidgetBinding("ManualControlSettings", "ResponseTime", inputChannelForm
->ui
->channelResponseTime
, indexRT
);
164 case ManualControlSettings::CHANNELGROUPS_THROTTLE
:
165 case ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
:
166 inputChannelForm
->ui
->channelResponseTime
->setVisible(false);
175 QList
<int> failsafeReloadGroup
;
176 failsafeReloadGroup
.append(555);
178 addWidgetBinding("ManualControlSettings", "FailsafeFlightModeSwitchPosition", ui
->failsafeFlightMode
, 0, 1, true, new QList
<int>(failsafeReloadGroup
));
180 // Generate the rows for the failsafe channel form GUI
182 foreach(QString name
, manualSettingsObj
->getField("FailsafeChannel")->getElementNames()) {
183 Q_ASSERT(index
< ManualControlSettings::FAILSAFECHANNEL_NUMELEM
);
185 // Failsafe channels setup
186 FailsafeChannelForm
*failsafeChannelForm
= new FailsafeChannelForm(index
, this);
187 addWidget(failsafeChannelForm
->ui
->channelValueSpinner
);
188 failsafeChannelForm
->setName(name
);
189 failsafeChannelForm
->moveTo(*(ui
->failsafeChannelsLayout
));
190 addWidgetBinding("ManualControlSettings", "FailsafeChannel", failsafeChannelForm
->ui
->channelValue
, index
, 0.01, true, new QList
<int>(failsafeReloadGroup
));
193 addWidget(ui
->failsafeDefault
);
195 addWidgetBinding("ManualControlSettings", "Deadband", ui
->deadband
, 0, 1);
196 addWidgetBinding("ManualControlSettings", "DeadbandAssistedControl", ui
->assistedControlDeadband
, 0, 1);
198 connect(ui
->configurationWizard
, SIGNAL(clicked()), this, SLOT(goToWizard()));
199 connect(ui
->stackedWidget
, SIGNAL(currentChanged(int)), this, SLOT(disableWizardButton(int)));
200 connect(ui
->runCalibration
, SIGNAL(toggled(bool)), this, SLOT(simpleCalibration(bool)));
202 connect(wizardUi
->wzNext
, SIGNAL(clicked()), this, SLOT(wzNext()));
203 connect(wizardUi
->wzCancel
, SIGNAL(clicked()), this, SLOT(wzCancel()));
204 connect(wizardUi
->wzBack
, SIGNAL(clicked()), this, SLOT(wzBack()));
206 ui
->stackedWidget
->setCurrentIndex(0);
207 QList
<QWidget
*> widgets
= QList
<QWidget
*>() << ui
->fmsModePos1
<< ui
->fmsModePos2
<< ui
->fmsModePos3
<<
208 ui
->fmsModePos4
<< ui
->fmsModePos5
<< ui
->fmsModePos6
;
210 foreach(QWidget
* widget
, widgets
) {
211 addWidgetBinding("FlightModeSettings", "FlightModePosition", widget
, index
++, 1, true);
214 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui
->fmsSsPos1Roll
, "Roll", 1, true);
215 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui
->fmsSsPos2Roll
, "Roll", 1, true);
216 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui
->fmsSsPos3Roll
, "Roll", 1, true);
217 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui
->fmsSsPos4Roll
, "Roll", 1, true);
218 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui
->fmsSsPos5Roll
, "Roll", 1, true);
219 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui
->fmsSsPos6Roll
, "Roll", 1, true);
221 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui
->fmsSsPos1Pitch
, "Pitch", 1, true);
222 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui
->fmsSsPos2Pitch
, "Pitch", 1, true);
223 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui
->fmsSsPos3Pitch
, "Pitch", 1, true);
224 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui
->fmsSsPos4Pitch
, "Pitch", 1, true);
225 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui
->fmsSsPos5Pitch
, "Pitch", 1, true);
226 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui
->fmsSsPos6Pitch
, "Pitch", 1, true);
228 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui
->fmsSsPos1Yaw
, "Yaw", 1, true);
229 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui
->fmsSsPos2Yaw
, "Yaw", 1, true);
230 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui
->fmsSsPos3Yaw
, "Yaw", 1, true);
231 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui
->fmsSsPos4Yaw
, "Yaw", 1, true);
232 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui
->fmsSsPos5Yaw
, "Yaw", 1, true);
233 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui
->fmsSsPos6Yaw
, "Yaw", 1, true);
235 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui
->fmsSsPos1Thrust
, "Thrust", 1, true);
236 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui
->fmsSsPos2Thrust
, "Thrust", 1, true);
237 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui
->fmsSsPos3Thrust
, "Thrust", 1, true);
238 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui
->fmsSsPos4Thrust
, "Thrust", 1, true);
239 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui
->fmsSsPos5Thrust
, "Thrust", 1, true);
240 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui
->fmsSsPos6Thrust
, "Thrust", 1, true);
242 addWidgetBinding("ManualControlSettings", "FlightModeNumber", ui
->fmsPosNum
);
244 addWidgetBinding("FlightModeSettings", "Arming", ui
->armControl
);
245 addWidgetBinding("FlightModeSettings", "ArmedTimeout", ui
->armTimeout
, 0, 1000);
246 connect(ManualControlCommand::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveFMSlider()));
247 connect(ManualControlSettings::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(updatePositionSlider()));
248 connect(SystemAlarms::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(updateConfigAlarmStatus()));
250 connect(ui
->failsafeFlightMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(failsafeFlightModeChanged(int)));
251 connect(ui
->failsafeFlightModeCb
, SIGNAL(toggled(bool)), this, SLOT(failsafeFlightModeCbToggled(bool)));
253 connect(this, SIGNAL(enableControlsChanged(bool)), this, SLOT(enableControlsChanged(bool)));
255 addWidget(ui
->configurationWizard
);
256 addWidget(ui
->runCalibration
);
257 addWidget(ui
->failsafeFlightModeCb
);
262 refreshWidgetsValues();
264 // Connect the help button
265 connect(ui
->inputHelp
, SIGNAL(clicked()), this, SLOT(openHelp()));
267 wizardUi
->graphicsView
->setScene(new QGraphicsScene(this));
268 wizardUi
->graphicsView
->setViewportUpdateMode(QGraphicsView::FullViewportUpdate
);
269 m_renderer
= new QSvgRenderer();
270 QGraphicsScene
*l_scene
= wizardUi
->graphicsView
->scene();
271 wizardUi
->graphicsView
->setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor()));
272 if (QFile::exists(":/configgadget/images/TX2.svg") && m_renderer
->load(QString(":/configgadget/images/TX2.svg")) && m_renderer
->isValid()) {
273 l_scene
->clear(); // Deletes all items contained in the scene as well.
275 m_txBackground
= new QGraphicsSvgItem();
276 // All other items will be clipped to the shape of the background
277 m_txBackground
->setFlags(QGraphicsItem::ItemClipsChildrenToShape
|
278 QGraphicsItem::ItemClipsToShape
);
279 m_txBackground
->setSharedRenderer(m_renderer
);
280 m_txBackground
->setElementId("background");
281 l_scene
->addItem(m_txBackground
);
283 m_txMainBody
= new QGraphicsSvgItem();
284 m_txMainBody
->setParentItem(m_txBackground
);
285 m_txMainBody
->setSharedRenderer(m_renderer
);
286 m_txMainBody
->setElementId("body");
287 l_scene
->addItem(m_txMainBody
);
289 m_txLeftStick
= new QGraphicsSvgItem();
290 m_txLeftStick
->setParentItem(m_txBackground
);
291 m_txLeftStick
->setSharedRenderer(m_renderer
);
292 m_txLeftStick
->setElementId("ljoy");
294 m_txRightStick
= new QGraphicsSvgItem();
295 m_txRightStick
->setParentItem(m_txBackground
);
296 m_txRightStick
->setSharedRenderer(m_renderer
);
297 m_txRightStick
->setElementId("rjoy");
299 m_txAccess0
= new QGraphicsSvgItem();
300 m_txAccess0
->setParentItem(m_txBackground
);
301 m_txAccess0
->setSharedRenderer(m_renderer
);
302 m_txAccess0
->setElementId("access0");
304 m_txAccess1
= new QGraphicsSvgItem();
305 m_txAccess1
->setParentItem(m_txBackground
);
306 m_txAccess1
->setSharedRenderer(m_renderer
);
307 m_txAccess1
->setElementId("access1");
309 m_txAccess2
= new QGraphicsSvgItem();
310 m_txAccess2
->setParentItem(m_txBackground
);
311 m_txAccess2
->setSharedRenderer(m_renderer
);
312 m_txAccess2
->setElementId("access2");
314 m_txAccess3
= new QGraphicsSvgItem();
315 m_txAccess3
->setParentItem(m_txBackground
);
316 m_txAccess3
->setSharedRenderer(m_renderer
);
317 m_txAccess3
->setElementId("access3");
319 m_txFlightMode
= new QGraphicsSvgItem();
320 m_txFlightMode
->setParentItem(m_txBackground
);
321 m_txFlightMode
->setSharedRenderer(m_renderer
);
322 m_txFlightMode
->setElementId("flightModeCenter");
323 m_txFlightMode
->setZValue(-10);
325 m_txFlightModeCountBG
= new QGraphicsSvgItem();
326 m_txFlightModeCountBG
->setParentItem(m_txBackground
);
327 m_txFlightModeCountBG
->setSharedRenderer(m_renderer
);
328 m_txFlightModeCountBG
->setElementId("fm_count_bg");
329 l_scene
->addItem(m_txFlightModeCountBG
);
331 m_txFlightModeCountText
= new QGraphicsSimpleTextItem("?", m_txFlightModeCountBG
);
332 m_txFlightModeCountText
->setBrush(QColor(40, 40, 40));
333 m_txFlightModeCountText
->setFont(QFont("Arial Bold"));
335 m_txArrows
= new QGraphicsSvgItem();
336 m_txArrows
->setParentItem(m_txBackground
);
337 m_txArrows
->setSharedRenderer(m_renderer
);
338 m_txArrows
->setElementId("arrows");
339 m_txArrows
->setVisible(false);
341 QRectF orig
= m_renderer
->boundsOnElement("ljoy");
342 QMatrix Matrix
= m_renderer
->matrixForElement("ljoy");
343 orig
= Matrix
.mapRect(orig
);
344 m_txLeftStickOrig
.translate(orig
.x(), orig
.y());
345 m_txLeftStick
->setTransform(m_txLeftStickOrig
, false);
347 orig
= m_renderer
->boundsOnElement("arrows");
348 Matrix
= m_renderer
->matrixForElement("arrows");
349 orig
= Matrix
.mapRect(orig
);
350 m_txArrowsOrig
.translate(orig
.x(), orig
.y());
351 m_txArrows
->setTransform(m_txArrowsOrig
, false);
353 orig
= m_renderer
->boundsOnElement("body");
354 Matrix
= m_renderer
->matrixForElement("body");
355 orig
= Matrix
.mapRect(orig
);
356 m_txMainBodyOrig
.translate(orig
.x(), orig
.y());
357 m_txMainBody
->setTransform(m_txMainBodyOrig
, false);
359 orig
= m_renderer
->boundsOnElement("flightModeCenter");
360 Matrix
= m_renderer
->matrixForElement("flightModeCenter");
361 orig
= Matrix
.mapRect(orig
);
362 m_txFlightModeCOrig
.translate(orig
.x(), orig
.y());
363 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
365 orig
= m_renderer
->boundsOnElement("flightModeLeft");
366 Matrix
= m_renderer
->matrixForElement("flightModeLeft");
367 orig
= Matrix
.mapRect(orig
);
368 m_txFlightModeLOrig
.translate(orig
.x(), orig
.y());
369 orig
= m_renderer
->boundsOnElement("flightModeRight");
370 Matrix
= m_renderer
->matrixForElement("flightModeRight");
371 orig
= Matrix
.mapRect(orig
);
372 m_txFlightModeROrig
.translate(orig
.x(), orig
.y());
374 orig
= m_renderer
->boundsOnElement("fm_count_bg");
375 Matrix
= m_renderer
->matrixForElement("fm_count_bg");
376 orig
= Matrix
.mapRect(orig
);
377 m_txFlightModeCountBGOrig
.translate(orig
.x(), orig
.y());
378 m_txFlightModeCountBG
->setTransform(m_txFlightModeCountBGOrig
, false);
380 QRectF flightModeBGRect
= m_txFlightModeCountBG
->boundingRect();
381 QRectF flightModeTextRect
= m_txFlightModeCountText
->boundingRect();
383 m_txFlightModeCountTextOrig
.translate(flightModeBGRect
.width() - (flightModeBGRect
.height() / 2), flightModeBGRect
.height() / 2);
384 m_txFlightModeCountTextOrig
.scale(scale
, scale
);
385 m_txFlightModeCountTextOrig
.translate(-flightModeTextRect
.width() / 2, -flightModeTextRect
.height() / 2);
386 m_txFlightModeCountText
->setTransform(m_txFlightModeCountTextOrig
, false);
388 orig
= m_renderer
->boundsOnElement("rjoy");
389 Matrix
= m_renderer
->matrixForElement("rjoy");
390 orig
= Matrix
.mapRect(orig
);
391 m_txRightStickOrig
.translate(orig
.x(), orig
.y());
392 m_txRightStick
->setTransform(m_txRightStickOrig
, false);
394 orig
= m_renderer
->boundsOnElement("access0");
395 Matrix
= m_renderer
->matrixForElement("access0");
396 orig
= Matrix
.mapRect(orig
);
397 m_txAccess0Orig
.translate(orig
.x(), orig
.y());
398 m_txAccess0
->setTransform(m_txAccess0Orig
, false);
400 orig
= m_renderer
->boundsOnElement("access1");
401 Matrix
= m_renderer
->matrixForElement("access1");
402 orig
= Matrix
.mapRect(orig
);
403 m_txAccess1Orig
.translate(orig
.x(), orig
.y());
404 m_txAccess1
->setTransform(m_txAccess1Orig
, false);
406 orig
= m_renderer
->boundsOnElement("access2");
407 Matrix
= m_renderer
->matrixForElement("access2");
408 orig
= Matrix
.mapRect(orig
);
409 m_txAccess2Orig
.translate(orig
.x(), orig
.y());
410 m_txAccess2
->setTransform(m_txAccess2Orig
, true);
412 orig
= m_renderer
->boundsOnElement("access3");
413 Matrix
= m_renderer
->matrixForElement("access3");
414 orig
= Matrix
.mapRect(orig
);
415 m_txAccess3Orig
.translate(orig
.x(), orig
.y());
416 m_txAccess3
->setTransform(m_txAccess3Orig
, true);
418 wizardUi
->graphicsView
->fitInView(m_txMainBody
, Qt::KeepAspectRatio
);
419 animate
= new QTimer(this);
420 connect(animate
, SIGNAL(timeout()), this, SLOT(moveTxControls()));
422 heliChannelOrder
<< ManualControlSettings::CHANNELGROUPS_COLLECTIVE
<<
423 ManualControlSettings::CHANNELGROUPS_THROTTLE
<<
424 ManualControlSettings::CHANNELGROUPS_ROLL
<<
425 ManualControlSettings::CHANNELGROUPS_PITCH
<<
426 ManualControlSettings::CHANNELGROUPS_YAW
<<
427 ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
<<
428 ManualControlSettings::CHANNELGROUPS_ACCESSORY0
<<
429 ManualControlSettings::CHANNELGROUPS_ACCESSORY1
<<
430 ManualControlSettings::CHANNELGROUPS_ACCESSORY2
<<
431 ManualControlSettings::CHANNELGROUPS_ACCESSORY3
;
433 acroChannelOrder
<< ManualControlSettings::CHANNELGROUPS_THROTTLE
<<
434 ManualControlSettings::CHANNELGROUPS_ROLL
<<
435 ManualControlSettings::CHANNELGROUPS_PITCH
<<
436 ManualControlSettings::CHANNELGROUPS_YAW
<<
437 ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
<<
438 ManualControlSettings::CHANNELGROUPS_ACCESSORY0
<<
439 ManualControlSettings::CHANNELGROUPS_ACCESSORY1
<<
440 ManualControlSettings::CHANNELGROUPS_ACCESSORY2
<<
441 ManualControlSettings::CHANNELGROUPS_ACCESSORY3
;
443 groundChannelOrder
<< ManualControlSettings::CHANNELGROUPS_THROTTLE
<<
444 ManualControlSettings::CHANNELGROUPS_YAW
<<
445 ManualControlSettings::CHANNELGROUPS_ACCESSORY0
;
447 updateEnableControls();
450 void ConfigInputWidget::buildOptionComboBox(QComboBox
*combo
, UAVObjectField
*field
, int index
, bool applyLimits
)
452 if (combo
== ui
->failsafeFlightMode
) {
453 for (quint32 i
= 0; i
< FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM
; i
++) {
454 ui
->failsafeFlightMode
->addItem(QString("Position %1").arg(i
+ 1), QVariant(i
));
457 ConfigTaskWidget::buildOptionComboBox(combo
, field
, index
, applyLimits
);
461 void ConfigInputWidget::resetTxControls()
463 m_txLeftStick
->setTransform(m_txLeftStickOrig
, false);
464 m_txRightStick
->setTransform(m_txRightStickOrig
, false);
465 m_txAccess0
->setTransform(m_txAccess0Orig
, false);
466 m_txAccess1
->setTransform(m_txAccess1Orig
, false);
467 m_txAccess2
->setTransform(m_txAccess2Orig
, false);
468 m_txAccess3
->setTransform(m_txAccess3Orig
, false);
469 m_txFlightMode
->setElementId("flightModeCenter");
470 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
471 m_txArrows
->setVisible(false);
472 m_txFlightModeCountText
->setText("?");
473 m_txFlightModeCountText
->setVisible(false);
474 m_txFlightModeCountBG
->setVisible(false);
477 ConfigInputWidget::~ConfigInputWidget()
480 void ConfigInputWidget::enableControls(bool enable
)
482 ConfigTaskWidget::enableControls(enable
);
485 updatePositionSlider();
487 // Hide configAlarmStatus when disconnected
488 ui
->configAlarmStatus
->setVisible(false);
492 void ConfigInputWidget::resizeEvent(QResizeEvent
*event
)
494 QWidget::resizeEvent(event
);
496 wizardUi
->graphicsView
->fitInView(m_txBackground
, Qt::KeepAspectRatio
);
499 void ConfigInputWidget::openHelp()
501 QDesktopServices::openUrl(QUrl(QString(WIKI_URL_ROOT
) + QString("Input+Configuration"),
505 void ConfigInputWidget::goToWizard()
509 msgBox
.setText(tr("Arming Settings are now set to 'Always Disarmed' for your safety."));
510 msgBox
.setDetailedText(tr("You will have to reconfigure the arming settings manually "
511 "when the wizard is finished. After the last step of the "
512 "wizard you will be taken to the Arming Settings screen."));
513 msgBox
.setStandardButtons(QMessageBox::Ok
);
514 msgBox
.setDefaultButton(QMessageBox::Ok
);
517 // Set correct tab visible before starting wizard.
518 if (ui
->tabWidget
->currentIndex() != 0) {
519 ui
->tabWidget
->setCurrentIndex(0);
522 // Stash current manual settings data in case the wizard is
523 // cancelled or the user proceeds far enough into the wizard such
524 // that the UAVO is changed, but then backs out to the start and
525 // chooses a different TX type (which could otherwise result in
526 // unexpected TX channels being enabled)
527 manualSettingsData
= manualSettingsObj
->getData();
528 memento
.manualSettingsData
= manualSettingsData
;
529 flightModeSettingsData
= flightModeSettingsObj
->getData();
530 memento
.flightModeSettingsData
= flightModeSettingsData
;
531 flightModeSettingsData
.Arming
= FlightModeSettings::ARMING_ALWAYSDISARMED
;
532 flightModeSettingsObj
->setData(flightModeSettingsData
);
533 // Stash actuatorSettings
534 actuatorSettingsData
= actuatorSettingsObj
->getData();
535 memento
.actuatorSettingsData
= actuatorSettingsData
;
537 // Stash systemSettings
538 systemSettingsData
= systemSettingsObj
->getData();
539 memento
.systemSettingsData
= systemSettingsData
;
541 // Now reset channel and actuator settings (disable outputs)
542 resetChannelSettings();
543 resetActuatorSettings();
545 // Use faster input update rate.
549 wizardSetUpStep(wizardWelcome
);
550 wizardUi
->graphicsView
->fitInView(m_txBackground
, Qt::KeepAspectRatio
);
553 void ConfigInputWidget::disableWizardButton(int value
)
556 ui
->groupBox_3
->setVisible(false);
558 ui
->groupBox_3
->setVisible(true);
562 void ConfigInputWidget::wzCancel()
564 dimOtherControls(false);
566 // Cancel any ongoing delayd next trigger.
567 wzNextDelayedCancel();
569 // Restore original input update rate.
572 ui
->stackedWidget
->setCurrentIndex(0);
574 if (wizardStep
!= wizardNone
) {
575 wizardTearDownStep(wizardStep
);
577 wizardStep
= wizardNone
;
578 ui
->stackedWidget
->setCurrentIndex(0);
580 // Load settings back from beginning of wizard
581 manualSettingsObj
->setData(memento
.manualSettingsData
);
582 flightModeSettingsObj
->setData(memento
.flightModeSettingsData
);
583 actuatorSettingsObj
->setData(memento
.actuatorSettingsData
);
584 systemSettingsObj
->setData(memento
.systemSettingsData
);
587 void ConfigInputWidget::registerControlActivity()
589 nextDelayedLatestActivityTick
= nextDelayedTick
;
592 void ConfigInputWidget::wzNextDelayed()
596 // Call next after the full 2500 ms timeout has been reached,
597 // or if no input activity has occurred the last 500 ms.
598 if (nextDelayedTick
== 25 ||
599 nextDelayedTick
- nextDelayedLatestActivityTick
>= 5) {
604 void ConfigInputWidget::wzNextDelayedStart()
606 // Call wzNextDelayed every 100 ms, to see if it's time to go to the next page.
607 connect(&nextDelayedTimer
, SIGNAL(timeout()), this, SLOT(wzNextDelayed()));
608 nextDelayedTimer
.start(100);
611 // Cancel the delayed next timer, if it's active.
612 void ConfigInputWidget::wzNextDelayedCancel()
615 nextDelayedLatestActivityTick
= 0;
616 if (nextDelayedTimer
.isActive()) {
617 nextDelayedTimer
.stop();
618 disconnect(&nextDelayedTimer
, SIGNAL(timeout()), this, SLOT(wzNextDelayed()));
622 void ConfigInputWidget::wzNext()
624 wzNextDelayedCancel();
626 // In identify sticks mode the next button can indicate
628 if (wizardStep
!= wizardNone
&&
629 wizardStep
!= wizardIdentifySticks
) {
630 wizardTearDownStep(wizardStep
);
633 // State transitions for next button
634 switch (wizardStep
) {
636 wizardSetUpStep(wizardChooseType
);
638 case wizardChooseType
:
639 wizardSetUpStep(wizardChooseMode
);
641 case wizardChooseMode
:
642 wizardSetUpStep(wizardIdentifySticks
);
644 case wizardIdentifySticks
:
646 if (currentChannelNum
== -1) { // Gone through all channels
647 wizardTearDownStep(wizardIdentifySticks
);
648 wizardSetUpStep(wizardIdentifyCenter
);
651 case wizardIdentifyCenter
:
652 resetFlightModeSettings();
653 wizardSetUpStep(wizardIdentifyLimits
);
655 case wizardIdentifyLimits
:
656 wizardSetUpStep(wizardIdentifyInverted
);
658 case wizardIdentifyInverted
:
659 wizardSetUpStep(wizardFinish
);
662 wizardStep
= wizardNone
;
664 // Restore original input update rate.
667 // Load actuator settings back from beginning of wizard
668 actuatorSettingsObj
->setData(memento
.actuatorSettingsData
);
670 // Force flight mode neutral to middle and Throttle neutral at 4%
671 adjustSpecialNeutrals();
672 throttleError
= false;
673 checkThrottleRange();
675 // Force flight mode number to be 1 if 2 CH ground vehicle was selected
676 if (transmitterType
== ground
) {
677 forceOneFlightMode();
680 manualSettingsObj
->setData(manualSettingsData
);
681 // move to Arming Settings tab
682 ui
->stackedWidget
->setCurrentIndex(0);
683 ui
->tabWidget
->setCurrentIndex(3);
690 void ConfigInputWidget::wzBack()
692 wzNextDelayedCancel();
694 if (wizardStep
!= wizardNone
&&
695 wizardStep
!= wizardIdentifySticks
) {
696 wizardTearDownStep(wizardStep
);
699 // State transitions for back button
700 switch (wizardStep
) {
701 case wizardChooseType
:
702 wizardSetUpStep(wizardWelcome
);
704 case wizardChooseMode
:
705 wizardSetUpStep(wizardChooseType
);
707 case wizardIdentifySticks
:
709 if (currentChannelNum
== -1) {
710 wizardTearDownStep(wizardIdentifySticks
);
711 wizardSetUpStep(wizardChooseMode
);
714 case wizardIdentifyCenter
:
715 wizardSetUpStep(wizardIdentifySticks
);
717 case wizardIdentifyLimits
:
718 wizardSetUpStep(wizardIdentifyCenter
);
720 case wizardIdentifyInverted
:
721 resetFlightModeSettings();
722 wizardSetUpStep(wizardIdentifyLimits
);
725 wizardSetUpStep(wizardIdentifyInverted
);
732 void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step
)
734 wizardUi
->wzNext
->setText(tr("Next"));
738 foreach(QPointer
<QWidget
> wd
, extraWidgets
) {
743 extraWidgets
.clear();
744 wizardUi
->graphicsView
->setVisible(false);
745 setTxMovement(nothing
);
746 wizardUi
->wzBack
->setEnabled(false);
747 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->welcomePage
);
748 ui
->stackedWidget
->setCurrentIndex(1);
750 case wizardChooseType
:
752 wizardUi
->graphicsView
->setVisible(true);
753 wizardUi
->graphicsView
->fitInView(m_txBackground
, Qt::KeepAspectRatio
);
754 setTxMovement(nothing
);
755 wizardUi
->wzBack
->setEnabled(true);
756 if (transmitterType
== heli
) {
757 wizardUi
->typeHeli
->setChecked(true);
758 } else if (transmitterType
== ground
) {
759 wizardUi
->typeGround
->setChecked(true);
761 wizardUi
->typeAcro
->setChecked(true);
763 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->chooseTypePage
);
766 case wizardChooseMode
:
768 wizardUi
->wzBack
->setEnabled(true);
769 QRadioButton
*modeButtons
[] = {
770 wizardUi
->mode1Button
,
771 wizardUi
->mode2Button
,
772 wizardUi
->mode3Button
,
773 wizardUi
->mode4Button
776 for (int i
= 0; i
<= mode4
; ++i
) {
778 txMode mode
= static_cast<txMode
>(i
);
779 if (transmitterType
== heli
) {
781 case mode1
: label
= tr("Mode 1: Fore/Aft Cyclic and Yaw on the left, Throttle/Collective and Left/Right Cyclic on the right"); break;
782 case mode2
: label
= tr("Mode 2: Throttle/Collective and Yaw on the left, Cyclic on the right"); break;
783 case mode3
: label
= tr("Mode 3: Cyclic on the left, Throttle/Collective and Yaw on the right"); break;
784 case mode4
: label
= tr("Mode 4: Throttle/Collective and Left/Right Cyclic on the left, Fore/Aft Cyclic and Yaw on the right"); break;
785 default: Q_ASSERT(0); break;
787 wizardUi
->typePageFooter
->setText(" ");
790 case mode1
: label
= tr("Mode 1: Elevator and Rudder on the left, Throttle and Ailerons on the right"); break;
791 case mode2
: label
= tr("Mode 2: Throttle and Rudder on the left, Elevator and Ailerons on the right"); break;
792 case mode3
: label
= tr("Mode 3: Elevator and Ailerons on the left, Throttle and Rudder on the right"); break;
793 case mode4
: label
= tr("Mode 4: Throttle and Ailerons on the left, Elevator and Rudder on the right"); break;
794 default: Q_ASSERT(0); break;
796 wizardUi
->typePageFooter
->setText(tr("For a Quad: Elevator is Pitch, Ailerons are Roll, and Rudder is Yaw."));
798 modeButtons
[i
]->setText(label
);
799 if (transmitterMode
== mode
) {
800 modeButtons
[i
]->setChecked(true);
803 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->chooseModePage
);
806 case wizardIdentifySticks
:
807 usedChannels
.clear();
808 currentChannelNum
= -1;
810 manualSettingsData
= manualSettingsObj
->getData();
811 connect(receiverActivityObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(identifyControls()));
812 wizardUi
->wzNext
->setEnabled(false);
813 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->identifySticksPage
);
815 case wizardIdentifyCenter
:
816 setTxMovement(centerAll
);
817 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->identifyCenterPage
);
818 if (transmitterType
== ground
) {
819 wizardUi
->identifyCenterInstructions
->setText(QString(tr("Please center all controls and trims and press Next when ready.\n\n"
820 "For a ground vehicle, this center position will be used as neutral value of each channel.")));
823 case wizardIdentifyLimits
:
825 setTxMovement(nothing
);
826 manualSettingsData
= manualSettingsObj
->getData();
827 for (uint i
= 0; i
< ManualControlSettings::CHANNELMAX_NUMELEM
; ++i
) {
828 // Preserve the inverted status
829 if (manualSettingsData
.ChannelMin
[i
] <= manualSettingsData
.ChannelMax
[i
]) {
830 manualSettingsData
.ChannelMin
[i
] = manualSettingsData
.ChannelNeutral
[i
];
831 manualSettingsData
.ChannelMax
[i
] = manualSettingsData
.ChannelNeutral
[i
];
833 // Make this detect as still inverted
834 manualSettingsData
.ChannelMin
[i
] = manualSettingsData
.ChannelNeutral
[i
] + 1;
835 manualSettingsData
.ChannelMax
[i
] = manualSettingsData
.ChannelNeutral
[i
];
838 connect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(identifyLimits()));
839 connect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
840 connect(flightStatusObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
841 connect(accessoryDesiredObj0
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
843 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->identifyLimitsPage
);
846 case wizardIdentifyInverted
:
847 dimOtherControls(true);
848 setTxMovement(nothing
);
849 extraWidgets
.clear();
850 for (int index
= 0; index
< manualSettingsObj
->getField("ChannelMax")->getElementNames().length(); index
++) {
851 QString name
= manualSettingsObj
->getField("ChannelMax")->getElementNames().at(index
);
852 if (!name
.contains("Access") && !name
.contains("Flight") &&
853 (!name
.contains("Collective") || transmitterType
== heli
)) {
854 QCheckBox
*cb
= new QCheckBox(name
, this);
855 // Make sure checked status matches current one
856 cb
->setChecked(manualSettingsData
.ChannelMax
[index
] < manualSettingsData
.ChannelMin
[index
]);
857 wizardUi
->checkBoxesLayout
->addWidget(cb
, extraWidgets
.size() / 4, extraWidgets
.size() % 4);
858 extraWidgets
.append(cb
);
859 connect(cb
, SIGNAL(toggled(bool)), this, SLOT(invertControls()));
862 connect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
863 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->identifyInvertedPage
);
866 dimOtherControls(false);
867 connect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
868 connect(flightStatusObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
869 connect(accessoryDesiredObj0
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
870 wizardUi
->pagesStack
->setCurrentWidget(wizardUi
->finishPage
);
878 void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step
)
880 Q_ASSERT(step
== wizardStep
);
884 case wizardChooseType
:
885 if (wizardUi
->typeAcro
->isChecked()) {
886 transmitterType
= acro
;
887 } else if (wizardUi
->typeGround
->isChecked()) {
888 transmitterType
= ground
;
889 /* Make sure to tell controller, this is really a ground vehicle. */
890 systemSettingsData
= systemSettingsObj
->getData();
891 systemSettingsData
.AirframeType
= SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR
;
892 systemSettingsObj
->setData(systemSettingsData
);
894 transmitterType
= heli
;
897 case wizardChooseMode
:
899 QRadioButton
*modeButtons
[] = {
900 wizardUi
->mode1Button
,
901 wizardUi
->mode2Button
,
902 wizardUi
->mode3Button
,
903 wizardUi
->mode4Button
905 for (int i
= mode1
; i
<= mode4
; ++i
) {
906 if (modeButtons
[i
]->isChecked()) {
907 transmitterMode
= static_cast<txMode
>(i
);
912 case wizardIdentifySticks
:
913 disconnect(receiverActivityObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(identifyControls()));
914 wizardUi
->wzNext
->setEnabled(true);
915 setTxMovement(nothing
);
916 /* If flight mode stick isn't identified, force flight mode number to be 1 */
917 manualSettingsData
= manualSettingsObj
->getData();
918 if (manualSettingsData
.ChannelGroups
[ManualControlSettings::CHANNELNUMBER_FLIGHTMODE
] ==
919 ManualControlSettings::CHANNELGROUPS_NONE
) {
920 forceOneFlightMode();
923 case wizardIdentifyCenter
:
924 manualCommandData
= manualCommandObj
->getData();
925 manualSettingsData
= manualSettingsObj
->getData();
926 for (unsigned int i
= 0; i
< ManualControlCommand::CHANNEL_NUMELEM
; ++i
) {
927 // Set Accessory neutral to middle range
928 if (i
>= ManualControlSettings::CHANNELNUMBER_ACCESSORY0
) {
929 manualSettingsData
.ChannelNeutral
[i
] = manualSettingsData
.ChannelMin
[i
] + ((manualSettingsData
.ChannelMax
[i
] - manualSettingsData
.ChannelMin
[i
]) / 2);
931 manualSettingsData
.ChannelNeutral
[i
] = manualCommandData
.Channel
[i
];
934 manualSettingsObj
->setData(manualSettingsData
);
935 setTxMovement(nothing
);
937 case wizardIdentifyLimits
:
938 disconnect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(identifyLimits()));
939 disconnect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
940 disconnect(flightStatusObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
941 disconnect(accessoryDesiredObj0
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
942 manualSettingsObj
->setData(manualSettingsData
);
943 setTxMovement(nothing
);
945 case wizardIdentifyInverted
:
946 dimOtherControls(false);
947 foreach(QWidget
* wd
, extraWidgets
) {
948 QCheckBox
*cb
= qobject_cast
<QCheckBox
*>(wd
);
951 disconnect(cb
, SIGNAL(toggled(bool)), this, SLOT(invertControls()));
955 extraWidgets
.clear();
956 disconnect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
959 dimOtherControls(false);
960 setTxMovement(nothing
);
961 disconnect(manualCommandObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
962 disconnect(flightStatusObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
963 disconnect(accessoryDesiredObj0
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(moveSticks()));
970 static void fastMdataSingle(UAVDataObject
*object
, UAVObject::Metadata
*savedMdata
)
972 *savedMdata
= object
->getMetadata();
973 UAVObject::Metadata mdata
= *savedMdata
;
974 UAVObject::SetFlightTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_PERIODIC
);
975 mdata
.flightTelemetryUpdatePeriod
= 150;
976 object
->setMetadata(mdata
);
979 static void restoreMdataSingle(UAVDataObject
*object
, UAVObject::Metadata
*savedMdata
)
981 object
->setMetadata(*savedMdata
);
985 * Set manual control command to fast updates
987 void ConfigInputWidget::fastMdata()
989 fastMdataSingle(manualCommandObj
, &manualControlMdata
);
990 fastMdataSingle(accessoryDesiredObj0
, &accessoryDesiredMdata0
);
994 * Restore previous update settings for manual control data
996 void ConfigInputWidget::restoreMdata()
998 restoreMdataSingle(manualCommandObj
, &manualControlMdata
);
999 restoreMdataSingle(accessoryDesiredObj0
, &accessoryDesiredMdata0
);
1003 * Set the display to indicate which channel the person should move
1005 void ConfigInputWidget::setChannel(int newChan
)
1007 bool canBeSkipped
= false;
1009 if (newChan
== ManualControlSettings::CHANNELGROUPS_COLLECTIVE
) {
1010 wizardUi
->identifyStickInstructions
->setText(QString(tr("<p>Please enable throttle hold mode.</p>"
1011 "<p>Move the Collective Pitch stick.</p>")));
1012 } else if (newChan
== ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
) {
1013 wizardUi
->identifyStickInstructions
->setText(QString(tr("<p>Please toggle the Flight Mode switch.</p>"
1014 "<p>For switches you may have to repeat this rapidly.</p>"
1015 "<p>Alternatively, you can click Next to skip this channel, but you will get only <b>ONE</b> Flight Mode.</p>")));
1016 canBeSkipped
= true;
1017 } else if ((transmitterType
== heli
) && (newChan
== ManualControlSettings::CHANNELGROUPS_THROTTLE
)) {
1018 wizardUi
->identifyStickInstructions
->setText(QString(tr("<p>Please disable throttle hold mode.</p>"
1019 "<p>Move the Throttle stick.</p>")));
1021 wizardUi
->identifyStickInstructions
->setText(QString(tr("<p>Please move each control one at a time according to the instructions and picture below.</p>"
1022 "<p>Move the %1 stick.</p>")).arg(manualSettingsObj
->getField("ChannelGroups")->getElementNames().at(newChan
)));
1025 if (manualSettingsObj
->getField("ChannelGroups")->getElementNames().at(newChan
).contains("Accessory")) {
1026 wizardUi
->identifyStickInstructions
->setText(wizardUi
->identifyStickInstructions
->text() + tr("<p>Alternatively, click Next to skip this channel.</p>"));
1027 canBeSkipped
= true;
1031 wizardUi
->wzNext
->setEnabled(true);
1032 wizardUi
->wzNext
->setText(tr("Next / Skip"));
1034 wizardUi
->wzNext
->setEnabled(false);
1037 setMoveFromCommand(newChan
);
1038 currentChannelNum
= newChan
;
1039 channelDetected
= false;
1043 * Unfortunately order of channel should be different in different conditions. Selects
1044 * next channel based on heli or acro mode
1046 void ConfigInputWidget::nextChannel()
1049 switch (transmitterType
) {
1051 order
= heliChannelOrder
;
1054 order
= groundChannelOrder
;
1057 order
= acroChannelOrder
;
1061 if (currentChannelNum
== -1) {
1062 setChannel(order
[0]);
1065 for (int i
= 0; i
< order
.length() - 1; i
++) {
1066 if (order
[i
] == currentChannelNum
) {
1067 setChannel(order
[i
+ 1]);
1071 currentChannelNum
= -1; // hit end of list
1075 * Unfortunately order of channel should be different in different conditions. Selects
1076 * previous channel based on heli or acro mode
1078 void ConfigInputWidget::prevChannel()
1081 switch (transmitterType
) {
1083 order
= heliChannelOrder
;
1086 order
= groundChannelOrder
;
1089 order
= acroChannelOrder
;
1093 // No previous from unset channel or next state
1094 if (currentChannelNum
== -1) {
1098 for (int i
= 1; i
< order
.length(); i
++) {
1099 if (order
[i
] == currentChannelNum
) {
1100 if (!usedChannels
.isEmpty() &&
1101 usedChannels
.back().channelIndex
== order
[i
- 1]) {
1102 usedChannels
.removeLast();
1104 setChannel(order
[i
- 1]);
1108 currentChannelNum
= -1; // hit end of list
1111 void ConfigInputWidget::identifyControls()
1113 static const int DEBOUNCE_COUNT
= 4;
1114 static int debounce
= 0;
1116 receiverActivityData
= receiverActivityObj
->getData();
1118 if (receiverActivityData
.ActiveChannel
== 255) {
1122 if (channelDetected
) {
1123 registerControlActivity();
1127 receiverActivityData
= receiverActivityObj
->getData();
1128 currentChannel
.group
= receiverActivityData
.ActiveGroup
;
1129 currentChannel
.number
= receiverActivityData
.ActiveChannel
;
1131 if (debounce
== 0) {
1132 // Register a channel to be debounced.
1133 lastChannel
.group
= currentChannel
.group
;
1134 lastChannel
.number
= currentChannel
.number
;
1135 lastChannel
.channelIndex
= currentChannelNum
;
1140 if (currentChannel
!= lastChannel
) {
1141 // A new channel was seen. Only register it if we count down to 0.
1146 if (debounce
< DEBOUNCE_COUNT
) {
1147 // We still haven't seen enough enough activity on this channel yet.
1152 // Channel has been debounced and it's enough record it.
1154 if (usedChannels
.contains(lastChannel
)) {
1155 // Channel is already recorded.
1159 // Record the channel.
1161 channelDetected
= true;
1163 usedChannels
.append(lastChannel
);
1164 manualSettingsData
= manualSettingsObj
->getData();
1165 manualSettingsData
.ChannelGroups
[currentChannelNum
] = currentChannel
.group
;
1166 manualSettingsData
.ChannelNumber
[currentChannelNum
] = currentChannel
.number
;
1167 manualSettingsObj
->setData(manualSettingsData
);
1169 // m_config->wzText->clear();
1170 setTxMovement(nothing
);
1172 wzNextDelayedStart();
1175 void ConfigInputWidget::identifyLimits()
1177 manualCommandData
= manualCommandObj
->getData();
1178 for (uint i
= 0; i
< ManualControlSettings::CHANNELMAX_NUMELEM
; ++i
) {
1179 if (manualSettingsData
.ChannelMin
[i
] <= manualSettingsData
.ChannelMax
[i
]) {
1180 // Non inverted channel
1181 if (manualSettingsData
.ChannelMin
[i
] > manualCommandData
.Channel
[i
]) {
1182 manualSettingsData
.ChannelMin
[i
] = manualCommandData
.Channel
[i
];
1184 if (manualSettingsData
.ChannelMax
[i
] < manualCommandData
.Channel
[i
]) {
1185 manualSettingsData
.ChannelMax
[i
] = manualCommandData
.Channel
[i
];
1189 if (manualSettingsData
.ChannelMax
[i
] > manualCommandData
.Channel
[i
]) {
1190 manualSettingsData
.ChannelMax
[i
] = manualCommandData
.Channel
[i
];
1192 if (manualSettingsData
.ChannelMin
[i
] < manualCommandData
.Channel
[i
]) {
1193 manualSettingsData
.ChannelMin
[i
] = manualCommandData
.Channel
[i
];
1196 // Flightmode channel
1197 if (i
== ManualControlSettings::CHANNELGROUPS_FLIGHTMODE
) {
1198 bool newFlightModeValue
= true;
1199 // Avoid duplicate values too close and error due to RcTx drift
1200 int minSpacing
= 100; // 100µs
1201 for (int pos
= 0; pos
< manualSettingsData
.FlightModeNumber
+ 1; ++pos
) {
1202 if (flightModeSignalValue
[pos
] == 0) {
1203 // A new flightmode value can be set now
1204 for (int checkpos
= 0; checkpos
< manualSettingsData
.FlightModeNumber
+ 1; ++checkpos
) {
1205 // Check if value is already used, MinSpacing needed between values.
1206 if ((flightModeSignalValue
[checkpos
] < manualCommandData
.Channel
[i
] + minSpacing
) &&
1207 (flightModeSignalValue
[checkpos
] > manualCommandData
.Channel
[i
] - minSpacing
)) {
1208 newFlightModeValue
= false;
1211 // Be sure FlightModeNumber is < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM (6)
1212 if ((manualSettingsData
.FlightModeNumber
< FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM
) && newFlightModeValue
) {
1213 // Start from 0, erase previous count
1215 manualSettingsData
.FlightModeNumber
= 0;
1217 // Store new value and increase FlightModeNumber
1218 flightModeSignalValue
[pos
] = manualCommandData
.Channel
[i
];
1219 manualSettingsData
.FlightModeNumber
++;
1220 // Show flight mode number
1221 m_txFlightModeCountText
->setText(QString().number(manualSettingsData
.FlightModeNumber
));
1222 m_txFlightModeCountText
->setVisible(true);
1223 m_txFlightModeCountBG
->setVisible(true);
1229 manualSettingsObj
->setData(manualSettingsData
);
1232 void ConfigInputWidget::setMoveFromCommand(int command
)
1234 // ManualControlSettings::ChannelNumberElem:
1235 // CHANNELNUMBER_ROLL=0,
1236 // CHANNELNUMBER_PITCH=1,
1237 // CHANNELNUMBER_YAW=2,
1238 // CHANNELNUMBER_THROTTLE=3,
1239 // CHANNELNUMBER_FLIGHTMODE=4,
1240 // CHANNELNUMBER_ACCESSORY0=5,
1241 // CHANNELNUMBER_ACCESSORY1=6,
1242 // CHANNELNUMBER_ACCESSORY2=7
1244 txMovements movement
= moveLeftVerticalStick
;
1247 case ManualControlSettings::CHANNELNUMBER_ROLL
:
1248 movement
= ((transmitterMode
== mode3
|| transmitterMode
== mode4
) ?
1249 moveLeftHorizontalStick
: moveRightHorizontalStick
);
1251 case ManualControlSettings::CHANNELNUMBER_PITCH
:
1252 movement
= (transmitterMode
== mode1
|| transmitterMode
== mode3
) ?
1253 moveLeftVerticalStick
: moveRightVerticalStick
;
1255 case ManualControlSettings::CHANNELNUMBER_YAW
:
1256 movement
= ((transmitterMode
== mode1
|| transmitterMode
== mode2
) ?
1257 moveLeftHorizontalStick
: moveRightHorizontalStick
);
1259 case ManualControlSettings::CHANNELNUMBER_THROTTLE
:
1260 movement
= (transmitterMode
== mode2
|| transmitterMode
== mode4
) ?
1261 moveLeftVerticalStick
: moveRightVerticalStick
;
1263 case ManualControlSettings::CHANNELNUMBER_COLLECTIVE
:
1264 movement
= (transmitterMode
== mode2
|| transmitterMode
== mode4
) ?
1265 moveLeftVerticalStick
: moveRightVerticalStick
;
1267 case ManualControlSettings::CHANNELNUMBER_FLIGHTMODE
:
1268 movement
= moveFlightMode
;
1270 case ManualControlSettings::CHANNELNUMBER_ACCESSORY0
:
1271 movement
= moveAccess0
;
1273 case ManualControlSettings::CHANNELNUMBER_ACCESSORY1
:
1274 movement
= moveAccess1
;
1276 case ManualControlSettings::CHANNELNUMBER_ACCESSORY2
:
1277 movement
= moveAccess2
;
1279 case ManualControlSettings::CHANNELNUMBER_ACCESSORY3
:
1280 movement
= moveAccess3
;
1286 setTxMovement(movement
);
1289 void ConfigInputWidget::setTxMovement(txMovements movement
)
1293 case moveLeftVerticalStick
:
1296 currentMovement
= moveLeftVerticalStick
;
1297 animate
->start(100);
1299 case moveRightVerticalStick
:
1302 currentMovement
= moveRightVerticalStick
;
1303 animate
->start(100);
1305 case moveLeftHorizontalStick
:
1308 currentMovement
= moveLeftHorizontalStick
;
1309 animate
->start(100);
1311 case moveRightHorizontalStick
:
1314 currentMovement
= moveRightHorizontalStick
;
1315 animate
->start(100);
1320 currentMovement
= moveAccess0
;
1321 animate
->start(100);
1326 currentMovement
= moveAccess1
;
1327 animate
->start(100);
1332 currentMovement
= moveAccess2
;
1333 animate
->start(100);
1338 currentMovement
= moveAccess3
;
1339 animate
->start(100);
1341 case moveFlightMode
:
1344 currentMovement
= moveFlightMode
;
1345 animate
->start(1000);
1349 currentMovement
= centerAll
;
1350 animate
->start(1000);
1355 currentMovement
= moveAll
;
1368 void ConfigInputWidget::moveTxControls()
1371 QGraphicsItem
*item
= NULL
;
1372 txMovementType move
= vertical
;
1375 static bool auxFlag
= false;
1377 switch (currentMovement
) {
1378 case moveLeftVerticalStick
:
1379 item
= m_txLeftStick
;
1380 trans
= m_txLeftStickOrig
;
1381 limitMax
= STICK_MAX_MOVE
;
1382 limitMin
= STICK_MIN_MOVE
;
1385 case moveRightVerticalStick
:
1386 item
= m_txRightStick
;
1387 trans
= m_txRightStickOrig
;
1388 limitMax
= STICK_MAX_MOVE
;
1389 limitMin
= STICK_MIN_MOVE
;
1392 case moveLeftHorizontalStick
:
1393 item
= m_txLeftStick
;
1394 trans
= m_txLeftStickOrig
;
1395 limitMax
= STICK_MAX_MOVE
;
1396 limitMin
= STICK_MIN_MOVE
;
1399 case moveRightHorizontalStick
:
1400 item
= m_txRightStick
;
1401 trans
= m_txRightStickOrig
;
1402 limitMax
= STICK_MAX_MOVE
;
1403 limitMin
= STICK_MIN_MOVE
;
1408 trans
= m_txAccess0Orig
;
1409 limitMax
= ACCESS_MAX_MOVE
;
1410 limitMin
= ACCESS_MIN_MOVE
;
1415 trans
= m_txAccess1Orig
;
1416 limitMax
= ACCESS_MAX_MOVE
;
1417 limitMin
= ACCESS_MIN_MOVE
;
1422 trans
= m_txAccess2Orig
;
1423 limitMax
= ACCESS_MAX_MOVE
;
1424 limitMin
= ACCESS_MIN_MOVE
;
1429 trans
= m_txAccess3Orig
;
1430 limitMax
= ACCESS_MAX_MOVE
;
1431 limitMin
= ACCESS_MIN_MOVE
;
1434 case moveFlightMode
:
1435 item
= m_txFlightMode
;
1443 limitMax
= STICK_MAX_MOVE
;
1444 limitMin
= STICK_MIN_MOVE
;
1450 if (move
== vertical
) {
1451 item
->setTransform(trans
.translate(0, movePos
* 10), false);
1452 } else if (move
== horizontal
) {
1453 item
->setTransform(trans
.translate(movePos
* 10, 0), false);
1454 } else if (move
== jump
) {
1455 if (item
== m_txArrows
) {
1456 m_txArrows
->setVisible(!m_txArrows
->isVisible());
1457 } else if (item
== m_txFlightMode
) {
1458 QGraphicsSvgItem
*svg
;
1459 svg
= (QGraphicsSvgItem
*)item
;
1461 if (svg
->elementId() == "flightModeCenter") {
1463 svg
->setElementId("flightModeRight");
1464 m_txFlightMode
->setTransform(m_txFlightModeROrig
, false);
1466 svg
->setElementId("flightModeLeft");
1467 m_txFlightMode
->setTransform(m_txFlightModeLOrig
, false);
1469 } else if (svg
->elementId() == "flightModeRight") {
1471 svg
->setElementId("flightModeCenter");
1472 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
1473 } else if (svg
->elementId() == "flightModeLeft") {
1475 svg
->setElementId("flightModeCenter");
1476 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
1480 } else if (move
== mix
) {
1481 trans
= m_txAccess0Orig
;
1482 m_txAccess0
->setTransform(trans
.translate(movePos
* 10 * ACCESS_MAX_MOVE
/ STICK_MAX_MOVE
, 0), false);
1483 trans
= m_txAccess1Orig
;
1484 m_txAccess1
->setTransform(trans
.translate(movePos
* 10 * ACCESS_MAX_MOVE
/ STICK_MAX_MOVE
, 0), false);
1485 trans
= m_txAccess2Orig
;
1486 m_txAccess2
->setTransform(trans
.translate(movePos
* 10 * ACCESS_MAX_MOVE
/ STICK_MAX_MOVE
, 0), false);
1487 trans
= m_txAccess3Orig
;
1488 m_txAccess3
->setTransform(trans
.translate(movePos
* 10 * ACCESS_MAX_MOVE
/ STICK_MAX_MOVE
, 0), false);
1491 trans
= m_txLeftStickOrig
;
1492 m_txLeftStick
->setTransform(trans
.translate(0, movePos
* 10), false);
1493 trans
= m_txRightStickOrig
;
1494 m_txRightStick
->setTransform(trans
.translate(0, movePos
* 10), false);
1496 trans
= m_txLeftStickOrig
;
1497 m_txLeftStick
->setTransform(trans
.translate(movePos
* 10, 0), false);
1498 trans
= m_txRightStickOrig
;
1499 m_txRightStick
->setTransform(trans
.translate(movePos
* 10, 0), false);
1503 m_txFlightMode
->setElementId("flightModeCenter");
1504 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
1505 } else if (movePos
== ACCESS_MAX_MOVE
/ 2) {
1506 m_txFlightMode
->setElementId("flightModeRight");
1507 m_txFlightMode
->setTransform(m_txFlightModeROrig
, false);
1508 } else if (movePos
== ACCESS_MIN_MOVE
/ 2) {
1509 m_txFlightMode
->setElementId("flightModeLeft");
1510 m_txFlightMode
->setTransform(m_txFlightModeLOrig
, false);
1513 if (move
== horizontal
|| move
== vertical
|| move
== mix
) {
1514 if (movePos
== 0 && growing
) {
1522 if (movePos
> limitMax
) {
1523 movePos
= movePos
- 2;
1526 if (movePos
< limitMin
) {
1527 movePos
= movePos
+ 2;
1533 AccessoryDesired
*ConfigInputWidget::getAccessoryDesiredInstance(int instance
)
1537 if (accessoryDesiredObj0
== NULL
) {
1538 accessoryDesiredObj0
= AccessoryDesired::GetInstance(getObjectManager(), 0);
1540 return accessoryDesiredObj0
;
1543 if (accessoryDesiredObj1
== NULL
) {
1544 accessoryDesiredObj1
= AccessoryDesired::GetInstance(getObjectManager(), 1);
1546 return accessoryDesiredObj1
;
1549 if (accessoryDesiredObj2
== NULL
) {
1550 accessoryDesiredObj2
= AccessoryDesired::GetInstance(getObjectManager(), 2);
1552 return accessoryDesiredObj2
;
1555 if (accessoryDesiredObj3
== NULL
) {
1556 accessoryDesiredObj3
= AccessoryDesired::GetInstance(getObjectManager(), 3);
1558 return accessoryDesiredObj3
;
1567 float ConfigInputWidget::getAccessoryDesiredValue(int instance
)
1569 AccessoryDesired
*accessoryDesiredObj
= getAccessoryDesiredInstance(instance
);
1571 if (accessoryDesiredObj
== NULL
) {
1576 AccessoryDesired::DataFields data
= accessoryDesiredObj
->getData();
1578 return data
.AccessoryVal
;
1581 void ConfigInputWidget::moveSticks()
1585 manualCommandData
= manualCommandObj
->getData();
1586 flightStatusData
= flightStatusObj
->getData();
1588 switch (transmitterMode
) {
1590 trans
= m_txLeftStickOrig
;
1591 m_txLeftStick
->setTransform(trans
.translate(manualCommandData
.Yaw
* STICK_MAX_MOVE
* 10, manualCommandData
.Pitch
* STICK_MAX_MOVE
* 10), false);
1592 trans
= m_txRightStickOrig
;
1593 m_txRightStick
->setTransform(trans
.translate(manualCommandData
.Roll
* STICK_MAX_MOVE
* 10, -manualCommandData
.Throttle
* STICK_MAX_MOVE
* 10), false);
1596 trans
= m_txLeftStickOrig
;
1597 m_txLeftStick
->setTransform(trans
.translate(manualCommandData
.Yaw
* STICK_MAX_MOVE
* 10, -manualCommandData
.Throttle
* STICK_MAX_MOVE
* 10), false);
1598 trans
= m_txRightStickOrig
;
1599 m_txRightStick
->setTransform(trans
.translate(manualCommandData
.Roll
* STICK_MAX_MOVE
* 10, manualCommandData
.Pitch
* STICK_MAX_MOVE
* 10), false);
1602 trans
= m_txLeftStickOrig
;
1603 m_txLeftStick
->setTransform(trans
.translate(manualCommandData
.Roll
* STICK_MAX_MOVE
* 10, manualCommandData
.Pitch
* STICK_MAX_MOVE
* 10), false);
1604 trans
= m_txRightStickOrig
;
1605 m_txRightStick
->setTransform(trans
.translate(manualCommandData
.Yaw
* STICK_MAX_MOVE
* 10, -manualCommandData
.Throttle
* STICK_MAX_MOVE
* 10), false);
1608 trans
= m_txLeftStickOrig
;
1609 m_txLeftStick
->setTransform(trans
.translate(manualCommandData
.Roll
* STICK_MAX_MOVE
* 10, -manualCommandData
.Throttle
* STICK_MAX_MOVE
* 10), false);
1610 trans
= m_txRightStickOrig
;
1611 m_txRightStick
->setTransform(trans
.translate(manualCommandData
.Yaw
* STICK_MAX_MOVE
* 10, manualCommandData
.Pitch
* STICK_MAX_MOVE
* 10), false);
1617 if ((flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[0]) ||
1618 (flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[5])) {
1619 m_txFlightMode
->setElementId("flightModeLeft");
1620 m_txFlightMode
->setTransform(m_txFlightModeLOrig
, false);
1621 } else if ((flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[1]) ||
1622 (flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[4])) {
1623 m_txFlightMode
->setElementId("flightModeCenter");
1624 m_txFlightMode
->setTransform(m_txFlightModeCOrig
, false);
1625 } else if ((flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[2]) ||
1626 (flightStatusData
.FlightMode
== flightModeSettingsData
.FlightModePosition
[3])) {
1627 m_txFlightMode
->setElementId("flightModeRight");
1628 m_txFlightMode
->setTransform(m_txFlightModeROrig
, false);
1631 m_txAccess0
->setTransform(QTransform(m_txAccess0Orig
).translate(getAccessoryDesiredValue(0) * ACCESS_MAX_MOVE
* 10, 0), false);
1632 m_txAccess1
->setTransform(QTransform(m_txAccess1Orig
).translate(getAccessoryDesiredValue(1) * ACCESS_MAX_MOVE
* 10, 0), false);
1633 m_txAccess2
->setTransform(QTransform(m_txAccess2Orig
).translate(getAccessoryDesiredValue(2) * ACCESS_MAX_MOVE
* 10, 0), false);
1634 m_txAccess3
->setTransform(QTransform(m_txAccess3Orig
).translate(getAccessoryDesiredValue(3) * ACCESS_MAX_MOVE
* 10, 0), false);
1637 void ConfigInputWidget::dimOtherControls(bool value
)
1646 m_txAccess0
->setOpacity(opac
);
1647 m_txAccess1
->setOpacity(opac
);
1648 m_txAccess2
->setOpacity(opac
);
1649 m_txAccess3
->setOpacity(opac
);
1650 m_txFlightMode
->setOpacity(opac
);
1653 void ConfigInputWidget::invertControls()
1655 manualSettingsData
= manualSettingsObj
->getData();
1656 foreach(QWidget
* wd
, extraWidgets
) {
1657 QCheckBox
*cb
= qobject_cast
<QCheckBox
*>(wd
);
1660 int index
= manualSettingsObj
->getField("ChannelNumber")->getElementNames().indexOf(cb
->text());
1661 if ((cb
->isChecked() && (manualSettingsData
.ChannelMax
[index
] > manualSettingsData
.ChannelMin
[index
])) ||
1662 (!cb
->isChecked() && (manualSettingsData
.ChannelMax
[index
] < manualSettingsData
.ChannelMin
[index
]))) {
1664 aux
= manualSettingsData
.ChannelMax
[index
];
1665 manualSettingsData
.ChannelMax
[index
] = manualSettingsData
.ChannelMin
[index
];
1666 manualSettingsData
.ChannelMin
[index
] = aux
;
1670 manualSettingsObj
->setData(manualSettingsData
);
1673 void ConfigInputWidget::moveFMSlider()
1675 ManualControlSettings::DataFields manualSettingsDataPriv
= manualSettingsObj
->getData();
1676 ManualControlCommand::DataFields manualCommandDataPriv
= manualCommandObj
->getData();
1679 int chMin
= manualSettingsDataPriv
.ChannelMin
[ManualControlSettings::CHANNELMIN_FLIGHTMODE
];
1680 int chMax
= manualSettingsDataPriv
.ChannelMax
[ManualControlSettings::CHANNELMAX_FLIGHTMODE
];
1681 int chNeutral
= manualSettingsDataPriv
.ChannelNeutral
[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE
];
1683 int value
= manualCommandDataPriv
.Channel
[ManualControlSettings::CHANNELMIN_FLIGHTMODE
];
1685 if ((chMax
> chMin
&& value
>= chNeutral
) || (chMin
> chMax
&& value
<= chNeutral
)) {
1686 if (chMax
!= chNeutral
) {
1687 valueScaled
= (float)(value
- chNeutral
) / (float)(chMax
- chNeutral
);
1692 if (chMin
!= chNeutral
) {
1693 valueScaled
= (float)(value
- chNeutral
) / (float)(chNeutral
- chMin
);
1699 // Bound and scale FlightMode from [-1..+1] to [0..1] range
1700 if (valueScaled
< -1.0) {
1702 } else if (valueScaled
> 1.0) {
1706 // Convert flightMode value into the switch position in the range [0..N-1]
1707 // This uses the same optimized computation as flight code to be consistent
1708 uint8_t pos
= ((int16_t)(valueScaled
* 256) + 256) * manualSettingsDataPriv
.FlightModeNumber
>> 9;
1709 if (pos
>= manualSettingsDataPriv
.FlightModeNumber
) {
1710 pos
= manualSettingsDataPriv
.FlightModeNumber
- 1;
1712 ui
->fmsSlider
->setValue(pos
);
1713 highlightStabilizationMode(pos
);
1716 void ConfigInputWidget::highlightStabilizationMode(int pos
)
1718 QComboBox
*comboboxFm
= this->findChild
<QComboBox
*>("fmsModePos" + QString::number(pos
+ 1));
1719 QString customStyleSheet
= "QComboBox:editable:!on{background: #feb103;}";
1722 QString flightModeText
= comboboxFm
->currentText();
1723 comboboxFm
->setStyleSheet("");
1724 for (uint8_t i
= 0; i
< FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM
; i
++) {
1725 QLabel
*label
= this->findChild
<QLabel
*>("stab" + QString::number(i
+ 1) + "_label");
1726 QComboBox
*comboRoll
= this->findChild
<QComboBox
*>("fmsSsPos" + QString::number(i
+ 1) + "Roll");
1727 QComboBox
*comboPitch
= this->findChild
<QComboBox
*>("fmsSsPos" + QString::number(i
+ 1) + "Pitch");
1728 QComboBox
*comboYaw
= this->findChild
<QComboBox
*>("fmsSsPos" + QString::number(i
+ 1) + "Yaw");
1729 QComboBox
*comboThrust
= this->findChild
<QComboBox
*>("fmsSsPos" + QString::number(i
+ 1) + "Thrust");
1730 QComboBox
*comboboxFm2
= this->findChild
<QComboBox
*>("fmsModePos" + QString::number(i
+ 1));
1731 comboboxFm2
->setStyleSheet("");
1733 // Highlight current stabilization mode if any.
1734 if ((flightModeText
.contains("Stabilized", Qt::CaseInsensitive
)) && (flightModeText
.contains(QString::number(i
+ 1), Qt::CaseInsensitive
))) {
1735 label
->setStyleSheet("border-radius: 4px; border:3px solid #feb103;");
1736 comboRoll
->setStyleSheet(customStyleSheet
);
1737 comboPitch
->setStyleSheet(customStyleSheet
);
1738 comboYaw
->setStyleSheet(customStyleSheet
);
1739 comboThrust
->setStyleSheet(customStyleSheet
);
1741 label
->setStyleSheet("");
1742 comboRoll
->setStyleSheet("");
1743 comboPitch
->setStyleSheet("");
1744 comboYaw
->setStyleSheet("");
1745 comboThrust
->setStyleSheet("");
1746 if (!flightModeText
.contains("Stabilized", Qt::CaseInsensitive
)) {
1747 // Highlight PosHold, Return to Base, ... flightmodes
1748 comboboxFm
->setStyleSheet(customStyleSheet
);
1755 void setComboBoxItemEnabled(QComboBox
*combo
, int index
, bool enabled
= true)
1757 combo
->setItemData(index
, enabled
? QVariant(1 | 32) : QVariant(0), Qt::UserRole
- 1);
1760 void ConfigInputWidget::updatePositionSlider()
1762 ManualControlSettings::DataFields manualSettingsDataPriv
= manualSettingsObj
->getData();
1764 switch (manualSettingsDataPriv
.FlightModeNumber
) {
1767 ui
->fmsModePos6
->setEnabled(true);
1768 ui
->pidBankSs1_5
->setEnabled(true);
1769 ui
->assistControlPos6
->setEnabled(true);
1770 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 5);
1773 ui
->fmsModePos5
->setEnabled(true);
1774 ui
->pidBankSs1_4
->setEnabled(true);
1775 ui
->assistControlPos5
->setEnabled(true);
1776 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 4);
1779 ui
->fmsModePos4
->setEnabled(true);
1780 ui
->pidBankSs1_3
->setEnabled(true);
1781 ui
->assistControlPos4
->setEnabled(true);
1782 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 3);
1785 ui
->fmsModePos3
->setEnabled(true);
1786 ui
->pidBankSs1_2
->setEnabled(true);
1787 ui
->assistControlPos3
->setEnabled(true);
1788 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 2);
1791 ui
->fmsModePos2
->setEnabled(true);
1792 ui
->pidBankSs1_1
->setEnabled(true);
1793 ui
->assistControlPos2
->setEnabled(true);
1794 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 1);
1797 ui
->fmsModePos1
->setEnabled(true);
1798 ui
->pidBankSs1_0
->setEnabled(true);
1799 ui
->assistControlPos1
->setEnabled(true);
1800 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 0);
1806 switch (manualSettingsDataPriv
.FlightModeNumber
) {
1808 ui
->fmsModePos1
->setEnabled(false);
1809 ui
->pidBankSs1_0
->setEnabled(false);
1810 ui
->assistControlPos1
->setEnabled(false);
1811 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 0, false);
1814 ui
->fmsModePos2
->setEnabled(false);
1815 ui
->pidBankSs1_1
->setEnabled(false);
1816 ui
->assistControlPos2
->setEnabled(false);
1817 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 1, false);
1820 ui
->fmsModePos3
->setEnabled(false);
1821 ui
->pidBankSs1_2
->setEnabled(false);
1822 ui
->assistControlPos3
->setEnabled(false);
1823 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 2, false);
1826 ui
->fmsModePos4
->setEnabled(false);
1827 ui
->pidBankSs1_3
->setEnabled(false);
1828 ui
->assistControlPos4
->setEnabled(false);
1829 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 3, false);
1832 ui
->fmsModePos5
->setEnabled(false);
1833 ui
->pidBankSs1_4
->setEnabled(false);
1834 ui
->assistControlPos5
->setEnabled(false);
1835 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 4, false);
1838 ui
->fmsModePos6
->setEnabled(false);
1839 ui
->pidBankSs1_5
->setEnabled(false);
1840 ui
->assistControlPos6
->setEnabled(false);
1841 setComboBoxItemEnabled(ui
->failsafeFlightMode
, 5, false);
1848 QString fmNumber
= QString().setNum(manualSettingsDataPriv
.FlightModeNumber
);
1850 foreach(QSlider
* sp
, findChildren
<QSlider
*>()) {
1851 // Find FlightMode slider and apply stylesheet
1852 if (sp
->objectName() == "channelNeutral") {
1855 "QSlider::groove:horizontal {border: 2px solid rgb(196, 196, 196); margin: 0px 23px 0px 23px; height: 12px; border-radius: 5px; "
1856 "border-image:url(:/configgadget/images/flightmode_bg" + fmNumber
+ ".png); }"
1857 "QSlider::add-page:horizontal { background: none; border: none; }"
1858 "QSlider::sub-page:horizontal { background: none; border: none; }"
1859 "QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, "
1860 "stop: 0 rgba(196, 196, 196, 180), stop: 0.45 rgba(196, 196, 196, 180), "
1861 "stop: 0.46 rgba(255,0,0,100), stop: 0.54 rgba(255,0,0,100), "
1862 "stop: 0.55 rgba(196, 196, 196, 180), stop: 1 rgba(196, 196, 196, 180)); "
1863 "width: 46px; height: 28px; margin: -6px -23px -6px -23px; border-radius: 5px; border: 1px solid #777; }");
1872 void ConfigInputWidget::updateConfigAlarmStatus()
1874 SystemAlarms
*systemAlarmsObj
= SystemAlarms::GetInstance(getObjectManager());
1875 SystemAlarms::DataFields systemAlarms
= systemAlarmsObj
->getData();
1877 QString message
= tr("Config OK");
1878 QString tooltipMessage
= tr("All fine, no config alarm!");
1879 QString bgColor
= "green";
1881 if (systemAlarms
.Alarm
[SystemAlarms::ALARM_SYSTEMCONFIGURATION
] > SystemAlarms::ALARM_WARNING
) {
1882 switch (systemAlarms
.ExtendedAlarmStatus
[SystemAlarms::EXTENDEDALARMSTATUS_SYSTEMCONFIGURATION
]) {
1883 case SystemAlarms::EXTENDEDALARMSTATUS_FLIGHTMODE
:
1884 message
= tr("Config error");
1885 tooltipMessage
= tr("There is something wrong with your config,\nusually a Thrust mode or Assisted mode not supported.\n\n"
1886 "Tip: Reduce the Flight Mode Count to find the culprit.");
1890 ui
->configAlarmStatus
->setVisible(true);
1891 ui
->configAlarmStatus
->setStyleSheet(
1892 "QLabel { background-color: " + bgColor
+ ";"
1893 "color: rgb(255, 255, 255); border-radius: 5; margin:1px; font:bold; }");
1894 ui
->configAlarmStatus
->setText(message
);
1895 ui
->configAlarmStatus
->setToolTip(tooltipMessage
);
1898 void ConfigInputWidget::updateCalibration()
1900 manualCommandData
= manualCommandObj
->getData();
1901 for (uint i
= 0; i
< ManualControlSettings::CHANNELMAX_NUMELEM
; ++i
) {
1902 if ((!reverse
[i
] && manualSettingsData
.ChannelMin
[i
] > manualCommandData
.Channel
[i
]) ||
1903 (reverse
[i
] && manualSettingsData
.ChannelMin
[i
] < manualCommandData
.Channel
[i
])) {
1904 manualSettingsData
.ChannelMin
[i
] = manualCommandData
.Channel
[i
];
1906 if ((!reverse
[i
] && manualSettingsData
.ChannelMax
[i
] < manualCommandData
.Channel
[i
]) ||
1907 (reverse
[i
] && manualSettingsData
.ChannelMax
[i
] > manualCommandData
.Channel
[i
])) {
1908 manualSettingsData
.ChannelMax
[i
] = manualCommandData
.Channel
[i
];
1910 if ((i
== ManualControlSettings::CHANNELNUMBER_FLIGHTMODE
) || (i
== ManualControlSettings::CHANNELNUMBER_THROTTLE
)) {
1911 adjustSpecialNeutrals();
1913 // Set Accessory neutral to middle range
1914 if (i
>= ManualControlSettings::CHANNELNUMBER_ACCESSORY0
) {
1915 manualSettingsData
.ChannelNeutral
[i
] = manualSettingsData
.ChannelMin
[i
] + ((manualSettingsData
.ChannelMax
[i
] - manualSettingsData
.ChannelMin
[i
]) / 2);
1917 manualSettingsData
.ChannelNeutral
[i
] = manualCommandData
.Channel
[i
];
1922 manualSettingsObj
->setData(manualSettingsData
);
1923 manualSettingsObj
->updated();
1926 void ConfigInputWidget::simpleCalibration(bool enable
)
1929 ui
->configurationWizard
->setEnabled(false);
1930 ui
->saveRCInputToRAM
->setEnabled(false);
1931 ui
->saveRCInputToSD
->setEnabled(false);
1932 ui
->runCalibration
->setText(tr("Stop Manual Calibration"));
1933 throttleError
= false;
1936 msgBox
.setText(tr("<p>Arming Settings are now set to 'Always Disarmed' for your safety.</p>"
1937 "<p>Be sure your receiver is powered with an external source and Transmitter is on.</p>"
1938 "<p align='center'><b>Stop Manual Calibration</b> when done</p>"));
1939 msgBox
.setDetailedText(tr("You will have to reconfigure the arming settings manually when the manual calibration is finished."));
1940 msgBox
.setStandardButtons(QMessageBox::Ok
);
1941 msgBox
.setDefaultButton(QMessageBox::Ok
);
1944 manualCommandData
= manualCommandObj
->getData();
1946 manualSettingsData
= manualSettingsObj
->getData();
1947 flightModeSettingsData
= flightModeSettingsObj
->getData();
1948 flightModeSettingsData
.Arming
= FlightModeSettings::ARMING_ALWAYSDISARMED
;
1949 flightModeSettingsObj
->setData(flightModeSettingsData
);
1951 for (unsigned int i
= 0; i
< ManualControlCommand::CHANNEL_NUMELEM
; i
++) {
1952 reverse
[i
] = manualSettingsData
.ChannelMax
[i
] < manualSettingsData
.ChannelMin
[i
];
1953 manualSettingsData
.ChannelMin
[i
] = manualCommandData
.Channel
[i
];
1954 manualSettingsData
.ChannelNeutral
[i
] = manualCommandData
.Channel
[i
];
1955 manualSettingsData
.ChannelMax
[i
] = manualCommandData
.Channel
[i
];
1958 fastMdataSingle(manualCommandObj
, &manualControlMdata
);
1960 // Stash actuatorSettings
1961 actuatorSettingsData
= actuatorSettingsObj
->getData();
1962 memento
.actuatorSettingsData
= actuatorSettingsData
;
1964 // Disable all actuators
1965 resetActuatorSettings();
1967 connect(manualCommandObj
, SIGNAL(objectUnpacked(UAVObject
*)), this, SLOT(updateCalibration()));
1969 manualCommandData
= manualCommandObj
->getData();
1970 manualSettingsData
= manualSettingsObj
->getData();
1971 systemSettingsData
= systemSettingsObj
->getData();
1973 if (systemSettingsData
.AirframeType
== SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR
) {
1974 QMessageBox::warning(this, tr("Ground Vehicle"),
1975 tr("<p>Please <b>center</b> throttle control and press OK when ready.</p>"));
1977 transmitterType
= ground
;
1978 manualSettingsData
.ChannelNeutral
[ManualControlSettings::CHANNELNEUTRAL_THROTTLE
] =
1979 manualCommandData
.Channel
[ManualControlSettings::CHANNELNUMBER_THROTTLE
];
1982 restoreMdataSingle(manualCommandObj
, &manualControlMdata
);
1984 // Force flight mode number to be 1 if 2 channel ground vehicle was confirmed
1985 if (transmitterType
== ground
) {
1986 forceOneFlightMode();
1989 for (unsigned int i
= 0; i
< ManualControlCommand::CHANNEL_NUMELEM
; i
++) {
1990 if ((i
== ManualControlSettings::CHANNELNUMBER_FLIGHTMODE
) || (i
== ManualControlSettings::CHANNELNUMBER_THROTTLE
)) {
1991 adjustSpecialNeutrals();
1992 checkThrottleRange();
1994 // Set Accessory neutral to middle range
1995 if (i
>= ManualControlSettings::CHANNELNUMBER_ACCESSORY0
) {
1996 manualSettingsData
.ChannelNeutral
[i
] = manualSettingsData
.ChannelMin
[i
] + ((manualSettingsData
.ChannelMax
[i
] - manualSettingsData
.ChannelMin
[i
]) / 2);
1998 manualSettingsData
.ChannelNeutral
[i
] = manualCommandData
.Channel
[i
];
2002 manualSettingsObj
->setData(manualSettingsData
);
2004 // Load actuator settings back from beginning of manual calibration
2005 actuatorSettingsObj
->setData(memento
.actuatorSettingsData
);
2007 ui
->configurationWizard
->setEnabled(true);
2008 ui
->saveRCInputToRAM
->setEnabled(true);
2009 ui
->saveRCInputToSD
->setEnabled(true);
2010 ui
->runCalibration
->setText(tr("Start Manual Calibration"));
2012 disconnect(manualCommandObj
, SIGNAL(objectUnpacked(UAVObject
*)), this, SLOT(updateCalibration()));
2016 void ConfigInputWidget::adjustSpecialNeutrals()
2018 // FlightMode and Throttle need special neutral settings
2020 // Force flight mode neutral to middle
2021 manualSettingsData
.ChannelNeutral
[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE
] =
2022 (manualSettingsData
.ChannelMax
[ManualControlSettings::CHANNELMAX_FLIGHTMODE
] +
2023 manualSettingsData
.ChannelMin
[ManualControlSettings::CHANNELMIN_FLIGHTMODE
]) / 2;
2025 // A ground vehicle has a reversible motor, the center position of throttle is the neutral setting.
2026 // So do not have to set a special neutral value for it.
2027 if (transmitterType
== ground
) {
2031 // Force throttle to be near min, add 4% from total range to avoid arming issues
2032 manualSettingsData
.ChannelNeutral
[ManualControlSettings::CHANNELNEUTRAL_THROTTLE
] =
2033 manualSettingsData
.ChannelMin
[ManualControlSettings::CHANNELMIN_THROTTLE
] +
2034 ((manualSettingsData
.ChannelMax
[ManualControlSettings::CHANNELMAX_THROTTLE
] -
2035 manualSettingsData
.ChannelMin
[ManualControlSettings::CHANNELMIN_THROTTLE
]) * 0.04);
2038 void ConfigInputWidget::checkThrottleRange()
2040 int throttleRange
= abs(manualSettingsData
.ChannelMax
[ManualControlSettings::CHANNELMAX_THROTTLE
] -
2041 manualSettingsData
.ChannelMin
[ManualControlSettings::CHANNELMIN_THROTTLE
]);
2043 if (!throttleError
&& (throttleRange
< 300)) {
2044 throttleError
= true;
2045 QMessageBox::warning(this, tr("Warning"), tr("<p>There is something wrong with Throttle range. Please redo calibration and move <b>ALL sticks</b>, Throttle stick included.</p>"), QMessageBox::Ok
);
2047 // Set Throttle neutral to max value so Throttle can't be positive
2048 manualSettingsData
.ChannelNeutral
[ManualControlSettings::CHANNELNEUTRAL_THROTTLE
] =
2049 manualSettingsData
.ChannelMax
[ManualControlSettings::CHANNELMAX_THROTTLE
];
2053 bool ConfigInputWidget::shouldObjectBeSaved(UAVObject
*object
)
2055 // ManualControlCommand no need to be saved
2056 return dynamic_cast<ManualControlCommand
*>(object
) == NULL
;
2059 void ConfigInputWidget::resetChannelSettings()
2061 manualSettingsData
= manualSettingsObj
->getData();
2062 // Clear all channel data : Channel Type (PPM,PWM..) and Number
2063 for (unsigned int channel
= 0; channel
< ManualControlSettings::CHANNELNUMBER_NUMELEM
; channel
++) {
2064 manualSettingsData
.ChannelGroups
[channel
] = ManualControlSettings::CHANNELGROUPS_NONE
;
2065 manualSettingsData
.ChannelNumber
[channel
] = CHANNEL_NUMBER_NONE
;
2066 manualSettingsObj
->setData(manualSettingsData
);
2068 resetFlightModeSettings();
2071 void ConfigInputWidget::resetFlightModeSettings()
2073 // Reset FlightMode settings
2074 manualSettingsData
.FlightModeNumber
= DEFAULT_FLIGHT_MODE_NUMBER
;
2075 manualSettingsObj
->setData(manualSettingsData
);
2076 for (uint8_t pos
= 0; pos
< FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM
; pos
++) {
2077 flightModeSignalValue
[pos
] = 0;
2081 void ConfigInputWidget::resetActuatorSettings()
2083 actuatorSettingsData
= actuatorSettingsObj
->getData();
2085 UAVDataObject
*mixer
= dynamic_cast<UAVDataObject
*>(getObjectManager()->getObject(QString("MixerSettings")));
2090 // Clear all output data : Min, max, neutral at same value
2091 // 1000 for motors and 1500 for all others (Reversable motor included)
2092 for (unsigned int output
= 0; output
< ActuatorSettings::CHANNELMAX_NUMELEM
; output
++) {
2093 QString mixerNumType
= QString("Mixer%1Type").arg(output
+ 1);
2094 UAVObjectField
*field
= mixer
->getField(mixerNumType
);
2098 mixerType
= field
->getValue().toString();
2100 if ((mixerType
== "Motor") || (mixerType
== "Disabled")) {
2101 actuatorSettingsData
.ChannelMax
[output
] = 1000;
2102 actuatorSettingsData
.ChannelMin
[output
] = 1000;
2103 actuatorSettingsData
.ChannelNeutral
[output
] = 1000;
2105 actuatorSettingsData
.ChannelMax
[output
] = 1500;
2106 actuatorSettingsData
.ChannelMin
[output
] = 1500;
2107 actuatorSettingsData
.ChannelNeutral
[output
] = 1500;
2109 actuatorSettingsObj
->setData(actuatorSettingsData
);
2113 void ConfigInputWidget::forceOneFlightMode()
2115 manualSettingsData
= manualSettingsObj
->getData();
2116 manualSettingsData
.FlightModeNumber
= 1;
2117 manualSettingsObj
->setData(manualSettingsData
);
2120 void ConfigInputWidget::failsafeFlightModeChanged(int index
)
2122 ui
->failsafeFlightMode
->setEnabled(index
!= -1);
2123 ui
->failsafeFlightModeCb
->setChecked(index
!= -1);
2126 void ConfigInputWidget::failsafeFlightModeCbToggled(bool checked
)
2128 ui
->failsafeFlightMode
->setCurrentIndex(checked
? 0 : -1);
2131 void ConfigInputWidget::enableControlsChanged(bool enabled
)
2133 ui
->failsafeFlightMode
->setEnabled(enabled
&& ui
->failsafeFlightMode
->currentIndex() != -1);