Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / config / outputchannelform.cpp
blob421be8615ee34622975857774d1d93d2981a960e
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"
31 #include <QDebug>
33 OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) :
34 ChannelForm(index, parent), ui(new Ui::outputChannelForm), m_inChannelTest(false), m_updateChannelRangeEnabled(true)
36 ui->setupUi(this);
38 // The convention for OP is Channel 1 to Channel 10.
39 ui->actuatorNumber->setText(QString("%1").arg(index + 1));
40 setBank("-");
41 // Register for ActuatorSettings changes:
42 connect(ui->actuatorMin, SIGNAL(editingFinished()), this, SLOT(setChannelRange()));
43 connect(ui->actuatorMax, SIGNAL(editingFinished()), this, SLOT(setChannelRange()));
44 connect(ui->actuatorRev, SIGNAL(toggled(bool)), this, SLOT(reverseChannel(bool)));
45 // Now connect the channel out sliders to our signal to send updates in test mode
46 connect(ui->actuatorNeutral, SIGNAL(valueChanged(int)), this, SLOT(sendChannelTest(int)));
48 ui->actuatorLink->setChecked(false);
49 connect(ui->actuatorLink, SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool)));
51 setChannelRange();
53 disableMouseWheelEvents();
56 OutputChannelForm::~OutputChannelForm()
58 delete ui;
61 QString OutputChannelForm::name()
63 return ui->actuatorName->text();
66 QString OutputChannelForm::bank()
68 return ui->actuatorBankNumber->text();
71 /**
72 * Set the channel assignment label.
74 void OutputChannelForm::setName(const QString &name)
76 ui->actuatorName->setText(name);
79 void OutputChannelForm::setColor(const QColor &color)
81 QString stylesheet = ui->actuatorNumberFrame->styleSheet();
83 stylesheet = stylesheet.split("background-color").first();
84 stylesheet.append(
85 QString("background-color: rgb(%1, %2, %3)")
86 .arg(color.red()).arg(color.green()).arg(color.blue()));
87 ui->actuatorNumberFrame->setStyleSheet(stylesheet);
90 /**
91 * Set the channel bank label.
93 void OutputChannelForm::setBank(const QString &bank)
95 ui->actuatorBankNumber->setText(bank);
98 /**
99 * Restrict UI to protect users from accidental misuse.
101 void OutputChannelForm::enableChannelTest(bool state)
103 if (m_inChannelTest == state) {
104 return;
106 m_inChannelTest = state;
108 if (m_inChannelTest) {
109 // Prevent stupid users from touching the minimum & maximum ranges while
110 // moving the sliders. Thanks Ivan for the tip :)
111 ui->actuatorMin->setEnabled(false);
112 ui->actuatorMax->setEnabled(false);
113 ui->actuatorRev->setEnabled(false);
114 } else if (!isDisabledOutput()) {
115 ui->actuatorMin->setEnabled(true);
116 ui->actuatorMax->setEnabled(true);
117 if (!isNormalMotorOutput()) {
118 ui->actuatorRev->setEnabled(true);
124 * Enable/Disable setChannelRange
126 void OutputChannelForm::setChannelRangeEnabled(bool state)
128 if (m_updateChannelRangeEnabled == state) {
129 return;
131 m_updateChannelRangeEnabled = state;
135 * Toggles the channel linked state for use in testing mode
137 void OutputChannelForm::linkToggled(bool state)
139 Q_UNUSED(state)
141 if (!m_inChannelTest) {
142 return; // we are not in Test Output mode
144 // find the minimum slider value for the linked ones
145 if (!parent()) {
146 return;
148 int min = ui->actuatorMax->maximum();
149 int linked_count = 0;
150 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
151 // set the linked channels of the parent widget to the same value
152 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
153 if (!outputChannelForm->ui->actuatorLink->checkState()) {
154 continue;
156 if (this == outputChannelForm) {
157 continue;
159 int value = outputChannelForm->ui->actuatorNeutral->value();
160 if (min > value) {
161 min = value;
163 linked_count++;
166 if (linked_count <= 0) {
167 return; // no linked channels
169 // set the linked channels to the same value
170 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
171 if (!outputChannelForm->ui->actuatorLink->checkState()) {
172 continue;
174 outputChannelForm->ui->actuatorNeutral->setValue(min);
178 int OutputChannelForm::max() const
180 return ui->actuatorMax->value();
184 * Set maximal channel value.
186 void OutputChannelForm::setMax(int maximum)
188 setRange(ui->actuatorMax->value(), maximum);
191 int OutputChannelForm::min() const
193 return ui->actuatorMin->value();
197 * Set minimal channel value.
199 void OutputChannelForm::setMin(int minimum)
201 setRange(minimum, ui->actuatorMin->value());
204 int OutputChannelForm::neutral() const
206 return ui->actuatorNeutral->value();
210 * Set neutral of channel.
212 void OutputChannelForm::setNeutral(int value)
214 ui->actuatorNeutral->setValue(value);
219 * Set
221 void OutputChannelForm::setLimits(int actuatorMinMinimum, int actuatorMinMaximum, int actuatorMaxMinimum, int actuatorMaxMaximum)
223 ui->actuatorMin->setMaximum(actuatorMinMaximum);
224 ui->actuatorMax->setMaximum(actuatorMaxMaximum);
225 ui->actuatorMin->setMinimum(actuatorMinMinimum);
226 ui->actuatorMax->setMinimum(actuatorMaxMinimum);
227 // Neutral slider limits
228 ui->actuatorNeutral->setMinimum(actuatorMinMinimum);
229 ui->actuatorNeutral->setMaximum(actuatorMaxMaximum);
233 * Set minimal and maximal channel value.
235 void OutputChannelForm::setRange(int minimum, int maximum)
237 ui->actuatorMin->setValue(minimum);
238 ui->actuatorMax->setValue(maximum);
239 setChannelRange();
243 * Sets the minimum/maximum value of the channel output sliders.
244 * Have to do it here because setMinimum is not a slot.
246 * One added trick: if the slider is at its min when the value
247 * is changed, then keep it on the min.
249 void OutputChannelForm::setChannelRange()
251 // Disable outputs not already set in MixerSettings
252 if (isDisabledOutput()) {
253 setLimits(1000, 1000, 1000, 1000);
254 ui->actuatorMin->setValue(1000);
255 ui->actuatorMax->setValue(1000);
256 ui->actuatorRev->setChecked(false);
257 ui->actuatorLink->setChecked(false);
258 setControlsEnabled(false);
259 return;
262 if (!m_updateChannelRangeEnabled) {
263 // Nothing to do here
264 return;
267 setControlsEnabled(true);
269 int minValue = ui->actuatorMin->value();
270 int maxValue = ui->actuatorMax->value();
272 int oldMini = ui->actuatorNeutral->minimum();
273 int oldMaxi = ui->actuatorNeutral->maximum();
275 // Red handle for Motors
276 if (isNormalMotorOutput() || isReversibleMotorOutput()) {
277 ui->actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(255, 100, 100); width: 18px; height: 28px;"
278 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
279 } else {
280 ui->actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(196, 196, 196); width: 18px; height: 28px;"
281 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
284 // Normal motor will be *** never *** reversed : without arming a "Min" value (like 1900) can be applied !
285 if (isNormalMotorOutput()) {
286 if (minValue > maxValue) {
287 // Keep old values
288 ui->actuatorMin->setValue(oldMini);
289 ui->actuatorMax->setValue(oldMaxi);
291 ui->actuatorRev->setChecked(false);
292 ui->actuatorRev->setEnabled(false);
293 ui->actuatorNeutral->setInvertedAppearance(false);
294 ui->actuatorNeutral->setRange(ui->actuatorMin->value(), ui->actuatorMax->value());
295 } else {
296 // Others output (!Motor)
297 // Auto check reverse checkbox SpinBox Min/Max changes
298 ui->actuatorRev->setEnabled(true);
299 if (minValue <= maxValue) {
300 ui->actuatorRev->setChecked(false);
301 ui->actuatorNeutral->setInvertedAppearance(false);
302 ui->actuatorNeutral->setRange(minValue, maxValue);
303 } else {
304 ui->actuatorRev->setChecked(true);
305 ui->actuatorNeutral->setInvertedAppearance(true);
306 ui->actuatorNeutral->setRange(maxValue, minValue);
309 // If old neutral was Min, stay Min
310 if (ui->actuatorNeutral->value() == oldMini) {
311 ui->actuatorNeutral->setValue(ui->actuatorNeutral->minimum());
316 * Reverses the channel when the checkbox is clicked
318 void OutputChannelForm::reverseChannel(bool state)
320 // if 'state' (reverse channel requested) apply only if not already reversed
321 if ((state && (ui->actuatorMax->value() > ui->actuatorMin->value()))
322 || (!state && (ui->actuatorMax->value() < ui->actuatorMin->value()))) {
323 // Now, swap the min & max values (spin boxes)
324 int temp = ui->actuatorMax->value();
325 ui->actuatorMax->setValue(ui->actuatorMin->value());
326 ui->actuatorMin->setValue(temp);
327 ui->actuatorNeutral->setInvertedAppearance(state);
329 setChannelRange();
330 return;
335 * Enable/Disable UI controls
337 void OutputChannelForm::setControlsEnabled(bool state)
339 if (isDisabledOutput()) {
340 state = false;
342 ui->actuatorMin->setEnabled(state);
343 ui->actuatorMax->setEnabled(state);
344 ui->actuatorValue->setEnabled(state);
345 ui->actuatorLink->setEnabled(state);
346 // Reverse checkbox will be never checked
347 // or enabled for normal motor
348 if (isNormalMotorOutput()) {
349 ui->actuatorRev->setChecked(false);
350 ui->actuatorRev->setEnabled(false);
351 } else {
352 ui->actuatorRev->setEnabled(state);
357 * Emits the channel value which will be send to the UAV to move the servo.
358 * Returns immediately if we are not in testing mode.
360 void OutputChannelForm::sendChannelTest(int value)
362 int in_value = value;
364 QSlider *ob = (QSlider *)QObject::sender();
366 if (!ob) {
367 return;
370 // update the label
371 ui->actuatorValue->setValue(value);
373 if (ui->actuatorLink->checkState() && parent()) {
374 // the channel is linked to other channels
375 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
376 // set the linked channels of the parent widget to the same value
377 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
378 if (this == outputChannelForm) {
379 continue;
381 if (!outputChannelForm->ui->actuatorLink->checkState()) {
382 continue;
385 int val = in_value;
386 if (val < outputChannelForm->ui->actuatorNeutral->minimum()) {
387 val = outputChannelForm->ui->actuatorNeutral->minimum();
389 if (val > outputChannelForm->ui->actuatorNeutral->maximum()) {
390 val = outputChannelForm->ui->actuatorNeutral->maximum();
393 if (outputChannelForm->ui->actuatorNeutral->value() == val) {
394 continue;
397 outputChannelForm->ui->actuatorNeutral->setValue(val);
398 outputChannelForm->ui->actuatorValue->setValue(val);
402 if (!m_inChannelTest) {
403 // we are not in Test Output mode
404 return;
406 emit channelChanged(index(), value);
411 * Returns current neutral value
413 int OutputChannelForm::neutralValue()
415 return ui->actuatorNeutral->value();
420 * Returns MixerType
422 QString OutputChannelForm::outputMixerType()
424 UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
426 Q_ASSERT(mixer);
428 QString mixerNumType = QString("Mixer%1Type").arg(index() + 1);
429 UAVObjectField *field = mixer->getField(mixerNumType);
430 Q_ASSERT(field);
431 QString mixerType = field->getValue().toString();
433 return mixerType;
438 * Returns true if a servo output
440 bool OutputChannelForm::isServoOutput()
442 return !isNormalMotorOutput() && !isReversibleMotorOutput() && !isDisabledOutput();
447 * Returns true if output is a normal Motor
449 bool OutputChannelForm::isNormalMotorOutput()
451 return outputMixerType() == "Motor";
456 * Returns true if output is a reversible Motor
458 bool OutputChannelForm::isReversibleMotorOutput()
460 return outputMixerType() == "ReversableMotor";
465 * Returns true if output is disabled
467 bool OutputChannelForm::isDisabledOutput()
469 return outputMixerType() == "Disabled";