LP-56 - Better txpid option namings, fix tabs-spaces, tooltips. headers, variable...
[librepilot.git] / ground / openpilotgcs / src / plugins / config / outputchannelform.cpp
blobea8636250bb435a9a1d844ad27475ca666dda728
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 #define MAXOUTPUT_VALUE 2500
31 #define MINOUTPUT_VALUE 500
33 OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) :
34 ChannelForm(index, parent), ui(), m_inChannelTest(false)
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 // Set limits
52 ui.actuatorMin->setMaximum(MAXOUTPUT_VALUE);
53 ui.actuatorMax->setMaximum(MAXOUTPUT_VALUE);
54 ui.actuatorValue->setMaximum(MAXOUTPUT_VALUE);
55 ui.actuatorMin->setMinimum(MINOUTPUT_VALUE);
56 ui.actuatorMax->setMinimum(MINOUTPUT_VALUE);
57 ui.actuatorValue->setMinimum(MINOUTPUT_VALUE);
59 setChannelRange();
61 disableMouseWheelEvents();
64 OutputChannelForm::~OutputChannelForm()
66 // Do nothing
69 QString OutputChannelForm::name()
71 return ui.actuatorName->text();
74 QString OutputChannelForm::bank()
76 return ui.actuatorBankNumber->text();
79 /**
80 * Set the channel assignment label.
82 void OutputChannelForm::setName(const QString &name)
84 ui.actuatorName->setText(name);
87 void OutputChannelForm::setColor(const QColor &color)
89 QString stylesheet = ui.actuatorNumberFrame->styleSheet();
91 stylesheet = stylesheet.split("background-color").first();
92 stylesheet.append(
93 QString("background-color: rgb(%1, %2, %3)")
94 .arg(color.red()).arg(color.green()).arg(color.blue()));
95 ui.actuatorNumberFrame->setStyleSheet(stylesheet);
98 /**
99 * Set the channel bank label.
101 void OutputChannelForm::setBank(const QString &bank)
103 ui.actuatorBankNumber->setText(bank);
107 * Restrict UI to protect users from accidental misuse.
109 void OutputChannelForm::enableChannelTest(bool state)
111 if (m_inChannelTest == state) {
112 return;
114 m_inChannelTest = state;
116 if (m_inChannelTest) {
117 // Prevent stupid users from touching the minimum & maximum ranges while
118 // moving the sliders. Thanks Ivan for the tip :)
119 ui.actuatorMin->setEnabled(false);
120 ui.actuatorMax->setEnabled(false);
121 ui.actuatorRev->setEnabled(false);
122 } else if (m_mixerType != "Disabled") {
123 ui.actuatorMin->setEnabled(true);
124 ui.actuatorMax->setEnabled(true);
125 if (m_mixerType != "Motor") {
126 ui.actuatorRev->setEnabled(true);
132 * Toggles the channel linked state for use in testing mode
134 void OutputChannelForm::linkToggled(bool state)
136 Q_UNUSED(state)
138 if (!m_inChannelTest) {
139 return; // we are not in Test Output mode
141 // find the minimum slider value for the linked ones
142 if (!parent()) {
143 return;
145 int min = MAXOUTPUT_VALUE;
146 int linked_count = 0;
147 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
148 // set the linked channels of the parent widget to the same value
149 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
150 if (!outputChannelForm->ui.actuatorLink->checkState()) {
151 continue;
153 if (this == outputChannelForm) {
154 continue;
156 int value = outputChannelForm->ui.actuatorNeutral->value();
157 if (min > value) {
158 min = value;
160 linked_count++;
163 if (linked_count <= 0) {
164 return; // no linked channels
166 // set the linked channels to the same value
167 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
168 if (!outputChannelForm->ui.actuatorLink->checkState()) {
169 continue;
171 outputChannelForm->ui.actuatorNeutral->setValue(min);
175 int OutputChannelForm::max() const
177 return ui.actuatorMax->value();
181 * Set maximal channel value.
183 void OutputChannelForm::setMax(int maximum)
185 setRange(ui.actuatorMax->value(), maximum);
188 int OutputChannelForm::min() const
190 return ui.actuatorMin->value();
194 * Set minimal channel value.
196 void OutputChannelForm::setMin(int minimum)
198 setRange(minimum, ui.actuatorMin->value());
201 int OutputChannelForm::neutral() const
203 return ui.actuatorNeutral->value();
207 * Set neutral of channel.
209 void OutputChannelForm::setNeutral(int value)
211 ui.actuatorNeutral->setValue(value);
215 * Set minimal and maximal channel value.
217 void OutputChannelForm::setRange(int minimum, int maximum)
219 ui.actuatorMin->setValue(minimum);
220 ui.actuatorMax->setValue(maximum);
221 setChannelRange();
225 * Sets the minimum/maximum value of the channel output sliders.
226 * Have to do it here because setMinimum is not a slot.
228 * One added trick: if the slider is at its min when the value
229 * is changed, then keep it on the min.
231 void OutputChannelForm::setChannelRange()
233 int minValue = ui.actuatorMin->value();
234 int maxValue = ui.actuatorMax->value();
236 int oldMini = ui.actuatorNeutral->minimum();
237 int oldMaxi = ui.actuatorNeutral->maximum();
239 m_mixerType = outputMixerType();
241 // Red handle for Motors
242 if ((m_mixerType == "Motor") || (m_mixerType == "ReversableMotor")) {
243 ui.actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(255, 100, 100); width: 18px; height: 28px;"
244 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
245 } else {
246 ui.actuatorNeutral->setStyleSheet("QSlider::handle:horizontal { background: rgb(196, 196, 196); width: 18px; height: 28px;"
247 "margin: -3px 0; border-radius: 3px; border: 1px solid #777; }");
250 // Normal motor will be *** never *** reversed : without arming a "Min" value (like 1900) can be applied !
251 if (m_mixerType == "Motor") {
252 if (minValue >= maxValue) {
253 // Keep old values
254 ui.actuatorMin->setValue(oldMini);
255 ui.actuatorMax->setValue(oldMaxi);
257 ui.actuatorRev->setChecked(false);
258 ui.actuatorRev->setEnabled(false);
259 ui.actuatorNeutral->setInvertedAppearance(false);
260 ui.actuatorNeutral->setRange(ui.actuatorMin->value(), ui.actuatorMax->value());
261 } else {
262 // Others output (!Motor)
263 // Auto check reverse checkbox SpinBox Min/Max changes
264 ui.actuatorRev->setEnabled(true);
265 if (minValue <= maxValue) {
266 ui.actuatorRev->setChecked(false);
267 ui.actuatorNeutral->setInvertedAppearance(false);
268 ui.actuatorNeutral->setRange(minValue, maxValue);
269 } else {
270 ui.actuatorRev->setChecked(true);
271 ui.actuatorNeutral->setInvertedAppearance(true);
272 ui.actuatorNeutral->setRange(maxValue, minValue);
275 // If old neutral was Min, stay Min
276 if (ui.actuatorNeutral->value() == oldMini) {
277 ui.actuatorNeutral->setValue(ui.actuatorNeutral->minimum());
280 // Enable only outputs already set in mixer
281 if (m_mixerType != "Disabled") {
282 ui.actuatorMin->setEnabled(true);
283 ui.actuatorMax->setEnabled(true);
284 ui.actuatorNeutral->setEnabled(true);
285 ui.actuatorValue->setEnabled(true);
286 ui.actuatorLink->setEnabled(true);
287 } else {
288 ui.actuatorMin->setEnabled(false);
289 ui.actuatorMax->setEnabled(false);
290 ui.actuatorRev->setEnabled(false);
291 ui.actuatorLink->setEnabled(false);
292 ui.actuatorMin->setValue(1000);
293 ui.actuatorMax->setValue(1000);
294 ui.actuatorNeutral->setRange(minValue, maxValue);
295 ui.actuatorNeutral->setValue(minValue);
296 ui.actuatorValue->setEnabled(false);
301 * Reverses the channel when the checkbox is clicked
303 void OutputChannelForm::reverseChannel(bool state)
305 // if 'state' (reverse channel requested) apply only if not already reversed
306 if ((state && (ui.actuatorMax->value() > ui.actuatorMin->value()))
307 || (!state && (ui.actuatorMax->value() < ui.actuatorMin->value()))) {
308 // Now, swap the min & max values (spin boxes)
309 int temp = ui.actuatorMax->value();
310 ui.actuatorMax->setValue(ui.actuatorMin->value());
311 ui.actuatorMin->setValue(temp);
312 ui.actuatorNeutral->setInvertedAppearance(state);
314 setChannelRange();
315 return;
320 * Emits the channel value which will be send to the UAV to move the servo.
321 * Returns immediately if we are not in testing mode.
323 void OutputChannelForm::sendChannelTest(int value)
325 int in_value = value;
327 QSlider *ob = (QSlider *)QObject::sender();
329 if (!ob) {
330 return;
333 // update the label
334 ui.actuatorValue->setValue(value);
336 if (ui.actuatorLink->checkState() && parent()) {
337 // the channel is linked to other channels
338 QList<OutputChannelForm *> outputChannelForms = parent()->findChildren<OutputChannelForm *>();
339 // set the linked channels of the parent widget to the same value
340 foreach(OutputChannelForm * outputChannelForm, outputChannelForms) {
341 if (this == outputChannelForm) {
342 continue;
344 if (!outputChannelForm->ui.actuatorLink->checkState()) {
345 continue;
348 int val = in_value;
349 if (val < outputChannelForm->ui.actuatorNeutral->minimum()) {
350 val = outputChannelForm->ui.actuatorNeutral->minimum();
352 if (val > outputChannelForm->ui.actuatorNeutral->maximum()) {
353 val = outputChannelForm->ui.actuatorNeutral->maximum();
356 if (outputChannelForm->ui.actuatorNeutral->value() == val) {
357 continue;
360 outputChannelForm->ui.actuatorNeutral->setValue(val);
361 outputChannelForm->ui.actuatorValue->setValue(val);
365 if (!m_inChannelTest) {
366 // we are not in Test Output mode
367 return;
369 emit channelChanged(index(), value);
374 * Returns MixerType
376 QString OutputChannelForm::outputMixerType()
378 UAVDataObject *mixer = dynamic_cast<UAVDataObject *>(getObjectManager()->getObject(QString("MixerSettings")));
380 Q_ASSERT(mixer);
382 QString mixerNumType = QString("Mixer%1Type").arg(index() + 1);
383 UAVObjectField *field = mixer->getField(mixerNumType);
384 Q_ASSERT(field);
385 QString mixerType = field->getValue().toString();
387 return mixerType;