2 ******************************************************************************
4 * @file configoutputwidget.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
6 * E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup ConfigPlugin Config Plugin
11 * @brief Servo 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 "configoutputwidget.h"
31 #include "ui_output.h"
32 #include "ui_outputchannelform.h"
34 #include "outputchannelform.h"
35 #include "configvehicletypewidget.h"
37 #include "uavsettingsimportexport/uavsettingsimportexportfactory.h"
38 #include <extensionsystem/pluginmanager.h>
39 #include <uavobjecthelper.h>
41 #include "mixersettings.h"
42 #include "actuatorcommand.h"
43 #include "actuatorsettings.h"
44 #include "flightmodesettings.h"
45 #include "flightstatus.h"
46 #include "systemsettings.h"
49 #include <QStringList>
52 #include <QMessageBox>
55 #define DSHOT_MAXOUTPUT_RANGE 2000
56 #define DSHOT_MINTOUTPUT_RANGE 0
57 #define PWMSYNC_MAXOUTPUT_RANGE 1900
58 #define DEFAULT_MAXOUTPUT_RANGE 2000
59 #define DEFAULT_MINOUTPUT_RANGE 900
61 #define DEFAULT_MINOUTPUT_VALUE 1000
64 #define SERVO_MAXOUTPUT_RANGE 2500
65 #define SERVO_MINOUTPUT_RANGE 500
66 #define SERVO_MAXOUTPUT_VALUE 2000
67 #define SERVO_MINOUTPUT_VALUE 1000
68 #define SERVO_NEUTRAL_VALUE 1500
70 ConfigOutputWidget::ConfigOutputWidget(QWidget
*parent
) : ConfigTaskWidget(parent
)
72 m_ui
= new Ui_OutputWidget();
75 // must be done before auto binding !
76 setWikiURL("Output+Configuration");
80 m_ui
->gvFrame
->setVisible(false);
82 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
83 UAVSettingsImportExportFactory
*importexportplugin
= pm
->getObject
<UAVSettingsImportExportFactory
>();
84 connect(importexportplugin
, SIGNAL(importAboutToBegin()), this, SLOT(stopTests()));
86 connect(m_ui
->channelOutTest
, SIGNAL(clicked(bool)), this, SLOT(runChannelTests(bool)));
88 // Configure the task widget
90 // Track the ActuatorSettings object
91 addUAVObject("ActuatorSettings");
93 // NOTE: we have channel indices from 0 to 9, but the convention for OP is Channel 1 to Channel 10.
94 // Register for ActuatorSettings changes:
95 for (unsigned int i
= 0; i
< ActuatorCommand::CHANNEL_NUMELEM
; i
++) {
96 OutputChannelForm
*form
= new OutputChannelForm(i
, this);
97 form
->moveTo(*(m_ui
->channelLayout
));
99 connect(m_ui
->channelOutTest
, SIGNAL(toggled(bool)), form
, SLOT(enableChannelTest(bool)));
100 connect(form
, SIGNAL(channelChanged(int, int)), this, SLOT(sendChannelTest(int, int)));
102 addWidget(form
->ui
->actuatorMin
);
103 addWidget(form
->ui
->actuatorNeutral
);
104 addWidget(form
->ui
->actuatorMax
);
105 addWidget(form
->ui
->actuatorRev
);
106 addWidget(form
->ui
->actuatorLink
);
109 // Associate the buttons with their UAVO fields
110 addWidget(m_ui
->spinningArmed
);
111 connect(m_ui
->spinningArmed
, SIGNAL(clicked(bool)), this, SLOT(updateSpinStabilizeCheckComboBoxes()));
113 addUAVObject("FlightModeSettings");
114 addWidgetBinding("FlightModeSettings", "AlwaysStabilizeWhenArmedSwitch", m_ui
->alwaysStabilizedSwitch
);
116 connect(FlightStatus::GetInstance(getObjectManager()), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(updateAlwaysStabilizeStatus()));
118 MixerSettings
*mixer
= MixerSettings::GetInstance(getObjectManager());
120 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank1
, QColor("#C6ECAE"), m_ui
->cb_outputRate1
, m_ui
->cb_outputMode1
);
121 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank2
, QColor("#91E5D3"), m_ui
->cb_outputRate2
, m_ui
->cb_outputMode2
);
122 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank3
, QColor("#FCEC52"), m_ui
->cb_outputRate3
, m_ui
->cb_outputMode3
);
123 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank4
, QColor("#C3A8FF"), m_ui
->cb_outputRate4
, m_ui
->cb_outputMode4
);
124 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank5
, QColor("#F7F7F2"), m_ui
->cb_outputRate5
, m_ui
->cb_outputMode5
);
125 m_banks
<< OutputBankControls(mixer
, m_ui
->chBank6
, QColor("#FF9F51"), m_ui
->cb_outputRate6
, m_ui
->cb_outputMode6
);
128 rates
<< 50 << 60 << 125 << 165 << 270 << 330 << 400 << 490;
130 foreach(OutputBankControls controls
, m_banks
) {
131 addWidget(controls
.rateCombo());
133 controls
.rateCombo()->addItem(tr("-"), QVariant(0));
134 controls
.rateCombo()->model()->setData(controls
.rateCombo()->model()->index(0, 0), QVariant(0), Qt::UserRole
- 1);
135 foreach(int rate
, rates
) {
136 controls
.rateCombo()->addItem(tr("%1 Hz").arg(rate
), rate
);
139 addWidgetBinding("ActuatorSettings", "BankMode", controls
.modeCombo(), i
++, 0, true);
140 connect(controls
.modeCombo(), SIGNAL(currentIndexChanged(int)), this, SLOT(onBankTypeChange()));
143 SystemAlarms
*systemAlarmsObj
= SystemAlarms::GetInstance(getObjectManager());
144 connect(systemAlarmsObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(updateWarnings(UAVObject
*)));
146 // TODO why do we do that ?
147 disconnect(this, SLOT(refreshWidgetsValues(UAVObject
*)));
150 ConfigOutputWidget::~ConfigOutputWidget()
152 SystemAlarms
*systemAlarmsObj
= SystemAlarms::GetInstance(getObjectManager());
154 disconnect(systemAlarmsObj
, SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(updateWarnings(UAVObject
*)));
155 foreach(OutputBankControls controls
, m_banks
) {
156 disconnect(controls
.modeCombo(), SIGNAL(currentIndexChanged(int)), this, SLOT(onBankTypeChange()));
160 void ConfigOutputWidget::enableControls(bool enable
)
162 ConfigTaskWidget::enableControls(enable
);
165 m_ui
->channelOutTest
->setChecked(false);
167 m_ui
->channelOutTest
->setEnabled(enable
);
171 Force update all channels with the values in the OutputChannelForms.
173 void ConfigOutputWidget::sendAllChannelTests()
175 for (unsigned int i
= 0; i
< ActuatorCommand::CHANNEL_NUMELEM
; i
++) {
176 OutputChannelForm
*form
= getOutputChannelForm(i
);
177 sendChannelTest(i
, form
->neutral());
182 Toggles the channel testing mode by making the GCS take over
183 the ActuatorCommand objects
185 void ConfigOutputWidget::runChannelTests(bool state
)
187 SystemAlarms
*systemAlarmsObj
= SystemAlarms::GetInstance(getObjectManager());
188 SystemAlarms::DataFields systemAlarms
= systemAlarmsObj
->getData();
190 if (state
&& systemAlarms
.Alarm
[SystemAlarms::ALARM_ACTUATOR
] != SystemAlarms::ALARM_OK
) {
192 mbox
.setText(QString(tr("The actuator module is in an error state. This can also occur because there are no inputs. "
193 "Please fix these before testing outputs.")));
194 mbox
.setStandardButtons(QMessageBox::Ok
);
197 // Unfortunately must cache this since callback will reoccur
198 m_accInitialData
= ActuatorCommand::GetInstance(getObjectManager())->getMetadata();
200 m_ui
->channelOutTest
->setChecked(false);
204 // Confirm this is definitely what they want
207 mbox
.setText(QString(tr("This option will start your motors by the amount selected on the sliders regardless of transmitter."
208 "It is recommended to remove any blades from motors. Are you sure you want to do this?")));
209 mbox
.setStandardButtons(QMessageBox::Yes
| QMessageBox::No
);
210 int retval
= mbox
.exec();
211 if (retval
!= QMessageBox::Yes
) {
213 qDebug() << "Cancelled";
214 m_ui
->channelOutTest
->setChecked(false);
219 ActuatorCommand
*obj
= ActuatorCommand::GetInstance(getObjectManager());
220 UAVObject::Metadata mdata
= obj
->getMetadata();
222 m_accInitialData
= mdata
;
223 UAVObject::SetFlightAccess(mdata
, UAVObject::ACCESS_READONLY
);
224 UAVObject::SetFlightTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_ONCHANGE
);
225 UAVObject::SetGcsTelemetryAcked(mdata
, false);
226 UAVObject::SetGcsTelemetryUpdateMode(mdata
, UAVObject::UPDATEMODE_ONCHANGE
);
227 mdata
.gcsTelemetryUpdatePeriod
= 100;
229 mdata
= m_accInitialData
; // Restore metadata
231 obj
->setMetadata(mdata
);
234 // Setup the correct initial channel values when the channel testing mode is turned on.
236 sendAllChannelTests();
240 if (!state
&& isDirty()) {
242 mbox
.setText(QString(tr("You may want to save your neutral settings.")));
243 mbox
.setStandardButtons(QMessageBox::Ok
);
244 mbox
.setIcon(QMessageBox::Information
);
249 OutputChannelForm
*ConfigOutputWidget::getOutputChannelForm(const int index
) const
251 QList
<OutputChannelForm
*> outputChannelForms
= findChildren
<OutputChannelForm
*>();
252 foreach(OutputChannelForm
* outputChannelForm
, outputChannelForms
) {
253 if (outputChannelForm
->index() == index
) {
254 return outputChannelForm
;
258 // no OutputChannelForm found with given index
263 * Set the label for a channel output assignement
265 void ConfigOutputWidget::assignOutputChannel(UAVDataObject
*obj
, QString
&str
)
267 // FIXME: use signal/ slot approach
268 UAVObjectField
*field
= obj
->getField(str
);
269 QStringList options
= field
->getOptions();
270 int index
= options
.indexOf(field
->getValue().toString());
272 OutputChannelForm
*outputChannelForm
= getOutputChannelForm(index
);
274 if (outputChannelForm
) {
275 outputChannelForm
->setName(str
);
280 Sends the channel value to the UAV to move the servo.
281 Returns immediately if we are not in testing mode
283 void ConfigOutputWidget::sendChannelTest(int index
, int value
)
285 if (!m_ui
->channelOutTest
->isChecked()) {
289 if (index
< 0 || (unsigned)index
>= ActuatorCommand::CHANNEL_NUMELEM
) {
293 ActuatorCommand
*actuatorCommand
= ActuatorCommand::GetInstance(getObjectManager());
294 Q_ASSERT(actuatorCommand
);
295 ActuatorCommand::DataFields actuatorCommandFields
= actuatorCommand
->getData();
296 actuatorCommandFields
.Channel
[index
] = value
;
297 actuatorCommand
->setData(actuatorCommandFields
);
300 void ConfigOutputWidget::setColor(QWidget
*widget
, const QColor color
)
302 QPalette
p(palette());
304 p
.setColor(QPalette::Background
, color
);
305 p
.setColor(QPalette::Base
, color
);
306 p
.setColor(QPalette::Active
, QPalette::Button
, color
);
307 p
.setColor(QPalette::Inactive
, QPalette::Button
, color
);
308 widget
->setAutoFillBackground(true);
309 widget
->setPalette(p
);
312 /********************************
314 *******************************/
317 Request the current config from the board (RC Output)
319 void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject
*obj
)
323 // Get Actuator Settings
324 ActuatorSettings
*actuatorSettings
= ActuatorSettings::GetInstance(getObjectManager());
326 Q_ASSERT(actuatorSettings
);
327 ActuatorSettings::DataFields actuatorSettingsData
= actuatorSettings
->getData();
329 // Get channel descriptions
330 QStringList channelDesc
= ConfigVehicleTypeWidget::getChannelDescriptions();
332 // Initialize output forms
333 QList
<OutputChannelForm
*> outputChannelForms
= findChildren
<OutputChannelForm
*>();
334 foreach(OutputChannelForm
* outputChannelForm
, outputChannelForms
) {
335 outputChannelForm
->setName(channelDesc
[outputChannelForm
->index()]);
337 // init min,max,neutral
338 int minValue
= actuatorSettingsData
.ChannelMin
[outputChannelForm
->index()];
339 int maxValue
= actuatorSettingsData
.ChannelMax
[outputChannelForm
->index()];
340 outputChannelForm
->setRange(minValue
, maxValue
);
342 int neutral
= actuatorSettingsData
.ChannelNeutral
[outputChannelForm
->index()];
343 outputChannelForm
->setNeutral(neutral
);
346 // Get the SpinWhileArmed setting
347 m_ui
->spinningArmed
->setChecked(actuatorSettingsData
.MotorsSpinWhileArmed
== ActuatorSettings::MOTORSSPINWHILEARMED_TRUE
);
349 for (int i
= 0; i
< m_banks
.count(); i
++) {
350 OutputBankControls controls
= m_banks
.at(i
);
351 // Reset to all disabled
352 controls
.label()->setText("-");
354 controls
.rateCombo()->setEnabled(false);
355 setColor(controls
.rateCombo(), palette().color(QPalette::Background
));
356 controls
.rateCombo()->setCurrentIndex(0);
358 controls
.modeCombo()->setEnabled(false);
359 setColor(controls
.modeCombo(), palette().color(QPalette::Background
));
362 // Get connected board model
363 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
365 UAVObjectUtilManager
*utilMngr
= pm
->getObject
<UAVObjectUtilManager
>();
367 QStringList bankLabels
;
368 QList
<int> channelBanks
;
371 int board
= utilMngr
->getBoardModel();
372 // Setup labels and combos for banks according to board type
373 if ((board
& 0xff00) == 0x0400) {
374 // Coptercontrol family of boards 4 timer banks
375 bankLabels
<< "1 (1-3)" << "2 (4)" << "3 (5,7-8)" << "4 (6,9-10)";
376 channelBanks
<< 1 << 1 << 1 << 2 << 3 << 4 << 3 << 3 << 4 << 4;
377 } else if (board
== 0x0903) {
378 // Revolution family of boards 6 timer banks
379 bankLabels
<< "1 (1-2)" << "2 (3)" << "3 (4)" << "4 (5-6)" << "5 (7,12)" << "6 (8-11)";
380 channelBanks
<< 1 << 1 << 2 << 3 << 4 << 4 << 5 << 6 << 6 << 6 << 6 << 5;
381 } else if (board
== 0x0905) {
383 bankLabels
<< "1 (1)" << "2 (2,7,11)" << "3 (3)" << "4 (4)" << "5 (5-6)" << "6 (8-10,12)";
384 channelBanks
<< 1 << 2 << 3 << 4 << 5 << 5 << 2 << 6 << 6 << 6 << 2 << 6;
385 } else if (board
== 0x9201) {
387 bankLabels
<< "1 (1-2)" << "2 (3)" << "3 (4)" << "4 (5-6)" << "5 (7-8)" << "6 (9-10)";
388 channelBanks
<< 1 << 1 << 2 << 3 << 4 << 4 << 5 << 5 << 6 << 6;
389 } else if (board
== 0x1001) {
391 bankLabels
<< "1 (1-3,7)" << "2 (4,8)" << "3 (5)" << "4 (6)";
392 channelBanks
<< 1 << 1 << 1 << 2 << 3 << 4 << 1 << 2;
393 } else if (board
== 0x1002 || board
== 0x1003) {
394 // SPRacingF3_EVO, NucleoF303RE
395 bankLabels
<< "1 (1-3)" << "2 (4)" << "3 (5-8)";
396 channelBanks
<< 1 << 1 << 1 << 2 << 3 << 3 << 3 << 3;
397 } else if (board
== 0x1005) { // PikoBLX
398 bankLabels
<< "1 (1-4)" << "2 (5-6)" << "3 (7)" << "4 (8)";
399 channelBanks
<< 1 << 1 << 1 << 1 << 2 << 2 << 3 << 4;
400 } else if (board
== 0x1006) { // tinyFISH
401 bankLabels
<< "1 (1)" << "2 (2)" << "3 (3-4)" << "4 (5-6)";
402 channelBanks
<< 1 << 2 << 3 << 3 << 4 << 4;
407 foreach(QString banklabel
, bankLabels
) {
408 OutputBankControls controls
= m_banks
.at(i
);
410 controls
.label()->setText(banklabel
);
411 int index
= controls
.rateCombo()->findData(actuatorSettingsData
.BankUpdateFreq
[i
]);
413 controls
.rateCombo()->addItem(tr("%1 Hz").arg(actuatorSettingsData
.BankUpdateFreq
[i
]), actuatorSettingsData
.BankUpdateFreq
[i
]);
415 controls
.rateCombo()->setCurrentIndex(index
);
416 controls
.rateCombo()->setEnabled(controls
.modeCombo()->currentIndex() == ActuatorSettings::BANKMODE_PWM
);
417 setColor(controls
.rateCombo(), controls
.color());
418 controls
.modeCombo()->setEnabled(true);
419 setColor(controls
.modeCombo(), controls
.color());
423 // Get Channel ranges:
425 foreach(OutputChannelForm
* outputChannelForm
, outputChannelForms
) {
426 int minValue
= actuatorSettingsData
.ChannelMin
[outputChannelForm
->index()];
427 int maxValue
= actuatorSettingsData
.ChannelMax
[outputChannelForm
->index()];
429 if (channelBanks
.count() > i
) {
430 int bankNumber
= channelBanks
.at(i
);
431 OutputBankControls bankControls
= m_banks
.at(bankNumber
- 1);
433 setChannelLimits(outputChannelForm
, &bankControls
);
435 outputChannelForm
->setBank(QString::number(bankNumber
));
436 outputChannelForm
->setColor(bankControls
.color());
440 outputChannelForm
->setRange(minValue
, maxValue
);
441 int neutral
= actuatorSettingsData
.ChannelNeutral
[outputChannelForm
->index()];
442 outputChannelForm
->setNeutral(neutral
);
445 updateSpinStabilizeCheckComboBoxes();
449 * Sends the config to the board, without saving to the SD card (RC Output)
451 void ConfigOutputWidget::updateObjectsFromWidgetsImpl()
453 ActuatorSettings
*actuatorSettings
= ActuatorSettings::GetInstance(getObjectManager());
455 Q_ASSERT(actuatorSettings
);
456 if (actuatorSettings
) {
457 ActuatorSettings::DataFields actuatorSettingsData
= actuatorSettings
->getData();
459 // Set channel ranges
460 QList
<OutputChannelForm
*> outputChannelForms
= findChildren
<OutputChannelForm
*>();
461 foreach(OutputChannelForm
* outputChannelForm
, outputChannelForms
) {
462 actuatorSettingsData
.ChannelMax
[outputChannelForm
->index()] = outputChannelForm
->max();
463 actuatorSettingsData
.ChannelMin
[outputChannelForm
->index()] = outputChannelForm
->min();
464 actuatorSettingsData
.ChannelNeutral
[outputChannelForm
->index()] = outputChannelForm
->neutral();
468 actuatorSettingsData
.BankUpdateFreq
[0] = m_ui
->cb_outputRate1
->currentData().toUInt();
469 actuatorSettingsData
.BankUpdateFreq
[1] = m_ui
->cb_outputRate2
->currentData().toUInt();
470 actuatorSettingsData
.BankUpdateFreq
[2] = m_ui
->cb_outputRate3
->currentData().toUInt();
471 actuatorSettingsData
.BankUpdateFreq
[3] = m_ui
->cb_outputRate4
->currentData().toUInt();
472 actuatorSettingsData
.BankUpdateFreq
[4] = m_ui
->cb_outputRate5
->currentData().toUInt();
473 actuatorSettingsData
.BankUpdateFreq
[5] = m_ui
->cb_outputRate6
->currentData().toUInt();
475 actuatorSettingsData
.MotorsSpinWhileArmed
= m_ui
->spinningArmed
->isChecked() ?
476 ActuatorSettings::MOTORSSPINWHILEARMED_TRUE
:
477 ActuatorSettings::MOTORSSPINWHILEARMED_FALSE
;
480 UAVObjectUpdaterHelper updateHelper
;
481 actuatorSettings
->setData(actuatorSettingsData
, false);
482 updateHelper
.doObjectAndWait(actuatorSettings
);
485 FlightModeSettings
*flightModeSettings
= FlightModeSettings::GetInstance(getObjectManager());
486 Q_ASSERT(flightModeSettings
);
488 if (flightModeSettings
) {
489 FlightModeSettings::DataFields flightModeSettingsData
= flightModeSettings
->getData();
490 flightModeSettingsData
.AlwaysStabilizeWhenArmedSwitch
= m_ui
->alwaysStabilizedSwitch
->currentIndex();
493 flightModeSettings
->setData(flightModeSettingsData
);
497 void ConfigOutputWidget::updateSpinStabilizeCheckComboBoxes()
499 m_ui
->alwayStabilizedLabel1
->setEnabled(m_ui
->spinningArmed
->isChecked());
500 m_ui
->alwayStabilizedLabel2
->setEnabled(m_ui
->spinningArmed
->isChecked());
501 m_ui
->alwaysStabilizedSwitch
->setEnabled(m_ui
->spinningArmed
->isChecked());
503 if (!m_ui
->spinningArmed
->isChecked()) {
504 m_ui
->alwaysStabilizedSwitch
->setCurrentIndex(FlightModeSettings::ALWAYSSTABILIZEWHENARMEDSWITCH_DISABLED
);
508 void ConfigOutputWidget::updateAlwaysStabilizeStatus()
510 FlightStatus
*flightStatusObj
= FlightStatus::GetInstance(getObjectManager());
511 FlightStatus::DataFields flightStatus
= flightStatusObj
->getData();
513 if (flightStatus
.AlwaysStabilizeWhenArmed
== FlightStatus::ALWAYSSTABILIZEWHENARMED_TRUE
) {
514 m_ui
->alwayStabilizedLabel2
->setText(tr("AlwaysStabilizeWhenArmed is <b>ACTIVE</b>. This prevents arming!."));
516 m_ui
->alwayStabilizedLabel2
->setText(tr("(Really be careful!)."));
520 void ConfigOutputWidget::setChannelLimits(OutputChannelForm
*channelForm
, OutputBankControls
*bankControls
)
522 // Set UI limits according to the bankmode and destination
523 switch (bankControls
->modeCombo()->currentIndex()) {
524 case ActuatorSettings::BANKMODE_DSHOT
:
525 // 0 - 2000 UI limits, DShot min value is fixed to zero
526 if (channelForm
->isServoOutput()) {
527 bank_mode_servo_warning
= "DShot";
530 channelForm
->setLimits(DSHOT_MINTOUTPUT_RANGE
, DSHOT_MINTOUTPUT_RANGE
, DSHOT_MINTOUTPUT_RANGE
, DSHOT_MAXOUTPUT_RANGE
);
531 channelForm
->setRange(DSHOT_MINTOUTPUT_RANGE
, DSHOT_MAXOUTPUT_RANGE
);
532 channelForm
->setNeutral(DSHOT_MINTOUTPUT_RANGE
);
534 case ActuatorSettings::BANKMODE_PWMSYNC
:
535 // 900 - 1900 UI limits
536 // Default values 1000 - 1900
537 channelForm
->setLimits(DEFAULT_MINOUTPUT_RANGE
, PWMSYNC_MAXOUTPUT_RANGE
, DEFAULT_MINOUTPUT_RANGE
, PWMSYNC_MAXOUTPUT_RANGE
);
538 channelForm
->setRange(DEFAULT_MINOUTPUT_VALUE
, PWMSYNC_MAXOUTPUT_RANGE
);
539 channelForm
->setNeutral(DEFAULT_MINOUTPUT_VALUE
);
540 if (channelForm
->isServoOutput()) {
541 // Servo: Some of them can handle PWMSync, 500 - 1900 UI limits
542 // Default values 1000 - 1900 + neutral 1500
543 channelForm
->setRange(SERVO_MINOUTPUT_VALUE
, PWMSYNC_MAXOUTPUT_RANGE
);
544 channelForm
->setNeutral(SERVO_NEUTRAL_VALUE
);
547 case ActuatorSettings::BANKMODE_PWM
:
548 // PWM motor outputs fall to default
549 if (channelForm
->isServoOutput()) {
550 // Servo: 500 - 2500 UI limits
551 // Default values 1000 - 2000 + neutral 1500
552 channelForm
->setLimits(SERVO_MINOUTPUT_RANGE
, SERVO_MAXOUTPUT_RANGE
, SERVO_MINOUTPUT_RANGE
, SERVO_MAXOUTPUT_RANGE
);
553 channelForm
->setRange(SERVO_MINOUTPUT_VALUE
, SERVO_MAXOUTPUT_VALUE
);
554 channelForm
->setNeutral(SERVO_NEUTRAL_VALUE
);
557 case ActuatorSettings::BANKMODE_ONESHOT125
:
558 if (channelForm
->isServoOutput()) {
559 bank_mode_servo_warning
= "OneShot125";
562 case ActuatorSettings::BANKMODE_ONESHOT42
:
563 if (channelForm
->isServoOutput()) {
564 bank_mode_servo_warning
= "OneShot42";
567 case ActuatorSettings::BANKMODE_MULTISHOT
:
568 if (channelForm
->isServoOutput()) {
569 bank_mode_servo_warning
= "MultiShot";
573 // Motors 900 - 2000 UI limits
574 // Default values 1000 - 2000, neutral set to min
575 channelForm
->setLimits(DEFAULT_MINOUTPUT_RANGE
, DEFAULT_MAXOUTPUT_RANGE
, DEFAULT_MINOUTPUT_RANGE
, DEFAULT_MAXOUTPUT_RANGE
);
576 channelForm
->setRange(DEFAULT_MINOUTPUT_VALUE
, DEFAULT_MAXOUTPUT_RANGE
);
577 channelForm
->setNeutral(DEFAULT_MINOUTPUT_VALUE
);
582 void ConfigOutputWidget::onBankTypeChange()
584 QComboBox
*bankModeCombo
= qobject_cast
<QComboBox
*>(sender());
586 bank_mode_servo_warning
= "";
588 if (bankModeCombo
!= NULL
) {
590 QList
<OutputChannelForm
*> outputChannelForms
= findChildren
<OutputChannelForm
*>();
591 foreach(OutputBankControls controls
, m_banks
) {
592 if (controls
.modeCombo() == bankModeCombo
) {
593 bool enabled
= bankModeCombo
->currentIndex() == ActuatorSettings::BANKMODE_PWM
;
594 controls
.rateCombo()->setEnabled(enabled
);
595 controls
.rateCombo()->setCurrentIndex(enabled
? 1 : 0);
596 foreach(OutputChannelForm
* outputChannelForm
, outputChannelForms
) {
597 if (outputChannelForm
->bank().toInt() == bankNumber
) {
598 setChannelLimits(outputChannelForm
, &controls
);
609 void ConfigOutputWidget::stopTests()
611 m_ui
->channelOutTest
->setChecked(false);
614 void ConfigOutputWidget::updateWarnings(UAVObject
*)
616 SystemAlarms
*systemAlarmsObj
= SystemAlarms::GetInstance(getObjectManager());
617 SystemAlarms::DataFields systemAlarms
= systemAlarmsObj
->getData();
619 if (systemAlarms
.Alarm
[SystemAlarms::ALARM_SYSTEMCONFIGURATION
] > SystemAlarms::ALARM_WARNING
) {
620 switch (systemAlarms
.ExtendedAlarmStatus
[SystemAlarms::EXTENDEDALARMSTATUS_SYSTEMCONFIGURATION
]) {
621 case SystemAlarms::EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT
:
622 setWarning(tr("OneShot and PWMSync output only works with Receiver Port settings marked with '+OneShot'<br>"
623 "When using Receiver Port setting 'PPM_PIN8+OneShot' "
624 "<b><font color='%1'>Bank %2</font></b> must be set to PWM")
625 .arg(m_banks
.at(3).color().name()).arg(m_banks
.at(3).label()->text()));
629 if (bank_mode_servo_warning
!= "") {
630 QString servo_warning_str
= QString("Bank using <b>%1</b> cannot drive a <b>servo output!</b>"
631 "<p>You must use PWM for this Bank or move the servo output to another compatible Bank.</p>").arg(bank_mode_servo_warning
);
632 setWarning(servo_warning_str
);
638 void ConfigOutputWidget::setWarning(QString message
)
640 m_ui
->gvFrame
->setVisible(!message
.isNull());
641 m_ui
->picWarning
->setPixmap(message
.isNull() ? QPixmap() : QPixmap(":/configgadget/images/error.svg"));
642 m_ui
->txtWarning
->setText(message
);
646 OutputBankControls::OutputBankControls(MixerSettings
*mixer
, QLabel
*label
, QColor color
, QComboBox
*rateCombo
, QComboBox
*modeCombo
) :
647 m_mixer(mixer
), m_label(label
), m_color(color
), m_rateCombo(rateCombo
), m_modeCombo(modeCombo
)
650 OutputBankControls::~OutputBankControls()