LP-311 Remove basic/advanced stabilization tab auto-switch (autotune/txpid lock issues)
[librepilot.git] / ground / gcs / src / plugins / config / outputchannelform.cpp
blobb093956a181396ff3daf58b3a9796ecf6e44cbb3
1 /**
2 ******************************************************************************
4 * @file outputchannelform.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup ConfigPlugin Config Plugin
9 * @{
10 * @brief Servo output configuration form for the config output gadget
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "outputchannelform.h"
30 #include "ui_outputchannelform.h"
32 #define MAXOUTPUT_VALUE 2500
33 #define MINOUTPUT_VALUE 500
35 OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) :
36 ChannelForm(index, parent), ui(new Ui::outputChannelForm), m_inChannelTest(false)
38 ui->setupUi(this);
40 // The convention for OP is Channel 1 to Channel 10.
41 ui->actuatorNumber->setText(QString("%1").arg(index + 1));
42 setBank("-");
43 // Register for ActuatorSettings changes:
44 connect(ui->actuatorMin, SIGNAL(editingFinished()), this, SLOT(setChannelRange()));
45 connect(ui->actuatorMax, SIGNAL(editingFinished()), this, SLOT(setChannelRange()));
46 connect(ui->actuatorRev, SIGNAL(toggled(bool)), this, SLOT(reverseChannel(bool)));
47 // Now connect the channel out sliders to our signal to send updates in test mode
48 connect(ui->actuatorNeutral, SIGNAL(valueChanged(int)), this, SLOT(sendChannelTest(int)));
50 ui->actuatorLink->setChecked(false);
51 connect(ui->actuatorLink, SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool)));
53 // Set limits
54 ui->actuatorMin->setMaximum(MAXOUTPUT_VALUE);
55 ui->actuatorMax->setMaximum(MAXOUTPUT_VALUE);
56 ui->actuatorValue->setMaximum(MAXOUTPUT_VALUE);
57 ui->actuatorMin->setMinimum(MINOUTPUT_VALUE);
58 ui->actuatorMax->setMinimum(MINOUTPUT_VALUE);
59 ui->actuatorValue->setMinimum(MINOUTPUT_VALUE);
61 setChannelRange();
63 disableMouseWheelEvents();
66 OutputChannelForm::~OutputChannelForm()
68 delete ui;
71 QString OutputChannelForm::name()
73 return ui->actuatorName->text();
76 QString OutputChannelForm::bank()
78 return ui->actuatorBankNumber->text();
81 /**
82 * Set the channel assignment label.
84 void OutputChannelForm::setName(const QString &name)
86 ui->actuatorName->setText(name);
89 void OutputChannelForm::setColor(const QColor &color)
91 QString stylesheet = ui->actuatorNumberFrame->styleSheet();
93 stylesheet = stylesheet.split("background-color").first();
94 stylesheet.append(
95 QString("background-color: rgb(%1, %2, %3)")
96 .arg(color.red()).arg(color.green()).arg(color.blue()));
97 ui->actuatorNumberFrame->setStyleSheet(stylesheet);
101 * Set the channel bank label.
103 void OutputChannelForm::setBank(const QString &bank)
105 ui->actuatorBankNumber->setText(bank);
109 * Restrict UI to protect users from accidental misuse.
111 void OutputChannelForm::enableChannelTest(bool state)
113 if (m_inChannelTest == state) {
114 return;
116 m_inChannelTest = state;
118 if (m_inChannelTest) {
119 // Prevent stupid users from touching the minimum & maximum ranges while
120 // moving the sliders. Thanks Ivan for the tip :)
121 ui->actuatorMin->setEnabled(false);
122 ui->actuatorMax->setEnabled(false);
123 ui->actuatorRev->setEnabled(false);
124 } else if (m_mixerType != "Disabled") {
125 ui->actuatorMin->setEnabled(true);
126 ui->actuatorMax->setEnabled(true);
127 if (m_mixerType != "Motor") {
128 ui->actuatorRev->setEnabled(true);
134 * Toggles the channel linked state for use in testing mode
136 void OutputChannelForm::linkToggled(bool state)
138 Q_UNUSED(state)
140 if (!m_inChannelTest) {
141 return; // we are not in Test Output mode
143 // find the minimum slider value for the linked ones
144 if (!parent()) {
145 return;
147 int min = MAXOUTPUT_VALUE;
148 int linked_count = 0;
149 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
150 // set the linked channels of the parent widget to the same value
151 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
152 if (!outputChannelForm->ui->actuatorLink->checkState()) {
153 continue;
155 if (this == outputChannelForm) {
156 continue;
158 int value = outputChannelForm->ui->actuatorNeutral->value();
159 if (min > value) {
160 min = value;
162 linked_count++;
165 if (linked_count <= 0) {
166 return; // no linked channels
168 // set the linked channels to the same value
169 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
170 if (!outputChannelForm->ui->actuatorLink->checkState()) {
171 continue;
173 outputChannelForm->ui->actuatorNeutral->setValue(min);
177 int OutputChannelForm::max() const
179 return ui->actuatorMax->value();
183 * Set maximal channel value.
185 void OutputChannelForm::setMax(int maximum)
187 setRange(ui->actuatorMax->value(), maximum);
190 int OutputChannelForm::min() const
192 return ui->actuatorMin->value();
196 * Set minimal channel value.
198 void OutputChannelForm::setMin(int minimum)
200 setRange(minimum, ui->actuatorMin->value());
203 int OutputChannelForm::neutral() const
205 return ui->actuatorNeutral->value();
209 * Set neutral of channel.
211 void OutputChannelForm::setNeutral(int value)
213 ui->actuatorNeutral->setValue(value);
217 * Set minimal and maximal channel value.
219 void OutputChannelForm::setRange(int minimum, int maximum)
221 ui->actuatorMin->setValue(minimum);
222 ui->actuatorMax->setValue(maximum);
223 setChannelRange();
227 * Sets the minimum/maximum value of the channel output sliders.
228 * Have to do it here because setMinimum is not a slot.
230 * One added trick: if the slider is at its min when the value
231 * is changed, then keep it on the min.
233 void OutputChannelForm::setChannelRange()
235 int minValue = ui->actuatorMin->value();
236 int maxValue = ui->actuatorMax->value();
238 int oldMini = ui->actuatorNeutral->minimum();
239 int oldMaxi = ui->actuatorNeutral->maximum();
241 m_mixerType = outputMixerType();
243 // Red handle for Motors
244 if ((m_mixerType == "Motor") || (m_mixerType == "ReversableMotor")) {
245 ui->actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(255, 100, 100); width: 18px; height: 28px;"
246 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
247 } else {
248 ui->actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(196, 196, 196); width: 18px; height: 28px;"
249 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
252 // Normal motor will be *** never *** reversed : without arming a "Min" value (like 1900) can be applied !
253 if (m_mixerType == "Motor") {
254 if (minValue >= maxValue) {
255 // Keep old values
256 ui->actuatorMin->setValue(oldMini);
257 ui->actuatorMax->setValue(oldMaxi);
259 ui->actuatorRev->setChecked(false);
260 ui->actuatorRev->setEnabled(false);
261 ui->actuatorNeutral->setInvertedAppearance(false);
262 ui->actuatorNeutral->setRange(ui->actuatorMin->value(), ui->actuatorMax->value());
263 } else {
264 // Others output (!Motor)
265 // Auto check reverse checkbox SpinBox Min/Max changes
266 ui->actuatorRev->setEnabled(true);
267 if (minValue <= maxValue) {
268 ui->actuatorRev->setChecked(false);
269 ui->actuatorNeutral->setInvertedAppearance(false);
270 ui->actuatorNeutral->setRange(minValue, maxValue);
271 } else {
272 ui->actuatorRev->setChecked(true);
273 ui->actuatorNeutral->setInvertedAppearance(true);
274 ui->actuatorNeutral->setRange(maxValue, minValue);
277 // If old neutral was Min, stay Min
278 if (ui->actuatorNeutral->value() == oldMini) {
279 ui->actuatorNeutral->setValue(ui->actuatorNeutral->minimum());
282 // Enable only outputs already set in mixer
283 if (m_mixerType != "Disabled") {
284 ui->actuatorMin->setEnabled(true);
285 ui->actuatorMax->setEnabled(true);
286 ui->actuatorNeutral->setEnabled(true);
287 ui->actuatorValue->setEnabled(true);
288 ui->actuatorLink->setEnabled(true);
289 } else {
290 ui->actuatorMin->setEnabled(false);
291 ui->actuatorMax->setEnabled(false);
292 ui->actuatorRev->setEnabled(false);
293 ui->actuatorLink->setEnabled(false);
294 ui->actuatorMin->setValue(1000);
295 ui->actuatorMax->setValue(1000);
296 ui->actuatorNeutral->setRange(minValue, maxValue);
297 ui->actuatorNeutral->setValue(minValue);
298 ui->actuatorValue->setEnabled(false);
303 * Reverses the channel when the checkbox is clicked
305 void OutputChannelForm::reverseChannel(bool state)
307 // if 'state' (reverse channel requested) apply only if not already reversed
308 if ((state && (ui->actuatorMax->value() > ui->actuatorMin->value()))
309 || (!state && (ui->actuatorMax->value() < ui->actuatorMin->value()))) {
310 // Now, swap the min & max values (spin boxes)
311 int temp = ui->actuatorMax->value();
312 ui->actuatorMax->setValue(ui->actuatorMin->value());
313 ui->actuatorMin->setValue(temp);
314 ui->actuatorNeutral->setInvertedAppearance(state);
316 setChannelRange();
317 return;
322 * Emits the channel value which will be send to the UAV to move the servo.
323 * Returns immediately if we are not in testing mode.
325 void OutputChannelForm::sendChannelTest(int value)
327 int in_value = value;
329 QSlider *ob = (QSlider *)QObject::sender();
331 if (!ob) {
332 return;
335 // update the label
336 ui->actuatorValue->setValue(value);
338 if (ui->actuatorLink->checkState() && parent()) {
339 // the channel is linked to other channels
340 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
341 // set the linked channels of the parent widget to the same value
342 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
343 if (this == outputChannelForm) {
344 continue;
346 if (!outputChannelForm->ui->actuatorLink->checkState()) {
347 continue;
350 int val = in_value;
351 if (val < outputChannelForm->ui->actuatorNeutral->minimum()) {
352 val = outputChannelForm->ui->actuatorNeutral->minimum();
354 if (val > outputChannelForm->ui->actuatorNeutral->maximum()) {
355 val = outputChannelForm->ui->actuatorNeutral->maximum();
358 if (outputChannelForm->ui->actuatorNeutral->value() == val) {
359 continue;
362 outputChannelForm->ui->actuatorNeutral->setValue(val);
363 outputChannelForm->ui->actuatorValue->setValue(val);
367 if (!m_inChannelTest) {
368 // we are not in Test Output mode
369 return;
371 emit channelChanged(index(), value);
376 * Returns MixerType
378 QString OutputChannelForm::outputMixerType()
380 UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
382 Q_ASSERT(mixer);
384 QString mixerNumType = QString("Mixer%1Type").arg(index() + 1);
385 UAVObjectField *field = mixer->getField(mixerNumType);
386 Q_ASSERT(field);
387 QString mixerType = field->getValue().toString();
389 return mixerType;