diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index bcf3fd2c57d75ac394dabca828217d73ee9659d3..d63cc0f6e50e2ae54db52fadc6ac806c49c3d780 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -282,7 +282,7 @@ FORMS += \ src/ui/designer/QGCParamSlider.ui \ src/ui/designer/QGCActionButton.ui \ src/ui/designer/QGCCommandButton.ui \ - src/ui/designer/QGCComboBox.ui \ + src/ui/designer/QGCToolWidgetComboBox.ui \ src/ui/designer/QGCTextLabel.ui \ src/ui/designer/QGCXYPlot.ui \ src/ui/QGCMAVLinkLogPlayer.ui \ @@ -391,7 +391,7 @@ HEADERS += \ src/ui/designer/QGCParamSlider.h \ src/ui/designer/QGCCommandButton.h \ src/ui/designer/QGCToolWidgetItem.h \ - src/ui/designer/QGCComboBox.h \ + src/ui/designer/QGCToolWidgetComboBox.h \ src/ui/designer/QGCTextLabel.h \ src/ui/designer/QGCRadioChannelDisplay.h \ src/ui/designer/QGCXYPlot.h \ @@ -477,7 +477,8 @@ HEADERS += \ src/CmdLineOptParser.h \ src/uas/QGXPX4UAS.h \ src/QGCFileDialog.h \ - src/QGCMessageBox.h + src/QGCMessageBox.h \ + src/QGCComboBox.h SOURCES += \ src/main.cc \ @@ -533,7 +534,7 @@ SOURCES += \ src/ui/designer/QGCParamSlider.cc \ src/ui/designer/QGCCommandButton.cc \ src/ui/designer/QGCToolWidgetItem.cc \ - src/ui/designer/QGCComboBox.cc \ + src/ui/designer/QGCToolWidgetComboBox.cc \ src/ui/designer/QGCTextLabel.cc \ src/ui/designer/QGCRadioChannelDisplay.cpp \ src/ui/designer/QGCXYPlot.cc \ @@ -614,8 +615,8 @@ SOURCES += \ src/uas/QGCUASWorker.cc \ src/CmdLineOptParser.cc \ src/uas/QGXPX4UAS.cc \ - src/QGCFileDialog.cc - + src/QGCFileDialog.cc \ + src/QGCComboBox.cc # # Unit Test specific configuration goes here @@ -652,7 +653,8 @@ HEADERS += \ src/qgcunittest/QGCUASFileManagerTest.h \ src/qgcunittest/PX4RCCalibrationTest.h \ src/qgcunittest/LinkManagerTest.h \ - src/qgcunittest/MainWindowTest.h + src/qgcunittest/MainWindowTest.h \ + src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h SOURCES += \ src/qgcunittest/UnitTest.cc \ @@ -672,7 +674,8 @@ SOURCES += \ src/qgcunittest/QGCUASFileManagerTest.cc \ src/qgcunittest/PX4RCCalibrationTest.cc \ src/qgcunittest/LinkManagerTest.cc \ - src/qgcunittest/MainWindowTest.cc + src/qgcunittest/MainWindowTest.cc \ + src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc } # @@ -682,7 +685,8 @@ FORMS += \ src/VehicleSetup/SetupView.ui \ src/VehicleSetup/SummaryPage.ui \ src/VehicleSetup/ParameterEditor.ui \ - src/ui/QGCPX4VehicleConfig.ui + src/ui/QGCPX4VehicleConfig.ui \ + src/AutoPilotPlugins/PX4/FlightModeConfig.ui HEADERS+= \ src/VehicleSetup/SetupView.h \ @@ -698,6 +702,7 @@ HEADERS+= \ src/AutoPilotPlugins/PX4/PX4Component.h \ src/AutoPilotPlugins/PX4/RadioComponent.h \ src/AutoPilotPlugins/PX4/FlightModesComponent.h \ + src/AutoPilotPlugins/PX4/FlightModeConfig.h \ src/AutoPilotPlugins/PX4/AirframeComponent.h \ src/AutoPilotPlugins/PX4/SensorsComponent.h @@ -712,5 +717,6 @@ SOURCES += \ src/AutoPilotPlugins/PX4/PX4Component.cc \ src/AutoPilotPlugins/PX4/RadioComponent.cc \ src/AutoPilotPlugins/PX4/FlightModesComponent.cc \ + src/AutoPilotPlugins/PX4/FlightModeConfig.cc \ src/AutoPilotPlugins/PX4/AirframeComponent.cc \ src/AutoPilotPlugins/PX4/SensorsComponent.cc diff --git a/qtlogging.ini b/qtlogging.ini new file mode 100644 index 0000000000000000000000000000000000000000..c67fdd4cf2ace3d3b61f16e05690bfc50a237b0b --- /dev/null +++ b/qtlogging.ini @@ -0,0 +1,2 @@ +[Rules] +*Log=false diff --git a/src/AutoPilotPlugins/PX4/FlightModeConfig.cc b/src/AutoPilotPlugins/PX4/FlightModeConfig.cc new file mode 100644 index 0000000000000000000000000000000000000000..78cd1fda4b4d22859d82bb2f45f5db33b5882d57 --- /dev/null +++ b/src/AutoPilotPlugins/PX4/FlightModeConfig.cc @@ -0,0 +1,253 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009, 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @brief Flight Mode Configuration +/// @author Don Gagne setupUi(this); + + // Expectation is that we have an active uas, it is connected and the parameters are ready + _mav = UASManager::instance()->getActiveUAS(); + Q_ASSERT(_mav); + + _paramMgr = _mav->getParamManager(); + Q_ASSERT(_paramMgr); + Q_ASSERT(_paramMgr->parametersReady()); + + _componentId = _paramMgr->getDefaultComponentId(); + + connect(_paramMgr, SIGNAL(parameterUpdated(int, QString, QVariant)), this, SLOT(_parameterUpdated(int, QString, QVariant))); + + _initUi(); +} + +/// @brief Intialize the UI elements +void FlightModeConfig::_initUi(void) { + struct Combo2Param { + QGCComboBox* combo; + QButtonGroup* buttonGroup; + const char* param; + const char* description; + }; + + struct Combo2Param rgCombo2ParamMap[] = { + { _ui->modeSwitchChannel, _ui->modeSwitchGroup, _modeSwitchParam, "Mode Switch" }, + { _ui->manualSwitchChannel, _ui->manualSwitchGroup, _manualSwitchParam, "Manual Switch" }, + { _ui->assistSwitchChannel, _ui->assistSwitchGroup, _assistSwitchParam, "Assist Switch" }, + { _ui->returnSwitchChannel, _ui->returnSwitchGroup, _returnSwitchParam, "Return Switch" }, + { _ui->loiterSwitchChannel, _ui->loiterSwitchGroup, _loiterSwitchParam, "Loiter Switch" }, + { NULL, NULL, "RC_MAP_THROTTLE", "Throttle" }, + { NULL, NULL, "RC_MAP_YAW", "Rudder" }, + { NULL, NULL, "RC_MAP_ROLL", "Aileron" }, + { NULL, NULL, "RC_MAP_PITCH", "Elevator" }, + { NULL, NULL, "RC_MAP_AUX1", "Aux1" }, + { NULL, NULL, "RC_MAP_AUX2", "Aux2" }, + { NULL, NULL, "RC_MAP_AUX3", "Aux3" } + }; + + // Setup up maps + for (size_t i=0; icombo) { + Q_ASSERT(!_mapChannelCombo2Param.contains(map->combo)); + _mapChannelCombo2Param[map->combo] = map->param; + + Q_ASSERT(!_mapChannelCombo2ButtonGroup.contains(map->combo)); + _mapChannelCombo2ButtonGroup[map->combo] = map->buttonGroup; + + // We connect to activated because we only want signals from user initiated changes + connect(map->combo, SIGNAL(activated(int)), this, SLOT(_channelSelected(int))); + } + + Q_ASSERT(!_mapParam2FunctionInfo.contains(map->param)); + _mapParam2FunctionInfo[map->param] = map->description; + } + + _updateAllSwitches(); + + // Finally if RC Calibration has not been performed disable the entire widget and inform user + if (_getChannelMapForParam(_modeSwitchParam) == 0) { + // FIXME: Do something more than disable + setEnabled(false); + } +} + +void FlightModeConfig::_updateAllSwitches(void) +{ + foreach(QGCComboBox* combo, _mapChannelCombo2Param.keys()) { + _updateSwitchUiGroup(combo); + } +} + +/// @brief Selects the channel in the combo for the given parameter +void FlightModeConfig::_selectChannelForParam(QGCComboBox* combo, const QString& parameter) +{ + int channel = _getChannelMapForParam(parameter); + + int index = combo->findData(channel); + Q_ASSERT(index != -1); + + combo->setCurrentIndex(index); +} + +/// @brief Fills a channel selection combo box with channel values +void FlightModeConfig::_updateSwitchUiGroup(QGCComboBox* combo) +{ + QMap mapChannelUsed2Description; + + // Make a map of all channels currently mapped + foreach(QString paramId, _mapParam2FunctionInfo.keys()) { + int channel = _getChannelMapForParam(paramId); + if (channel != 0) { + mapChannelUsed2Description[channel] = _mapParam2FunctionInfo[paramId]; + } + } + + combo->clear(); + combo->addItem("Disabled", 0); + for (int i=1; i<=_maxChannels; i++) { + QString comboText = QString("Channel %1").arg(i); + + if (mapChannelUsed2Description.contains(i)) { + comboText += QString(" (%1)").arg(mapChannelUsed2Description[i]); + } + + combo->addItem(comboText, i); + } + + _selectChannelForParam(combo, _mapChannelCombo2Param[combo]); + + // Enable/Disable radio buttons appropriately + + int channelMap = _getChannelMapForParam(_mapChannelCombo2Param[combo]); + + Q_ASSERT(_mapChannelCombo2ButtonGroup.contains(combo)); + Q_ASSERT(_mapChannelCombo2ButtonGroup[combo]->buttons().count() > 0); + + foreach(QAbstractButton* button, _mapChannelCombo2ButtonGroup[combo]->buttons()) { + QRadioButton* radio = qobject_cast(button); + + Q_ASSERT(radio); + + radio->setEnabled(channelMap != 0); + } +} + +/// @brief Returns channel mapping for the specified parameters +int FlightModeConfig::_getChannelMapForParam(const QString& paramId) +{ + QVariant value; + bool found = _paramMgr->getParameterValue(_componentId, paramId, value); + Q_UNUSED(found); + Q_ASSERT(found); + + bool conversionOk; + int channel = value.toInt(&conversionOk); + Q_UNUSED(conversionOk); + Q_ASSERT(conversionOk); + + return channel; +} + +/// @brief Called when a selection occurs in one of the channel combo boxes +void FlightModeConfig::_channelSelected(int requestedMapping) +{ + QGCComboBox* combo = qobject_cast(sender()); + Q_ASSERT(combo); + Q_ASSERT(_mapChannelCombo2Param.contains(combo)); + + // Check for no-op + + int currentMapping = _getChannelMapForParam(_mapChannelCombo2Param[combo]); + if (currentMapping == requestedMapping) { + return; + } + + // Make sure that channel is not already mapped + + if (requestedMapping == 0) { + // Channel was disabled + if (combo == _ui->modeSwitchChannel) { + // Mode switch is not allowed to be disabled. + QGCMessageBox::warning(tr("Flight Mode"), "Mode Switch is a required switch and cannot be disabled."); + _selectChannelForParam(combo, _mapChannelCombo2Param[combo]); + return; + } + } else { + // Channel was remapped to a non-disabled channel + foreach(QString paramId, _mapParam2FunctionInfo.keys()) { + int usedChannelMap = _getChannelMapForParam(paramId); + + if (requestedMapping == usedChannelMap) { + QGCMessageBox::warning(tr("Flight Mode"), "You cannot use a channel which is already mapped."); + _selectChannelForParam(combo, _mapChannelCombo2Param[combo]); + return; + } + } + } + + // Save the new setting to the parameter + _paramMgr->setParameter(_componentId, _mapChannelCombo2Param[combo], requestedMapping); + _paramMgr->sendPendingParameters(true, false); +} + +void FlightModeConfig::_parameterUpdated(int componentId, QString parameter, QVariant value) +{ + Q_UNUSED(componentId); + Q_UNUSED(value); + + // If this is a function mapping parameter update the combos + if (_mapParam2FunctionInfo.contains(parameter)) { + _updateAllSwitches(); + } + + // Finally if RC Calibration suddenly needs to be re-done disable the entire widget and inform user + if (parameter == _modeSwitchParam) { + // FIXME: Do something more than disable + if (isEnabled() == false && value.toInt() != 0) { + setEnabled(true); + } else if (isEnabled() == true && value.toInt() == 0) { + setEnabled(false); + } + } +} \ No newline at end of file diff --git a/src/AutoPilotPlugins/PX4/FlightModeConfig.h b/src/AutoPilotPlugins/PX4/FlightModeConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..891d5ce32a3f636e0b879de4d9a2a5376400ddf4 --- /dev/null +++ b/src/AutoPilotPlugins/PX4/FlightModeConfig.h @@ -0,0 +1,81 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009, 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + + +/// @file +/// @brief Flight Mode Configuration +/// @author Don Gagne + +#include "UASInterface.h" +#include "ui_FlightModeConfig.h" + +namespace Ui { + class FlightModeConfig; +} + + +class FlightModeConfig : public QWidget +{ + Q_OBJECT + + friend class FlightModeConfigTest; ///< This allows our unit test to access internal information needed. + +public: + explicit FlightModeConfig(QWidget *parent = 0); + +private slots: + void _channelSelected(int index); + void _parameterUpdated(int componentId, QString parameter, QVariant value); + +private: + void _initUi(void); + void _updateSwitchUiGroup(QGCComboBox* combo); + void _selectChannelForParam(QGCComboBox* combo, const QString& parameter); + void _updateAllSwitches(void); + int _getChannelMapForParam(const QString& parameter); + + UASInterface* _mav; ///< The current MAV + int _componentId; ///< Default component id + QGCUASParamManagerInterface* _paramMgr; + + static const int _maxChannels = 18; + + QMap _mapChannelCombo2Param; + QMap _mapChannelCombo2ButtonGroup; + QMap _mapParam2FunctionInfo; + + static const char* _modeSwitchParam; + static const char* _manualSwitchParam; + static const char* _assistSwitchParam; + static const char* _returnSwitchParam; + static const char* _loiterSwitchParam; + + Ui::FlightModeConfig* _ui; +}; + +#endif diff --git a/src/AutoPilotPlugins/PX4/FlightModeConfig.ui b/src/AutoPilotPlugins/PX4/FlightModeConfig.ui new file mode 100644 index 0000000000000000000000000000000000000000..c8ad74899e343ec1111b4a9f57285eea5f6543ff --- /dev/null +++ b/src/AutoPilotPlugins/PX4/FlightModeConfig.ui @@ -0,0 +1,392 @@ + + + FlightModeConfig + + + + 0 + 0 + 831 + 1286 + + + + + 0 + 0 + + + + Form + + + + + + + 22 + + + + This implementation is a work in progress. Visuals are meant to be functional only. Active display of switch positions is not yet implemented. If this entire screen is disabled, you must do a Radio Calibration before settings Flight Modes. + + + true + + + + + + + + + Flight Modes on multiple channels + + + true + + + modeSwitchGroup + + + + + + + false + + + Flight Modes on single channel (coming soon) + + + modeSwitchGroup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + 1 + + + + + + + + + + Main Mode Switch + + + + + + + + + + Current switch position: + + + + + + + Manual Mode + + + mainSwitchGroup + + + + + + + Assist Mode + + + mainSwitchGroup + + + + + + + Mission Mode + + + mainSwitchGroup + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Manual Mode Switch + + + + + + + + + + Current switch position: + + + + + + + Acro + + + manualSwitchGroup + + + + + + + Manual + + + manualSwitchGroup + + + + + + + Stabilize + + + manualSwitchGroup + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Assist Mode Switch + + + + + + + + + + Altitude Control + + + assistSwitchGroup + + + + + + + Position Control + + + assistSwitchGroup + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + Loiter Switch + + + + + + + + + + Current switch position + + + + + + + Loiter + + + loiterSwitchGroup + + + + + + + Off + + + loiterSwitchGroup + + + + + + + + + + + Return to Home Switch + + + + + + + + + + Current switch position + + + + + + + Return to Home + + + returnSwitchGroup + + + + + + + Off + + + returnSwitchGroup + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QGCComboBox + QComboBox +
QGCComboBox.h
+
+
+ + + + + + + + + + +
diff --git a/src/AutoPilotPlugins/PX4/FlightModesComponent.cc b/src/AutoPilotPlugins/PX4/FlightModesComponent.cc index bba49c0c92f595887f533aab351b5fcbb881c07a..d7a857a47f9ba5b39635d06371d44fefbc42d8f9 100644 --- a/src/AutoPilotPlugins/PX4/FlightModesComponent.cc +++ b/src/AutoPilotPlugins/PX4/FlightModesComponent.cc @@ -25,9 +25,7 @@ /// @author Don Gagne #include "FlightModesComponent.h" - -#include -#include +#include "FlightModeConfig.h" /// @brief Parameters which signal a change in setupComplete state static const char* triggerParams[] = { "RC_MAP_MODE_SW", NULL }; @@ -115,13 +113,7 @@ QStringList FlightModesComponent::paramFilterList(void) const QWidget* FlightModesComponent::setupWidget(void) const { - QWidget* widget = new QWidget; - QVBoxLayout* layout = new QVBoxLayout(widget); - QLabel* label = new QLabel("Coming Soon\nUse Radio setup for Main Mode Switch setup\n(Use Flight Modes Parameters for everything else)", widget); - label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - layout->addWidget(label); - - return widget; + return new FlightModeConfig(); } QList FlightModesComponent::summaryItems(void) const diff --git a/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc b/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc new file mode 100644 index 0000000000000000000000000000000000000000..0fc4b09dc41812ad44a58ec916662d17be6fc64d --- /dev/null +++ b/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc @@ -0,0 +1,304 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "FlightModeConfigTest.h" +#include "UASManager.h" +#include "MockQGCUASParamManager.h" +#include "QGCMessageBox.h" + +/// @file +/// @brief FlightModeConfig Widget unit test +/// +/// @author Don Gagne + +UT_REGISTER_TEST(FlightModeConfigTest) + +FlightModeConfigTest::FlightModeConfigTest(void) : + _mockUASManager(NULL), + _paramMgr(NULL), + _configWidget(NULL), + _defaultComponentId(0) +{ + +} + +void FlightModeConfigTest::initTestCase(void) +{ + +} + +void FlightModeConfigTest::init(void) +{ + UnitTest::init(); + + _mockUASManager = new MockUASManager(); + Q_ASSERT(_mockUASManager); + + UASManager::setMockUASManager(_mockUASManager); + + _mockUAS = new MockUAS(); + Q_CHECK_PTR(_mockUAS); + _paramMgr = _mockUAS->getParamManager(); + _defaultComponentId = _paramMgr->getDefaultComponentId(); + + _mockUASManager->setMockActiveUAS(_mockUAS); + + struct SetupParamInfo { + const char* param; + int mappedChannel; + }; + + struct SetupParamInfo rgSetupParamInfo[] = { + { "RC_MAP_MODE_SW", 5 }, + { "RC_MAP_ACRO_SW", 0 }, + { "RC_MAP_POSCTL_SW", 0 }, + { "RC_MAP_RETURN_SW", 0 }, + { "RC_MAP_LOITER_SW", 0 }, + { "RC_MAP_THROTTLE", 1 }, + { "RC_MAP_YAW", 2 }, + { "RC_MAP_ROLL", 3 }, + { "RC_MAP_PITCH", 4 }, + { "RC_MAP_AUX1", 0 }, + { "RC_MAP_AUX2", 0 }, + { "RC_MAP_AUX3", 0 } + }; + size_t crgSetupParamInfo = sizeof(rgSetupParamInfo) / sizeof(rgSetupParamInfo[0]); + + // Set initial parameter values + for (size_t i=0; isetParameter(_defaultComponentId, info->param, info->mappedChannel); + } + + _configWidget = new FlightModeConfig; + Q_CHECK_PTR(_configWidget); + _configWidget->setVisible(true); + + // Setup combo maps + + struct SetupComboInfo { + QGCComboBox* combo; + QButtonGroup* buttonGroup; + const char* param; + }; + + struct SetupComboInfo rgSetupComboInfo[] = { + { _configWidget->_ui->modeSwitchChannel, _configWidget->_ui->modeSwitchGroup, "RC_MAP_MODE_SW" }, + { _configWidget->_ui->manualSwitchChannel, _configWidget->_ui->manualSwitchGroup, "RC_MAP_ACRO_SW" }, + { _configWidget->_ui->assistSwitchChannel, _configWidget->_ui->assistSwitchGroup, "RC_MAP_POSCTL_SW" }, + { _configWidget->_ui->returnSwitchChannel, _configWidget->_ui->returnSwitchGroup, "RC_MAP_RETURN_SW" }, + { _configWidget->_ui->loiterSwitchChannel, _configWidget->_ui->loiterSwitchGroup, "RC_MAP_LOITER_SW" } + }; + size_t crgSetupComboInfo = sizeof(rgSetupComboInfo) / sizeof(rgSetupComboInfo[0]); + + Q_ASSERT(_mapChannelCombo2Param.count() == 0); + for (size_t i=0; icombo)); + _mapChannelCombo2Param[info->combo] = info->param; + + Q_ASSERT(!_mapChannelCombo2ButtonGroup.contains(info->combo)); + _mapChannelCombo2ButtonGroup[info->combo] = info->buttonGroup; + } +} + +void FlightModeConfigTest::cleanup(void) +{ + UnitTest::cleanup(); + + Q_ASSERT(_configWidget); + delete _configWidget; + + Q_ASSERT(_mockUAS); + delete _mockUAS; + + UASManager::setMockUASManager(NULL); + + Q_ASSERT(_mockUASManager); + delete _mockUASManager; + + _mapChannelCombo2Param.clear(); + _mapChannelCombo2ButtonGroup.clear(); +} + +/// @brief Returns channel mapping for the specified parameters +int FlightModeConfigTest::_getChannelMapForParam(const QString& paramId) +{ + QVariant value; + bool found = _paramMgr->getParameterValue(_defaultComponentId, paramId, value); + Q_UNUSED(found); + Q_ASSERT(found); + + bool conversionOk; + int channel = value.toInt(&conversionOk); + Q_UNUSED(conversionOk); + Q_ASSERT(conversionOk); + + return channel; +} + +void FlightModeConfigTest::_create_test(void) +{ + // This just test widget creation which is handled in init +} + +void FlightModeConfigTest::_validateInitialState_test(void) +{ + // Make sure that the combo boxes are set to the correct selections + foreach(QGCComboBox* combo, _mapChannelCombo2Param.keys()) { + QVariant value; + + Q_ASSERT(_mapChannelCombo2Param.contains(combo)); + int expectedMappedChannel = _getChannelMapForParam(_mapChannelCombo2Param[combo]); + + int currentIndex = combo->currentIndex(); + QVERIFY(currentIndex != -1); + + int comboMappedChannel = combo->itemData(currentIndex).toInt(); + + QCOMPARE(comboMappedChannel, expectedMappedChannel); + } + + QGCComboBox* combo = _configWidget->_ui->modeSwitchChannel; + + // combo should have entry for each channel plus disabled + QCOMPARE(combo->count(), _availableChannels + 1); + + for (int i=0; icount(); i++) { + // Combo data equates to channel mapping value. These are one-base channel values with + // 0 meaning disabled. The channel should match the index. + QCOMPARE(i, combo->itemData(i).toInt()); + + // Channels which are mapped are displayed after the channel number in the form "(name)". + // Check for the ending parentheses to indicate mapped channels + QString text = combo->itemText(i); + if (text.endsWith(")")) { + // Channels 1-5 are mapped + QVERIFY(i >= 1 && i <= 5); + } else { + QVERIFY(!(i >= 1 && i <= 5)); + } + } +} + +void FlightModeConfigTest::_validateRCCalCheck_test(void) +{ + // Mode switch mapped is used to signal RC Calibration not complete. You must complete RC Cal before + // doing Flight Mode Config. + + // Set mode switch mapping to not set + Q_ASSERT(_mapChannelCombo2Param.contains(_configWidget->_ui->modeSwitchChannel)); + _paramMgr->setParameter(_defaultComponentId, _mapChannelCombo2Param[_configWidget->_ui->modeSwitchChannel], 0); + + // Widget should disable + QCOMPARE(_configWidget->isEnabled(), false); + + // Set mode switch mapping to mapped + Q_ASSERT(_mapChannelCombo2Param.contains(_configWidget->_ui->modeSwitchChannel)); + _paramMgr->setParameter(_defaultComponentId, _mapChannelCombo2Param[_configWidget->_ui->modeSwitchChannel], 5); + + // Widget should re-enable + QCOMPARE(_configWidget->isEnabled(), true); +} + +void FlightModeConfigTest::_attempChannelReuse_test(void) +{ + // Attempt to select a channel that is already in use for a switch mapping + foreach(QGCComboBox* combo, _mapChannelCombo2Param.keys()) { + + Q_ASSERT(_mapChannelCombo2Param.contains(combo)); + int beforeMapping = _getChannelMapForParam(_mapChannelCombo2Param[combo]); + + setExpectedMessageBox(QMessageBox::Ok); + + // Channel 1 mapped to throttle. This should pop a message box and the parameter value should + // not change. + combo->simulateUserSetCurrentIndex(1); + + checkExpectedMessageBox(); + + int afterMapping = _getChannelMapForParam(_mapChannelCombo2Param[combo]); + + QCOMPARE(beforeMapping, afterMapping); + } +} + +void FlightModeConfigTest::_validateRadioButtonEnableDisable_test(void) +{ + // Radio button should enable/disable according to selection + foreach(QGCComboBox* combo, _mapChannelCombo2Param.keys()) { + // Mode switch can't be disabled + if (combo == _configWidget->_ui->modeSwitchChannel) { + continue; + } + + // Index 0 is disabled + combo->simulateUserSetCurrentIndex(0); + + Q_ASSERT(_mapChannelCombo2ButtonGroup.contains(combo)); + QButtonGroup* buttonGroup = _mapChannelCombo2ButtonGroup[combo]; + + foreach(QAbstractButton* button, buttonGroup->buttons()) { + QRadioButton* radio = qobject_cast(button); + Q_ASSERT(radio); + + QCOMPARE(radio->isEnabled(), false); + } + + // Index 6 should be a valid mapping + combo->simulateUserSetCurrentIndex(6); + + foreach(QAbstractButton* button, buttonGroup->buttons()) { + QRadioButton* radio = qobject_cast(button); + Q_ASSERT(radio); + + QCOMPARE(radio->isEnabled(), true); + } + + // Set back to disabled for next iteration through loop. Otherwise we'll error out + // with the channel already in use + combo->simulateUserSetCurrentIndex(0); + } +} + +void FlightModeConfigTest::_validateModeSwitchMustBeEnabled_test(void) +{ + QGCComboBox* modeCombo = _configWidget->_ui->modeSwitchChannel; + + Q_ASSERT(_mapChannelCombo2Param.contains(modeCombo)); + int beforeMapping = _getChannelMapForParam(_mapChannelCombo2Param[modeCombo]); + + setExpectedMessageBox(QMessageBox::Ok); + + // Index 0 is disabled. This should pop a message box and the parameter value should + // not change. + modeCombo->simulateUserSetCurrentIndex(0); + + checkExpectedMessageBox(); + + int afterMapping = _getChannelMapForParam(_mapChannelCombo2Param[modeCombo]); + + QCOMPARE(beforeMapping, afterMapping); +} diff --git a/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h b/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h new file mode 100644 index 0000000000000000000000000000000000000000..c6cb77eeafd3aabfeaaaf3544413fc943e2af40d --- /dev/null +++ b/src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h @@ -0,0 +1,71 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef FlightModeConfigTest_H +#define FlightModeConfigTest_H + +#include "UnitTest.h" +#include "MockUASManager.h" +#include "MockUAS.h" +#include "AutoPilotPlugins/PX4/FlightModeConfig.h" + +/// @file +/// @brief FlightModeConfig Widget unit test +/// +/// @author Don Gagne + +class FlightModeConfigTest : public UnitTest +{ + Q_OBJECT + +public: + FlightModeConfigTest(void); + +private slots: + void initTestCase(void); + void init(void); + void cleanup(void); + + void _create_test(void); + void _validateInitialState_test(void); + void _validateRCCalCheck_test(void); + void _attempChannelReuse_test(void); + void _validateRadioButtonEnableDisable_test(void); + void _validateModeSwitchMustBeEnabled_test(void); + +private: + int _getChannelMapForParam(const QString& parameter); + + MockUASManager* _mockUASManager; + MockUAS* _mockUAS; + QGCUASParamManagerInterface* _paramMgr; + FlightModeConfig* _configWidget; + int _defaultComponentId; + + QMap _mapChannelCombo2Param; + QMap _mapChannelCombo2ButtonGroup; + + static const int _availableChannels = 18; ///< Simulate 18 channel RC Transmitter +}; + +#endif diff --git a/src/QGCComboBox.cc b/src/QGCComboBox.cc new file mode 100644 index 0000000000000000000000000000000000000000..545b67f597f1de5068cbca23a99513ee106db8a5 --- /dev/null +++ b/src/QGCComboBox.cc @@ -0,0 +1,48 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +/// @file +/// @brief Subclass of QComboBox. Mainly used for unit test so you can simulate a user selection +/// with correct signalling. +/// +/// @author Don Gagne + +#include "QGCComboBox.h" + +QGCComboBox::QGCComboBox(QWidget* parent) : + QComboBox(parent) +{ + +} + +void QGCComboBox::simulateUserSetCurrentIndex(int index) +{ + Q_ASSERT(index >=0 && index < count()); + + // This will signal currentIndexChanged + setCurrentIndex(index); + + // We have to manually signal activated + emit activated(index); + emit activated(itemText(index)); +} diff --git a/src/QGCComboBox.h b/src/QGCComboBox.h new file mode 100644 index 0000000000000000000000000000000000000000..95a65f190a78f60019aeabb52f251d80e2a8b2eb --- /dev/null +++ b/src/QGCComboBox.h @@ -0,0 +1,46 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL 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. + + QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef QGCComboBox_H +#define QGCComboBox_H + +#include + +/// @file +/// @brief Subclass of QComboBox. Mainly used for unit test so you can simulate a user selection +/// with correct signalling. +/// +/// @author Don Gagne + +class QGCComboBox : public QComboBox { + Q_OBJECT + +public: + QGCComboBox(QWidget* parent = NULL); + + /// @brief Sets the current index on the combo. Signals activated, as well as currentIndexChanged. + void simulateUserSetCurrentIndex(int index); +}; + + +#endif diff --git a/src/qgcunittest/MockQGCUASParamManager.cc b/src/qgcunittest/MockQGCUASParamManager.cc index 1512c33109cdd8078f85e257e26e5bc348ad32a9..c2cad7b3f18a92c626b62ed33362226a63cfc5aa 100644 --- a/src/qgcunittest/MockQGCUASParamManager.cc +++ b/src/qgcunittest/MockQGCUASParamManager.cc @@ -22,12 +22,16 @@ ======================================================================*/ #include "MockQGCUASParamManager.h" +#include "mavlink.h" + #include #include +Q_LOGGING_CATEGORY(MockQGCUASParamManagerLog, "MockQGCUASParamManagerLog") + MockQGCUASParamManager::MockQGCUASParamManager(void) { - + _loadParams(); } bool MockQGCUASParamManager::getParameterValue(int component, const QString& parameter, QVariant& value) const @@ -36,13 +40,65 @@ bool MockQGCUASParamManager::getParameterValue(int component, const QString& par if (_mapParams.contains(parameter)) { value = _mapParams[parameter]; + return true; } + + qCDebug(MockQGCUASParamManagerLog) << QString("getParameterValue: parameter not found %1").arg(parameter); return false; } void MockQGCUASParamManager::setParameter(int component, QString parameterName, QVariant value) { - Q_UNUSED(component); + qCDebug(MockQGCUASParamManagerLog) << QString("setParameter: component(%1) parameter(%2) value(%3)").arg(component).arg(parameterName).arg(value.toString()); + + _mapParams[parameterName] = value; + emit parameterUpdated(_defaultComponentId, parameterName, value); +} - _mapParamsSet[parameterName] = value; +void MockQGCUASParamManager::_loadParams(void) +{ + QFile paramFile(":/unittest/MockLink.param"); + + bool success = paramFile.open(QFile::ReadOnly); + Q_UNUSED(success); + Q_ASSERT(success); + + QTextStream paramStream(¶mFile); + + while (!paramStream.atEnd()) { + QString line = paramStream.readLine(); + + if (line.startsWith("#")) { + continue; + } + + QStringList paramData = line.split("\t"); + Q_ASSERT(paramData.count() == 5); + + QString paramName = paramData.at(2); + QString valStr = paramData.at(3); + uint paramType = paramData.at(4).toUInt(); + + QVariant paramValue; + switch (paramType) { + case MAV_PARAM_TYPE_REAL32: + paramValue = QVariant(valStr.toFloat()); + break; + case MAV_PARAM_TYPE_UINT32: + paramValue = QVariant(valStr.toUInt()); + break; + case MAV_PARAM_TYPE_INT32: + paramValue = QVariant(valStr.toInt()); + break; + case MAV_PARAM_TYPE_INT8: + paramValue = QVariant((unsigned char)valStr.toUInt()); + break; + default: + Q_ASSERT(false); + break; + } + + Q_ASSERT(!_mapParams.contains(paramName)); + _mapParams[paramName] = paramValue; + } } diff --git a/src/qgcunittest/MockQGCUASParamManager.h b/src/qgcunittest/MockQGCUASParamManager.h index 91947072333db2dfd3e260671fd97aafac805c5d..e5d5871005700569a277ef821bfba6e7f881c75c 100644 --- a/src/qgcunittest/MockQGCUASParamManager.h +++ b/src/qgcunittest/MockQGCUASParamManager.h @@ -24,8 +24,12 @@ #ifndef MOCKQGCUASPARAMMANAGER_H #define MOCKQGCUASPARAMMANAGER_H +#include + #include "QGCUASParamManagerInterface.h" +Q_DECLARE_LOGGING_CATEGORY(MockQGCUASParamManagerLog) + /// @file /// @brief This is a mock implementation of QGCUASParamManager for writing Unit Tests. /// @@ -39,11 +43,12 @@ class MockQGCUASParamManager : public QGCUASParamManagerInterface signals: // The following QGCSUASParamManagerInterface signals are supported void parameterListUpToDate(); // You can connect to this signal, but it will never be emitted + void parameterUpdated(int compId, QString paramName, QVariant value); public: // Implemented QGCSUASParamManager overrides virtual bool getParameterValue(int component, const QString& parameter, QVariant& value) const; - virtual int getDefaultComponentId(void) { return 0; } + virtual int getDefaultComponentId(void) { return _defaultComponentId; } virtual int countOnboardParams(void) { return _mapParams.count(); } public slots: @@ -53,7 +58,7 @@ public slots: { Q_UNUSED(forceSend); setParameter(componentId, key, value); } virtual void sendPendingParameters(bool persistAfterSend = false, bool forceSend = false) { Q_UNUSED(persistAfterSend); Q_UNUSED(forceSend); } - virtual bool parametersReady(void) { return false; } + virtual bool parametersReady(void) { return true; } public: // MockQGCUASParamManager methods @@ -66,9 +71,9 @@ public: void setMockParameters(ParamMap_t& map) { _mapParams = map; } /// Returns the parameters which were set by calls to setParameter calls - ParamMap_t getMockSetParameters(void) { return _mapParamsSet; } + ParamMap_t getMockSetParameters(void) { return _mapParams; } /// Clears the set of parameters set by setParameter calls - void clearMockSetParameters(void) { _mapParamsSet.clear(); } + void clearMockSetParameters(void) { _mapParams.clear(); } public: // Unimplemented QGCUASParamManagerInterface overrides @@ -92,8 +97,11 @@ public slots: virtual void copyPersistentParamsToVolatile() { Q_ASSERT(false); } private: + void _loadParams(void); + ParamMap_t _mapParams; - ParamMap_t _mapParamsSet; + + static const int _defaultComponentId = 50; // Bogus variables used for return types of NYI methods QList _bogusQListInt; diff --git a/src/qgcunittest/PX4RCCalibrationTest.cc b/src/qgcunittest/PX4RCCalibrationTest.cc index f4e5ac35c7ed819248e8dfa992742800613544f2..793108a3f882b67daa80b3909b39125fe977545b 100644 --- a/src/qgcunittest/PX4RCCalibrationTest.cc +++ b/src/qgcunittest/PX4RCCalibrationTest.cc @@ -161,13 +161,14 @@ void PX4RCCalibrationTest::init(void) _mockUAS = new MockUAS(); Q_CHECK_PTR(_mockUAS); - // This will instatiate the widget with no active UAS set + _mockUASManager->setMockActiveUAS(_mockUAS); + + // This will instatiate the widget with an active uas with ready parameters _calWidget = new PX4RCCalibration(); Q_CHECK_PTR(_calWidget); _calWidget->_setUnitTestMode(); _calWidget->setVisible(true); - _mockUASManager->setMockActiveUAS(_mockUAS); // Get pointers to the push buttons _cancelButton = _calWidget->findChild("rcCalCancel"); @@ -215,17 +216,6 @@ void PX4RCCalibrationTest::cleanup(void) } -/// @brief Tests for correct behavior when active UAS is set into widget. -void PX4RCCalibrationTest::_setUAS_test(void) -{ - // Widget is initialized with UAS, so it should be enabled - QCOMPARE(_calWidget->isEnabled(), true); - - // Take away the UAS and widget should disable - _mockUASManager->setMockActiveUAS(NULL); - QCOMPARE(_calWidget->isEnabled(), false); -} - /// @brief Test for correct behavior in determining minimum numbers of channels for flight. void PX4RCCalibrationTest::_minRCChannels_test(void) { diff --git a/src/qgcunittest/PX4RCCalibrationTest.h b/src/qgcunittest/PX4RCCalibrationTest.h index 51429f3cbbd2c2ad976b471fe066bac4680db8da..5937933bc877ca912006cdee3eb0e28347f94e21 100644 --- a/src/qgcunittest/PX4RCCalibrationTest.h +++ b/src/qgcunittest/PX4RCCalibrationTest.h @@ -48,7 +48,6 @@ private slots: void init(void); void cleanup(void); - void _setUAS_test(void); void _minRCChannels_test(void); void _fullCalibration_test(void); diff --git a/src/qgcunittest/QGCUASFileManagerTest.cc b/src/qgcunittest/QGCUASFileManagerTest.cc index 0d55b3c1a367c8d8d45e29bb6ea54cb64c591164..84134650a0e9c5febee4e0ef1d5966a2a135bafc 100644 --- a/src/qgcunittest/QGCUASFileManagerTest.cc +++ b/src/qgcunittest/QGCUASFileManagerTest.cc @@ -42,8 +42,16 @@ QGCUASFileManagerUnitTest::QGCUASFileManagerUnitTest(void) : // Called once before all test cases are run void QGCUASFileManagerUnitTest::initTestCase(void) { - _mockUAS.setMockSystemId(_systemIdServer); - _mockUAS.setMockMavlinkPlugin(&_mockFileServer); + _mockUAS = new MockUAS(); + Q_CHECK_PTR(_mockUAS); + + _mockUAS->setMockSystemId(_systemIdServer); + _mockUAS->setMockMavlinkPlugin(&_mockFileServer); +} + +void QGCUASFileManagerUnitTest::cleanupTestCase(void) +{ + delete _mockUAS; } // Called before every test case @@ -53,7 +61,7 @@ void QGCUASFileManagerUnitTest::init(void) Q_ASSERT(_multiSpy == NULL); - _fileManager = new QGCUASFileManager(NULL, &_mockUAS, _systemIdQGC); + _fileManager = new QGCUASFileManager(NULL, _mockUAS, _systemIdQGC); Q_CHECK_PTR(_fileManager); // Reset any internal state back to normal diff --git a/src/qgcunittest/QGCUASFileManagerTest.h b/src/qgcunittest/QGCUASFileManagerTest.h index cf29decd4226e1ef6888503557687f419a04f474..13b3a0d939e2b12d4b8a2592303b8ad3029a57c9 100644 --- a/src/qgcunittest/QGCUASFileManagerTest.h +++ b/src/qgcunittest/QGCUASFileManagerTest.h @@ -48,6 +48,7 @@ public: private slots: // Test case initialization void initTestCase(void); + void cleanupTestCase(void); void init(void); void cleanup(void); @@ -84,7 +85,7 @@ private: static const uint8_t _systemIdQGC = 255; static const uint8_t _systemIdServer = 128; - MockUAS _mockUAS; + MockUAS* _mockUAS; MockMavlinkFileServer _mockFileServer; QGCUASFileManager* _fileManager; diff --git a/src/ui/designer/QGCToolWidget.cc b/src/ui/designer/QGCToolWidget.cc index 37a3226a9c581c6f97b63d51c917dede6f300580..72db2d02bef438ee627083dede5f5a8ac4453af7 100644 --- a/src/ui/designer/QGCToolWidget.cc +++ b/src/ui/designer/QGCToolWidget.cc @@ -10,7 +10,7 @@ #include #include "QGCParamSlider.h" -#include "QGCComboBox.h" +#include "QGCToolWidgetComboBox.h" #include "QGCTextLabel.h" #include "QGCXYPlot.h" #include "QGCCommandButton.h" @@ -230,7 +230,7 @@ void QGCToolWidget::setParameterValue(int uas, int component, QString parameterN QString checkparam = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID").toString(); if (checkparam == parameterName) { - item = new QGCComboBox(this); + item = new QGCToolWidgetComboBox(this); addToolWidget(item); item->readSettings(widgetName + "\\" + QString::number(j) + "\\",settingsMap); paramToItemMap[parameterName] = item; @@ -274,7 +274,7 @@ void QGCToolWidget::loadSettings(QVariantMap& settings) } else if (type == "COMBO") { - item = new QGCComboBox(this); + item = new QGCToolWidgetComboBox(this); //qDebug() << "CREATED COMBOBOX"; } else if (type == "XYPLOT") @@ -330,7 +330,7 @@ void QGCToolWidget::loadSettings(QSettings& settings) } else if (type == "COMBO") { - item = new QGCComboBox(this); + item = new QGCToolWidgetComboBox(this); item->setActiveUAS(mav); qDebug() << "CREATED PARAM COMBOBOX"; } diff --git a/src/ui/designer/QGCComboBox.cc b/src/ui/designer/QGCToolWidgetComboBox.cc similarity index 92% rename from src/ui/designer/QGCComboBox.cc rename to src/ui/designer/QGCToolWidgetComboBox.cc index 2a0747c0e43fb022a48130342bccf4c6014f972c..f4923842e96158949f8207ce3484cfab35505bd8 100644 --- a/src/ui/designer/QGCComboBox.cc +++ b/src/ui/designer/QGCToolWidgetComboBox.cc @@ -5,13 +5,13 @@ #include #include -#include "QGCComboBox.h" -#include "ui_QGCComboBox.h" +#include "QGCToolWidgetComboBox.h" +#include "ui_QGCToolWidgetComboBox.h" #include "UASInterface.h" #include "UASManager.h" -QGCComboBox::QGCComboBox(QWidget *parent) : +QGCToolWidgetComboBox::QGCToolWidgetComboBox(QWidget *parent) : QGCToolWidgetItem("Combo", parent), parameterName(""), parameterValue(0.0f), @@ -19,7 +19,7 @@ QGCComboBox::QGCComboBox(QWidget *parent) : parameterMin(0.0f), parameterMax(0.0f), componentId(0), - ui(new Ui::QGCComboBox) + ui(new Ui::QGCToolWidgetComboBox) { ui->setupUi(this); uas = NULL; @@ -64,12 +64,12 @@ QGCComboBox::QGCComboBox(QWidget *parent) : init(); } -QGCComboBox::~QGCComboBox() +QGCToolWidgetComboBox::~QGCToolWidgetComboBox() { delete ui; } -void QGCComboBox::showTooltip() +void QGCToolWidgetComboBox::showTooltip() { QWidget* sender = dynamic_cast(QObject::sender()); @@ -80,7 +80,7 @@ void QGCComboBox::showTooltip() } } -void QGCComboBox::refreshParameter() +void QGCToolWidgetComboBox::refreshParameter() { ui->editSelectParamComboBox->setEnabled(true); ui->editSelectComponentComboBox->setEnabled(true); @@ -90,7 +90,7 @@ void QGCComboBox::refreshParameter() } } -void QGCComboBox::setActiveUAS(UASInterface* activeUas) +void QGCToolWidgetComboBox::setActiveUAS(UASInterface* activeUas) { if (activeUas) { @@ -119,7 +119,7 @@ void QGCComboBox::setActiveUAS(UASInterface* activeUas) } } -void QGCComboBox::requestParameter() +void QGCToolWidgetComboBox::requestParameter() { if (!parameterName.isEmpty() && uas) { @@ -127,18 +127,18 @@ void QGCComboBox::requestParameter() } } -void QGCComboBox::showInfo(bool enable) +void QGCToolWidgetComboBox::showInfo(bool enable) { ui->editInfoCheckBox->setChecked(enable); ui->infoLabel->setVisible(enable); } -void QGCComboBox::selectComponent(int componentIndex) +void QGCToolWidgetComboBox::selectComponent(int componentIndex) { this->componentId = ui->editSelectComponentComboBox->itemData(componentIndex).toInt(); } -void QGCComboBox::selectParameter(int paramIndex) +void QGCToolWidgetComboBox::selectParameter(int paramIndex) { // Set name parameterName = ui->editSelectParamComboBox->itemText(paramIndex); @@ -165,7 +165,7 @@ void QGCComboBox::selectParameter(int paramIndex) } } -void QGCComboBox::setEditMode(bool editMode) +void QGCToolWidgetComboBox::setEditMode(bool editMode) { if(!editMode) { // Store component id @@ -203,7 +203,7 @@ void QGCComboBox::setEditMode(bool editMode) QGCToolWidgetItem::setEditMode(editMode); } -void QGCComboBox::setParamPending() +void QGCToolWidgetComboBox::setParamPending() { if (uas) { uas->getParamManager()->setPendingParam(componentId, parameterName, parameterValue); @@ -220,7 +220,7 @@ void QGCComboBox::setParamPending() * @brief parameterName Key/name of the parameter * @brief value Value of the parameter */ -void QGCComboBox::setParameterValue(int uas, int component, int paramCount, int paramIndex, QString parameterName, QVariant value) +void QGCToolWidgetComboBox::setParameterValue(int uas, int component, int paramCount, int paramIndex, QString parameterName, QVariant value) { Q_UNUSED(paramCount); // Check if this component and parameter are part of the list @@ -301,7 +301,7 @@ void QGCComboBox::setParameterValue(int uas, int component, int paramCount, int } } -void QGCComboBox::changeEvent(QEvent *e) +void QGCToolWidgetComboBox::changeEvent(QEvent *e) { QWidget::changeEvent(e); switch (e->type()) { @@ -314,7 +314,7 @@ void QGCComboBox::changeEvent(QEvent *e) } -void QGCComboBox::writeSettings(QSettings& settings) +void QGCToolWidgetComboBox::writeSettings(QSettings& settings) { settings.setValue("TYPE", "COMBOBOX"); settings.setValue("QGC_PARAM_COMBOBOX_DESCRIPTION", ui->nameLabel->text()); @@ -331,7 +331,7 @@ void QGCComboBox::writeSettings(QSettings& settings) } settings.sync(); } -void QGCComboBox::readSettings(const QString& pre,const QVariantMap& settings) +void QGCToolWidgetComboBox::readSettings(const QString& pre,const QVariantMap& settings) { parameterName = settings.value(pre + "QGC_PARAM_COMBOBOX_PARAMID").toString(); componentId = settings.value(pre + "QGC_PARAM_COMBOBOX_COMPONENTID").toInt(); @@ -370,7 +370,7 @@ void QGCComboBox::readSettings(const QString& pre,const QVariantMap& settings) // Get param value after settings have been loaded // requestParameter(); } -void QGCComboBox::readSettings(const QSettings& settings) +void QGCToolWidgetComboBox::readSettings(const QSettings& settings) { QVariantMap map; foreach (QString key,settings.allKeys()) @@ -410,19 +410,19 @@ void QGCComboBox::readSettings(const QSettings& settings) // Get param value after settings have been loaded //requestParameter(); } -void QGCComboBox::addButtonClicked() +void QGCToolWidgetComboBox::addButtonClicked() { ui->editOptionComboBox->addItem(ui->editItemNameLabel->text()); comboBoxTextToValMap[ui->editItemNameLabel->text()] = ui->editItemValueSpinBox->value(); } -void QGCComboBox::delButtonClicked() +void QGCToolWidgetComboBox::delButtonClicked() { int index = ui->editOptionComboBox->currentIndex(); comboBoxTextToValMap.remove(ui->editOptionComboBox->currentText()); ui->editOptionComboBox->removeItem(index); } -void QGCComboBox::comboBoxIndexChanged(QString val) +void QGCToolWidgetComboBox::comboBoxIndexChanged(QString val) { ui->imageLabel->setPixmap(comboBoxIndexToPixmap[ui->editOptionComboBox->currentIndex()]); if (comboBoxTextToParamMap.contains(ui->editOptionComboBox->currentText())) diff --git a/src/ui/designer/QGCComboBox.h b/src/ui/designer/QGCToolWidgetComboBox.h similarity index 88% rename from src/ui/designer/QGCComboBox.h rename to src/ui/designer/QGCToolWidgetComboBox.h index a698e1f0ed5460d3b7d743ddd4f4ebaf2f8368df..785d606a4ec7a860097a1a51c154d8ee026d2e5a 100644 --- a/src/ui/designer/QGCComboBox.h +++ b/src/ui/designer/QGCToolWidgetComboBox.h @@ -1,5 +1,5 @@ -#ifndef QGCCOMBOBOX_H -#define QGCCOMBOBOX_H +#ifndef QGCToolWidgetComboBox_H +#define QGCToolWidgetComboBox_H #include #include @@ -11,16 +11,16 @@ class QGCUASParamManagerInterface; namespace Ui { -class QGCComboBox; +class QGCToolWidgetComboBox; } -class QGCComboBox : public QGCToolWidgetItem +class QGCToolWidgetComboBox : public QGCToolWidgetItem { Q_OBJECT public: - explicit QGCComboBox(QWidget *parent = 0); - ~QGCComboBox(); + explicit QGCToolWidgetComboBox(QWidget *parent = 0); + ~QGCToolWidgetComboBox(); virtual void setEditMode(bool editMode); @@ -70,7 +70,7 @@ protected: void changeEvent(QEvent *e); private: - Ui::QGCComboBox *ui; + Ui::QGCToolWidgetComboBox *ui; }; -#endif // QGCCOMBOBOX_H +#endif // QGCToolWidgetComboBox_H diff --git a/src/ui/designer/QGCComboBox.ui b/src/ui/designer/QGCToolWidgetComboBox.ui similarity index 98% rename from src/ui/designer/QGCComboBox.ui rename to src/ui/designer/QGCToolWidgetComboBox.ui index fdfbc7935b1feb8710265f39886e15ea36b0482d..59d1fb03586fe32f5ee6a1b87bef0fea3d8c3c1e 100644 --- a/src/ui/designer/QGCComboBox.ui +++ b/src/ui/designer/QGCToolWidgetComboBox.ui @@ -1,7 +1,7 @@ - QGCComboBox - + QGCToolWidgetComboBox + 0 diff --git a/src/ui/px4_configuration/PX4RCCalibration.cc b/src/ui/px4_configuration/PX4RCCalibration.cc index e51fba060683ad0fb39e5ae706d133888e9af8f3..6185849bdf5a797d221ca4cdf6ba33e15a2f9485 100644 --- a/src/ui/px4_configuration/PX4RCCalibration.cc +++ b/src/ui/px4_configuration/PX4RCCalibration.cc @@ -86,7 +86,6 @@ PX4RCCalibration::PX4RCCalibration(QWidget *parent) : _rcCalState(rcCalStateChannelWait), _mav(NULL), _paramMgr(NULL), - _parameterListUpToDateSignalled(false), _ui(new Ui::PX4RCCalibration), _unitTestMode(false) { @@ -120,15 +119,21 @@ PX4RCCalibration::PX4RCCalibration(QWidget *parent) : _rgAttitudeControl[4].function = rcCalFunctionFlaps; _rgAttitudeControl[4].valueWidget = _ui->flapsValue; - _setActiveUAS(UASManager::instance()->getActiveUAS()); + // This code assume we already have an active UAS with ready parameters + _mav = UASManager::instance()->getActiveUAS(); + Q_ASSERT(_mav); + + // Connect new signals - // Connect signals bool fSucceeded; Q_UNUSED(fSucceeded); - - fSucceeded = connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(_setActiveUAS(UASInterface*))); + fSucceeded = connect(_mav, SIGNAL(remoteControlChannelRawChanged(int,float)), this, SLOT(_remoteControlChannelRawChanged(int,float))); Q_ASSERT(fSucceeded); - + + _paramMgr = _mav->getParamManager(); + Q_ASSERT(_paramMgr); + Q_ASSERT(_paramMgr->parametersReady()); + connect(_ui->spektrumBind, &QPushButton::clicked, this, &PX4RCCalibration::_spektrumBind); _updateTimer.setInterval(150); @@ -159,6 +164,9 @@ PX4RCCalibration::PX4RCCalibration(QWidget *parent) : connect(_ui->mode2, &QAbstractButton::toggled, this, &PX4RCCalibration::_mode2Toggled); _stopCalibration(); + + connect(&_updateTimer, &QTimer::timeout, this, &PX4RCCalibration::_updateView); + _setInternalCalibrationValuesFromParameters(); } PX4RCCalibration::~PX4RCCalibration() @@ -699,84 +707,82 @@ void PX4RCCalibration::_setInternalCalibrationValuesFromParameters(void) { Q_ASSERT(_paramMgr); - if (_parameterListUpToDateSignalled) { - // Initialize all function mappings to not set + // Initialize all function mappings to not set + + for (size_t i=0; i<_chanMax; i++) { + struct ChannelInfo* info = &_rgChannelInfo[i]; + info->function = rcCalFunctionMax; + } + + for (size_t i=0; igetDefaultComponentId(); + + for (int i = 0; i < _chanMax; ++i) { + struct ChannelInfo* info = &_rgChannelInfo[i]; - for (size_t i=0; i<_chanMax; i++) { - struct ChannelInfo* info = &_rgChannelInfo[i]; - info->function = rcCalFunctionMax; + paramFound = _paramMgr->getParameterValue(componentId, trimTpl.arg(i+1), value); + Q_ASSERT(paramFound); + if (paramFound) { + info->rcTrim = value.toInt(&convertOk); + Q_ASSERT(convertOk); } - for (size_t i=0; igetParameterValue(componentId, minTpl.arg(i+1), value); + Q_ASSERT(paramFound); + if (paramFound) { + info->rcMin = value.toInt(&convertOk); + Q_ASSERT(convertOk); } - - // FIXME: Hardwired component id - - // Pull parameters and update - - QString minTpl("RC%1_MIN"); - QString maxTpl("RC%1_MAX"); - QString trimTpl("RC%1_TRIM"); - QString revTpl("RC%1_REV"); - QVariant value; - bool paramFound; - bool convertOk; - int componentId = _paramMgr->getDefaultComponentId(); - - for (int i = 0; i < _chanMax; ++i) { - struct ChannelInfo* info = &_rgChannelInfo[i]; - - paramFound = _paramMgr->getParameterValue(componentId, trimTpl.arg(i+1), value); - Q_ASSERT(paramFound); - if (paramFound) { - info->rcTrim = value.toInt(&convertOk); - Q_ASSERT(convertOk); - } - - paramFound = _paramMgr->getParameterValue(componentId, minTpl.arg(i+1), value); - Q_ASSERT(paramFound); - if (paramFound) { - info->rcMin = value.toInt(&convertOk); - Q_ASSERT(convertOk); - } - paramFound = _paramMgr->getParameterValue(componentId, maxTpl.arg(i+1), value); - Q_ASSERT(paramFound); - if (paramFound) { - info->rcMax = value.toInt(&convertOk); - Q_ASSERT(convertOk); - } + paramFound = _paramMgr->getParameterValue(componentId, maxTpl.arg(i+1), value); + Q_ASSERT(paramFound); + if (paramFound) { + info->rcMax = value.toInt(&convertOk); + Q_ASSERT(convertOk); + } - paramFound = _paramMgr->getParameterValue(componentId, revTpl.arg(i+1), value); - Q_ASSERT(paramFound); - if (paramFound) { - float floatReversed = value.toFloat(&convertOk); - Q_ASSERT(convertOk); - Q_ASSERT(floatReversed == 1.0f || floatReversed == -1.0f); - info->reversed = floatReversed == -1.0f; - } + paramFound = _paramMgr->getParameterValue(componentId, revTpl.arg(i+1), value); + Q_ASSERT(paramFound); + if (paramFound) { + float floatReversed = value.toFloat(&convertOk); + Q_ASSERT(convertOk); + Q_ASSERT(floatReversed == 1.0f || floatReversed == -1.0f); + info->reversed = floatReversed == -1.0f; } + } + + for (int i=0; igetParameterValue(componentId, _rgFunctionInfo[i].parameterName, value); + Q_ASSERT(paramFound); + if (paramFound) { + paramChannel = value.toInt(&convertOk); + Q_ASSERT(convertOk); - paramFound = _paramMgr->getParameterValue(componentId, _rgFunctionInfo[i].parameterName, value); - Q_ASSERT(paramFound); - if (paramFound) { - paramChannel = value.toInt(&convertOk); - Q_ASSERT(convertOk); - - if (paramChannel != 0) { - _rgFunctionChannelMapping[i] = paramChannel - 1; - _rgChannelInfo[paramChannel - 1].function = (enum rcCalFunctions)i; - } + if (paramChannel != 0) { + _rgFunctionChannelMapping[i] = paramChannel - 1; + _rgChannelInfo[paramChannel - 1].function = (enum rcCalFunctions)i; } } - - _showMinMaxOnRadioWidgets(true); - _showTrimOnRadioWidgets(true); } + + _showMinMaxOnRadioWidgets(true); + _showTrimOnRadioWidgets(true); } /// @brief Sets a connected Spektrum receiver into bind mode @@ -811,38 +817,6 @@ void PX4RCCalibration::_spektrumBind(void) } } -void PX4RCCalibration::_setActiveUAS(UASInterface* active) -{ - // Disconnect old signals - if (_mav) { - disconnect(_mav, SIGNAL(remoteControlChannelRawChanged(int,float)), this, SLOT(_remoteControlChannelRawChanged(int,float))); - disconnect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_parameterListUpToDate())); - _paramMgr = NULL; - } - - _mav = active; - - if (_mav) { - // Connect new signals - bool fSucceeded; - Q_UNUSED(fSucceeded); - fSucceeded = connect(_mav, SIGNAL(remoteControlChannelRawChanged(int,float)), this, SLOT(_remoteControlChannelRawChanged(int,float))); - Q_ASSERT(fSucceeded); - - _paramMgr = _mav->getParamManager(); - Q_ASSERT(_paramMgr); - - fSucceeded = connect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_parameterListUpToDate())); - Q_ASSERT(fSucceeded); - - if (_paramMgr->parametersReady()) { - _parameterListUpToDate(); - } - } - - setEnabled(_mav ? true : false); -} - /// @brief Validates the current settings against the calibration rules resetting values as necessary. void PX4RCCalibration::_validateCalibration(void) { @@ -1073,17 +1047,6 @@ void PX4RCCalibration::_showTrimOnRadioWidgets(bool show) } } -void PX4RCCalibration::_parameterListUpToDate(void) -{ - _parameterListUpToDateSignalled = true; - - // Don't start updating the view until we have parameters - connect(&_updateTimer, &QTimer::timeout, this, &PX4RCCalibration::_updateView); - - if (_currentStep == -1) { - _setInternalCalibrationValuesFromParameters(); - } -} void PX4RCCalibration::_loadSettings(void) { diff --git a/src/ui/px4_configuration/PX4RCCalibration.h b/src/ui/px4_configuration/PX4RCCalibration.h index 49ba54c6f785a507c304dbf2e956693af00cf6c9..868c345cbdcc3b6e1ae26fc92b5b6689786c50c4 100644 --- a/src/ui/px4_configuration/PX4RCCalibration.h +++ b/src/ui/px4_configuration/PX4RCCalibration.h @@ -71,9 +71,6 @@ private slots: void _updateView(void); void _remoteControlChannelRawChanged(int chan, float val); - void _setActiveUAS(UASInterface* uas); - - void _parameterListUpToDate(void); private: /// @brief These identify the various controls functions. They are also used as indices into the _rgFunctioInfo @@ -257,8 +254,6 @@ private: UASInterface* _mav; ///< The current MAV QGCUASParamManagerInterface* _paramMgr; - bool _parameterListUpToDateSignalled; ///< true: we have received a parameterListUpToDate signal - Ui::PX4RCCalibration* _ui; QTimer _updateTimer; ///< Timer used to update widgete ui