diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index b2a1b625071c13eb1783a9d6ab3116b914b0b2fb..73a8d4d0f50a0258ffc9c73cf76b9d874e7af23d 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -669,7 +669,9 @@ HEADERS += \ src/qgcunittest/MainWindowTest.h \ src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.h \ src/qgcunittest/MavlinkLogTest.h \ - src/FactSystem/FactSystemTest.h + src/FactSystem/FactSystemTestBase.h \ + src/FactSystem/FactSystemTestPX4.h \ + src/FactSystem/FactSystemTestGeneric.h SOURCES += \ src/qgcunittest/UnitTest.cc \ @@ -691,7 +693,9 @@ SOURCES += \ src/qgcunittest/MainWindowTest.cc \ src/AutoPilotPlugins/PX4/Tests/FlightModeConfigTest.cc \ src/qgcunittest/MavlinkLogTest.cc \ - src/FactSystem/FactSystemTest.cc + src/FactSystem/FactSystemTestBase.cc \ + src/FactSystem/FactSystemTestPX4.cc \ + src/FactSystem/FactSystemTestGeneric.cc } # @@ -713,6 +717,7 @@ HEADERS+= \ src/AutoPilotPlugins/AutoPilotPluginManager.h \ src/AutoPilotPlugins/AutoPilotPlugin.h \ src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h \ + src/AutoPilotPlugins/Generic/GenericParameterFacts.h \ src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h \ src/AutoPilotPlugins/PX4/PX4Component.h \ src/AutoPilotPlugins/PX4/RadioComponent.h \ @@ -730,6 +735,7 @@ SOURCES += \ src/VehicleSetup/VehicleComponentSummaryItem.cc \ src/AutoPilotPlugins/AutoPilotPluginManager.cc \ src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc \ + src/AutoPilotPlugins/Generic/GenericParameterFacts.cc \ src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc \ src/AutoPilotPlugins/PX4/PX4Component.cc \ src/AutoPilotPlugins/PX4/RadioComponent.cc \ @@ -750,9 +756,11 @@ HEADERS += \ src/FactSystem/Fact.h \ src/FactSystem/FactMetaData.h \ src/FactSystem/FactValidator.h \ + src/FactSystem/FactLoader.h \ SOURCES += \ src/FactSystem/FactSystem.cc \ src/FactSystem/Fact.cc \ src/FactSystem/FactMetaData.cc \ src/FactSystem/FactValidator.cc \ + src/FactSystem/FactLoader.cc \ diff --git a/src/AutoPilotPlugins/AutoPilotPluginManager.cc b/src/AutoPilotPlugins/AutoPilotPluginManager.cc index c2a2206cdb22588f6bdfe51e6056cdd302be8adc..097198218d7ba6feaff553a04757aefc9ada1651 100644 --- a/src/AutoPilotPlugins/AutoPilotPluginManager.cc +++ b/src/AutoPilotPlugins/AutoPilotPluginManager.cc @@ -89,7 +89,7 @@ void AutoPilotPluginManager::_uasDeleted(UASInterface* uas) { Q_ASSERT(uas); - MAV_AUTOPILOT autopilotType = static_cast(uas->getAutopilotType()); + MAV_AUTOPILOT autopilotType = _installedAutopilotType(static_cast(uas->getAutopilotType())); int uasId = uas->getUASID(); Q_ASSERT(uasId != 0); @@ -103,7 +103,7 @@ AutoPilotPlugin* AutoPilotPluginManager::getInstanceForAutoPilotPlugin(UASInterf { Q_ASSERT(uas); - MAV_AUTOPILOT autopilotType = static_cast(uas->getAutopilotType()); + MAV_AUTOPILOT autopilotType = _installedAutopilotType(static_cast(uas->getAutopilotType())); int uasId = uas->getUASID(); Q_ASSERT(uasId != 0); @@ -134,3 +134,9 @@ QString AutoPilotPluginManager::getShortModeText(uint8_t baseMode, uint32_t cust return GenericAutoPilotPlugin::getShortModeText(baseMode, customMode); } } + +/// If autopilot is not an installed plugin, returns MAV_AUTOPILOT_GENERIC +MAV_AUTOPILOT AutoPilotPluginManager::_installedAutopilotType(MAV_AUTOPILOT autopilot) +{ + return _pluginMap.contains(autopilot) ? autopilot : MAV_AUTOPILOT_GENERIC; +} diff --git a/src/AutoPilotPlugins/AutoPilotPluginManager.h b/src/AutoPilotPlugins/AutoPilotPluginManager.h index c1417c24b7feb48ea7e05bc4597969603e77e3cd..03c76074438421736dbb1d92ee1d29b1657a0961 100644 --- a/src/AutoPilotPlugins/AutoPilotPluginManager.h +++ b/src/AutoPilotPlugins/AutoPilotPluginManager.h @@ -71,6 +71,8 @@ private: AutoPilotPluginManager(QObject* parent = NULL); ~AutoPilotPluginManager(); + MAV_AUTOPILOT _installedAutopilotType(MAV_AUTOPILOT autopilot); + QMap > _pluginMap; ///< Map of AutoPilot plugins _pluginMap[MAV_TYPE][UASid] }; diff --git a/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc b/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc index d6fd7b3d228b4a1af91495da14ea53c966e49558..03ebb8e1219f3bdb09a92a830cd90cd32fc9f900 100644 --- a/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc +++ b/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.cc @@ -30,6 +30,12 @@ GenericAutoPilotPlugin::GenericAutoPilotPlugin(UASInterface* uas, QObject* paren AutoPilotPlugin(parent) { Q_UNUSED(uas); + + _parameterFacts = new GenericParameterFacts(uas, this); + Q_CHECK_PTR(_parameterFacts); + + connect(_parameterFacts, &GenericParameterFacts::factsReady, this, &GenericAutoPilotPlugin::pluginReady); + } QList GenericAutoPilotPlugin::getModes(void) @@ -84,24 +90,17 @@ void GenericAutoPilotPlugin::clearStaticData(void) const QVariantList& GenericAutoPilotPlugin::components(void) { - static QVariantList staticList; + static QVariantList emptyList; - Q_ASSERT_X(false, "Not yet implemented", ""); - return staticList; + return emptyList; } const QVariantMap& GenericAutoPilotPlugin::parameters(void) { - static QVariantMap staticMap; - - Q_ASSERT_X(false, "Not yet implemented", ""); - return staticMap; + return _parameterFacts->factMap(); } QUrl GenericAutoPilotPlugin::setupBackgroundImage(void) { - static QUrl url; - - Q_ASSERT_X(false, "Not yet implemented", ""); - return url; + return QUrl::fromUserInput("qrc:/qml/px4fmu_2.x.png"); } diff --git a/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h b/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h index 9e9b4f86bcadb860417b1c045b20855d691dffe8..5a2262b1e6ba90a72a97b912410c8a147dfc801c 100644 --- a/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h +++ b/src/AutoPilotPlugins/Generic/GenericAutoPilotPlugin.h @@ -26,6 +26,7 @@ #include "AutoPilotPlugin.h" #include "AutoPilotPluginManager.h" +#include "GenericParameterFacts.h" /// @file /// @brief This is the generic implementation of the AutoPilotPlugin class for mavs @@ -40,7 +41,7 @@ public: GenericAutoPilotPlugin(UASInterface* uas, QObject* parent = NULL); // Overrides from AutoPilotPlugin - virtual bool pluginIsReady(void) const { return true; } + virtual bool pluginIsReady(void) const { return _parameterFacts->factsAreReady(); } virtual QUrl setupBackgroundImage(void); virtual const QVariantList& components(void); virtual const QVariantMap& parameters(void); @@ -49,7 +50,8 @@ public: static QString getShortModeText(uint8_t baseMode, uint32_t customMode); static void clearStaticData(void); -protected: +private: + GenericParameterFacts* _parameterFacts; }; #endif diff --git a/src/AutoPilotPlugins/Generic/GenericParameterFacts.cc b/src/AutoPilotPlugins/Generic/GenericParameterFacts.cc new file mode 100644 index 0000000000000000000000000000000000000000..c37d05dc5fec7d71b7511e5f16188d9a32c77268 --- /dev/null +++ b/src/AutoPilotPlugins/Generic/GenericParameterFacts.cc @@ -0,0 +1,37 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#include "GenericParameterFacts.h" +#include "QGCApplication.h" + +#include +#include + +GenericParameterFacts::GenericParameterFacts(UASInterface* uas, QObject* parent) : + FactLoader(uas, parent) +{ + Q_ASSERT(uas); +} diff --git a/src/AutoPilotPlugins/Generic/GenericParameterFacts.h b/src/AutoPilotPlugins/Generic/GenericParameterFacts.h new file mode 100644 index 0000000000000000000000000000000000000000..ae363b432494de6efc8492949cacd7485173fc87 --- /dev/null +++ b/src/AutoPilotPlugins/Generic/GenericParameterFacts.h @@ -0,0 +1,49 @@ +/*===================================================================== + + 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 GenericParameterFacts_h +#define GenericParameterFacts_h + +#include +#include +#include +#include + +#include "FactSystem.h" +#include "UASInterface.h" + +/// @file +/// @author Don Gagne + +/// Collection of Parameter Facts for Generic AutoPilot + +class GenericParameterFacts : public FactLoader +{ + Q_OBJECT + +public: + /// @param uas Uas which this set of facts is associated with + GenericParameterFacts(UASInterface* uas, QObject* parent = NULL); +}; + +#endif \ No newline at end of file diff --git a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h index 6607983a032a27bd95856ad103fe69c054cad639..abb65c45d1bf130dcfc8b553a1f197971333541f 100644 --- a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h +++ b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h @@ -56,7 +56,6 @@ public: private: UASInterface* _uas; PX4ParameterFacts* _parameterFacts; - bool _pluginReady; QVariantList _components; }; diff --git a/src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc b/src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc index f71945db73dfbf833afdc22767aba1098d7a41a2..b3f20f47402ddd247e0401fdaf102b32a591d99f 100644 --- a/src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc +++ b/src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc @@ -30,42 +30,15 @@ #include #include -Q_LOGGING_CATEGORY(PX4ParameterFactsLog, "PX4ParameterFactsLog") Q_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog, "PX4ParameterFactsMetaDataLog") bool PX4ParameterFacts::_parameterMetaDataLoaded = false; QMap PX4ParameterFacts::_mapParameterName2FactMetaData; PX4ParameterFacts::PX4ParameterFacts(UASInterface* uas, QObject* parent) : - QObject(parent), - _lastSeenComponent(-1), - _paramMgr(NULL), - _factsReady(false) + FactLoader(uas, parent) { Q_ASSERT(uas); - - _uasId = uas->getUASID(); - - _paramMgr = uas->getParamManager(); - Q_ASSERT(_paramMgr); - - // We need to be initialized before param mgr starts sending parameters so we catch each one - Q_ASSERT(!_paramMgr->parametersReady()); - - // We need to know when the param mgr is done sending the initial set of paramters - connect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate())); - - // UASInterface::parameterChanged has multiple overrides so we need to use SIGNAL/SLOT style connect - connect(uas, SIGNAL(parameterChanged(int, int, QString, QVariant)), this, SLOT(_parameterChanged(int, int, QString, QVariant))); -} - -PX4ParameterFacts::~PX4ParameterFacts() -{ - foreach(Fact* fact, _mapFact2ParameterName.keys()) { - delete fact; - } - _mapParameterName2Variant.clear(); - _mapFact2ParameterName.clear(); } void PX4ParameterFacts::deleteParameterFactMetaData(void) @@ -76,88 +49,6 @@ void PX4ParameterFacts::deleteParameterFactMetaData(void) _mapParameterName2FactMetaData.clear(); } -/// Connected to QGCUASParmManager::parameterChanged -/// -/// When a new parameter is seen it is added to the system. If the parameter is already known it is updated. -void PX4ParameterFacts::_parameterChanged(int uas, int component, QString parameterName, QVariant value) -{ - // Is this for our uas? - if (uas != _uasId) { - return; - } - - if (_lastSeenComponent == -1) { - _lastSeenComponent = component; - } else { - // Code cannot handle parameters coming form different components yets - Q_ASSERT(component == _lastSeenComponent); - } - - if (!_mapParameterName2Variant.contains(parameterName)) { - Fact* fact = new Fact(this); - - if (_mapParameterName2FactMetaData.contains(parameterName)) { - fact->setMetaData(_mapParameterName2FactMetaData[parameterName]); - } else { - qDebug() << "FactSystem meta data out of date. Missing parameter:" << parameterName; - } - - _mapParameterName2Variant[parameterName] = QVariant::fromValue(fact); - _mapFact2ParameterName[fact] = parameterName; - - // We need to know when the fact changes so that we can send the new value to the parameter manager - connect(fact, &Fact::_containerValueChanged, this, &PX4ParameterFacts::_valueUpdated); - - qCDebug(PX4ParameterFactsLog) << "Adding new fact" << parameterName; - } - - Q_ASSERT(_mapParameterName2Variant.contains(parameterName)); - - qCDebug(PX4ParameterFactsLog) << "Updating fact value" << parameterName << value; - - Fact* fact = _mapParameterName2Variant[parameterName].value(); - Q_ASSERT(fact); - fact->_containerSetValue(value); -} - -/// Connected to Fact::valueUpdated -/// -/// Sets the new value into the Parameter Manager. Paramter is persisted after send. -void PX4ParameterFacts::_valueUpdated(QVariant value) -{ - Fact* fact = qobject_cast(sender()); - Q_ASSERT(fact); - - Q_ASSERT(_lastSeenComponent != -1); - Q_ASSERT(_paramMgr); - Q_ASSERT(_mapFact2ParameterName.contains(fact)); - - QVariant typedValue; - switch (fact->type()) { - case FactMetaData::valueTypeInt8: - case FactMetaData::valueTypeInt16: - case FactMetaData::valueTypeInt32: - typedValue = QVariant(value.value()); - - case FactMetaData::valueTypeUint8: - case FactMetaData::valueTypeUint16: - case FactMetaData::valueTypeUint32: - typedValue = QVariant(value.value()); - break; - - case FactMetaData::valueTypeFloat: - typedValue = QVariant(value.toFloat()); - break; - - case FactMetaData::valueTypeDouble: - typedValue = QVariant(value.toDouble()); - break; - } - - _paramMgr->setParameter(_lastSeenComponent, _mapFact2ParameterName[fact], typedValue); - _paramMgr->sendPendingParameters(true /* persistAfterSend */, false /* forceSend */); -} - /// Parse the Parameter element of parameter xml meta data /// @param[in] xml stream reader /// @param[in] group fact group associated with this Param element @@ -327,7 +218,7 @@ void PX4ParameterFacts::loadParameterFactMetaData(void) // Just move to next state } else if (elementName == "group") { factGroup = xml.attributes().value("name").toString(); - qCDebug(PX4ParameterFactsLog) << "Found group: " << factGroup; + qCDebug(PX4ParameterFactsMetaDataLog) << "Found group: " << factGroup; } else if (elementName == "parameter") { metaData = _parseParameter(xml, factGroup); } else if (elementName == "short_desc") { @@ -365,23 +256,6 @@ void PX4ParameterFacts::loadParameterFactMetaData(void) } } -// Called when param mgr list is up to date -void PX4ParameterFacts::_paramMgrParameterListUpToDate(void) -{ - if (!_factsReady) { - _factsReady = true; - - // We don't need this any more - disconnect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate())); - - // There may be parameterUpdated signals still in our queue. Flush them out. - qgcApp()->processEvents(); - - // We should have all paramters now so we can signal ready - emit factsReady(); - } -} - void PX4ParameterFacts::clearStaticData(void) { foreach(QString parameterName, _mapParameterName2FactMetaData.keys()) { diff --git a/src/AutoPilotPlugins/PX4/PX4ParameterFacts.h b/src/AutoPilotPlugins/PX4/PX4ParameterFacts.h index e8964137f11cdb0fe5543f6ece69b6921dddd609..01771a264eaa63bd1f1ad6106fb16dae692b753f 100644 --- a/src/AutoPilotPlugins/PX4/PX4ParameterFacts.h +++ b/src/AutoPilotPlugins/PX4/PX4ParameterFacts.h @@ -29,27 +29,17 @@ #include #include -#include "Fact.h" +#include "FactSystem.h" #include "UASInterface.h" /// @file /// @author Don Gagne -// FIXME: This file should be auto-generated from the Parameter XML file. - -Q_DECLARE_LOGGING_CATEGORY(PX4ParameterFactsLog) Q_DECLARE_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog) /// Collection of Parameter Facts for PX4 AutoPilot -/// -/// These Facts are available for binding within QML code. For example: -/// @code{.unparsed} -/// TextInput { -/// text: parameters["RC_MAP_THROTTLE"].value -/// } -/// @endcode -class PX4ParameterFacts : public QObject +class PX4ParameterFacts : public FactLoader { Q_OBJECT @@ -57,45 +47,17 @@ public: /// @param uas Uas which this set of facts is associated with PX4ParameterFacts(UASInterface* uas, QObject* parent = NULL); - ~PX4ParameterFacts(); - - /// Returns true if the full set of facts are ready - bool factsAreReady(void) { return _factsReady; } - - /// Returns the fact QVariantMap - const QVariantMap& factMap(void) { return _mapParameterName2Variant; } - static void loadParameterFactMetaData(void); static void deleteParameterFactMetaData(void); static void clearStaticData(void); -signals: - /// Signalled when the full set of facts are ready - void factsReady(void); - -private slots: - void _parameterChanged(int uas, int component, QString parameterName, QVariant value); - void _valueUpdated(QVariant value); - void _paramMgrParameterListUpToDate(void); - private: static FactMetaData* _parseParameter(QXmlStreamReader& xml, const QString& group); static void _initMetaData(FactMetaData* metaData); static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk = false); - QMap _mapFact2ParameterName; ///< Maps from a Fact to a parameter name - static bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded static QMap _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData - - int _uasId; ///< Id for uas which this set of Facts are associated with - int _lastSeenComponent; - - QGCUASParamManagerInterface* _paramMgr; - - QVariantMap _mapParameterName2Variant; - - bool _factsReady; ///< All facts received from param mgr }; #endif \ No newline at end of file diff --git a/src/FactSystem/FactLoader.cc b/src/FactSystem/FactLoader.cc new file mode 100644 index 0000000000000000000000000000000000000000..c1ad52872f37b4d29d1cf1ab1e1fce9f1d66c4a5 --- /dev/null +++ b/src/FactSystem/FactLoader.cc @@ -0,0 +1,159 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#include "FactLoader.h" +#include "QGCApplication.h" + +#include +#include + +Q_LOGGING_CATEGORY(FactLoaderLog, "FactLoaderLog") + +FactLoader::FactLoader(UASInterface* uas, QObject* parent) : + QObject(parent), + _lastSeenComponent(-1), + _paramMgr(NULL), + _factsReady(false) +{ + Q_ASSERT(uas); + + _uasId = uas->getUASID(); + + _paramMgr = uas->getParamManager(); + Q_ASSERT(_paramMgr); + + // We need to be initialized before param mgr starts sending parameters so we catch each one + Q_ASSERT(!_paramMgr->parametersReady()); + + // We need to know when the param mgr is done sending the initial set of paramters + connect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate())); + + // We track parameters changes to keep Facts up to date. UASInterface::parameterChanged has multiple overrides so we need to + // use SIGNAL/SLOT style connect + connect(uas, SIGNAL(parameterChanged(int, int, QString, QVariant)), this, SLOT(_parameterChanged(int, int, QString, QVariant))); +} + +FactLoader::~FactLoader() +{ + foreach(Fact* fact, _mapFact2ParameterName.keys()) { + delete fact; + } + _mapParameterName2Variant.clear(); + _mapFact2ParameterName.clear(); +} + +/// Connected to QGCUASParmManager::parameterChanged +/// +/// When a new parameter is seen it is added to the system. If the parameter is already known it is updated. +void FactLoader::_parameterChanged(int uas, int component, QString parameterName, QVariant value) +{ + // Is this for our uas? + if (uas != _uasId) { + return; + } + + if (_lastSeenComponent == -1) { + _lastSeenComponent = component; + } else { + // Code cannot handle parameters coming form different components yets + Q_ASSERT(component == _lastSeenComponent); + } + + if (!_mapParameterName2Variant.contains(parameterName)) { + Fact* fact = new Fact(this); + + _mapParameterName2Variant[parameterName] = QVariant::fromValue(fact); + _mapFact2ParameterName[fact] = parameterName; + + // We need to know when the fact changes from QML so that we can send the new value to the parameter manager + connect(fact, &Fact::_containerValueChanged, this, &FactLoader::_valueUpdated); + + qCDebug(FactLoaderLog) << "Adding new fact" << parameterName; + } + + Q_ASSERT(_mapParameterName2Variant.contains(parameterName)); + + qCDebug(FactLoaderLog) << "Updating fact value" << parameterName << value; + + Fact* fact = _mapParameterName2Variant[parameterName].value(); + Q_ASSERT(fact); + fact->_containerSetValue(value); +} + +/// Connected to Fact::valueUpdated +/// +/// Sets the new value into the Parameter Manager. Paramter is persisted after send. +void FactLoader::_valueUpdated(QVariant value) +{ + Fact* fact = qobject_cast(sender()); + Q_ASSERT(fact); + + Q_ASSERT(_lastSeenComponent != -1); + Q_ASSERT(_paramMgr); + Q_ASSERT(_mapFact2ParameterName.contains(fact)); + + QVariant typedValue; + switch (fact->type()) { + case FactMetaData::valueTypeInt8: + case FactMetaData::valueTypeInt16: + case FactMetaData::valueTypeInt32: + typedValue = QVariant(value.value()); + + case FactMetaData::valueTypeUint8: + case FactMetaData::valueTypeUint16: + case FactMetaData::valueTypeUint32: + typedValue = QVariant(value.value()); + break; + + case FactMetaData::valueTypeFloat: + typedValue = QVariant(value.toFloat()); + break; + + case FactMetaData::valueTypeDouble: + typedValue = QVariant(value.toDouble()); + break; + } + + _paramMgr->setParameter(_lastSeenComponent, _mapFact2ParameterName[fact], typedValue); + _paramMgr->sendPendingParameters(true /* persistAfterSend */, false /* forceSend */); +} + +// Called when param mgr list is up to date +void FactLoader::_paramMgrParameterListUpToDate(void) +{ + if (!_factsReady) { + _factsReady = true; + + // We don't need this any more + disconnect(_paramMgr, SIGNAL(parameterListUpToDate()), this, SLOT(_paramMgrParameterListUpToDate())); + + // There may be parameterUpdated signals still in our queue. Flush them out. + qgcApp()->processEvents(); + + // We should have all paramters now so we can signal ready + emit factsReady(); + } +} diff --git a/src/FactSystem/FactLoader.h b/src/FactSystem/FactLoader.h new file mode 100644 index 0000000000000000000000000000000000000000..ed9503df08a3d0bcccaf0255882bd195dbfb0984 --- /dev/null +++ b/src/FactSystem/FactLoader.h @@ -0,0 +1,89 @@ +/*===================================================================== + + 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 FactLoader_h +#define FactLoader_h + +#include +#include +#include +#include + +#include "Fact.h" +#include "UASInterface.h" + +/// @file +/// @author Don Gagne + +Q_DECLARE_LOGGING_CATEGORY(FactLoaderLog) + +/// Connects to Parameter Manager to load/update Facts +/// +/// These Facts are available for binding within QML code. For example: +/// @code{.unparsed} +/// TextInput { +/// text: autopilot.parameters["RC_MAP_THROTTLE"].value +/// } +/// @endcode + +class FactLoader : public QObject +{ + Q_OBJECT + +public: + /// @param uas Uas which this set of facts is associated with + FactLoader(UASInterface* uas, QObject* parent = NULL); + + ~FactLoader(); + + /// Returns true if the full set of facts are ready + bool factsAreReady(void) { return _factsReady; } + + /// Returns the fact QVariantMap + const QVariantMap& factMap(void) { return _mapParameterName2Variant; } + +signals: + /// Signalled when the full set of facts are ready + void factsReady(void); + +private slots: + void _parameterChanged(int uas, int component, QString parameterName, QVariant value); + void _valueUpdated(QVariant value); + void _paramMgrParameterListUpToDate(void); + +private: + static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk = false); + + QMap _mapFact2ParameterName; ///< Maps from a Fact to a parameter name + + int _uasId; ///< Id for uas which this set of Facts are associated with + int _lastSeenComponent; + + QGCUASParamManagerInterface* _paramMgr; + + QVariantMap _mapParameterName2Variant; + + bool _factsReady; ///< All facts received from param mgr +}; + +#endif \ No newline at end of file diff --git a/src/FactSystem/FactSystem.h b/src/FactSystem/FactSystem.h index 1883ed61a5c430923c42d1fd3beadbbf1b4b233c..8a9b533ac685fc66adde0cee9c0a46c27ce34c3d 100644 --- a/src/FactSystem/FactSystem.h +++ b/src/FactSystem/FactSystem.h @@ -28,6 +28,7 @@ #define FactSystem_h #include "Fact.h" +#include "FactLoader.h" #include "FactMetaData.h" #include "UASInterface.h" #include "QGCSingleton.h" diff --git a/src/FactSystem/FactSystemTest.cc b/src/FactSystem/FactSystemTestBase.cc similarity index 93% rename from src/FactSystem/FactSystemTest.cc rename to src/FactSystem/FactSystemTestBase.cc index bc0f6060dd4801aebde3643cb686e154b06bfc17..d8bf606b56e682aa3b5829760936adc6d1989b0f 100644 --- a/src/FactSystem/FactSystemTest.cc +++ b/src/FactSystem/FactSystemTestBase.cc @@ -24,7 +24,7 @@ /// @file /// @author Don Gagne -#include "FactSystemTest.h" +#include "FactSystemTestBase.h" #include "LinkManager.h" #include "MockLink.h" #include "AutoPilotPluginManager.h" @@ -34,21 +34,20 @@ #include -UT_REGISTER_TEST(FactSystemTest) - /// FactSystem Unit Test -FactSystemTest::FactSystemTest(void) +FactSystemTestBase::FactSystemTestBase(void) { } -void FactSystemTest::init(void) +void FactSystemTestBase::_init(MAV_AUTOPILOT autopilot) { UnitTest::init(); LinkManager* _linkMgr = LinkManager::instance(); MockLink* link = new MockLink(); + link->setAutopilotType(autopilot); _linkMgr->addLink(link); _linkMgr->connectLink(link); @@ -80,13 +79,13 @@ void FactSystemTest::init(void) Q_ASSERT(_plugin->pluginIsReady()); } -void FactSystemTest::cleanup(void) +void FactSystemTestBase::_cleanup(void) { UnitTest::cleanup(); } /// Basic test of parameter values in Fact System -void FactSystemTest::_parameter_test(void) +void FactSystemTestBase::_parameter_test(void) { // Get the parameter facts from the AutoPilot @@ -106,7 +105,7 @@ void FactSystemTest::_parameter_test(void) } /// Test that QML can reference a Fact -void FactSystemTest::_qml_test(void) +void FactSystemTestBase::_qml_test(void) { QGCQuickWidget* widget = new QGCQuickWidget; @@ -126,7 +125,7 @@ void FactSystemTest::_qml_test(void) } // Test correct behavior when the Param Manager gets a parameter update -void FactSystemTest::_paramMgrSignal_test(void) +void FactSystemTestBase::_paramMgrSignal_test(void) { // Get the parameter Fact from the AutoPilot @@ -156,7 +155,7 @@ void FactSystemTest::_paramMgrSignal_test(void) } /// Test QML getting an updated Fact value -void FactSystemTest::_qmlUpdate_test(void) +void FactSystemTestBase::_qmlUpdate_test(void) { QGCQuickWidget* widget = new QGCQuickWidget; diff --git a/src/FactSystem/FactSystemTest.h b/src/FactSystem/FactSystemTestBase.h similarity index 84% rename from src/FactSystem/FactSystemTest.h rename to src/FactSystem/FactSystemTestBase.h index 07d43f2d0611991245e40437cd31a283bc6fcdcf..818f765cd174d20a51eaa0203e58fc687f043af8 100644 --- a/src/FactSystem/FactSystemTest.h +++ b/src/FactSystem/FactSystemTestBase.h @@ -24,31 +24,30 @@ /// @file /// @author Don Gagne -#ifndef FactSystemTest_H -#define FactSystemTest_H +#ifndef FactSystemTestBase_H +#define FactSystemTestBase_H #include "UnitTest.h" #include "UASInterface.h" #include "AutoPilotPlugin.h" -// Unit Test for Fact System -class FactSystemTest : public UnitTest +// Base class for FactSystemTest[PX4|Generic] unit tests +class FactSystemTestBase : public UnitTest { Q_OBJECT public: - FactSystemTest(void); + FactSystemTestBase(void); -private slots: - void init(void); - void cleanup(void); +protected: + void _init(MAV_AUTOPILOT autopilot); + void _cleanup(void); void _parameter_test(void); void _qml_test(void); void _paramMgrSignal_test(void); void _qmlUpdate_test(void); -private: UASInterface* _uas; QGCUASParamManagerInterface* _paramMgr; AutoPilotPlugin* _plugin; diff --git a/src/FactSystem/FactSystemTestGeneric.cc b/src/FactSystem/FactSystemTestGeneric.cc new file mode 100644 index 0000000000000000000000000000000000000000..dc86e1ff6a40706fc81a4635a38aad2f0bcecd99 --- /dev/null +++ b/src/FactSystem/FactSystemTestGeneric.cc @@ -0,0 +1,49 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#include "FactSystemTestGeneric.h" +#include "LinkManager.h" +#include "MockLink.h" +#include "AutoPilotPluginManager.h" +#include "UASManager.h" +#include "QGCApplication.h" +#include "QGCQuickWidget.h" + +#include + +UT_REGISTER_TEST(FactSystemTestGeneric) + +/// FactSystem Unit Test for PX4 autpilot +FactSystemTestGeneric::FactSystemTestGeneric(void) +{ + +} + +void FactSystemTestGeneric::init(void) +{ + UnitTest::init(); + _init(MAV_AUTOPILOT_ARDUPILOTMEGA); +} diff --git a/src/FactSystem/FactSystemTestGeneric.h b/src/FactSystem/FactSystemTestGeneric.h new file mode 100644 index 0000000000000000000000000000000000000000..0435ccf6510adcaccad8c35343f44bfd064d3d08 --- /dev/null +++ b/src/FactSystem/FactSystemTestGeneric.h @@ -0,0 +1,52 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#ifndef FactSystemTestGeneric_H +#define FactSystemTestGeneric_H + +#include "FactSystemTestBase.h" +#include "UASInterface.h" +#include "AutoPilotPlugin.h" + +// Unit Test for Fact System on PX4 autopilot +class FactSystemTestGeneric : public FactSystemTestBase +{ + Q_OBJECT + +public: + FactSystemTestGeneric(void); + +private slots: + void init(void); + void cleanup(void) { _cleanup(); } + + void parameter_test(void) { _parameter_test(); } + void qml_test(void) { _qml_test(); } + void paramMgrSignal_test(void) { _paramMgrSignal_test(); } + void qmlUpdate_test(void) { _qmlUpdate_test(); } +}; + +#endif diff --git a/src/FactSystem/FactSystemTestPX4.cc b/src/FactSystem/FactSystemTestPX4.cc new file mode 100644 index 0000000000000000000000000000000000000000..2e30f72a0c27b35e735a677fd3405e0f3b8c69e5 --- /dev/null +++ b/src/FactSystem/FactSystemTestPX4.cc @@ -0,0 +1,49 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#include "FactSystemTestPX4.h" +#include "LinkManager.h" +#include "MockLink.h" +#include "AutoPilotPluginManager.h" +#include "UASManager.h" +#include "QGCApplication.h" +#include "QGCQuickWidget.h" + +#include + +UT_REGISTER_TEST(FactSystemTestPX4) + +/// FactSystem Unit Test for PX4 autpilot +FactSystemTestPX4::FactSystemTestPX4(void) +{ + +} + +void FactSystemTestPX4::init(void) +{ + UnitTest::init(); + _init(MAV_AUTOPILOT_PX4); +} diff --git a/src/FactSystem/FactSystemTestPX4.h b/src/FactSystem/FactSystemTestPX4.h new file mode 100644 index 0000000000000000000000000000000000000000..54118e9070c3861ea8c07cda2ad1bbf3952b39ca --- /dev/null +++ b/src/FactSystem/FactSystemTestPX4.h @@ -0,0 +1,52 @@ +/*===================================================================== + + 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 +/// @author Don Gagne + +#ifndef FactSystemTestPX4_H +#define FactSystemTestPX4_H + +#include "FactSystemTestBase.h" +#include "UASInterface.h" +#include "AutoPilotPlugin.h" + +// Unit Test for Fact System on PX4 autopilot +class FactSystemTestPX4 : public FactSystemTestBase +{ + Q_OBJECT + +public: + FactSystemTestPX4(void); + +private slots: + void init(void); + void cleanup(void) { _cleanup(); } + + void parameter_test(void) { _parameter_test(); } + void qml_test(void) { _qml_test(); } + void paramMgrSignal_test(void) { _paramMgrSignal_test(); } + void qmlUpdate_test(void) { _qmlUpdate_test(); } +}; + +#endif diff --git a/src/qgcunittest/MainWindowTest.cc b/src/qgcunittest/MainWindowTest.cc index 3aa5b712d0f685cffcd7da0294669322fe8eec04..da0dec57434775f240cd36fbd69843c10261bf27 100644 --- a/src/qgcunittest/MainWindowTest.cc +++ b/src/qgcunittest/MainWindowTest.cc @@ -69,13 +69,14 @@ void MainWindowTest::_clickThrough_test(void) } -void MainWindowTest::_connectWindowClose_test(void) +void MainWindowTest::_connectWindowClose_test(MAV_AUTOPILOT autopilot) { LinkManager* linkMgr = LinkManager::instance(); Q_CHECK_PTR(linkMgr); MockLink* link = new MockLink(); Q_CHECK_PTR(link); + link->setAutopilotType(autopilot); LinkManager::instance()->addLink(link); linkMgr->connectLink(link); QTest::qWait(5000); // Give enough time for UI to settle and heartbeats to go through @@ -92,3 +93,11 @@ void MainWindowTest::_connectWindowClose_test(void) QTest::qWait(1000); // Need to allow signals to move between threads checkExpectedFileDialog(); } + +void MainWindowTest::_connectWindowClosePX4_test(void) { + _connectWindowClose_test(MAV_AUTOPILOT_PX4); +} + +void MainWindowTest::_connectWindowCloseGeneric_test(void) { + _connectWindowClose_test(MAV_AUTOPILOT_ARDUPILOTMEGA); +} diff --git a/src/qgcunittest/MainWindowTest.h b/src/qgcunittest/MainWindowTest.h index 87eb8270eafde5d5b2e59799ca00af8b23b11dac..e37cf9e33a30ffcd766cf2f4f06b05482642c513 100644 --- a/src/qgcunittest/MainWindowTest.h +++ b/src/qgcunittest/MainWindowTest.h @@ -44,9 +44,11 @@ private slots: void cleanup(void); void _clickThrough_test(void); - void _connectWindowClose_test(void); + void _connectWindowClosePX4_test(void); + void _connectWindowCloseGeneric_test(void); private: + void _connectWindowClose_test(MAV_AUTOPILOT autopilot); MainWindow* _mainWindow; }; diff --git a/src/qgcunittest/MockLink.cc b/src/qgcunittest/MockLink.cc index cad0dcc924c7f7004e0c18c3db36450a4f1b55c8..16a00e6de3b6b184135df06b2165c68707468cdc 100644 --- a/src/qgcunittest/MockLink.cc +++ b/src/qgcunittest/MockLink.cc @@ -74,7 +74,8 @@ MockLink::MockLink(void) : _inNSH(false), _mavlinkStarted(false), _mavBaseMode(MAV_MODE_FLAG_MANUAL_INPUT_ENABLED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED), - _mavState(MAV_STATE_STANDBY) + _mavState(MAV_STATE_STANDBY), + _autopilotType(MAV_AUTOPILOT_PX4) { union px4_custom_mode px4_cm; @@ -145,20 +146,20 @@ void MockLink::run(void) void MockLink::_run1HzTasks(void) { - if (_mavlinkStarted) { + if (_mavlinkStarted && _connected) { _sendHeartBeat(); } } void MockLink::_run10HzTasks(void) { - if (_mavlinkStarted) { + if (_mavlinkStarted && _connected) { } } void MockLink::_run50HzTasks(void) { - if (_mavlinkStarted) { + if (_mavlinkStarted && _connected) { } } @@ -219,7 +220,7 @@ void MockLink::_sendHeartBeat(void) _vehicleComponentId, &msg, MAV_TYPE_QUADROTOR, // MAV_TYPE - MAV_AUTOPILOT_PX4, // MAV_AUTOPILOT + _autopilotType, // MAV_AUTOPILOT _mavBaseMode, // MAV_MODE _mavCustomMode, // custom mode _mavState); // MAV_STATE diff --git a/src/qgcunittest/MockLink.h b/src/qgcunittest/MockLink.h index d6814b42ec050ac5b0cabf6c55c3ee834c1dd0de..5fbfdc0712f593401183d30aabb7dfd909581392 100644 --- a/src/qgcunittest/MockLink.h +++ b/src/qgcunittest/MockLink.h @@ -54,6 +54,10 @@ public: virtual qint64 getConnectionSpeed(void) const { return 100000000; } virtual qint64 bytesAvailable(void) { return 0; } + // MockLink methods + MAV_AUTOPILOT getAutopilotType(void) { return _autopilotType; } + void setAutopilotType(MAV_AUTOPILOT autopilot) { _autopilotType = autopilot; } + // These are left unimplemented in order to cause linker errors which indicate incorrect usage of // connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager. bool connect(void); @@ -122,6 +126,8 @@ private: uint8_t _mavBaseMode; uint8_t _mavCustomMode; uint8_t _mavState; + + MAV_AUTOPILOT _autopilotType; }; #endif