From 0ac62c77defea0c2edd6b71bc814a857fc2605d8 Mon Sep 17 00:00:00 2001 From: Michael Schulz Date: Wed, 9 Nov 2011 19:35:53 +0100 Subject: [PATCH 1/5] Output widget: Converted to an array of output channels. --- .../src/plugins/config/config.pro | 22 +- .../src/plugins/config/configoutputwidget.cpp | 389 ++----- .../src/plugins/config/configoutputwidget.h | 16 +- .../openpilotgcs/src/plugins/config/output.ui | 968 +----------------- .../src/plugins/config/outputchannelform.cpp | 297 ++++++ .../src/plugins/config/outputchannelform.h | 92 ++ .../src/plugins/config/outputchannelform.ui | 281 +++++ 7 files changed, 750 insertions(+), 1315 deletions(-) create mode 100644 ground/openpilotgcs/src/plugins/config/outputchannelform.cpp create mode 100644 ground/openpilotgcs/src/plugins/config/outputchannelform.h create mode 100644 ground/openpilotgcs/src/plugins/config/outputchannelform.ui diff --git a/ground/openpilotgcs/src/plugins/config/config.pro b/ground/openpilotgcs/src/plugins/config/config.pro index b99fc9edc..091a7d45c 100644 --- a/ground/openpilotgcs/src/plugins/config/config.pro +++ b/ground/openpilotgcs/src/plugins/config/config.pro @@ -1,7 +1,6 @@ TEMPLATE = lib TARGET = Config QT += svg - include(../../openpilotgcsplugin.pri) include(../../libs/utils/utils.pri) include(../../plugins/uavtalk/uavtalk.pri) @@ -10,9 +9,7 @@ include(../../plugins/uavobjects/uavobjects.pri) include(../../plugins/uavobjectutil/uavobjectutil.pri) include(../../plugins/uavsettingsimportexport/uavsettingsimportexport.pri) INCLUDEPATH += ../../libs/eigen - OTHER_FILES += Config.pluginspec - HEADERS += configplugin.h \ configgadgetconfiguration.h \ configgadgetwidget.h \ @@ -39,8 +36,8 @@ HEADERS += configplugin.h \ smartsavebutton.h \ defaulthwsettingswidget.h \ inputchannelform.h \ - configcamerastabilizationwidget.h - + configcamerastabilizationwidget.h \ + outputchannelform.h SOURCES += configplugin.cpp \ configgadgetconfiguration.cpp \ configgadgetwidget.cpp \ @@ -69,10 +66,9 @@ SOURCES += configplugin.cpp \ smartsavebutton.cpp \ defaulthwsettingswidget.cpp \ inputchannelform.cpp \ - configcamerastabilizationwidget.cpp - -FORMS += \ - airframe.ui \ + configcamerastabilizationwidget.cpp \ + outputchannelform.cpp +FORMS += airframe.ui \ cc_hw_settings.ui \ pro_hw_settings.ui \ ahrs.ui \ @@ -84,10 +80,6 @@ FORMS += \ defaultattitude.ui \ defaulthwsettings.ui \ inputchannelform.ui \ - camerastabilization.ui - + camerastabilization.ui \ + outputchannelform.ui RESOURCES += configgadget.qrc - - - - diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 0fc683da4..0b62c5442 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -26,6 +26,7 @@ */ #include "configoutputwidget.h" +#include "outputchannelform.h" #include "uavtalk/telemetrymanager.h" @@ -46,103 +47,23 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren m_config = new Ui_OutputWidget(); m_config->setupUi(this); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); addUAVObject("ActuatorSettings"); - // First of all, put all the channel widgets into lists, so that we can - // manipulate those: - - // NOTE: for historical reasons, we have objects below called ch0 to ch7, but the convention for OP is Channel 1 to Channel 8. - outLabels << m_config->ch0OutValue - << m_config->ch1OutValue - << m_config->ch2OutValue - << m_config->ch3OutValue - << m_config->ch4OutValue - << m_config->ch5OutValue - << m_config->ch6OutValue - << m_config->ch7OutValue - << m_config->ch8OutValue - << m_config->ch9OutValue; - - outSliders << m_config->ch0OutSlider - << m_config->ch1OutSlider - << m_config->ch2OutSlider - << m_config->ch3OutSlider - << m_config->ch4OutSlider - << m_config->ch5OutSlider - << m_config->ch6OutSlider - << m_config->ch7OutSlider - << m_config->ch8OutSlider - << m_config->ch9OutSlider; - - outMin << m_config->ch0OutMin - << m_config->ch1OutMin - << m_config->ch2OutMin - << m_config->ch3OutMin - << m_config->ch4OutMin - << m_config->ch5OutMin - << m_config->ch6OutMin - << m_config->ch7OutMin - << m_config->ch8OutMin - << m_config->ch9OutMin; - - outMax << m_config->ch0OutMax - << m_config->ch1OutMax - << m_config->ch2OutMax - << m_config->ch3OutMax - << m_config->ch4OutMax - << m_config->ch5OutMax - << m_config->ch6OutMax - << m_config->ch7OutMax - << m_config->ch8OutMax - << m_config->ch9OutMax; - - reversals << m_config->ch0Rev - << m_config->ch1Rev - << m_config->ch2Rev - << m_config->ch3Rev - << m_config->ch4Rev - << m_config->ch5Rev - << m_config->ch6Rev - << m_config->ch7Rev - << m_config->ch8Rev - << m_config->ch9Rev; - - links << m_config->ch0Link - << m_config->ch1Link - << m_config->ch2Link - << m_config->ch3Link - << m_config->ch4Link - << m_config->ch5Link - << m_config->ch6Link - << m_config->ch7Link - << m_config->ch8Link - << m_config->ch9Link; - + // NOTE: we have channel indices from 0 to 9, but the convention for OP is Channel 1 to Channel 10. // Register for ActuatorSettings changes: - for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { - connect(outMin[i], SIGNAL(editingFinished()), this, SLOT(setChOutRange())); - connect(outMax[i], SIGNAL(editingFinished()), this, SLOT(setChOutRange())); - connect(reversals[i], SIGNAL(toggled(bool)), this, SLOT(reverseChannel(bool))); - // Now connect the channel out sliders to our signal to send updates in test mode - connect(outSliders[i], SIGNAL(valueChanged(int)), this, SLOT(sendChannelTest(int))); - - addWidget(outMin[i]); - addWidget(outMax[i]); - addWidget(reversals[i]); - addWidget(outSliders[i]); - addWidget(links[i]); + for (unsigned int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) + { + OutputChannelForm *form = new OutputChannelForm(i, this, i==0); + connect(m_config->channelOutTest, SIGNAL(toggled(bool)), + form, SLOT(enableChannelTest(bool))); + connect(form, SIGNAL(channelChanged(int,int)), + this, SLOT(sendChannelTest(int,int))); + m_config->channelLayout->addWidget(form); } connect(m_config->channelOutTest, SIGNAL(toggled(bool)), this, SLOT(runChannelTests(bool))); - for (int i = 0; i < links.count(); i++) - links[i]->setChecked(false); - for (int i = 0; i < links.count(); i++) - connect(links[i], SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool))); - - refreshWidgetsValues(); firstUpdate = true; @@ -166,37 +87,6 @@ ConfigOutputWidget::~ConfigOutputWidget() // ************************************ -/** - Toggles the channel linked state for use in testing mode - */ -void ConfigOutputWidget::linkToggled(bool state) -{ - Q_UNUSED(state) - // find the minimum slider value for the linked ones - int min = 10000; - int linked_count = 0; - for (int i = 0; i < outSliders.count(); i++) - { - if (!links[i]->checkState()) continue; - int value = outSliders[i]->value(); - if (min > value) min = value; - linked_count++; - } - - if (linked_count <= 0) - return; // no linked channels - - if (!m_config->channelOutTest->checkState()) - return; // we are not in Test Output mode - - // set the linked channels to the same value - for (int i = 0; i < outSliders.count(); i++) - { - if (!links[i]->checkState()) continue; - outSliders[i]->setValue(min); - } -} - /** Toggles the channel testing mode by making the GCS take over the ActuatorCommand objects @@ -243,77 +133,41 @@ void ConfigOutputWidget::runChannelTests(bool state) mdata.gcsTelemetryAcked = false; mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE; mdata.gcsTelemetryUpdatePeriod = 100; - - // Prevent stupid users from touching the minimum & maximum ranges while - // moving the sliders. Thanks Ivan for the tip :) - foreach (QSpinBox* box, outMin) { - box->setEnabled(false); - } - foreach (QSpinBox* box, outMax) { - box->setEnabled(false); - } - foreach (QCheckBox* box, reversals) { - box->setEnabled(false); - } - } else { mdata = accInitialData; // Restore metadata - foreach (QSpinBox* box, outMin) { - box->setEnabled(true); - } - foreach (QSpinBox* box, outMax) { - box->setEnabled(true); - } - foreach (QCheckBox* box, reversals) { - box->setEnabled(true); - } - } obj->setMetadata(mdata); } +OutputChannelForm* ConfigOutputWidget::getOutputChannelForm(const int index) const +{ + QList outputChannelForms = findChildren(); + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + if( outputChannelForm->index() == index) + return outputChannelForm; + } + + // no OutputChannelForm found with given index + return NULL; +} + /** * Set the label for a channel output assignement */ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) { + //FIXME: use signal/ slot approach UAVObjectField* field = obj->getField(str); QStringList options = field->getOptions(); - switch (options.indexOf(field->getValue().toString())) { - case 0: - m_config->ch0Output->setText(str); - break; - case 1: - m_config->ch1Output->setText(str); - break; - case 2: - m_config->ch2Output->setText(str); - break; - case 3: - m_config->ch3Output->setText(str); - break; - case 4: - m_config->ch4Output->setText(str); - break; - case 5: - m_config->ch5Output->setText(str); - break; - case 6: - m_config->ch6Output->setText(str); - break; - case 7: - m_config->ch7Output->setText(str); - break; - case 8: - m_config->ch8Output->setText(str); - break; - case 9: - m_config->ch9Output->setText(str); - break; - } + int index = options.indexOf(field->getValue().toString()); + + OutputChannelForm *outputChannelForm = getOutputChannelForm(index); + if(outputChannelForm) + outputChannelForm->setAssignment(str); } /** @@ -335,48 +189,19 @@ void ConfigOutputWidget::setSpinningArmed(bool val) Sends the channel value to the UAV to move the servo. Returns immediately if we are not in testing mode */ -void ConfigOutputWidget::sendChannelTest(int value) +void ConfigOutputWidget::sendChannelTest(int index, int value) { - int in_value = value; + if (!m_config->channelOutTest->isChecked()) + return; - QSlider *ob = (QSlider *)QObject::sender(); - if (!ob) return; - int index = outSliders.indexOf(ob); - if (index < 0) return; + if(index < 0 || (unsigned)index >= ActuatorCommand::CHANNEL_NUMELEM) + return; - if (reversals[index]->isChecked()) - value = outMin[index]->value() - value + outMax[index]->value(); // the chsnnel is reversed - - // update the label - outLabels[index]->setText(QString::number(value)); - - if (links[index]->checkState()) - { // the channel is linked to other channels - // set the linked channels to the same value - for (int i = 0; i < outSliders.count(); i++) - { - if (i == index) continue; - if (!links[i]->checkState()) continue; - - int val = in_value; - if (val < outSliders[i]->minimum()) val = outSliders[i]->minimum(); - if (val > outSliders[i]->maximum()) val = outSliders[i]->maximum(); - - if (outSliders[i]->value() == val) continue; - - outSliders[i]->setValue(val); - outLabels[i]->setText(QString::number(val)); - } - } - - if (!m_config->channelOutTest->isChecked()) - return; - - UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); - if (!obj) return; - UAVObjectField *channel = obj->getField("Channel"); - if (!channel) return; - channel->setValue(value, index); + UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); + if (!obj) return; + UAVObjectField *channel = obj->getField("Channel"); + if (!channel) return; + channel->setValue(value, index); obj->updated(); } @@ -396,8 +221,11 @@ void ConfigOutputWidget::refreshWidgetsValues() UAVObjectManager *objManager = pm->getObject(); // Reset all channel assignements: - for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) - outLabels[i]->setText("-"); + QList outputChannelForms = findChildren(); + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + outputChannelForm->setAssignment("-"); + } // Get the channel assignements: UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); @@ -447,34 +275,21 @@ void ConfigOutputWidget::refreshWidgetsValues() } } - // Get Channel ranges: - for (int i=0;igetField(QString("ChannelMin")); - int minValue = field->getValue(i).toInt(); - outMin[i]->setValue(minValue); + int minValue = field->getValue(outputChannelForm->index()).toInt(); field = obj->getField(QString("ChannelMax")); - int maxValue = field->getValue(i).toInt(); - outMax[i]->setValue(maxValue); - if (maxValue>minValue) { - outSliders[i]->setMinimum(minValue); - outSliders[i]->setMaximum(maxValue); - reversals[i]->setChecked(false); - } else { - outSliders[i]->setMinimum(maxValue); - outSliders[i]->setMaximum(minValue); - reversals[i]->setChecked(true); - } + int maxValue = field->getValue(outputChannelForm->index()).toInt(); + outputChannelForm->minmax(minValue, maxValue); + + field = obj->getField(QString("ChannelNeutral")); + int value = field->getValue(outputChannelForm->index()).toInt(); + outputChannelForm->neutral(value); } - field = obj->getField(QString("ChannelNeutral")); - for (int i=0; igetValue(i).toInt(); - outSliders[i]->setValue(value); - outLabels[i]->setText(QString::number(value)); - } setDirty(dirty); - } /** @@ -488,101 +303,31 @@ void ConfigOutputWidget::updateObjectsFromWidgets() Q_ASSERT(obj); // Now send channel ranges: - UAVObjectField * field = obj->getField(QString("ChannelMax")); - for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { - field->setValue(outMax[i]->value(),i); - } + UAVObjectField * field; + QList outputChannelForms = findChildren(); + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + field = obj->getField(QString("ChannelMax")); + Q_ASSERT(field); + field->setValue(outputChannelForm->max(), outputChannelForm->index()); - field = obj->getField(QString("ChannelMin")); - for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { - field->setValue(outMin[i]->value(),i); - } + field = obj->getField(QString("ChannelMin")); + Q_ASSERT(field); + field->setValue(outputChannelForm->min(), outputChannelForm->index()); - field = obj->getField(QString("ChannelNeutral")); - for (int i = 0; i < ActuatorCommand::CHANNEL_NUMELEM; i++) { - field->setValue(outSliders[i]->value(),i); + field = obj->getField(QString("ChannelNeutral")); + Q_ASSERT(field); + field->setValue(outputChannelForm->neutral(), outputChannelForm->index()); } field = obj->getField(QString("ChannelUpdateFreq")); + Q_ASSERT(field); field->setValue(m_config->outputRate1->value(),0); field->setValue(m_config->outputRate2->value(),1); field->setValue(m_config->outputRate3->value(),2); field->setValue(m_config->outputRate4->value(),3); } -/** - Sets the minimum/maximum value of the channel 0 to seven output sliders. - Have to do it here because setMinimum is not a slot. - - One added trick: if the slider is at its min when the value - is changed, then keep it on the min. - */ -void ConfigOutputWidget::setChOutRange() -{ - QSpinBox *spinbox = (QSpinBox*)QObject::sender(); - - int index = outMin.indexOf(spinbox); // This is the channel number - if (index < 0) - index = outMax.indexOf(spinbox); // We can't know if the signal came from min or max - - QSlider *slider = outSliders[index]; - - int oldMini = slider->minimum(); -// int oldMaxi = slider->maximum(); - - if (outMin[index]->value()value()) - { - slider->setRange(outMin[index]->value(), outMax[index]->value()); - reversals[index]->setChecked(false); - } - else - { - slider->setRange(outMax[index]->value(), outMin[index]->value()); - reversals[index]->setChecked(true); - } - - if (slider->value() == oldMini) - slider->setValue(slider->minimum()); - -// if (slider->value() == oldMaxi) -// slider->setValue(slider->maximum()); // this can be dangerous if it happens to be controlling a motor at the time! -} - -/** - Reverses the channel when the checkbox is clicked - */ -void ConfigOutputWidget::reverseChannel(bool state) -{ - QCheckBox *checkbox = (QCheckBox*)QObject::sender(); - int index = reversals.indexOf(checkbox); // This is the channel number - - // Sanity check: if state became true, make sure the Maxvalue was higher than Minvalue - // the situations below can happen! - if (state && (outMax[index]->value()value())) - return; - if (!state && (outMax[index]->value()>outMin[index]->value())) - return; - - // Now, swap the min & max values (only on the spinboxes, the slider - // does not change! - int temp = outMax[index]->value(); - outMax[index]->setValue(outMin[index]->value()); - outMin[index]->setValue(temp); - - // Also update the channel value - // This is a trick to force the slider to update its value and - // emit the right signal itself, because our sendChannelTest(int) method - // relies on the object sender's identity. - if (outSliders[index]->value()maximum()) { - outSliders[index]->setValue(outSliders[index]->value()+1); - outSliders[index]->setValue(outSliders[index]->value()-1); - } else { - outSliders[index]->setValue(outSliders[index]->value()-1); - outSliders[index]->setValue(outSliders[index]->value()+1); - } - -} - void ConfigOutputWidget::openHelp() { diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h index 492109df1..3b475eb0c 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h @@ -37,6 +37,7 @@ #include class Ui_OutputWidget; +class OutputChannelForm; class ConfigOutputWidget: public ConfigTaskWidget { @@ -55,18 +56,12 @@ private: void assignChannel(UAVDataObject *obj, QString str); void assignOutputChannel(UAVDataObject *obj, QString str); + OutputChannelForm* getOutputChannelForm(const int index) const; int mccDataRate; UAVObject::Metadata accInitialData; - QList outSliders; - QList outMin; - QList outMax; - QList reversals; - QList links; - QList outLabels; - bool firstUpdate; @@ -74,10 +69,9 @@ private slots: virtual void refreshWidgetsValues(); void updateObjectsFromWidgets(); void runChannelTests(bool state); - void sendChannelTest(int value); - void setChOutRange(); - void reverseChannel(bool state); - void linkToggled(bool state); + void sendChannelTest(int index, int value); + void setChOutRange(); + void reverseChannel(bool state); void setSpinningArmed(bool val); void openHelp(); }; diff --git a/ground/openpilotgcs/src/plugins/config/output.ui b/ground/openpilotgcs/src/plugins/config/output.ui index b66c12cdc..47940e1ae 100644 --- a/ground/openpilotgcs/src/plugins/config/output.ui +++ b/ground/openpilotgcs/src/plugins/config/output.ui @@ -210,933 +210,7 @@ Leave at 50Hz for fixed wing. - - - - - Channel 1: - - - - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum PWM value, beware of not overdriving your servo.</p></body></html> - - - 9999 - - - - - - - true - - - 9999 - - - Qt::Horizontal - - - - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum PWM value, beware of not overdriving your servo.</p></body></html> - - - 9999 - - - - - - - Current value of slider. - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Link - - - - - - - Rev. - - - - - - - Channel 2: - - - - - - - true - - - 9999 - - - - - - - true - - - 9999 - - - Qt::Horizontal - - - - - - - true - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Channel 3: - - - - - - - true - - - 9999 - - - - - - - true - - - 9999 - - - Qt::Horizontal - - - - - - - true - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Channel 4: - - - - - - - true - - - 9999 - - - - - - - true - - - 9999 - - - Qt::Horizontal - - - - - - - true - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Channel 5: - - - - - - - 9999 - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Channel 6: - - - - - - - 9999 - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Channel 7: - - - - - - - Channel 8: - - - - - - - 9999 - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - 9999 - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - Assignment - - - - - - - Min - - - - - - - Neutral (slowest for motor) - - - - - - - Max - - - - - - - Channel 9: - - - - - - - Channel 10: - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - - - - 9999 - - - - - - - 9999 - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - Qt::Horizontal - - - - - - - 9999 - - - - - - - 9999 - - - - - - - 0000 - - - - - - - 0000 - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - - FreeSans - 8 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'FreeSans'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Check to invert the channel.</p></body></html> - - - - - - - - - - Only used with Test Output mode - - - - - - - - - - Only used with Test Output mode - - - - - - - + @@ -1281,46 +355,6 @@ Applies and Saves all settings to SD outputRate2 outputRate3 outputRate4 - ch0OutMin - ch0OutMax - ch1OutMin - ch1OutMax - ch2OutMin - ch2OutMax - ch3OutMin - ch3OutMax - ch4OutMin - ch4OutMax - ch5OutMin - ch5OutMax - ch6OutMin - ch6OutMax - ch7OutMin - ch7OutMax - ch0OutSlider - ch0Rev - ch0Link - ch1OutSlider - ch1Rev - ch1Link - ch2OutSlider - ch2Rev - ch2Link - ch3OutSlider - ch3Rev - ch3Link - ch4OutSlider - ch4Rev - ch4Link - ch5OutSlider - ch5Rev - ch5Link - ch6OutSlider - ch6Rev - ch6Link - ch7OutSlider - ch7Rev - ch7Link channelOutTest saveRCOutputToRAM saveRCOutputToSD diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp new file mode 100644 index 000000000..938e09b5b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp @@ -0,0 +1,297 @@ +/** + ****************************************************************************** + * + * @file outputchannelform.cpp + * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Servo output configuration form for the config output gadget + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "outputchannelform.h" +#include "configoutputwidget.h" + +OutputChannelForm::OutputChannelForm(const int index, QWidget *parent, const bool showLegend) : + QWidget(parent), + ui(), + m_index(index), + m_inChannelTest(false) +{ + ui.setupUi(this); + if(!showLegend) + { + // Remove legend + QGridLayout *grid_layout = dynamic_cast(layout()); + Q_ASSERT(grid_layout); + for (int col = 0; col < grid_layout->columnCount(); col++) + { // remove every item in first row + QLayoutItem *item = grid_layout->itemAtPosition(0, col); + if (!item) continue; + // get widget from layout item + QWidget *legend_widget = item->widget(); + if (!legend_widget) continue; + // delete widget + grid_layout->removeWidget(legend_widget); + delete legend_widget; + } + } + + // The convention for OP is Channel 1 to Channel 10. + ui.actuatorNumber->setText(QString("%1:").arg(m_index+1)); + + // Register for ActuatorSettings changes: + connect(ui.actuatorMin, SIGNAL(editingFinished()), + this, SLOT(setChannelRange())); + connect(ui.actuatorMax, SIGNAL(editingFinished()), + this, SLOT(setChannelRange())); + connect(ui.actuatorRev, SIGNAL(toggled(bool)), + this, SLOT(reverseChannel(bool))); + // Now connect the channel out sliders to our signal to send updates in test mode + connect(ui.actuatorNeutral, SIGNAL(valueChanged(int)), + this, SLOT(sendChannelTest(int))); + + ui.actuatorLink->setChecked(false); + connect(ui.actuatorLink, SIGNAL(toggled(bool)), + this, SLOT(linkToggled(bool))); +} + +OutputChannelForm::~OutputChannelForm() +{ + // Do nothing +} + +/** + * Restrict UI to protect users from accidental misuse. + */ +void OutputChannelForm::enableChannelTest(bool state) +{ + if (m_inChannelTest == state) return; + m_inChannelTest = state; + + if(m_inChannelTest) + { + // Prevent stupid users from touching the minimum & maximum ranges while + // moving the sliders. Thanks Ivan for the tip :) + ui.actuatorMin->setEnabled(false); + ui.actuatorMax->setEnabled(false); + ui.actuatorRev->setEnabled(false); + } + else + { + ui.actuatorMin->setEnabled(true); + ui.actuatorMax->setEnabled(true); + ui.actuatorRev->setEnabled(true); + } +} + + +/** + * Toggles the channel linked state for use in testing mode + */ +void OutputChannelForm::linkToggled(bool state) +{ + Q_UNUSED(state) + + if (!m_inChannelTest) + return; // we are not in Test Output mode + + // find the minimum slider value for the linked ones + if (!parent()) return; + int min = 10000; + int linked_count = 0; + QList outputChannelForms = parent()->findChildren(); + // set the linked channels of the parent widget to the same value + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + if (!outputChannelForm->ui.actuatorLink->checkState()) + continue; + if (this == outputChannelForm) + continue; + int value = outputChannelForm->ui.actuatorNeutral->value(); + if(min > value) min = value; + linked_count++; + } + + if (linked_count <= 0) + return; // no linked channels + + // set the linked channels to the same value + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + if (!outputChannelForm->ui.actuatorLink->checkState()) + continue; + outputChannelForm->ui.actuatorNeutral->setValue(min); + } +} + +/** + * Set maximal channel value. + */ +void OutputChannelForm::max(int maximum) +{ + minmax(ui.actuatorMin->value(), maximum); +} + +/** + * Set minimal channel value. + */ +void OutputChannelForm::min(int minimum) +{ + minmax(minimum, ui.actuatorMax->value()); +} + +/** + * Set minimal and maximal channel value. + */ +void OutputChannelForm::minmax(int minimum, int maximum) +{ + ui.actuatorMin->setValue(minimum); + ui.actuatorMax->setValue(maximum); + setChannelRange(); + if(ui.actuatorMin->value() > ui.actuatorMax->value()) + ui.actuatorRev->setChecked(true); + else + ui.actuatorRev->setChecked(false); +} + +/** + * Set neutral of channel. + */ +void OutputChannelForm::neutral(int value) +{ + ui.actuatorNeutral->setValue(value); +} + +/** + * Set the channel assignment label. + */ +void OutputChannelForm::setAssignment(const QString &assignment) +{ + ui.actuatorName->setText(assignment); +} + +/** + * Sets the minimum/maximum value of the channel output sliders. + * Have to do it here because setMinimum is not a slot. + * + * One added trick: if the slider is at its min when the value + * is changed, then keep it on the min. + */ +void OutputChannelForm::setChannelRange() +{ + int oldMini = ui.actuatorNeutral->minimum(); +// int oldMaxi = ui.actuatorNeutral->maximum(); + + if (ui.actuatorMin->value() < ui.actuatorMax->value()) + { + ui.actuatorNeutral->setRange(ui.actuatorMin->value(), ui.actuatorMax->value()); + ui.actuatorRev->setChecked(false); + } + else + { + ui.actuatorNeutral->setRange(ui.actuatorMax->value(), ui.actuatorMin->value()); + ui.actuatorRev->setChecked(true); + } + + if (ui.actuatorNeutral->value() == oldMini) + ui.actuatorNeutral->setValue(ui.actuatorNeutral->minimum()); + +// if (ui.actuatorNeutral->value() == oldMaxi) +// ui.actuatorNeutral->setValue(ui.actuatorNeutral->maximum()); // this can be dangerous if it happens to be controlling a motor at the time! +} + +/** + * Reverses the channel when the checkbox is clicked + */ +void OutputChannelForm::reverseChannel(bool state) +{ + // Sanity check: if state became true, make sure the Maxvalue was higher than Minvalue + // the situations below can happen! + if (state && (ui.actuatorMax->value() < ui.actuatorMin->value())) + return; + if (!state && (ui.actuatorMax->value() > ui.actuatorMin->value())) + return; + + // Now, swap the min & max values (only on the spinboxes, the slider + // does not change! + int temp = ui.actuatorMax->value(); + ui.actuatorMax->setValue(ui.actuatorMin->value()); + ui.actuatorMin->setValue(temp); + + // Also update the channel value + // This is a trick to force the slider to update its value and + // emit the right signal itself, because our sendChannelTest(int) method + // relies on the object sender's identity. + if (ui.actuatorNeutral->value() < ui.actuatorNeutral->maximum()) + { + ui.actuatorNeutral->setValue(ui.actuatorNeutral->value()+1); + ui.actuatorNeutral->setValue(ui.actuatorNeutral->value()-1); + } + else + { + ui.actuatorNeutral->setValue(ui.actuatorNeutral->value()-1); + ui.actuatorNeutral->setValue(ui.actuatorNeutral->value()+1); + } +} + +/** + * Emits the channel value which will be send to the UAV to move the servo. + * Returns immediately if we are not in testing mode. + */ +void OutputChannelForm::sendChannelTest(int value) +{ + int in_value = value; + + QSlider *ob = (QSlider *)QObject::sender(); + if (!ob) return; + + if (ui.actuatorRev->isChecked()) + value = ui.actuatorMin->value() - value + ui.actuatorMax->value(); // the channel is reversed + + // update the label + ui.actuatorValue->setText(QString::number(value)); + + if (ui.actuatorLink->checkState() && parent()) + { // the channel is linked to other channels + QList outputChannelForms = parent()->findChildren(); + // set the linked channels of the parent widget to the same value + foreach(OutputChannelForm *outputChannelForm, outputChannelForms) + { + if (this == outputChannelForm) continue; + if (!outputChannelForm->ui.actuatorLink->checkState()) continue; + + int val = in_value; + if (val < outputChannelForm->ui.actuatorNeutral->minimum()) + val = outputChannelForm->ui.actuatorNeutral->minimum(); + if (val > outputChannelForm->ui.actuatorNeutral->maximum()) + val = outputChannelForm->ui.actuatorNeutral->maximum(); + + if (outputChannelForm->ui.actuatorNeutral->value() == val) continue; + + outputChannelForm->ui.actuatorNeutral->setValue(val); + outputChannelForm->ui.actuatorValue->setText(QString::number(val)); + } + } + + if (!m_inChannelTest) + return; // we are not in Test Output mode + + emit channelChanged(index(), value); +} diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.h b/ground/openpilotgcs/src/plugins/config/outputchannelform.h new file mode 100644 index 000000000..e0cae75d2 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.h @@ -0,0 +1,92 @@ +/** + ****************************************************************************** + * + * @file outputchannelform.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Servo output configuration form for the config output gadget + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef OUTPUTCHANNELFORM_H +#define OUTPUTCHANNELFORM_H + +#include +#include "ui_outputchannelform.h" + +class ConfigInputWidget; + +class OutputChannelForm : public QWidget +{ + Q_OBJECT + +public: + explicit OutputChannelForm(const int index, QWidget *parent = NULL, const bool showLegend = false); + ~OutputChannelForm(); + friend class ConfigInputWidget; + + void setAssignment(const QString &assignment); + int index() const; + +public slots: + void max(int maximum); + int max() const; + void min(int minimum); + int min() const; + void minmax(int minimum, int maximum); + void neutral(int value); + int neutral() const; + void enableChannelTest(bool state); + +signals: + void channelChanged(int index, int value); + +private: + Ui::outputChannelForm ui; + /// Channel index + int m_index; + bool m_inChannelTest; + +private slots: + void linkToggled(bool state); + void reverseChannel(bool state); + void sendChannelTest(int value); + void setChannelRange(); +}; + +inline int OutputChannelForm::index() const +{ + return m_index; +} + +inline int OutputChannelForm::max() const +{ + return ui.actuatorMax->value(); +} + +inline int OutputChannelForm::min() const +{ + return ui.actuatorMin->value(); +} + +inline int OutputChannelForm::neutral() const +{ + return ui.actuatorNeutral->value(); +} +#endif // OUTPUTCHANNELFORM_H diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.ui b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui new file mode 100644 index 000000000..b488872e3 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui @@ -0,0 +1,281 @@ + + + outputChannelForm + + + + 0 + 0 + 562 + 49 + + + + Form + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + Channel Number + + + Qt::LeftToRight + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + TextLabel + + + Qt::AlignCenter + + + + + + + Minimum PWM value, beware of not overdriving your servo. + + + 9999 + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 0 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 9999 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 5 + 20 + + + + + + + + Check to invert the channel. + + + + + + + Output mode + + + + + + + Maximum PWM value, beware of not overdriving your servo. + + + 9999 + + + + + + + + 0 + 0 + + + + Assignment + + + + + + + + 0 + 0 + + + + Min + + + + + + + + 0 + 0 + + + + Neutral (slowest for motor) + + + + + + + + 0 + 0 + + + + Max + + + + + + + + 0 + 0 + + + + Rev. + + + + + + + + 0 + 0 + + + + Link + + + + + + + + 0 + 0 + + + + Current value of slider. + + + 0000 + + + + + + + + 0 + 0 + + + + + 20 + 0 + + + + Qt::LeftToRight + + + # + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0 + + + + + + + + From 9bd74bb591e3cebbf6c9e2eba48dce4b67dd3e02 Mon Sep 17 00:00:00 2001 From: Michael Schulz Date: Mon, 14 Nov 2011 21:13:34 +0100 Subject: [PATCH 2/5] minor fixes due to last merge --- .../src/plugins/config/configoutputwidget.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index cad3f604a..3154c0d1e 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -49,12 +49,14 @@ ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(paren m_config->setupUi(this); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - Q_ASSERT(pm); - UAVSettingsImportExportFactor * importexportplugin = pm->getObject(); + setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); + addUAVObject("ActuatorSettings"); + + UAVSettingsImportExportFactory * importexportplugin = pm->getObject(); connect(importexportplugin,SIGNAL(importAboutToBegin()),this,SLOT(stopTests())); setupButtons(m_config->saveRCOutputToRAM,m_config->saveRCOutputToSD); - addUAVObject("ActuatorSettings"); + addUAVObject("ActuatorSettings"); // NOTE: we have channel indices from 0 to 9, but the convention for OP is Channel 1 to Channel 10. // Register for ActuatorSettings changes: From 93267dd26ffefe647d881c8817f298650ba91985 Mon Sep 17 00:00:00 2001 From: Michael Schulz Date: Thu, 17 Nov 2011 14:33:49 +0100 Subject: [PATCH 3/5] Implemented suggestions from code review * reduced top and bottom margins of outputchannelform * removed obsolete methods in configoutputwidget.h * fixed comment block * switched to static accessor methods for UAVO --- .../src/plugins/config/configoutputwidget.cpp | 106 +++++++++--------- .../src/plugins/config/configoutputwidget.h | 6 +- .../src/plugins/config/outputchannelform.cpp | 2 +- .../src/plugins/config/outputchannelform.ui | 8 +- 4 files changed, 62 insertions(+), 60 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp index 3154c0d1e..18040a967 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.cpp @@ -1,13 +1,13 @@ /** ****************************************************************************** * - * @file configservowidget.cpp + * @file configoutputwidget.cpp * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ConfigPlugin Config Plugin * @{ - * @brief Servo input/output configuration panel for the config gadget + * @brief Servo output configuration panel for the config gadget *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify @@ -40,6 +40,7 @@ #include #include #include "actuatorcommand.h" +#include "actuatorsettings.h" #include "systemalarms.h" #include "uavsettingsimportexport/uavsettingsimportexportfactory.h" @@ -192,14 +193,17 @@ void ConfigOutputWidget::assignOutputChannel(UAVDataObject *obj, QString str) */ void ConfigOutputWidget::setSpinningArmed(bool val) { - UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorSettings"))); - if (!obj) return; - UAVObjectField *field = obj->getField("MotorsSpinWhileArmed"); - if (!field) return; + ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); + Q_ASSERT(actuatorSettings); + ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); + if(val) - field->setValue("TRUE"); + actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_TRUE; else - field->setValue("FALSE"); + actuatorSettingsData.MotorsSpinWhileArmed = ActuatorSettings::MOTORSSPINWHILEARMED_FALSE; + + // Apply settings + actuatorSettings->setData(actuatorSettingsData); } /** @@ -214,12 +218,11 @@ void ConfigOutputWidget::sendChannelTest(int index, int value) if(index < 0 || (unsigned)index >= ActuatorCommand::CHANNEL_NUMELEM) return; - UAVDataObject *obj = dynamic_cast(getObjectManager()->getObject(QString("ActuatorCommand"))); - if (!obj) return; - UAVObjectField *channel = obj->getField("Channel"); - if (!channel) return; - channel->setValue(value, index); - obj->updated(); + ActuatorCommand *actuatorCommand = ActuatorCommand::GetInstance(getObjectManager()); + Q_ASSERT(actuatorCommand); + ActuatorCommand::DataFields actuatorCommandFields = actuatorCommand->getData(); + actuatorCommandFields.Channel[index] = value; + actuatorCommand->setData(actuatorCommandFields); } @@ -234,8 +237,6 @@ void ConfigOutputWidget::sendChannelTest(int index, int value) void ConfigOutputWidget::refreshWidgetsValues() { bool dirty=isDirty(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); // Reset all channel assignements: QList outputChannelForms = findChildren(); @@ -244,7 +245,13 @@ void ConfigOutputWidget::refreshWidgetsValues() outputChannelForm->setAssignment("-"); } - // Get the channel assignements: + // FIXME: Use static accessor method for retrieving channel assignments + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + Q_ASSERT(pm); + UAVObjectManager *objManager = pm->getObject(); + Q_ASSERT(objManager); + + // Get the channel assignements: UAVDataObject * obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); Q_ASSERT(obj); QList fieldList = obj->getFields(); @@ -254,15 +261,17 @@ void ConfigOutputWidget::refreshWidgetsValues() } } + ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); + Q_ASSERT(actuatorSettings); + ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); + // Get the SpinWhileArmed setting - UAVObjectField *field = obj->getField(QString("MotorsSpinWhileArmed")); - m_config->spinningArmed->setChecked(field->getValue().toString().contains("TRUE")); + m_config->spinningArmed->setChecked(actuatorSettingsData.MotorsSpinWhileArmed == ActuatorSettings::MOTORSSPINWHILEARMED_TRUE); // Get Output rates for both banks - field = obj->getField(QString("ChannelUpdateFreq")); + m_config->outputRate1->setValue(actuatorSettingsData.ChannelUpdateFreq[0]); + m_config->outputRate2->setValue(actuatorSettingsData.ChannelUpdateFreq[1]); UAVObjectUtilManager* utilMngr = pm->getObject(); - m_config->outputRate1->setValue(field->getValue(0).toInt()); - m_config->outputRate2->setValue(field->getValue(1).toInt()); if (utilMngr) { int board = utilMngr->getBoardModel(); if ((board & 0xff00) == 1024) { @@ -275,8 +284,8 @@ void ConfigOutputWidget::refreshWidgetsValues() m_config->outputRate2->setEnabled(true); m_config->outputRate3->setEnabled(true); m_config->outputRate4->setEnabled(true); - m_config->outputRate3->setValue(field->getValue(2).toInt()); - m_config->outputRate4->setValue(field->getValue(3).toInt()); + m_config->outputRate3->setValue(actuatorSettingsData.ChannelUpdateFreq[2]); + m_config->outputRate4->setValue(actuatorSettingsData.ChannelUpdateFreq[3]); } else if ((board & 0xff00) == 256 ) { // Mainboard family m_config->outputRate1->setEnabled(true); @@ -295,15 +304,12 @@ void ConfigOutputWidget::refreshWidgetsValues() // Get Channel ranges: foreach(OutputChannelForm *outputChannelForm, outputChannelForms) { - field = obj->getField(QString("ChannelMin")); - int minValue = field->getValue(outputChannelForm->index()).toInt(); - field = obj->getField(QString("ChannelMax")); - int maxValue = field->getValue(outputChannelForm->index()).toInt(); + int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()]; + int maxValue = actuatorSettingsData.ChannelMax[outputChannelForm->index()]; outputChannelForm->minmax(minValue, maxValue); - field = obj->getField(QString("ChannelNeutral")); - int value = field->getValue(outputChannelForm->index()).toInt(); - outputChannelForm->neutral(value); + int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()]; + outputChannelForm->neutral(neutral); } setDirty(dirty); @@ -314,35 +320,27 @@ void ConfigOutputWidget::refreshWidgetsValues() */ void ConfigOutputWidget::updateObjectsFromWidgets() { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - UAVDataObject* obj = dynamic_cast(objManager->getObject(QString("ActuatorSettings"))); - Q_ASSERT(obj); + ActuatorSettings *actuatorSettings = ActuatorSettings::GetInstance(getObjectManager()); + Q_ASSERT(actuatorSettings); + ActuatorSettings::DataFields actuatorSettingsData = actuatorSettings->getData(); - // Now send channel ranges: - UAVObjectField * field; + // Set channel ranges QList outputChannelForms = findChildren(); foreach(OutputChannelForm *outputChannelForm, outputChannelForms) { - field = obj->getField(QString("ChannelMax")); - Q_ASSERT(field); - field->setValue(outputChannelForm->max(), outputChannelForm->index()); - - field = obj->getField(QString("ChannelMin")); - Q_ASSERT(field); - field->setValue(outputChannelForm->min(), outputChannelForm->index()); - - field = obj->getField(QString("ChannelNeutral")); - Q_ASSERT(field); - field->setValue(outputChannelForm->neutral(), outputChannelForm->index()); + actuatorSettingsData.ChannelMax[outputChannelForm->index()] = outputChannelForm->max(); + actuatorSettingsData.ChannelMin[outputChannelForm->index()] = outputChannelForm->min(); + actuatorSettingsData.ChannelNeutral[outputChannelForm->index()] = outputChannelForm->neutral(); } - field = obj->getField(QString("ChannelUpdateFreq")); - Q_ASSERT(field); - field->setValue(m_config->outputRate1->value(),0); - field->setValue(m_config->outputRate2->value(),1); - field->setValue(m_config->outputRate3->value(),2); - field->setValue(m_config->outputRate4->value(),3); + // Set update rates + actuatorSettingsData.ChannelUpdateFreq[0] = m_config->outputRate1->value(); + actuatorSettingsData.ChannelUpdateFreq[1] = m_config->outputRate2->value(); + actuatorSettingsData.ChannelUpdateFreq[2] = m_config->outputRate3->value(); + actuatorSettingsData.ChannelUpdateFreq[3] = m_config->outputRate4->value(); + + // Apply settings + actuatorSettings->setData(actuatorSettingsData); } void ConfigOutputWidget::openHelp() diff --git a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h index 7b287db7c..0140c9bf4 100644 --- a/ground/openpilotgcs/src/plugins/config/configoutputwidget.h +++ b/ground/openpilotgcs/src/plugins/config/configoutputwidget.h @@ -1,13 +1,13 @@ /** ****************************************************************************** * - * @file configservowidget.h + * @file configoutputwidget.h * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ConfigPlugin Config Plugin * @{ - * @brief Servo input/output configuration panel for the config gadget + * @brief Servo output configuration panel for the config gadget *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify @@ -72,8 +72,6 @@ private slots: void updateObjectsFromWidgets(); void runChannelTests(bool state); void sendChannelTest(int index, int value); - void setChOutRange(); - void reverseChannel(bool state); void setSpinningArmed(bool val); void openHelp(); }; diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp index 938e09b5b..131af2623 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file outputchannelform.cpp - * @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ConfigPlugin Config Plugin diff --git a/ground/openpilotgcs/src/plugins/config/outputchannelform.ui b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui index b488872e3..5c7dbd79a 100644 --- a/ground/openpilotgcs/src/plugins/config/outputchannelform.ui +++ b/ground/openpilotgcs/src/plugins/config/outputchannelform.ui @@ -13,7 +13,13 @@ Form - + + + 1 + + + 1 + From fae611a01f631a255c2b95baa9593062dc2d6f2e Mon Sep 17 00:00:00 2001 From: James Cotton Date: Fri, 25 Nov 2011 11:23:56 -0600 Subject: [PATCH 4/5] Fix bug where clicking back at last screen of input wizard would go back to main screen and then in future buttons hung around for no reason --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 ++ .../src/plugins/config/configinputwidget.cpp | 36 +++++-------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index d807e49ad..ed4340a11 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -3139,6 +3139,7 @@ 65F93D0712EE09290047DB36 /* uavtalk_comms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uavtalk_comms.c; sourceTree = ""; }; 65F93D0812EE09290047DB36 /* watchdog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = watchdog.c; sourceTree = ""; }; 65FAA03F133B669400F6F5CD /* GTOP_BIN.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GTOP_BIN.c; sourceTree = ""; }; + 65FAB8CF147FFD76000FF8B2 /* receiveractivity.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = receiveractivity.xml; sourceTree = ""; }; 65FBE14412E7C98100176B5A /* pios_servo_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pios_servo_priv.h; sourceTree = ""; }; 65FC66AA123F30F100B04F74 /* ahrs_timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ahrs_timer.c; path = ../../AHRS/ahrs_timer.c; sourceTree = SOURCE_ROOT; }; 65FC66AB123F312A00B04F74 /* ahrs_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ahrs_timer.h; sourceTree = ""; }; @@ -7469,6 +7470,7 @@ 65C35E6E12EFB2F3004811C2 /* positionactual.xml */, 65C35E6F12EFB2F3004811C2 /* positiondesired.xml */, 65C35E7012EFB2F3004811C2 /* ratedesired.xml */, + 65FAB8CF147FFD76000FF8B2 /* receiveractivity.xml */, 652C856A132B6EA600BFCC70 /* sonaraltitude.xml */, 6536D47B1307962C0042A298 /* stabilizationdesired.xml */, 65C35E7112EFB2F3004811C2 /* stabilizationsettings.xml */, diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp index 407377d3c..a8827436c 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp @@ -293,6 +293,7 @@ void ConfigInputWidget::wzCancel() if(wizardStep != wizardNone) wizardTearDownStep(wizardStep); wizardStep=wizardNone; + m_config->stackedWidget->setCurrentIndex(0); // Load settings back from beginning of wizard manualSettingsObj->setData(previousManualSettingsData); @@ -334,23 +335,8 @@ void ConfigInputWidget::wzNext() wizardSetUpStep(wizardFinish); break; case wizardFinish: - setTxMovement(nothing); - manualCommandObj->setMetadata(manualCommandObj->getDefaultMetadata()); - disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); - manualSettingsData=manualSettingsObj->getData(); - manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_THROTTLE]= - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE]+ - ((manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_THROTTLE]- - manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_THROTTLE])*0.02); - if((abs(manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100) || - (abs(manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]-manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE])<100)) - { - manualSettingsData.ChannelNeutral[ManualControlSettings::CHANNELNEUTRAL_FLIGHTMODE]=manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE]+ - (manualSettingsData.ChannelMax[ManualControlSettings::CHANNELMAX_FLIGHTMODE]-manualSettingsData.ChannelMin[ManualControlSettings::CHANNELMIN_FLIGHTMODE])/2; - } - manualSettingsObj->setData(manualSettingsData); - m_config->stackedWidget->setCurrentIndex(0); wizardStep=wizardNone; + m_config->stackedWidget->setCurrentIndex(0); break; default: Q_ASSERT(0); @@ -463,7 +449,6 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) break; case wizardIdentifyLimits: { - dimOtherControls(false); setTxMovement(nothing); m_config->wzText->setText(QString(tr("Please move all controls to their maximum extents on both directions and press next when ready"))); fastMdata(); @@ -496,16 +481,7 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) fastMdata(); break; case wizardFinish: - foreach(QWidget * wd,extraWidgets) - { - QCheckBox * cb=qobject_cast(wd); - if(cb) - { - disconnect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls())); - delete cb; - } - } - extraWidgets.clear(); + dimOtherControls(true); connect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); m_config->wzText->setText(QString(tr("You have completed this wizard, please check below if the picture below mimics your sticks movement.\n" "This new settings aren't saved to the board yet, after pressing next you will go to the initial screen where you can do that."))); @@ -559,6 +535,7 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) case wizardIdentifySticks: disconnect(receiverActivityObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyControls())); m_config->wzNext->setEnabled(true); + setTxMovement(nothing); break; case wizardIdentifyCenter: manualCommandData=manualCommandObj->getData(); @@ -568,14 +545,17 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) manualSettingsData.ChannelNeutral[i]=manualCommandData.Channel[i]; } manualSettingsObj->setData(manualSettingsData); + setTxMovement(nothing); break; case wizardIdentifyLimits: disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(identifyLimits())); disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); manualSettingsObj->setData(manualSettingsData); restoreMdata(); + setTxMovement(nothing); break; case wizardIdentifyInverted: + dimOtherControls(false); foreach(QWidget * wd,extraWidgets) { QCheckBox * cb=qobject_cast(wd); @@ -590,8 +570,8 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) restoreMdata(); break; case wizardFinish: + dimOtherControls(false); setTxMovement(nothing); - m_config->stackedWidget->setCurrentIndex(0); disconnect(manualCommandObj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(moveSticks())); restoreMdata(); break; From d3cc67f5c49aaab455fa120aff007d9d5b5edc6e Mon Sep 17 00:00:00 2001 From: James Cotton Date: Fri, 25 Nov 2011 12:30:17 -0600 Subject: [PATCH 5/5] Make the input wizard detect already inverted channels and preserve them. --- .../src/plugins/config/configinputwidget.cpp | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp index a8827436c..128f9885b 100644 --- a/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp +++ b/ground/openpilotgcs/src/plugins/config/configinputwidget.cpp @@ -455,8 +455,15 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) manualSettingsData=manualSettingsObj->getData(); for(uint i=0;igetFields().at(0)->getElementNames()) + + for (int index = 0; index < manualSettingsObj->getField("ChannelMax")->getElementNames().length(); index++) { + QString name = manualSettingsObj->getField("ChannelMax")->getElementNames().at(index); if(!name.contains("Access") && !name.contains("Flight")) { QCheckBox * cb=new QCheckBox(name,this); + // Make sure checked status matches current one + cb->setChecked(manualSettingsData.ChannelMax[index] < manualSettingsData.ChannelMin[index]); + extraWidgets.append(cb); m_config->checkBoxesLayout->layout()->addWidget(cb); + connect(cb,SIGNAL(toggled(bool)),this,SLOT(invertControls())); } } @@ -711,10 +724,19 @@ void ConfigInputWidget::identifyLimits() manualCommandData=manualCommandObj->getData(); for(uint i=0;imanualCommandData.Channel[i]) - manualSettingsData.ChannelMin[i]=manualCommandData.Channel[i]; - if(manualSettingsData.ChannelMax[i]manualCommandData.Channel[i]) + manualSettingsData.ChannelMin[i]=manualCommandData.Channel[i]; + if(manualSettingsData.ChannelMax[i]manualCommandData.Channel[i]) + manualSettingsData.ChannelMax[i]=manualCommandData.Channel[i]; + if(manualSettingsData.ChannelMin[i]setData(manualSettingsData); }