2 ******************************************************************************
4 * @file outputchannelform.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup ConfigPlugin Config Plugin
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
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)
38 // The convention for OP is Channel 1 to Channel 10.
39 ui
.actuatorNumber
->setText(QString("%1").arg(index
+ 1));
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)));
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
);
61 disableMouseWheelEvents();
64 OutputChannelForm::~OutputChannelForm()
69 QString
OutputChannelForm::name()
71 return ui
.actuatorName
->text();
74 QString
OutputChannelForm::bank()
76 return ui
.actuatorBankNumber
->text();
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();
93 QString("background-color: rgb(%1, %2, %3)")
94 .arg(color
.red()).arg(color
.green()).arg(color
.blue()));
95 ui
.actuatorNumberFrame
->setStyleSheet(stylesheet
);
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
) {
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
)
138 if (!m_inChannelTest
) {
139 return; // we are not in Test Output mode
141 // find the minimum slider value for the linked ones
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()) {
153 if (this == outputChannelForm
) {
156 int value
= outputChannelForm
->ui
.actuatorNeutral
->value();
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()) {
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
);
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; }");
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
) {
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());
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
);
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);
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
);
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();
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
) {
344 if (!outputChannelForm
->ui
.actuatorLink
->checkState()) {
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
) {
360 outputChannelForm
->ui
.actuatorNeutral
->setValue(val
);
361 outputChannelForm
->ui
.actuatorValue
->setValue(val
);
365 if (!m_inChannelTest
) {
366 // we are not in Test Output mode
369 emit
channelChanged(index(), value
);
376 QString
OutputChannelForm::outputMixerType()
378 UAVDataObject
*mixer
= dynamic_cast<UAVDataObject
*>(getObjectManager()->getObject(QString("MixerSettings")));
382 QString mixerNumType
= QString("Mixer%1Type").arg(index() + 1);
383 UAVObjectField
*field
= mixer
->getField(mixerNumType
);
385 QString mixerType
= field
->getValue().toString();