Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / config / configinputwidget.cpp
blob3afd3761f636b6c70bfb059738a17496a88dd331
1 /**
2 ******************************************************************************
4 * @file configinputwidget.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
8 * @{
9 * @addtogroup ConfigPlugin Config Plugin
10 * @{
11 * @brief Servo input 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
22 * for more details.
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 "ui_input.h"
32 #include "ui_input_wizard.h"
34 #include "inputchannelform.h"
35 #include "ui_inputchannelform.h"
37 #include "failsafechannelform.h"
38 #include "ui_failsafechannelform.h"
40 #include <uavobjectmanager.h>
41 #include <uavobjecthelper.h>
42 #include <utils/stylehelper.h>
44 #include <systemalarms.h>
46 #include <QDebug>
47 #include <QWidget>
48 #include <QMessageBox>
49 #include <QGraphicsSvgItem>
50 #include <QSvgRenderer>
52 #define ACCESS_MIN_MOVE -3
53 #define ACCESS_MAX_MOVE 3
54 #define STICK_MIN_MOVE -8
55 #define STICK_MAX_MOVE 8
57 #define MIN_INPUT_US 100
58 #define MAX_INPUT_US 2500
60 #define CHANNEL_NUMBER_NONE 0
61 #define DEFAULT_FLIGHT_MODE_NUMBER 1
63 ConfigInputWidget::ConfigInputWidget(QWidget *parent) :
64 ConfigTaskWidget(parent),
65 wizardStep(wizardNone),
66 // not currently stored in the settings UAVO
67 transmitterMode(mode2),
68 transmitterType(acro),
70 loop(NULL),
71 skipflag(false),
72 nextDelayedTimer(),
73 nextDelayedTick(0),
74 nextDelayedLatestActivityTick(0),
75 accessoryDesiredObj0(NULL),
76 accessoryDesiredObj1(NULL),
77 accessoryDesiredObj2(NULL),
78 accessoryDesiredObj3(NULL),
79 rssiDesiredObj4(NULL)
81 ui = new Ui_InputWidget();
82 ui->setupUi(this);
84 // must be done before auto binding !
85 setWikiURL("Input+Configuration");
87 addAutoBindings();
89 connect(this, SIGNAL(enableControlsChanged(bool)), this, SLOT(enableControlsChanged(bool)));
91 manualCommandObj = ManualControlCommand::GetInstance(getObjectManager());
92 manualSettingsObj = ManualControlSettings::GetInstance(getObjectManager());
93 flightModeSettingsObj = FlightModeSettings::GetInstance(getObjectManager());
94 flightStatusObj = FlightStatus::GetInstance(getObjectManager());
95 receiverActivityObj = ReceiverActivity::GetInstance(getObjectManager());
96 accessoryDesiredObj0 = AccessoryDesired::GetInstance(getObjectManager(), 0);
97 accessoryDesiredObj1 = AccessoryDesired::GetInstance(getObjectManager(), 1);
98 accessoryDesiredObj2 = AccessoryDesired::GetInstance(getObjectManager(), 2);
99 accessoryDesiredObj3 = AccessoryDesired::GetInstance(getObjectManager(), 3);
100 rssiDesiredObj4 = AccessoryDesired::GetInstance(getObjectManager(), 4);
101 actuatorSettingsObj = ActuatorSettings::GetInstance(getObjectManager());
102 systemSettingsObj = SystemSettings::GetInstance(getObjectManager());
103 hwSettingsObj = HwSettings::GetInstance(getObjectManager());
104 // Only instance 0 is present if the board is not connected.
105 // The other instances are populated lazily.
106 Q_ASSERT(accessoryDesiredObj0);
108 // Generate the rows of buttons in the input channel form GUI
109 quint32 index = 0;
110 quint32 indexRT = 0;
111 foreach(QString name, manualSettingsObj->getField("ChannelNumber")->getElementNames()) {
112 Q_ASSERT(index < ManualControlSettings::CHANNELGROUPS_NUMELEM);
114 // Input channel setup
115 InputChannelForm *inputChannelForm = new InputChannelForm(index, this);
116 inputChannelForm->setName(name);
118 inputChannelForm->moveTo(*(ui->channelLayout));
120 // The order of the following binding calls is important. Since the values will be populated
121 // in reverse order of the binding order otherwise the 'Reversed' logic will floor the neutral value
122 // to the max value ( which is smaller than the neutral value when reversed ) and the channel number
123 // will not be set correctly.
124 addWidgetBinding("ManualControlSettings", "ChannelNumber", inputChannelForm->ui->channelNumber, index);
125 addWidgetBinding("ManualControlSettings", "ChannelGroups", inputChannelForm->ui->channelGroup, index);
126 // Slider position based on real time Rcinput (allow monitoring)
127 addWidgetBinding("ManualControlCommand", "Channel", inputChannelForm->ui->channelNeutral, index);
128 // Neutral value stored on board (SpinBox)
129 // Rssi neutral is always set to min
130 if (index == ManualControlSettings::CHANNELGROUPS_RSSI) {
131 addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->neutralValue, index);
132 } else {
133 addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm->ui->neutralValue, index);
135 addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index);
136 addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->channelMin, index);
137 addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index);
139 addWidget(inputChannelForm->ui->channelRev);
141 // Reversing supported for some channels only
142 bool reversable = ((index == ManualControlSettings::CHANNELGROUPS_THROTTLE) ||
143 (index == ManualControlSettings::CHANNELGROUPS_ROLL) ||
144 (index == ManualControlSettings::CHANNELGROUPS_PITCH) ||
145 (index == ManualControlSettings::CHANNELGROUPS_YAW));
146 inputChannelForm->ui->channelRev->setVisible(reversable);
148 // Input filter response time fields supported for some channels only
149 // Set Neutral field to readonly for Rssi
150 switch (index) {
151 case ManualControlSettings::CHANNELGROUPS_RSSI:
152 inputChannelForm->ui->neutralValue->setReadOnly(true);
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);
162 ++indexRT;
163 break;
164 case ManualControlSettings::CHANNELGROUPS_THROTTLE:
165 case ManualControlSettings::CHANNELGROUPS_FLIGHTMODE:
166 inputChannelForm->ui->channelResponseTime->setVisible(false);
167 break;
168 default:
169 Q_ASSERT(0);
170 break;
172 ++index;
175 QList<int> failsafeReloadGroup;
176 failsafeReloadGroup.append(555);
178 addWidgetBinding("ManualControlSettings", "FailsafeFlightModeSwitchPosition", ui->failsafeFlightMode, 0, 1, true, new QList<int>(failsafeReloadGroup));
180 addWidgetBinding("FlightModeSettings", "BatteryFailsafeSwitchPositions", ui->failsafeBatteryWarningFlightMode, 0, 1, true, new QList<int>(failsafeReloadGroup));
181 addWidgetBinding("FlightModeSettings", "BatteryFailsafeSwitchPositions", ui->failsafeBatteryCriticalFlightMode, 1, 1, true, new QList<int>(failsafeReloadGroup));
183 // Generate the rows for the failsafe channel form GUI
184 index = 0;
185 foreach(QString name, manualSettingsObj->getField("FailsafeChannel")->getElementNames()) {
186 Q_ASSERT(index < ManualControlSettings::FAILSAFECHANNEL_NUMELEM);
188 // Failsafe channels setup
189 FailsafeChannelForm *failsafeChannelForm = new FailsafeChannelForm(index, this);
190 addWidget(failsafeChannelForm->ui->channelValueSpinner);
191 failsafeChannelForm->setName(name);
192 failsafeChannelForm->moveTo(*(ui->failsafeChannelsLayout));
193 addWidgetBinding("ManualControlSettings", "FailsafeChannel", failsafeChannelForm->ui->channelValue, index, 0.01, true, new QList<int>(failsafeReloadGroup));
194 ++index;
196 addWidget(ui->failsafeDefault);
198 addWidgetBinding("ManualControlSettings", "Deadband", ui->deadband, 0, 1);
199 addWidgetBinding("ManualControlSettings", "DeadbandAssistedControl", ui->assistedControlDeadband, 0, 1);
201 connect(ui->configurationWizard, SIGNAL(clicked()), this, SLOT(goToWizard()));
202 connect(ui->stackedWidget, SIGNAL(currentChanged(int)), this, SLOT(disableWizardButton(int)));
203 connect(ui->runCalibration, SIGNAL(toggled(bool)), this, SLOT(simpleCalibration(bool)));
205 connect(ReceiverActivity::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateReceiverActivityStatus()));
206 connect(FlightStatus::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateReceiverActivityStatus()));
208 ui->receiverActivityStatus->setStyleSheet("QLabel { background-color: darkGreen; color: rgb(255, 255, 255); \
209 border: 1px solid grey; border-radius: 5; margin:1px; font:bold;}");
211 ui->stackedWidget->setCurrentIndex(0);
212 QList<QWidget *> widgets = QList<QWidget *>() << ui->fmsModePos1 << ui->fmsModePos2 << ui->fmsModePos3 <<
213 ui->fmsModePos4 << ui->fmsModePos5 << ui->fmsModePos6;
214 index = 0;
215 foreach(QWidget * widget, widgets) {
216 addWidgetBinding("FlightModeSettings", "FlightModePosition", widget, index++, 1, true);
219 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui->fmsSsPos1Roll, "Roll", 1, true);
220 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui->fmsSsPos2Roll, "Roll", 1, true);
221 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui->fmsSsPos3Roll, "Roll", 1, true);
222 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui->fmsSsPos4Roll, "Roll", 1, true);
223 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui->fmsSsPos5Roll, "Roll", 1, true);
224 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui->fmsSsPos6Roll, "Roll", 1, true);
226 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui->fmsSsPos1Pitch, "Pitch", 1, true);
227 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui->fmsSsPos2Pitch, "Pitch", 1, true);
228 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui->fmsSsPos3Pitch, "Pitch", 1, true);
229 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui->fmsSsPos4Pitch, "Pitch", 1, true);
230 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui->fmsSsPos5Pitch, "Pitch", 1, true);
231 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui->fmsSsPos6Pitch, "Pitch", 1, true);
233 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui->fmsSsPos1Yaw, "Yaw", 1, true);
234 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui->fmsSsPos2Yaw, "Yaw", 1, true);
235 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui->fmsSsPos3Yaw, "Yaw", 1, true);
236 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui->fmsSsPos4Yaw, "Yaw", 1, true);
237 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui->fmsSsPos5Yaw, "Yaw", 1, true);
238 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui->fmsSsPos6Yaw, "Yaw", 1, true);
240 addWidgetBinding("FlightModeSettings", "Stabilization1Settings", ui->fmsSsPos1Thrust, "Thrust", 1, true);
241 addWidgetBinding("FlightModeSettings", "Stabilization2Settings", ui->fmsSsPos2Thrust, "Thrust", 1, true);
242 addWidgetBinding("FlightModeSettings", "Stabilization3Settings", ui->fmsSsPos3Thrust, "Thrust", 1, true);
243 addWidgetBinding("FlightModeSettings", "Stabilization4Settings", ui->fmsSsPos4Thrust, "Thrust", 1, true);
244 addWidgetBinding("FlightModeSettings", "Stabilization5Settings", ui->fmsSsPos5Thrust, "Thrust", 1, true);
245 addWidgetBinding("FlightModeSettings", "Stabilization6Settings", ui->fmsSsPos6Thrust, "Thrust", 1, true);
247 addWidgetBinding("ManualControlSettings", "FlightModeNumber", ui->fmsPosNum);
249 addWidgetBinding("FlightModeSettings", "Arming", ui->armControl);
250 addWidgetBinding("FlightModeSettings", "ArmedTimeout", ui->armTimeout, 0, 1000);
251 connect(ManualControlCommand::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveFMSlider()));
252 connect(ManualControlSettings::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updatePositionSlider()));
253 connect(SystemAlarms::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateConfigAlarmStatus()));
255 connect(ui->failsafeFlightMode, SIGNAL(currentIndexChanged(int)), this, SLOT(failsafeFlightModeChanged(int)));
256 connect(ui->failsafeFlightModeCb, SIGNAL(toggled(bool)), this, SLOT(failsafeFlightModeCbToggled(bool)));
258 connect(ui->failsafeBatteryWarningFlightMode, SIGNAL(currentIndexChanged(int)), this, SLOT(failsafeBatteryWarningFlightModeChanged(int)));
259 connect(ui->failsafeBatteryWarningFlightModeCb, SIGNAL(toggled(bool)), this, SLOT(failsafeBatteryWarningFlightModeCbToggled(bool)));
261 connect(ui->failsafeBatteryCriticalFlightMode, SIGNAL(currentIndexChanged(int)), this, SLOT(failsafeBatteryCriticalFlightModeChanged(int)));
262 connect(ui->failsafeBatteryCriticalFlightModeCb, SIGNAL(toggled(bool)), this, SLOT(failsafeBatteryCriticalFlightModeCbToggled(bool)));
265 addWidget(ui->configurationWizard);
266 addWidget(ui->runCalibration);
267 addWidget(ui->failsafeFlightModeCb);
268 addWidget(ui->failsafeBatteryWarningFlightModeCb);
269 addWidget(ui->failsafeBatteryCriticalFlightModeCb);
271 // Wizard
272 wizardUi = new Ui_InputWizardWidget();
273 wizardUi->setupUi(ui->wizard);
275 connect(wizardUi->wzNext, SIGNAL(clicked()), this, SLOT(wzNext()));
276 connect(wizardUi->wzCancel, SIGNAL(clicked()), this, SLOT(wzCancel()));
277 connect(wizardUi->wzBack, SIGNAL(clicked()), this, SLOT(wzBack()));
279 wizardUi->graphicsView->setScene(new QGraphicsScene(this));
280 wizardUi->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
281 m_renderer = new QSvgRenderer();
282 QGraphicsScene *l_scene = wizardUi->graphicsView->scene();
283 wizardUi->graphicsView->setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor()));
284 if (QFile::exists(":/configgadget/images/TX2.svg") && m_renderer->load(QString(":/configgadget/images/TX2.svg")) && m_renderer->isValid()) {
285 l_scene->clear(); // Deletes all items contained in the scene as well.
287 m_txBackground = new QGraphicsSvgItem();
288 // All other items will be clipped to the shape of the background
289 m_txBackground->setFlags(QGraphicsItem::ItemClipsChildrenToShape |
290 QGraphicsItem::ItemClipsToShape);
291 m_txBackground->setSharedRenderer(m_renderer);
292 m_txBackground->setElementId("background");
293 l_scene->addItem(m_txBackground);
295 m_txMainBody = new QGraphicsSvgItem();
296 m_txMainBody->setParentItem(m_txBackground);
297 m_txMainBody->setSharedRenderer(m_renderer);
298 m_txMainBody->setElementId("body");
299 l_scene->addItem(m_txMainBody);
301 m_txLeftStick = new QGraphicsSvgItem();
302 m_txLeftStick->setParentItem(m_txBackground);
303 m_txLeftStick->setSharedRenderer(m_renderer);
304 m_txLeftStick->setElementId("ljoy");
306 m_txRightStick = new QGraphicsSvgItem();
307 m_txRightStick->setParentItem(m_txBackground);
308 m_txRightStick->setSharedRenderer(m_renderer);
309 m_txRightStick->setElementId("rjoy");
311 m_txAccess0 = new QGraphicsSvgItem();
312 m_txAccess0->setParentItem(m_txBackground);
313 m_txAccess0->setSharedRenderer(m_renderer);
314 m_txAccess0->setElementId("access0");
316 m_txAccess1 = new QGraphicsSvgItem();
317 m_txAccess1->setParentItem(m_txBackground);
318 m_txAccess1->setSharedRenderer(m_renderer);
319 m_txAccess1->setElementId("access1");
321 m_txAccess2 = new QGraphicsSvgItem();
322 m_txAccess2->setParentItem(m_txBackground);
323 m_txAccess2->setSharedRenderer(m_renderer);
324 m_txAccess2->setElementId("access2");
326 m_txAccess3 = new QGraphicsSvgItem();
327 m_txAccess3->setParentItem(m_txBackground);
328 m_txAccess3->setSharedRenderer(m_renderer);
329 m_txAccess3->setElementId("access3");
331 m_txFlightMode = new QGraphicsSvgItem();
332 m_txFlightMode->setParentItem(m_txBackground);
333 m_txFlightMode->setSharedRenderer(m_renderer);
334 m_txFlightMode->setElementId("flightModeCenter");
335 m_txFlightMode->setZValue(-10);
337 m_txFlightModeCountBG = new QGraphicsSvgItem();
338 m_txFlightModeCountBG->setParentItem(m_txBackground);
339 m_txFlightModeCountBG->setSharedRenderer(m_renderer);
340 m_txFlightModeCountBG->setElementId("fm_count_bg");
341 l_scene->addItem(m_txFlightModeCountBG);
343 m_txFlightModeCountText = new QGraphicsSimpleTextItem("?", m_txFlightModeCountBG);
344 m_txFlightModeCountText->setBrush(QColor(40, 40, 40));
345 m_txFlightModeCountText->setFont(QFont("Arial Bold"));
347 m_txArrows = new QGraphicsSvgItem();
348 m_txArrows->setParentItem(m_txBackground);
349 m_txArrows->setSharedRenderer(m_renderer);
350 m_txArrows->setElementId("arrows");
351 m_txArrows->setVisible(false);
353 QRectF orig = m_renderer->boundsOnElement("ljoy");
354 QMatrix Matrix = m_renderer->matrixForElement("ljoy");
355 orig = Matrix.mapRect(orig);
356 m_txLeftStickOrig.translate(orig.x(), orig.y());
357 m_txLeftStick->setTransform(m_txLeftStickOrig, false);
359 orig = m_renderer->boundsOnElement("arrows");
360 Matrix = m_renderer->matrixForElement("arrows");
361 orig = Matrix.mapRect(orig);
362 m_txArrowsOrig.translate(orig.x(), orig.y());
363 m_txArrows->setTransform(m_txArrowsOrig, false);
365 orig = m_renderer->boundsOnElement("body");
366 Matrix = m_renderer->matrixForElement("body");
367 orig = Matrix.mapRect(orig);
368 m_txMainBodyOrig.translate(orig.x(), orig.y());
369 m_txMainBody->setTransform(m_txMainBodyOrig, false);
371 orig = m_renderer->boundsOnElement("flightModeCenter");
372 Matrix = m_renderer->matrixForElement("flightModeCenter");
373 orig = Matrix.mapRect(orig);
374 m_txFlightModeCOrig.translate(orig.x(), orig.y());
375 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
377 orig = m_renderer->boundsOnElement("flightModeLeft");
378 Matrix = m_renderer->matrixForElement("flightModeLeft");
379 orig = Matrix.mapRect(orig);
380 m_txFlightModeLOrig.translate(orig.x(), orig.y());
381 orig = m_renderer->boundsOnElement("flightModeRight");
382 Matrix = m_renderer->matrixForElement("flightModeRight");
383 orig = Matrix.mapRect(orig);
384 m_txFlightModeROrig.translate(orig.x(), orig.y());
386 orig = m_renderer->boundsOnElement("fm_count_bg");
387 Matrix = m_renderer->matrixForElement("fm_count_bg");
388 orig = Matrix.mapRect(orig);
389 m_txFlightModeCountBGOrig.translate(orig.x(), orig.y());
390 m_txFlightModeCountBG->setTransform(m_txFlightModeCountBGOrig, false);
392 QRectF flightModeBGRect = m_txFlightModeCountBG->boundingRect();
393 QRectF flightModeTextRect = m_txFlightModeCountText->boundingRect();
394 qreal scale = 2.5;
395 m_txFlightModeCountTextOrig.translate(flightModeBGRect.width() - (flightModeBGRect.height() / 2), flightModeBGRect.height() / 2);
396 m_txFlightModeCountTextOrig.scale(scale, scale);
397 m_txFlightModeCountTextOrig.translate(-flightModeTextRect.width() / 2, -flightModeTextRect.height() / 2);
398 m_txFlightModeCountText->setTransform(m_txFlightModeCountTextOrig, false);
400 orig = m_renderer->boundsOnElement("rjoy");
401 Matrix = m_renderer->matrixForElement("rjoy");
402 orig = Matrix.mapRect(orig);
403 m_txRightStickOrig.translate(orig.x(), orig.y());
404 m_txRightStick->setTransform(m_txRightStickOrig, false);
406 orig = m_renderer->boundsOnElement("access0");
407 Matrix = m_renderer->matrixForElement("access0");
408 orig = Matrix.mapRect(orig);
409 m_txAccess0Orig.translate(orig.x(), orig.y());
410 m_txAccess0->setTransform(m_txAccess0Orig, false);
412 orig = m_renderer->boundsOnElement("access1");
413 Matrix = m_renderer->matrixForElement("access1");
414 orig = Matrix.mapRect(orig);
415 m_txAccess1Orig.translate(orig.x(), orig.y());
416 m_txAccess1->setTransform(m_txAccess1Orig, false);
418 orig = m_renderer->boundsOnElement("access2");
419 Matrix = m_renderer->matrixForElement("access2");
420 orig = Matrix.mapRect(orig);
421 m_txAccess2Orig.translate(orig.x(), orig.y());
422 m_txAccess2->setTransform(m_txAccess2Orig, true);
424 orig = m_renderer->boundsOnElement("access3");
425 Matrix = m_renderer->matrixForElement("access3");
426 orig = Matrix.mapRect(orig);
427 m_txAccess3Orig.translate(orig.x(), orig.y());
428 m_txAccess3->setTransform(m_txAccess3Orig, true);
430 wizardUi->graphicsView->fitInView(m_txMainBody, Qt::KeepAspectRatio);
431 animate = new QTimer(this);
432 connect(animate, SIGNAL(timeout()), this, SLOT(moveTxControls()));
434 heliChannelOrder << ManualControlSettings::CHANNELGROUPS_COLLECTIVE <<
435 ManualControlSettings::CHANNELGROUPS_THROTTLE <<
436 ManualControlSettings::CHANNELGROUPS_ROLL <<
437 ManualControlSettings::CHANNELGROUPS_PITCH <<
438 ManualControlSettings::CHANNELGROUPS_YAW <<
439 ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
440 ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
441 ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
442 ManualControlSettings::CHANNELGROUPS_ACCESSORY2 <<
443 ManualControlSettings::CHANNELGROUPS_ACCESSORY3;
445 acroChannelOrder << ManualControlSettings::CHANNELGROUPS_THROTTLE <<
446 ManualControlSettings::CHANNELGROUPS_ROLL <<
447 ManualControlSettings::CHANNELGROUPS_PITCH <<
448 ManualControlSettings::CHANNELGROUPS_YAW <<
449 ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
450 ManualControlSettings::CHANNELGROUPS_ACCESSORY0 <<
451 ManualControlSettings::CHANNELGROUPS_ACCESSORY1 <<
452 ManualControlSettings::CHANNELGROUPS_ACCESSORY2 <<
453 ManualControlSettings::CHANNELGROUPS_ACCESSORY3;
455 groundChannelOrder << ManualControlSettings::CHANNELGROUPS_THROTTLE <<
456 ManualControlSettings::CHANNELGROUPS_YAW <<
457 ManualControlSettings::CHANNELGROUPS_FLIGHTMODE <<
458 ManualControlSettings::CHANNELGROUPS_ACCESSORY0;
461 void ConfigInputWidget::buildOptionComboBox(QComboBox *combo, UAVObjectField *field, int index, bool applyLimits)
463 if (combo == ui->failsafeFlightMode || combo == ui->failsafeBatteryCriticalFlightMode || combo == ui->failsafeBatteryWarningFlightMode) {
464 for (quint32 i = 0; i < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM; i++) {
465 combo->addItem(QString("Position %1").arg(i + 1), QVariant(i));
467 } else {
468 ConfigTaskWidget::buildOptionComboBox(combo, field, index, applyLimits);
472 void ConfigInputWidget::resetTxControls()
474 m_txLeftStick->setTransform(m_txLeftStickOrig, false);
475 m_txRightStick->setTransform(m_txRightStickOrig, false);
476 m_txAccess0->setTransform(m_txAccess0Orig, false);
477 m_txAccess1->setTransform(m_txAccess1Orig, false);
478 m_txAccess2->setTransform(m_txAccess2Orig, false);
479 m_txAccess3->setTransform(m_txAccess3Orig, false);
480 m_txFlightMode->setElementId("flightModeCenter");
481 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
482 m_txArrows->setVisible(false);
483 m_txFlightModeCountText->setText("?");
484 m_txFlightModeCountText->setVisible(false);
485 m_txFlightModeCountBG->setVisible(false);
488 ConfigInputWidget::~ConfigInputWidget()
491 void ConfigInputWidget::enableControls(bool enable)
493 ConfigTaskWidget::enableControls(enable);
495 if (enable) {
496 updatePositionSlider();
497 } else {
498 // Hide configAlarmStatus when disconnected
499 ui->configAlarmStatus->setVisible(false);
500 if (wizardStep != wizardNone) {
501 // Close input wizard
502 wzCancel();
504 if (ui->runCalibration->isChecked()) {
505 // Close manual calibration
506 ui->runCalibration->setChecked(false);
507 ui->runCalibration->setText(tr("Start Manual Calibration"));
508 emit inputCalibrationStateChanged(false);
513 void ConfigInputWidget::resizeEvent(QResizeEvent *event)
515 QWidget::resizeEvent(event);
517 wizardUi->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
520 void ConfigInputWidget::goToWizard()
522 if (!outputConfigIsSafe) {
523 QMessageBox::warning(this, tr("Warning"), tr("There is something wrong in <b>Output</b> tab."
524 "<p>Please fix the issue before starting the Transmitter wizard.</p>"), QMessageBox::Ok);
525 return;
528 QMessageBox msgBox;
530 msgBox.setText(tr("Arming Settings are now set to 'Always Disarmed' for your safety."));
531 msgBox.setDetailedText(tr("You will have to reconfigure the arming settings manually "
532 "when the wizard is finished. After the last step of the "
533 "wizard you will be taken to the Arming Settings screen."));
534 msgBox.setStandardButtons(QMessageBox::Ok);
535 msgBox.setDefaultButton(QMessageBox::Ok);
536 msgBox.exec();
538 // Tell Output tab we freeze actuators soon
539 emit inputCalibrationStateChanged(true);
541 // Set correct tab visible before starting wizard.
542 if (ui->tabWidget->currentIndex() != 0) {
543 ui->tabWidget->setCurrentIndex(0);
546 // Stash current manual settings data in case the wizard is
547 // cancelled or the user proceeds far enough into the wizard such
548 // that the UAVO is changed, but then backs out to the start and
549 // chooses a different TX type (which could otherwise result in
550 // unexpected TX channels being enabled)
551 manualSettingsData = manualSettingsObj->getData();
552 memento.manualSettingsData = manualSettingsData;
553 flightModeSettingsData = flightModeSettingsObj->getData();
554 memento.flightModeSettingsData = flightModeSettingsData;
555 flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED;
556 flightModeSettingsObj->setData(flightModeSettingsData);
557 // Stash actuatorSettings
558 actuatorSettingsData = actuatorSettingsObj->getData();
559 memento.actuatorSettingsData = actuatorSettingsData;
561 // Stash systemSettings
562 systemSettingsData = systemSettingsObj->getData();
563 memento.systemSettingsData = systemSettingsData;
565 // Now reset channel and actuator settings (disable outputs)
566 resetChannelSettings();
567 resetActuatorSettings();
569 // Use faster input update rate.
570 fastMdata();
572 // start the wizard
573 wizardSetUpStep(wizardWelcome);
574 wizardUi->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
577 void ConfigInputWidget::disableWizardButton(int value)
579 if (value != 0) {
580 ui->groupBox_3->setVisible(false);
581 } else {
582 ui->groupBox_3->setVisible(true);
586 void ConfigInputWidget::wzCancel()
588 dimOtherControls(false);
590 // Cancel any ongoing delayd next trigger.
591 wzNextDelayedCancel();
593 // Restore original input update rate.
594 restoreMdata();
596 ui->stackedWidget->setCurrentIndex(0);
598 if (wizardStep != wizardNone) {
599 wizardTearDownStep(wizardStep);
601 wizardStep = wizardNone;
602 ui->stackedWidget->setCurrentIndex(0);
604 // Load settings back from beginning of wizard
605 manualSettingsObj->setData(memento.manualSettingsData);
606 flightModeSettingsObj->setData(memento.flightModeSettingsData);
607 actuatorSettingsObj->setData(memento.actuatorSettingsData);
608 systemSettingsObj->setData(memento.systemSettingsData);
610 // Tell Output tab the calibration is ended
611 emit inputCalibrationStateChanged(false);
614 void ConfigInputWidget::registerControlActivity()
616 nextDelayedLatestActivityTick = nextDelayedTick;
619 void ConfigInputWidget::wzNextDelayed()
621 nextDelayedTick++;
623 // Call next after the full 2500 ms timeout has been reached,
624 // or if no input activity has occurred the last 500 ms.
625 if (nextDelayedTick == 25 ||
626 nextDelayedTick - nextDelayedLatestActivityTick >= 5) {
627 wzNext();
631 void ConfigInputWidget::wzNextDelayedStart()
633 // Call wzNextDelayed every 100 ms, to see if it's time to go to the next page.
634 connect(&nextDelayedTimer, SIGNAL(timeout()), this, SLOT(wzNextDelayed()));
635 nextDelayedTimer.start(100);
638 // Cancel the delayed next timer, if it's active.
639 void ConfigInputWidget::wzNextDelayedCancel()
641 nextDelayedTick = 0;
642 nextDelayedLatestActivityTick = 0;
643 if (nextDelayedTimer.isActive()) {
644 nextDelayedTimer.stop();
645 disconnect(&nextDelayedTimer, SIGNAL(timeout()), this, SLOT(wzNextDelayed()));
649 void ConfigInputWidget::wzNext()
651 wzNextDelayedCancel();
653 // In identify sticks mode the next button can indicate
654 // channel advance
655 if (wizardStep != wizardNone &&
656 wizardStep != wizardIdentifySticks) {
657 wizardTearDownStep(wizardStep);
660 // State transitions for next button
661 switch (wizardStep) {
662 case wizardWelcome:
663 wizardSetUpStep(wizardChooseType);
664 break;
665 case wizardChooseType:
666 wizardSetUpStep(wizardChooseMode);
667 break;
668 case wizardChooseMode:
669 wizardSetUpStep(wizardIdentifySticks);
670 break;
671 case wizardIdentifySticks:
672 nextChannel();
673 if (currentChannelNum == -1) { // Gone through all channels
674 wizardTearDownStep(wizardIdentifySticks);
675 wizardSetUpStep(wizardIdentifyCenter);
677 break;
678 case wizardIdentifyCenter:
679 resetFlightModeSettings();
680 wizardSetUpStep(wizardIdentifyLimits);
681 break;
682 case wizardIdentifyLimits:
683 wizardSetUpStep(wizardIdentifyInverted);
684 break;
685 case wizardIdentifyInverted:
686 wizardSetUpStep(wizardFinish);
687 break;
688 case wizardFinish:
689 wizardStep = wizardNone;
691 // Restore original input update rate.
692 restoreMdata();
694 // Load actuator settings back from beginning of wizard
695 actuatorSettingsObj->setData(memento.actuatorSettingsData);
697 // Force flight mode neutral to middle and Throttle neutral at 4%
698 adjustSpecialNeutrals();
699 throttleError = false;
700 checkThrottleRange();
702 manualSettingsObj->setData(manualSettingsData);
704 // move to Arming Settings tab
705 ui->stackedWidget->setCurrentIndex(0);
706 ui->tabWidget->setCurrentIndex(3);
708 // Tell Output tab the calibration is ended
709 emit inputCalibrationStateChanged(false);
710 break;
711 default:
712 Q_ASSERT(0);
716 void ConfigInputWidget::wzBack()
718 wzNextDelayedCancel();
720 if (wizardStep != wizardNone &&
721 wizardStep != wizardIdentifySticks) {
722 wizardTearDownStep(wizardStep);
725 // State transitions for back button
726 switch (wizardStep) {
727 case wizardChooseType:
728 wizardSetUpStep(wizardWelcome);
729 break;
730 case wizardChooseMode:
731 wizardSetUpStep(wizardChooseType);
732 break;
733 case wizardIdentifySticks:
734 prevChannel();
735 if (currentChannelNum == -1) {
736 wizardTearDownStep(wizardIdentifySticks);
737 wizardSetUpStep(wizardChooseMode);
739 break;
740 case wizardIdentifyCenter:
741 wizardSetUpStep(wizardIdentifySticks);
742 break;
743 case wizardIdentifyLimits:
744 wizardSetUpStep(wizardIdentifyCenter);
745 break;
746 case wizardIdentifyInverted:
747 resetFlightModeSettings();
748 wizardSetUpStep(wizardIdentifyLimits);
749 break;
750 case wizardFinish:
751 wizardSetUpStep(wizardIdentifyInverted);
752 break;
753 default:
754 Q_ASSERT(0);
758 void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step)
760 wizardUi->wzNext->setText(tr("Next"));
762 switch (step) {
763 case wizardWelcome:
764 foreach(QPointer<QWidget> wd, extraWidgets) {
765 if (!wd.isNull()) {
766 delete wd;
769 extraWidgets.clear();
770 wizardUi->graphicsView->setVisible(false);
771 setTxMovement(nothing);
772 wizardUi->wzBack->setEnabled(false);
773 wizardUi->pagesStack->setCurrentWidget(wizardUi->welcomePage);
774 ui->stackedWidget->setCurrentIndex(1);
775 break;
776 case wizardChooseType:
778 wizardUi->graphicsView->setVisible(true);
779 wizardUi->graphicsView->fitInView(m_txBackground, Qt::KeepAspectRatio);
780 setTxMovement(nothing);
781 wizardUi->wzBack->setEnabled(true);
782 if (transmitterType == heli) {
783 wizardUi->typeHeli->setChecked(true);
784 } else if (transmitterType == ground) {
785 wizardUi->typeGround->setChecked(true);
786 } else {
787 wizardUi->typeAcro->setChecked(true);
789 wizardUi->pagesStack->setCurrentWidget(wizardUi->chooseTypePage);
791 break;
792 case wizardChooseMode:
794 wizardUi->wzBack->setEnabled(true);
795 QRadioButton *modeButtons[] = {
796 wizardUi->mode1Button,
797 wizardUi->mode2Button,
798 wizardUi->mode3Button,
799 wizardUi->mode4Button
802 for (int i = 0; i <= mode4; ++i) {
803 QString label;
804 txMode mode = static_cast<txMode>(i);
805 if (transmitterType == heli) {
806 switch (mode) {
807 case mode1: label = tr("Mode 1: Fore/Aft Cyclic and Yaw on the left, Throttle/Collective and Left/Right Cyclic on the right"); break;
808 case mode2: label = tr("Mode 2: Throttle/Collective and Yaw on the left, Cyclic on the right"); break;
809 case mode3: label = tr("Mode 3: Cyclic on the left, Throttle/Collective and Yaw on the right"); break;
810 case mode4: label = tr("Mode 4: Throttle/Collective and Left/Right Cyclic on the left, Fore/Aft Cyclic and Yaw on the right"); break;
811 default: Q_ASSERT(0); break;
813 wizardUi->typePageFooter->setText(" ");
814 } else {
815 switch (mode) {
816 case mode1: label = tr("Mode 1: Elevator and Rudder on the left, Throttle and Ailerons on the right"); break;
817 case mode2: label = tr("Mode 2: Throttle and Rudder on the left, Elevator and Ailerons on the right"); break;
818 case mode3: label = tr("Mode 3: Elevator and Ailerons on the left, Throttle and Rudder on the right"); break;
819 case mode4: label = tr("Mode 4: Throttle and Ailerons on the left, Elevator and Rudder on the right"); break;
820 default: Q_ASSERT(0); break;
822 wizardUi->typePageFooter->setText(tr("For a Quad: Elevator is Pitch, Ailerons are Roll, and Rudder is Yaw."));
824 modeButtons[i]->setText(label);
825 if (transmitterMode == mode) {
826 modeButtons[i]->setChecked(true);
829 wizardUi->pagesStack->setCurrentWidget(wizardUi->chooseModePage);
831 break;
832 case wizardIdentifySticks:
833 usedChannels.clear();
834 currentChannelNum = -1;
835 nextChannel();
836 manualSettingsData = manualSettingsObj->getData();
837 connect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(identifyControls()));
838 wizardUi->wzNext->setEnabled(false);
839 wizardUi->pagesStack->setCurrentWidget(wizardUi->identifySticksPage);
840 break;
841 case wizardIdentifyCenter:
842 setTxMovement(centerAll);
843 wizardUi->pagesStack->setCurrentWidget(wizardUi->identifyCenterPage);
844 if (transmitterType == ground) {
845 wizardUi->identifyCenterInstructions->setText(QString(tr("Please center all controls and trims and press Next when ready.\n\n"
846 "For a ground vehicle, this center position will be used as neutral value of each channel.")));
848 break;
849 case wizardIdentifyLimits:
851 setTxMovement(nothing);
852 manualSettingsData = manualSettingsObj->getData();
853 for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) {
854 // Preserve the inverted status
855 if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) {
856 manualSettingsData.ChannelMin[i] = manualSettingsData.ChannelNeutral[i];
857 manualSettingsData.ChannelMax[i] = manualSettingsData.ChannelNeutral[i];
858 } else {
859 // Make this detect as still inverted
860 manualSettingsData.ChannelMin[i] = manualSettingsData.ChannelNeutral[i] + 1;
861 manualSettingsData.ChannelMax[i] = manualSettingsData.ChannelNeutral[i];
864 UAVObjectUpdaterHelper updateHelper;
865 manualSettingsObj->setData(manualSettingsData, false);
866 updateHelper.doObjectAndWait(manualSettingsObj);
868 connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(identifyLimits()));
869 connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
870 connect(flightStatusObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
871 connect(accessoryDesiredObj0, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
873 wizardUi->pagesStack->setCurrentWidget(wizardUi->identifyLimitsPage);
875 break;
876 case wizardIdentifyInverted:
877 dimOtherControls(true);
878 setTxMovement(nothing);
879 extraWidgets.clear();
880 for (int index = 0; index < manualSettingsObj->getField("ChannelMax")->getElementNames().length(); index++) {
881 QString name = manualSettingsObj->getField("ChannelMax")->getElementNames().at(index);
882 if (!name.contains("Access") && !name.contains("Flight") && !name.contains("Rssi") &&
883 (!name.contains("Collective") || transmitterType == heli)) {
884 QCheckBox *cb = new QCheckBox(name, this);
885 // Make sure checked status matches current one
886 cb->setChecked(manualSettingsData.ChannelMax[index] < manualSettingsData.ChannelMin[index]);
887 wizardUi->checkBoxesLayout->addWidget(cb, extraWidgets.size() / 5, extraWidgets.size() % 5);
888 extraWidgets.append(cb);
889 connect(cb, SIGNAL(toggled(bool)), this, SLOT(invertControls()));
892 connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
893 wizardUi->pagesStack->setCurrentWidget(wizardUi->identifyInvertedPage);
894 break;
895 case wizardFinish:
896 dimOtherControls(false);
897 connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
898 connect(flightStatusObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
899 connect(accessoryDesiredObj0, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
900 wizardUi->pagesStack->setCurrentWidget(wizardUi->finishPage);
901 break;
902 default:
903 Q_ASSERT(0);
905 wizardStep = step;
908 void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step)
910 UAVObjectUpdaterHelper updateHelper;
912 Q_ASSERT(step == wizardStep);
913 switch (step) {
914 case wizardWelcome:
915 break;
916 case wizardChooseType:
917 if (wizardUi->typeAcro->isChecked()) {
918 transmitterType = acro;
919 } else if (wizardUi->typeGround->isChecked()) {
920 transmitterType = ground;
922 systemSettingsData = systemSettingsObj->getData();
923 /* Make sure to tell controller, this is really a ground vehicle. */
924 if ((systemSettingsData.AirframeType != SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR) ||
925 (systemSettingsData.AirframeType != SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIAL) ||
926 (systemSettingsData.AirframeType != SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEMOTORCYCLE) ||
927 (systemSettingsData.AirframeType != SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEBOAT) ||
928 (systemSettingsData.AirframeType != SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIALBOAT)) {
929 // Apply default ground vehicle airframe
930 systemSettingsData.AirframeType = SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR;
931 systemSettingsObj->setData(systemSettingsData);
933 } else {
934 transmitterType = heli;
936 break;
937 case wizardChooseMode:
939 QRadioButton *modeButtons[] = {
940 wizardUi->mode1Button,
941 wizardUi->mode2Button,
942 wizardUi->mode3Button,
943 wizardUi->mode4Button
945 for (int i = mode1; i <= mode4; ++i) {
946 if (modeButtons[i]->isChecked()) {
947 transmitterMode = static_cast<txMode>(i);
951 break;
952 case wizardIdentifySticks:
953 disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(identifyControls()));
954 wizardUi->wzNext->setEnabled(true);
955 setTxMovement(nothing);
956 break;
957 case wizardIdentifyCenter:
958 manualCommandData = manualCommandObj->getData();
959 manualSettingsData = manualSettingsObj->getData();
960 // Ignore last Rssi channel
961 for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) {
962 // Set Accessory neutral to middle range
963 if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) {
964 manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2);
965 } else {
966 manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
969 manualSettingsObj->setData(manualSettingsData, false);
970 updateHelper.doObjectAndWait(manualSettingsObj);
971 setTxMovement(nothing);
972 break;
973 case wizardIdentifyLimits:
974 disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(identifyLimits()));
975 disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
976 disconnect(flightStatusObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
977 disconnect(accessoryDesiredObj0, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
978 manualSettingsObj->setData(manualSettingsData, false);
979 updateHelper.doObjectAndWait(manualSettingsObj);
980 setTxMovement(nothing);
981 break;
982 case wizardIdentifyInverted:
983 dimOtherControls(false);
984 foreach(QWidget * wd, extraWidgets) {
985 QCheckBox *cb = qobject_cast<QCheckBox *>(wd);
987 if (cb) {
988 disconnect(cb, SIGNAL(toggled(bool)), this, SLOT(invertControls()));
989 delete cb;
992 extraWidgets.clear();
993 disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
994 break;
995 case wizardFinish:
996 dimOtherControls(false);
997 setTxMovement(nothing);
998 disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
999 disconnect(flightStatusObj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
1000 disconnect(accessoryDesiredObj0, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(moveSticks()));
1001 break;
1002 default:
1003 Q_ASSERT(0);
1007 static void fastMdataSingle(UAVDataObject *object, UAVObject::Metadata *savedMdata)
1009 *savedMdata = object->getMetadata();
1010 UAVObject::Metadata mdata = *savedMdata;
1011 UAVObject::SetFlightTelemetryUpdateMode(mdata, UAVObject::UPDATEMODE_PERIODIC);
1012 mdata.flightTelemetryUpdatePeriod = 150;
1013 object->setMetadata(mdata);
1016 static void restoreMdataSingle(UAVDataObject *object, UAVObject::Metadata *savedMdata)
1018 object->setMetadata(*savedMdata);
1022 * Set manual control command to fast updates
1024 void ConfigInputWidget::fastMdata()
1026 fastMdataSingle(manualCommandObj, &manualControlMdata);
1027 fastMdataSingle(accessoryDesiredObj0, &accessoryDesiredMdata0);
1031 * Restore previous update settings for manual control data
1033 void ConfigInputWidget::restoreMdata()
1035 restoreMdataSingle(manualCommandObj, &manualControlMdata);
1036 restoreMdataSingle(accessoryDesiredObj0, &accessoryDesiredMdata0);
1040 * Set the display to indicate which channel the person should move
1042 void ConfigInputWidget::setChannel(int newChan)
1044 bool canBeSkipped = false;
1046 if (newChan == ManualControlSettings::CHANNELGROUPS_COLLECTIVE) {
1047 wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please enable throttle hold mode.</p>"
1048 "<p>Move the Collective Pitch stick.</p>")));
1049 } else if (newChan == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE) {
1050 wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please toggle the Flight Mode switch.</p>"
1051 "<p>For switches you may have to repeat this rapidly.</p>"
1052 "<p>Alternatively, you can click Next to skip this channel, but you will get only <b>ONE</b> Flight Mode.</p>")));
1053 canBeSkipped = true;
1054 } else if ((transmitterType == heli) && (newChan == ManualControlSettings::CHANNELGROUPS_THROTTLE)) {
1055 wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please disable throttle hold mode.</p>"
1056 "<p>Move the Throttle stick.</p>")));
1057 } else {
1058 wizardUi->identifyStickInstructions->setText(QString(tr("<p>Please move each control one at a time according to the instructions and picture below.</p>"
1059 "<p>Move the %1 stick.</p>")).arg(manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan)));
1062 if (manualSettingsObj->getField("ChannelGroups")->getElementNames().at(newChan).contains("Accessory")) {
1063 wizardUi->identifyStickInstructions->setText(wizardUi->identifyStickInstructions->text() + tr("<p>Alternatively, click Next to skip this channel.</p>"));
1064 canBeSkipped = true;
1067 if (canBeSkipped) {
1068 wizardUi->wzNext->setEnabled(true);
1069 wizardUi->wzNext->setText(tr("Next / Skip"));
1070 } else {
1071 wizardUi->wzNext->setEnabled(false);
1074 setMoveFromCommand(newChan);
1075 currentChannelNum = newChan;
1076 channelDetected = false;
1080 * Unfortunately order of channel should be different in different conditions. Selects
1081 * next channel based on heli or acro mode
1083 void ConfigInputWidget::nextChannel()
1085 QList <int> order;
1086 switch (transmitterType) {
1087 case heli:
1088 order = heliChannelOrder;
1089 break;
1090 case ground:
1091 order = groundChannelOrder;
1092 break;
1093 default:
1094 order = acroChannelOrder;
1095 break;
1098 if (currentChannelNum == -1) {
1099 setChannel(order[0]);
1100 return;
1102 for (int i = 0; i < order.length() - 1; i++) {
1103 if (order[i] == currentChannelNum) {
1104 setChannel(order[i + 1]);
1105 return;
1108 currentChannelNum = -1; // hit end of list
1112 * Unfortunately order of channel should be different in different conditions. Selects
1113 * previous channel based on heli or acro mode
1115 void ConfigInputWidget::prevChannel()
1117 QList <int> order;
1118 switch (transmitterType) {
1119 case heli:
1120 order = heliChannelOrder;
1121 break;
1122 case ground:
1123 order = groundChannelOrder;
1124 break;
1125 default:
1126 order = acroChannelOrder;
1127 break;
1130 // No previous from unset channel or next state
1131 if (currentChannelNum == -1) {
1132 return;
1135 for (int i = 1; i < order.length(); i++) {
1136 if (order[i] == currentChannelNum) {
1137 if (!usedChannels.isEmpty() &&
1138 usedChannels.back().channelIndex == order[i - 1]) {
1139 usedChannels.removeLast();
1141 setChannel(order[i - 1]);
1142 return;
1145 currentChannelNum = -1; // hit end of list
1148 void ConfigInputWidget::identifyControls()
1150 static const int DEBOUNCE_COUNT = 4;
1151 static int debounce = 0;
1153 receiverActivityData = receiverActivityObj->getData();
1155 if (receiverActivityData.ActiveChannel == 255) {
1156 return;
1159 if (channelDetected) {
1160 registerControlActivity();
1161 return;
1164 receiverActivityData = receiverActivityObj->getData();
1165 currentChannel.group = receiverActivityData.ActiveGroup;
1166 currentChannel.number = receiverActivityData.ActiveChannel;
1168 if (debounce == 0) {
1169 // Register a channel to be debounced.
1170 lastChannel.group = currentChannel.group;
1171 lastChannel.number = currentChannel.number;
1172 lastChannel.channelIndex = currentChannelNum;
1173 ++debounce;
1174 return;
1177 if (currentChannel != lastChannel) {
1178 // A new channel was seen. Only register it if we count down to 0.
1179 --debounce;
1180 return;
1183 if (debounce < DEBOUNCE_COUNT) {
1184 // We still haven't seen enough enough activity on this channel yet.
1185 ++debounce;
1186 return;
1189 // Channel has been debounced and it's enough record it.
1191 if (usedChannels.contains(lastChannel)) {
1192 // Channel is already recorded.
1193 return;
1196 // Record the channel.
1198 channelDetected = true;
1199 debounce = 0;
1200 usedChannels.append(lastChannel);
1201 manualSettingsData = manualSettingsObj->getData();
1202 manualSettingsData.ChannelGroups[currentChannelNum] = currentChannel.group;
1203 manualSettingsData.ChannelNumber[currentChannelNum] = currentChannel.number;
1204 manualSettingsObj->setData(manualSettingsData);
1206 // m_config->wzText->clear();
1207 setTxMovement(nothing);
1209 wzNextDelayedStart();
1212 void ConfigInputWidget::identifyLimits()
1214 uint16_t inputValue;
1215 static uint16_t previousInputFMValue;
1216 bool newLimitValue = false;
1217 bool newFlightModeValue = false;
1219 manualCommandData = manualCommandObj->getData();
1220 for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) {
1221 inputValue = manualCommandData.Channel[i];
1222 // Check if channel is already detected and prevent glitches
1223 if ((manualSettingsData.ChannelNumber[i] != CHANNEL_NUMBER_NONE) &&
1224 (inputValue > MIN_INPUT_US) && (inputValue < MAX_INPUT_US)) {
1225 if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) {
1226 // Non inverted channel
1227 if (manualSettingsData.ChannelMin[i] > inputValue) {
1228 manualSettingsData.ChannelMin[i] = inputValue;
1229 newLimitValue = true;
1231 if (manualSettingsData.ChannelMax[i] < inputValue) {
1232 manualSettingsData.ChannelMax[i] = inputValue;
1233 newLimitValue = true;
1235 } else {
1236 // Inverted channel
1237 if (manualSettingsData.ChannelMax[i] > inputValue) {
1238 manualSettingsData.ChannelMax[i] = inputValue;
1239 newLimitValue = true;
1241 if (manualSettingsData.ChannelMin[i] < inputValue) {
1242 manualSettingsData.ChannelMin[i] = inputValue;
1243 newLimitValue = true;
1246 // Flightmode channel
1247 if (i == ManualControlSettings::CHANNELGROUPS_FLIGHTMODE) {
1248 int deltaInput = abs(previousInputFMValue - inputValue);
1249 previousInputFMValue = inputValue;
1250 // Expecting two consecutive readings within a close value
1251 if (deltaInput < 5) {
1252 // Avoid duplicate values too close and error due to RcTx drift
1253 int minSpacing = 100; // 100µs
1254 for (int pos = 0; pos < manualSettingsData.FlightModeNumber + 1; ++pos) {
1255 if (flightModeSignalValue[pos] == 0) {
1256 newFlightModeValue = true;
1257 // A new flightmode value can be set now
1258 for (int checkpos = 0; checkpos < manualSettingsData.FlightModeNumber + 1; ++checkpos) {
1259 // Check if value is already used, MinSpacing needed between values.
1260 if ((flightModeSignalValue[checkpos] < inputValue + minSpacing) &&
1261 (flightModeSignalValue[checkpos] > inputValue - minSpacing)) {
1262 newFlightModeValue = false;
1265 // Be sure FlightModeNumber is < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM (6)
1266 if ((manualSettingsData.FlightModeNumber < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM) && newFlightModeValue) {
1267 // Start from 0, erase previous count
1268 if (pos == 0) {
1269 manualSettingsData.FlightModeNumber = 0;
1271 // Store new value and increase FlightModeNumber
1272 flightModeSignalValue[pos] = inputValue;
1273 manualSettingsData.FlightModeNumber++;
1274 // Show flight mode number
1275 m_txFlightModeCountText->setText(QString().number(manualSettingsData.FlightModeNumber));
1276 m_txFlightModeCountText->setVisible(true);
1277 m_txFlightModeCountBG->setVisible(true);
1285 // Save only if something changed
1286 if (newLimitValue || newFlightModeValue) {
1287 UAVObjectUpdaterHelper updateHelper;
1288 manualSettingsObj->setData(manualSettingsData, false);
1289 updateHelper.doObjectAndWait(manualSettingsObj);
1293 void ConfigInputWidget::setMoveFromCommand(int command)
1295 // ManualControlSettings::ChannelNumberElem:
1296 // CHANNELNUMBER_ROLL=0,
1297 // CHANNELNUMBER_PITCH=1,
1298 // CHANNELNUMBER_YAW=2,
1299 // CHANNELNUMBER_THROTTLE=3,
1300 // CHANNELNUMBER_FLIGHTMODE=4,
1301 // CHANNELNUMBER_ACCESSORY0=5,
1302 // CHANNELNUMBER_ACCESSORY1=6,
1303 // CHANNELNUMBER_ACCESSORY2=7
1305 txMovements movement = moveLeftVerticalStick;
1307 switch (command) {
1308 case ManualControlSettings::CHANNELNUMBER_ROLL:
1309 movement = ((transmitterMode == mode3 || transmitterMode == mode4) ?
1310 moveLeftHorizontalStick : moveRightHorizontalStick);
1311 break;
1312 case ManualControlSettings::CHANNELNUMBER_PITCH:
1313 movement = (transmitterMode == mode1 || transmitterMode == mode3) ?
1314 moveLeftVerticalStick : moveRightVerticalStick;
1315 break;
1316 case ManualControlSettings::CHANNELNUMBER_YAW:
1317 movement = ((transmitterMode == mode1 || transmitterMode == mode2) ?
1318 moveLeftHorizontalStick : moveRightHorizontalStick);
1319 break;
1320 case ManualControlSettings::CHANNELNUMBER_THROTTLE:
1321 movement = (transmitterMode == mode2 || transmitterMode == mode4) ?
1322 moveLeftVerticalStick : moveRightVerticalStick;
1323 break;
1324 case ManualControlSettings::CHANNELNUMBER_COLLECTIVE:
1325 movement = (transmitterMode == mode2 || transmitterMode == mode4) ?
1326 moveLeftVerticalStick : moveRightVerticalStick;
1327 break;
1328 case ManualControlSettings::CHANNELNUMBER_FLIGHTMODE:
1329 movement = moveFlightMode;
1330 break;
1331 case ManualControlSettings::CHANNELNUMBER_ACCESSORY0:
1332 movement = moveAccess0;
1333 break;
1334 case ManualControlSettings::CHANNELNUMBER_ACCESSORY1:
1335 movement = moveAccess1;
1336 break;
1337 case ManualControlSettings::CHANNELNUMBER_ACCESSORY2:
1338 movement = moveAccess2;
1339 break;
1340 case ManualControlSettings::CHANNELNUMBER_ACCESSORY3:
1341 movement = moveAccess3;
1342 break;
1343 default:
1344 Q_ASSERT(0);
1345 break;
1347 setTxMovement(movement);
1350 void ConfigInputWidget::setTxMovement(txMovements movement)
1352 resetTxControls();
1353 switch (movement) {
1354 case moveLeftVerticalStick:
1355 movePos = 0;
1356 growing = true;
1357 currentMovement = moveLeftVerticalStick;
1358 animate->start(100);
1359 break;
1360 case moveRightVerticalStick:
1361 movePos = 0;
1362 growing = true;
1363 currentMovement = moveRightVerticalStick;
1364 animate->start(100);
1365 break;
1366 case moveLeftHorizontalStick:
1367 movePos = 0;
1368 growing = true;
1369 currentMovement = moveLeftHorizontalStick;
1370 animate->start(100);
1371 break;
1372 case moveRightHorizontalStick:
1373 movePos = 0;
1374 growing = true;
1375 currentMovement = moveRightHorizontalStick;
1376 animate->start(100);
1377 break;
1378 case moveAccess0:
1379 movePos = 0;
1380 growing = true;
1381 currentMovement = moveAccess0;
1382 animate->start(100);
1383 break;
1384 case moveAccess1:
1385 movePos = 0;
1386 growing = true;
1387 currentMovement = moveAccess1;
1388 animate->start(100);
1389 break;
1390 case moveAccess2:
1391 movePos = 0;
1392 growing = true;
1393 currentMovement = moveAccess2;
1394 animate->start(100);
1395 break;
1396 case moveAccess3:
1397 movePos = 0;
1398 growing = true;
1399 currentMovement = moveAccess3;
1400 animate->start(100);
1401 break;
1402 case moveFlightMode:
1403 movePos = 0;
1404 growing = true;
1405 currentMovement = moveFlightMode;
1406 animate->start(1000);
1407 break;
1408 case centerAll:
1409 movePos = 0;
1410 currentMovement = centerAll;
1411 animate->start(1000);
1412 break;
1413 case moveAll:
1414 movePos = 0;
1415 growing = true;
1416 currentMovement = moveAll;
1417 animate->start(50);
1418 break;
1419 case nothing:
1420 movePos = 0;
1421 animate->stop();
1422 break;
1423 default:
1424 Q_ASSERT(0);
1425 break;
1429 void ConfigInputWidget::moveTxControls()
1431 QTransform trans;
1432 QGraphicsItem *item = NULL;
1433 txMovementType move = vertical;
1434 int limitMax = 0;
1435 int limitMin = 0;
1436 static bool auxFlag = false;
1438 switch (currentMovement) {
1439 case moveLeftVerticalStick:
1440 item = m_txLeftStick;
1441 trans = m_txLeftStickOrig;
1442 limitMax = STICK_MAX_MOVE;
1443 limitMin = STICK_MIN_MOVE;
1444 move = vertical;
1445 break;
1446 case moveRightVerticalStick:
1447 item = m_txRightStick;
1448 trans = m_txRightStickOrig;
1449 limitMax = STICK_MAX_MOVE;
1450 limitMin = STICK_MIN_MOVE;
1451 move = vertical;
1452 break;
1453 case moveLeftHorizontalStick:
1454 item = m_txLeftStick;
1455 trans = m_txLeftStickOrig;
1456 limitMax = STICK_MAX_MOVE;
1457 limitMin = STICK_MIN_MOVE;
1458 move = horizontal;
1459 break;
1460 case moveRightHorizontalStick:
1461 item = m_txRightStick;
1462 trans = m_txRightStickOrig;
1463 limitMax = STICK_MAX_MOVE;
1464 limitMin = STICK_MIN_MOVE;
1465 move = horizontal;
1466 break;
1467 case moveAccess0:
1468 item = m_txAccess0;
1469 trans = m_txAccess0Orig;
1470 limitMax = ACCESS_MAX_MOVE;
1471 limitMin = ACCESS_MIN_MOVE;
1472 move = horizontal;
1473 break;
1474 case moveAccess1:
1475 item = m_txAccess1;
1476 trans = m_txAccess1Orig;
1477 limitMax = ACCESS_MAX_MOVE;
1478 limitMin = ACCESS_MIN_MOVE;
1479 move = horizontal;
1480 break;
1481 case moveAccess2:
1482 item = m_txAccess2;
1483 trans = m_txAccess2Orig;
1484 limitMax = ACCESS_MAX_MOVE;
1485 limitMin = ACCESS_MIN_MOVE;
1486 move = horizontal;
1487 break;
1488 case moveAccess3:
1489 item = m_txAccess3;
1490 trans = m_txAccess3Orig;
1491 limitMax = ACCESS_MAX_MOVE;
1492 limitMin = ACCESS_MIN_MOVE;
1493 move = horizontal;
1494 break;
1495 case moveFlightMode:
1496 item = m_txFlightMode;
1497 move = jump;
1498 break;
1499 case centerAll:
1500 item = m_txArrows;
1501 move = jump;
1502 break;
1503 case moveAll:
1504 limitMax = STICK_MAX_MOVE;
1505 limitMin = STICK_MIN_MOVE;
1506 move = mix;
1507 break;
1508 default:
1509 break;
1511 if (move == vertical) {
1512 item->setTransform(trans.translate(0, movePos * 10), false);
1513 } else if (move == horizontal) {
1514 item->setTransform(trans.translate(movePos * 10, 0), false);
1515 } else if (move == jump) {
1516 if (item == m_txArrows) {
1517 m_txArrows->setVisible(!m_txArrows->isVisible());
1518 } else if (item == m_txFlightMode) {
1519 QGraphicsSvgItem *svg;
1520 svg = (QGraphicsSvgItem *)item;
1521 if (svg) {
1522 if (svg->elementId() == "flightModeCenter") {
1523 if (growing) {
1524 svg->setElementId("flightModeRight");
1525 m_txFlightMode->setTransform(m_txFlightModeROrig, false);
1526 } else {
1527 svg->setElementId("flightModeLeft");
1528 m_txFlightMode->setTransform(m_txFlightModeLOrig, false);
1530 } else if (svg->elementId() == "flightModeRight") {
1531 growing = false;
1532 svg->setElementId("flightModeCenter");
1533 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
1534 } else if (svg->elementId() == "flightModeLeft") {
1535 growing = true;
1536 svg->setElementId("flightModeCenter");
1537 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
1541 } else if (move == mix) {
1542 trans = m_txAccess0Orig;
1543 m_txAccess0->setTransform(trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0), false);
1544 trans = m_txAccess1Orig;
1545 m_txAccess1->setTransform(trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0), false);
1546 trans = m_txAccess2Orig;
1547 m_txAccess2->setTransform(trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0), false);
1548 trans = m_txAccess3Orig;
1549 m_txAccess3->setTransform(trans.translate(movePos * 10 * ACCESS_MAX_MOVE / STICK_MAX_MOVE, 0), false);
1551 if (auxFlag) {
1552 trans = m_txLeftStickOrig;
1553 m_txLeftStick->setTransform(trans.translate(0, movePos * 10), false);
1554 trans = m_txRightStickOrig;
1555 m_txRightStick->setTransform(trans.translate(0, movePos * 10), false);
1556 } else {
1557 trans = m_txLeftStickOrig;
1558 m_txLeftStick->setTransform(trans.translate(movePos * 10, 0), false);
1559 trans = m_txRightStickOrig;
1560 m_txRightStick->setTransform(trans.translate(movePos * 10, 0), false);
1563 if (movePos == 0) {
1564 m_txFlightMode->setElementId("flightModeCenter");
1565 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
1566 } else if (movePos == ACCESS_MAX_MOVE / 2) {
1567 m_txFlightMode->setElementId("flightModeRight");
1568 m_txFlightMode->setTransform(m_txFlightModeROrig, false);
1569 } else if (movePos == ACCESS_MIN_MOVE / 2) {
1570 m_txFlightMode->setElementId("flightModeLeft");
1571 m_txFlightMode->setTransform(m_txFlightModeLOrig, false);
1574 if (move == horizontal || move == vertical || move == mix) {
1575 if (movePos == 0 && growing) {
1576 auxFlag = !auxFlag;
1578 if (growing) {
1579 ++movePos;
1580 } else {
1581 --movePos;
1583 if (movePos > limitMax) {
1584 movePos = movePos - 2;
1585 growing = false;
1587 if (movePos < limitMin) {
1588 movePos = movePos + 2;
1589 growing = true;
1594 AccessoryDesired *ConfigInputWidget::getAccessoryDesiredInstance(int instance)
1596 switch (instance) {
1597 case 0:
1598 if (accessoryDesiredObj0 == NULL) {
1599 accessoryDesiredObj0 = AccessoryDesired::GetInstance(getObjectManager(), 0);
1601 return accessoryDesiredObj0;
1603 case 1:
1604 if (accessoryDesiredObj1 == NULL) {
1605 accessoryDesiredObj1 = AccessoryDesired::GetInstance(getObjectManager(), 1);
1607 return accessoryDesiredObj1;
1609 case 2:
1610 if (accessoryDesiredObj2 == NULL) {
1611 accessoryDesiredObj2 = AccessoryDesired::GetInstance(getObjectManager(), 2);
1613 return accessoryDesiredObj2;
1615 case 3:
1616 if (accessoryDesiredObj3 == NULL) {
1617 accessoryDesiredObj3 = AccessoryDesired::GetInstance(getObjectManager(), 3);
1619 return accessoryDesiredObj3;
1621 default:
1622 Q_ASSERT(false);
1625 return NULL;
1628 float ConfigInputWidget::getAccessoryDesiredValue(int instance)
1630 AccessoryDesired *accessoryDesiredObj = getAccessoryDesiredInstance(instance);
1632 if (accessoryDesiredObj == NULL) {
1633 Q_ASSERT(false);
1634 return 0.0f;
1637 AccessoryDesired::DataFields data = accessoryDesiredObj->getData();
1639 return data.AccessoryVal;
1642 void ConfigInputWidget::moveSticks()
1644 QTransform trans;
1646 manualCommandData = manualCommandObj->getData();
1647 flightStatusData = flightStatusObj->getData();
1649 switch (transmitterMode) {
1650 case mode1:
1651 trans = m_txLeftStickOrig;
1652 m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10, manualCommandData.Pitch * STICK_MAX_MOVE * 10), false);
1653 trans = m_txRightStickOrig;
1654 m_txRightStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10, -manualCommandData.Throttle * STICK_MAX_MOVE * 10), false);
1655 break;
1656 case mode2:
1657 trans = m_txLeftStickOrig;
1658 m_txLeftStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10, -manualCommandData.Throttle * STICK_MAX_MOVE * 10), false);
1659 trans = m_txRightStickOrig;
1660 m_txRightStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10, manualCommandData.Pitch * STICK_MAX_MOVE * 10), false);
1661 break;
1662 case mode3:
1663 trans = m_txLeftStickOrig;
1664 m_txLeftStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10, manualCommandData.Pitch * STICK_MAX_MOVE * 10), false);
1665 trans = m_txRightStickOrig;
1666 m_txRightStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10, -manualCommandData.Throttle * STICK_MAX_MOVE * 10), false);
1667 break;
1668 case mode4:
1669 trans = m_txLeftStickOrig;
1670 m_txLeftStick->setTransform(trans.translate(manualCommandData.Roll * STICK_MAX_MOVE * 10, -manualCommandData.Throttle * STICK_MAX_MOVE * 10), false);
1671 trans = m_txRightStickOrig;
1672 m_txRightStick->setTransform(trans.translate(manualCommandData.Yaw * STICK_MAX_MOVE * 10, manualCommandData.Pitch * STICK_MAX_MOVE * 10), false);
1673 break;
1674 default:
1675 Q_ASSERT(0);
1676 break;
1678 if ((flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[0]) ||
1679 (flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[5])) {
1680 m_txFlightMode->setElementId("flightModeLeft");
1681 m_txFlightMode->setTransform(m_txFlightModeLOrig, false);
1682 } else if ((flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[1]) ||
1683 (flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[4])) {
1684 m_txFlightMode->setElementId("flightModeCenter");
1685 m_txFlightMode->setTransform(m_txFlightModeCOrig, false);
1686 } else if ((flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[2]) ||
1687 (flightStatusData.FlightMode == flightModeSettingsData.FlightModePosition[3])) {
1688 m_txFlightMode->setElementId("flightModeRight");
1689 m_txFlightMode->setTransform(m_txFlightModeROrig, false);
1692 m_txAccess0->setTransform(QTransform(m_txAccess0Orig).translate(getAccessoryDesiredValue(0) * ACCESS_MAX_MOVE * 10, 0), false);
1693 m_txAccess1->setTransform(QTransform(m_txAccess1Orig).translate(getAccessoryDesiredValue(1) * ACCESS_MAX_MOVE * 10, 0), false);
1694 m_txAccess2->setTransform(QTransform(m_txAccess2Orig).translate(getAccessoryDesiredValue(2) * ACCESS_MAX_MOVE * 10, 0), false);
1695 m_txAccess3->setTransform(QTransform(m_txAccess3Orig).translate(getAccessoryDesiredValue(3) * ACCESS_MAX_MOVE * 10, 0), false);
1698 void ConfigInputWidget::dimOtherControls(bool value)
1700 qreal opac;
1702 if (value) {
1703 opac = 0.1;
1704 } else {
1705 opac = 1;
1707 m_txAccess0->setOpacity(opac);
1708 m_txAccess1->setOpacity(opac);
1709 m_txAccess2->setOpacity(opac);
1710 m_txAccess3->setOpacity(opac);
1711 m_txFlightMode->setOpacity(opac);
1714 void ConfigInputWidget::invertControls()
1716 manualSettingsData = manualSettingsObj->getData();
1717 foreach(QWidget * wd, extraWidgets) {
1718 QCheckBox *cb = qobject_cast<QCheckBox *>(wd);
1720 if (cb) {
1721 int index = manualSettingsObj->getField("ChannelNumber")->getElementNames().indexOf(cb->text());
1722 if ((cb->isChecked() && (manualSettingsData.ChannelMax[index] > manualSettingsData.ChannelMin[index])) ||
1723 (!cb->isChecked() && (manualSettingsData.ChannelMax[index] < manualSettingsData.ChannelMin[index]))) {
1724 qint16 aux;
1725 aux = manualSettingsData.ChannelMax[index];
1726 manualSettingsData.ChannelMax[index] = manualSettingsData.ChannelMin[index];
1727 manualSettingsData.ChannelMin[index] = aux;
1731 UAVObjectUpdaterHelper updateHelper;
1732 manualSettingsObj->setData(manualSettingsData, false);
1733 updateHelper.doObjectAndWait(manualSettingsObj);
1736 void ConfigInputWidget::moveFMSlider()
1738 ManualControlSettings::DataFields manualSettingsDataPriv = manualSettingsObj->getData();
1739 ManualControlCommand::DataFields manualCommandDataPriv = manualCommandObj->getData();
1741 float valueScaled;
1742 int chMin = manualSettingsDataPriv.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE];
1743 int chMax = manualSettingsDataPriv.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE];
1744 int chNeutral = manualSettingsDataPriv.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE];
1746 int value = manualCommandDataPriv.Channel[ManualControlSettings::CHANNELMIN_FLIGHTMODE];
1748 if ((chMax > chMin && value >= chNeutral) || (chMin > chMax && value <= chNeutral)) {
1749 if (chMax != chNeutral) {
1750 valueScaled = (float)(value - chNeutral) / (float)(chMax - chNeutral);
1751 } else {
1752 valueScaled = 0;
1754 } else {
1755 if (chMin != chNeutral) {
1756 valueScaled = (float)(value - chNeutral) / (float)(chNeutral - chMin);
1757 } else {
1758 valueScaled = 0;
1762 // Bound and scale FlightMode from [-1..+1] to [0..1] range
1763 if (valueScaled < -1.0) {
1764 valueScaled = -1.0;
1765 } else if (valueScaled > 1.0) {
1766 valueScaled = 1.0;
1769 // Convert flightMode value into the switch position in the range [0..N-1]
1770 // This uses the same optimized computation as flight code to be consistent
1771 uint8_t pos = ((int16_t)(valueScaled * 256) + 256) * manualSettingsDataPriv.FlightModeNumber >> 9;
1772 if (pos >= manualSettingsDataPriv.FlightModeNumber) {
1773 pos = manualSettingsDataPriv.FlightModeNumber - 1;
1775 ui->fmsSlider->setValue(pos);
1776 highlightStabilizationMode(pos);
1779 void ConfigInputWidget::highlightStabilizationMode(int pos)
1781 QComboBox *comboboxFm = this->findChild<QComboBox *>("fmsModePos" + QString::number(pos + 1));
1782 QString customStyleSheet = "QComboBox:editable:!on{background: #feb103;}";
1784 if (comboboxFm) {
1785 QString flightModeText = comboboxFm->currentText();
1786 comboboxFm->setStyleSheet("");
1787 for (uint8_t i = 0; i < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM; i++) {
1788 QLabel *label = this->findChild<QLabel *>("stab" + QString::number(i + 1) + "_label");
1789 QComboBox *comboRoll = this->findChild<QComboBox *>("fmsSsPos" + QString::number(i + 1) + "Roll");
1790 QComboBox *comboPitch = this->findChild<QComboBox *>("fmsSsPos" + QString::number(i + 1) + "Pitch");
1791 QComboBox *comboYaw = this->findChild<QComboBox *>("fmsSsPos" + QString::number(i + 1) + "Yaw");
1792 QComboBox *comboThrust = this->findChild<QComboBox *>("fmsSsPos" + QString::number(i + 1) + "Thrust");
1793 QComboBox *comboboxFm2 = this->findChild<QComboBox *>("fmsModePos" + QString::number(i + 1));
1794 comboboxFm2->setStyleSheet("");
1796 // Highlight current stabilization mode if any.
1797 if ((flightModeText.contains("Stabilized", Qt::CaseInsensitive)) && (flightModeText.contains(QString::number(i + 1), Qt::CaseInsensitive))) {
1798 label->setStyleSheet("border-radius: 4px; border:3px solid #feb103;");
1799 comboRoll->setStyleSheet(customStyleSheet);
1800 comboPitch->setStyleSheet(customStyleSheet);
1801 comboYaw->setStyleSheet(customStyleSheet);
1802 comboThrust->setStyleSheet(customStyleSheet);
1803 } else {
1804 label->setStyleSheet("");
1805 comboRoll->setStyleSheet("");
1806 comboPitch->setStyleSheet("");
1807 comboYaw->setStyleSheet("");
1808 comboThrust->setStyleSheet("");
1809 if (!flightModeText.contains("Stabilized", Qt::CaseInsensitive)) {
1810 // Highlight PosHold, Return to Base, ... flightmodes
1811 comboboxFm->setStyleSheet(customStyleSheet);
1818 void setComboBoxItemEnabled(QComboBox *combo, int index, bool enabled = true)
1820 combo->setItemData(index, enabled ? QVariant(1 | 32) : QVariant(0), Qt::UserRole - 1);
1823 void ConfigInputWidget::updatePositionSlider()
1825 ManualControlSettings::DataFields manualSettingsDataPriv = manualSettingsObj->getData();
1827 QWidget *fmsModes[] = {
1828 ui->fmsModePos1,
1829 ui->fmsModePos2,
1830 ui->fmsModePos3,
1831 ui->fmsModePos4,
1832 ui->fmsModePos5,
1833 ui->fmsModePos6
1835 QWidget *pidBanks[] = {
1836 ui->pidBankSs1_0,
1837 ui->pidBankSs1_1,
1838 ui->pidBankSs1_2,
1839 ui->pidBankSs1_3,
1840 ui->pidBankSs1_4,
1841 ui->pidBankSs1_5
1843 QWidget *assistControls[] = {
1844 ui->assistControlPos1,
1845 ui->assistControlPos2,
1846 ui->assistControlPos3,
1847 ui->assistControlPos4,
1848 ui->assistControlPos5,
1849 ui->assistControlPos6
1852 for (quint32 i = 0; i < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM; i++) {
1853 bool enabled = i < manualSettingsDataPriv.FlightModeNumber;
1855 fmsModes[i]->setEnabled(enabled);
1856 pidBanks[i]->setEnabled(enabled);
1857 assistControls[i]->setEnabled(enabled);
1858 setComboBoxItemEnabled(ui->failsafeFlightMode, i, enabled);
1859 setComboBoxItemEnabled(ui->failsafeBatteryCriticalFlightMode, i, enabled);
1860 setComboBoxItemEnabled(ui->failsafeBatteryWarningFlightMode, i, enabled);
1863 QString fmNumber = QString().setNum(manualSettingsDataPriv.FlightModeNumber);
1864 int count = 0;
1865 foreach(QSlider * sp, findChildren<QSlider *>()) {
1866 // Find FlightMode slider and apply stylesheet
1867 if (sp->objectName() == "channelNeutral") {
1868 if (count == 4) {
1869 sp->setStyleSheet(
1870 "QSlider::groove:horizontal {border: 2px solid rgb(196, 196, 196); margin: 0px 23px 0px 23px; height: 12px; border-radius: 5px; "
1871 "border-image:url(:/configgadget/images/flightmode_bg" + fmNumber + ".png); }"
1872 "QSlider::add-page:horizontal { background: none; border: none; }"
1873 "QSlider::sub-page:horizontal { background: none; border: none; }"
1874 "QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, "
1875 "stop: 0 rgba(196, 196, 196, 180), stop: 0.45 rgba(196, 196, 196, 180), "
1876 "stop: 0.46 rgba(255,0,0,100), stop: 0.54 rgba(255,0,0,100), "
1877 "stop: 0.55 rgba(196, 196, 196, 180), stop: 1 rgba(196, 196, 196, 180)); "
1878 "width: 46px; height: 28px; margin: -6px -23px -6px -23px; border-radius: 5px; border: 1px solid #777; }");
1879 count++;
1880 } else {
1881 count++;
1887 void ConfigInputWidget::updateConfigAlarmStatus()
1889 SystemAlarms *systemAlarmsObj = SystemAlarms::GetInstance(getObjectManager());
1890 SystemAlarms::DataFields systemAlarms = systemAlarmsObj->getData();
1892 QString message = tr("Config OK");
1893 QString tooltipMessage = tr("All fine, no config alarm!");
1894 QString bgColor = "green";
1896 if (systemAlarms.Alarm[SystemAlarms::ALARM_SYSTEMCONFIGURATION] > SystemAlarms::ALARM_WARNING) {
1897 switch (systemAlarms.ExtendedAlarmStatus[SystemAlarms::EXTENDEDALARMSTATUS_SYSTEMCONFIGURATION]) {
1898 case SystemAlarms::EXTENDEDALARMSTATUS_FLIGHTMODE:
1899 message = tr("Config error");
1900 tooltipMessage = tr("There is something wrong in the current config,\nusually a Thrust mode or Assisted mode not supported.\n\n"
1901 "Tip: Reduce the Flight Mode Count to find the culprit.");
1902 bgColor = "red";
1905 ui->configAlarmStatus->setVisible(true);
1906 ui->configAlarmStatus->setStyleSheet(
1907 "QLabel { background-color: " + bgColor + ";"
1908 "color: rgb(255, 255, 255); border-radius: 5; margin:1px; font:bold; }");
1909 ui->configAlarmStatus->setText(message);
1910 ui->configAlarmStatus->setToolTip(tooltipMessage);
1913 void ConfigInputWidget::updateCalibration()
1915 manualCommandData = manualCommandObj->getData();
1916 for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) {
1917 if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) ||
1918 (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) {
1919 manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i];
1921 if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i]) ||
1922 (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i])) {
1923 manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i];
1925 if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) {
1926 adjustSpecialNeutrals();
1927 } else {
1928 // Set Accessory neutral to middle range
1929 if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) {
1930 manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2);
1931 } else {
1932 manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
1936 UAVObjectUpdaterHelper updateHelper;
1937 manualSettingsObj->setData(manualSettingsData, false);
1938 updateHelper.doObjectAndWait(manualSettingsObj);
1939 manualSettingsObj->updated();
1942 void ConfigInputWidget::simpleCalibration(bool enable)
1944 if (!isConnected()) {
1945 return;
1948 if (!outputConfigIsSafe) {
1949 if (enable) {
1950 QMessageBox::warning(this, tr("Warning"), tr("There is something wrong in <b>Output</b> tab."
1951 "<p>Please fix the issue before starting the Manual Calibration.</p>"), QMessageBox::Ok);
1952 ui->runCalibration->setChecked(false);
1954 return;
1957 if (enable) {
1958 ui->configurationWizard->setEnabled(false);
1959 ui->applyButton->setEnabled(false);
1960 ui->saveButton->setEnabled(false);
1961 ui->runCalibration->setText(tr("Stop Manual Calibration"));
1962 throttleError = false;
1964 QMessageBox msgBox;
1965 msgBox.setText(tr("<p>Arming Settings are now set to 'Always Disarmed' for your safety.</p>"
1966 "<p>Be sure your receiver is powered with an external source and Transmitter is on.</p>"
1967 "<p align='center'><b>Stop Manual Calibration</b> when done</p>"));
1968 msgBox.setDetailedText(tr("You will have to reconfigure the arming settings manually when the manual calibration is finished."));
1969 msgBox.setStandardButtons(QMessageBox::Ok);
1970 msgBox.setDefaultButton(QMessageBox::Ok);
1971 msgBox.exec();
1973 // Tell Output tab we freeze actuators soon
1974 emit inputCalibrationStateChanged(true);
1976 manualCommandData = manualCommandObj->getData();
1978 manualSettingsData = manualSettingsObj->getData();
1979 flightModeSettingsData = flightModeSettingsObj->getData();
1980 flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED;
1981 flightModeSettingsObj->setData(flightModeSettingsData);
1982 // Ignore last Rssi channel
1983 for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) {
1984 reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i];
1985 manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i];
1986 manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
1987 manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i];
1990 fastMdataSingle(manualCommandObj, &manualControlMdata);
1992 // Stash actuatorSettings
1993 actuatorSettingsData = actuatorSettingsObj->getData();
1994 memento.actuatorSettingsData = actuatorSettingsData;
1996 // Disable all actuators
1997 resetActuatorSettings();
1999 connect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject *)), this, SLOT(updateCalibration()));
2000 } else {
2001 manualCommandData = manualCommandObj->getData();
2002 manualSettingsData = manualSettingsObj->getData();
2003 systemSettingsData = systemSettingsObj->getData();
2005 if ((systemSettingsData.AirframeType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLECAR) ||
2006 (systemSettingsData.AirframeType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIAL) ||
2007 (systemSettingsData.AirframeType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEMOTORCYCLE) ||
2008 (systemSettingsData.AirframeType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEBOAT) ||
2009 (systemSettingsData.AirframeType == SystemSettings::AIRFRAMETYPE_GROUNDVEHICLEDIFFERENTIALBOAT)) {
2010 QMessageBox::warning(this, tr("Ground Vehicle"),
2011 tr("<p>Please <b>center</b> throttle control and press OK when ready.</p>"));
2013 transmitterType = ground;
2014 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE] =
2015 manualCommandData.Channel[ManualControlSettings::CHANNELNUMBER_THROTTLE];
2018 restoreMdataSingle(manualCommandObj, &manualControlMdata);
2020 for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) {
2021 if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) {
2022 adjustSpecialNeutrals();
2023 checkThrottleRange();
2024 } else {
2025 // Set Accessory neutral to middle range
2026 if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) {
2027 manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2);
2028 } else {
2029 manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i];
2033 manualSettingsObj->setData(manualSettingsData);
2035 // Load actuator settings back from beginning of manual calibration
2036 actuatorSettingsObj->setData(memento.actuatorSettingsData);
2038 ui->configurationWizard->setEnabled(true);
2039 ui->applyButton->setEnabled(true);
2040 ui->saveButton->setEnabled(true);
2041 ui->runCalibration->setText(tr("Start Manual Calibration"));
2043 // Tell Output tab the calibration is ended
2044 emit inputCalibrationStateChanged(false);
2046 disconnect(manualCommandObj, SIGNAL(objectUnpacked(UAVObject *)), this, SLOT(updateCalibration()));
2050 void ConfigInputWidget::adjustSpecialNeutrals()
2052 // FlightMode and Throttle need special neutral settings
2054 // Force flight mode neutral to middle
2055 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE] =
2056 (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE] +
2057 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]) / 2;
2059 // A ground vehicle has a reversible motor, the center position of throttle is the neutral setting.
2060 // So do not have to set a special neutral value for it.
2061 if (transmitterType == ground) {
2062 return;
2065 // Force throttle to be near min, add 4% from total range to avoid arming issues
2066 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE] =
2067 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE] +
2068 ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE] -
2069 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]) * 0.04);
2072 void ConfigInputWidget::checkThrottleRange()
2074 int throttleRange = abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE] -
2075 manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]);
2077 if (!throttleError && (throttleRange < 300)) {
2078 throttleError = true;
2079 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);
2081 // Set Throttle neutral to max value so Throttle can't be positive
2082 manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE] =
2083 manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE];
2087 bool ConfigInputWidget::shouldObjectBeSaved(UAVObject *object)
2089 // ManualControlCommand no need to be saved
2090 return dynamic_cast<ManualControlCommand *>(object) == NULL;
2093 void ConfigInputWidget::resetChannelSettings()
2095 manualSettingsData = manualSettingsObj->getData();
2096 // Clear all channel data : Channel Type (PPM,PWM..) and Number, except for Rssi
2097 for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_RSSI; channel++) {
2098 manualSettingsData.ChannelGroups[channel] = ManualControlSettings::CHANNELGROUPS_NONE;
2099 manualSettingsData.ChannelNumber[channel] = CHANNEL_NUMBER_NONE;
2100 UAVObjectUpdaterHelper updateHelper;
2101 manualSettingsObj->setData(manualSettingsData, false);
2102 updateHelper.doObjectAndWait(manualSettingsObj);
2104 resetFlightModeSettings();
2107 void ConfigInputWidget::resetFlightModeSettings()
2109 // Reset FlightMode settings
2110 manualSettingsData.FlightModeNumber = DEFAULT_FLIGHT_MODE_NUMBER;
2111 UAVObjectUpdaterHelper updateHelper;
2112 manualSettingsObj->setData(manualSettingsData, false);
2113 updateHelper.doObjectAndWait(manualSettingsObj);
2114 for (uint8_t pos = 0; pos < FlightModeSettings::FLIGHTMODEPOSITION_NUMELEM; pos++) {
2115 flightModeSignalValue[pos] = 0;
2119 void ConfigInputWidget::resetActuatorSettings()
2121 actuatorSettingsData = actuatorSettingsObj->getData();
2123 UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
2124 Q_ASSERT(mixer);
2126 QString mixerType;
2128 // Clear all output data : Min, max, neutral at same value
2129 // min value for motors and neutral for all others (Reversable motor, servo)
2130 for (unsigned int output = 0; output < ActuatorSettings::CHANNELMAX_NUMELEM; output++) {
2131 QString mixerNumType = QString("Mixer%1Type").arg(output + 1);
2132 UAVObjectField *field = mixer->getField(mixerNumType);
2133 Q_ASSERT(field);
2135 if (field) {
2136 mixerType = field->getValue().toString();
2138 if ((mixerType == "Motor") || (mixerType == "Disabled")) {
2139 // Apply current min setting to neutral/max values
2140 actuatorSettingsData.ChannelMax[output] = actuatorSettingsData.ChannelMin[output];
2141 actuatorSettingsData.ChannelNeutral[output] = actuatorSettingsData.ChannelMin[output];
2142 } else {
2143 // Apply current neutral setting to min/max values
2144 actuatorSettingsData.ChannelMax[output] = actuatorSettingsData.ChannelNeutral[output];
2145 actuatorSettingsData.ChannelMin[output] = actuatorSettingsData.ChannelNeutral[output];
2147 UAVObjectUpdaterHelper updateHelper;
2148 actuatorSettingsObj->setData(actuatorSettingsData, false);
2149 updateHelper.doObjectAndWait(actuatorSettingsObj);
2153 void ConfigInputWidget::updateReceiverActivityStatus()
2155 ReceiverActivity *receiverActivity = ReceiverActivity::GetInstance(getObjectManager());
2157 Q_ASSERT(receiverActivity);
2159 FlightStatus *flightStatus = FlightStatus::GetInstance(getObjectManager());
2161 Q_ASSERT(flightStatus);
2163 UAVObjectField *activeGroup = receiverActivity->getField(QString("ActiveGroup"));
2164 Q_ASSERT(activeGroup);
2166 UAVObjectField *activeChannel = receiverActivity->getField(QString("ActiveChannel"));
2167 Q_ASSERT(activeChannel);
2169 QString activeGroupText = activeGroup->getValue().toString();
2170 QString activeChannelText = activeChannel->getValue().toString();
2173 if (activeGroupText != "None") {
2174 ui->receiverActivityStatus->setText(tr("%1 input - Channel %2").arg(activeGroupText).arg(activeChannelText));
2175 ui->receiverActivityStatus->setStyleSheet("QLabel { background-color: green; color: rgb(255, 255, 255); \
2176 border: 1px solid grey; border-radius: 5; margin:1px; font:bold;}");
2177 } else {
2178 bool armed = (flightStatus->getArmed() == FlightStatus::ARMED_ARMED);
2179 QString receiverActivityText = armed ? tr("Disabled (Armed)") : tr("No activity");
2180 ui->receiverActivityStatus->setText(receiverActivityText);
2181 ui->receiverActivityStatus->setStyleSheet("QLabel { background-color: darkGreen; color: rgb(255, 255, 255); \
2182 border: 1px solid grey; border-radius: 5; margin:1px; font:bold;}");
2186 void ConfigInputWidget::failsafeBatteryWarningFlightModeChanged(int index)
2188 HwSettings::DataFields hwSettingsData = hwSettingsObj->getData();
2189 bool batteryModuleEnabled = (hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_BATTERY] == HwSettings::OPTIONALMODULES_ENABLED);
2191 ui->failsafeBatteryWarningFlightMode->setEnabled(batteryModuleEnabled && index != -1);
2192 ui->failsafeBatteryWarningFlightModeCb->setChecked(index != -1);
2195 void ConfigInputWidget::failsafeBatteryCriticalFlightModeChanged(int index)
2197 HwSettings::DataFields hwSettingsData = hwSettingsObj->getData();
2198 bool batteryModuleEnabled = (hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_BATTERY] == HwSettings::OPTIONALMODULES_ENABLED);
2200 ui->failsafeBatteryCriticalFlightMode->setEnabled(batteryModuleEnabled && index != -1);
2201 ui->failsafeBatteryCriticalFlightModeCb->setChecked(index != -1);
2204 void ConfigInputWidget::failsafeFlightModeChanged(int index)
2206 ui->failsafeFlightMode->setEnabled(index != -1);
2207 ui->failsafeFlightModeCb->setChecked(index != -1);
2210 void ConfigInputWidget::failsafeFlightModeCbToggled(bool checked)
2212 ui->failsafeFlightMode->setCurrentIndex(checked ? 0 : -1);
2215 void ConfigInputWidget::failsafeBatteryWarningFlightModeCbToggled(bool checked)
2217 ui->failsafeBatteryWarningFlightMode->setCurrentIndex(checked ? 0 : -1);
2220 void ConfigInputWidget::failsafeBatteryCriticalFlightModeCbToggled(bool checked)
2222 ui->failsafeBatteryCriticalFlightMode->setCurrentIndex(checked ? 0 : -1);
2225 void ConfigInputWidget::enableControlsChanged(bool enabled)
2227 ui->failsafeFlightMode->setEnabled(enabled && ui->failsafeFlightMode->currentIndex() != -1);
2229 HwSettings::DataFields hwSettingsData = hwSettingsObj->getData();
2230 bool batteryModuleEnabled = (hwSettingsData.OptionalModules[HwSettings::OPTIONALMODULES_BATTERY] == HwSettings::OPTIONALMODULES_ENABLED);
2231 ui->failsafeBatteryWarningFlightMode->setEnabled(batteryModuleEnabled && enabled && ui->failsafeBatteryWarningFlightMode->currentIndex() != -1);
2232 ui->failsafeBatteryCriticalFlightMode->setEnabled(batteryModuleEnabled && enabled && ui->failsafeBatteryCriticalFlightMode->currentIndex() != -1);
2233 ui->failsafeBatteryWarningFlightModeCb->setEnabled(enabled && batteryModuleEnabled);
2234 ui->failsafeBatteryCriticalFlightModeCb->setEnabled(enabled && batteryModuleEnabled);
2237 void ConfigInputWidget::setOutputConfigSafe(bool status)
2239 outputConfigIsSafe = status;