diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 23f04bd924d2ebbdf7e2e7fd308262ffc56b9f0c..f48ea1857f3caa9eeb4ee7153ab95b4e9f094ecb 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -776,7 +776,7 @@ HEADERS += \ src/FactSystem/FactBinder.h \ src/FactSystem/FactMetaData.h \ src/FactSystem/FactValidator.h \ - src/FactSystem/FactLoader.h \ + src/FactSystem/ParameterLoader.h \ SOURCES += \ src/FactSystem/FactSystem.cc \ @@ -784,4 +784,4 @@ SOURCES += \ src/FactSystem/FactBinder.cc \ src/FactSystem/FactMetaData.cc \ src/FactSystem/FactValidator.cc \ - src/FactSystem/FactLoader.cc \ + src/FactSystem/ParameterLoader.cc \ diff --git a/src/FactSystem/FactLoader.cc b/src/FactSystem/FactLoader.cc deleted file mode 100644 index 3b207542a1b30048e673313226c15d511dc3e3f0..0000000000000000000000000000000000000000 --- a/src/FactSystem/FactLoader.cc +++ /dev/null @@ -1,200 +0,0 @@ -/*===================================================================== - - 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 "QGCLoggingCategory.h" - -#include -#include - -QGC_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. - connect(uas, &UASInterface::parameterUpdate, this, &FactLoader::_parameterUpdate); -} - -FactLoader::~FactLoader() -{ - -} - -/// Called whenever a parameter is updated or first seen. -void FactLoader::_parameterUpdate(int uas, int component, QString parameterName, int mavType, 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); - } - - bool setMetaData = false; - if (!_mapParameterName2Variant.contains(parameterName)) { - qCDebug(FactLoaderLog) << "Adding new fact" << parameterName; - - FactMetaData::ValueType_t factType; - switch (mavType) { - case MAV_PARAM_TYPE_UINT8: - factType = FactMetaData::valueTypeUint8; - break; - case MAV_PARAM_TYPE_INT8: - factType = FactMetaData::valueTypeUint8; - break; - case MAV_PARAM_TYPE_UINT16: - factType = FactMetaData::valueTypeUint16; - break; - case MAV_PARAM_TYPE_INT16: - factType = FactMetaData::valueTypeInt16; - break; - case MAV_PARAM_TYPE_UINT32: - factType = FactMetaData::valueTypeUint32; - break; - case MAV_PARAM_TYPE_INT32: - factType = FactMetaData::valueTypeInt32; - break; - case MAV_PARAM_TYPE_REAL32: - factType = FactMetaData::valueTypeFloat; - break; - case MAV_PARAM_TYPE_REAL64: - factType = FactMetaData::valueTypeDouble; - break; - default: - factType = FactMetaData::valueTypeInt32; - qCritical() << "Unsupported fact type" << mavType; - break; - } - - Fact* fact = new Fact(parameterName, factType, this); - setMetaData = true; - - _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); - } - - Q_ASSERT(_mapParameterName2Variant.contains(parameterName)); - - qCDebug(FactLoaderLog) << "Updating fact value" << parameterName << value; - - Fact* fact = _mapParameterName2Variant[parameterName].value(); - Q_ASSERT(fact); - fact->_containerSetValue(value); - - if (setMetaData) { - _addMetaDataToFact(fact); - } -} - -/// Connected to Fact::valueUpdated -/// -/// Sets the new value into the Parameter Manager. Parameter is persisted after send. -void FactLoader::_valueUpdated(const 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.setValue(QVariant(value.toInt())); - break; - - case FactMetaData::valueTypeUint8: - case FactMetaData::valueTypeUint16: - case FactMetaData::valueTypeUint32: - typedValue.setValue(value.toUInt()); - break; - - case FactMetaData::valueTypeFloat: - typedValue.setValue(value.toFloat()); - break; - - case FactMetaData::valueTypeDouble: - typedValue.setValue(value.toDouble()); - break; - } - - qCDebug(FactLoaderLog) << "Set parameter" << fact->name() << typedValue; - - _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(); - } -} - -void FactLoader::_addMetaDataToFact(Fact* fact) -{ - FactMetaData* metaData = new FactMetaData(this); - metaData->initFromTypeOnly(fact->type()); -} diff --git a/src/FactSystem/FactLoader.h b/src/FactSystem/FactLoader.h deleted file mode 100644 index a61b147543b943d2841ff0f63fcf026265ee8402..0000000000000000000000000000000000000000 --- a/src/FactSystem/FactLoader.h +++ /dev/null @@ -1,86 +0,0 @@ -/*===================================================================== - - 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 -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); - -protected: - /// Base implementation adds generic meta data based on variant type. Derived class can override to provide - /// more details meta data. - virtual void _addMetaDataToFact(Fact* fact); - -private slots: - void _parameterUpdate(int uas, int component, QString parameterName, int mavType, QVariant value); - void _valueUpdated(const 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/ParameterLoader.cc b/src/FactSystem/ParameterLoader.cc new file mode 100644 index 0000000000000000000000000000000000000000..5d66a9ccbec3101f10881505a6217968602d427c --- /dev/null +++ b/src/FactSystem/ParameterLoader.cc @@ -0,0 +1,282 @@ +/*===================================================================== + + 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 "ParameterLoader.h" +#include "QGCApplication.h" +#include "QGCLoggingCategory.h" + +#include +#include + +QGC_LOGGING_CATEGORY(ParameterLoaderLog, "ParameterLoaderLog") + +ParameterLoader::ParameterLoader(UASInterface* uas, QObject* parent) : + QObject(parent), + _paramMgr(NULL), + _parametersReady(false), + _defaultComponentId(FactSystem::defaultComponentId) +{ + 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. + connect(uas, &UASInterface::parameterUpdate, this, &ParameterLoader::_parameterUpdate); +} + +ParameterLoader::~ParameterLoader() +{ + +} + +/// Called whenever a parameter is updated or first seen. +void ParameterLoader::_parameterUpdate(int uas, int componentId, QString parameterName, int mavType, QVariant value) +{ + bool setMetaData = false; + + // Is this for our uas? + if (uas != _uasId) { + return; + } + + // Attempt to determine default component id + if (_defaultComponentId == FactSystem::defaultComponentId && _defaultComponentIdParam.isEmpty()) { + _defaultComponentIdParam = getDefaultComponentIdParam(); + } + if (!_defaultComponentIdParam.isEmpty() && _defaultComponentIdParam == parameterName) { + _defaultComponentId = componentId; + } + + if (!_mapParameterName2Variant.contains(componentId) || !_mapParameterName2Variant[componentId].contains(parameterName)) { + // These should not get our of sync + Q_ASSERT(_mapParameterName2Variant.contains(componentId) == _mapFact2ParameterName.contains(componentId)); + + qCDebug(ParameterLoaderLog) << "Adding new fact (component:" << componentId << "name:" << parameterName << ")"; + + FactMetaData::ValueType_t factType; + switch (mavType) { + case MAV_PARAM_TYPE_UINT8: + factType = FactMetaData::valueTypeUint8; + break; + case MAV_PARAM_TYPE_INT8: + factType = FactMetaData::valueTypeUint8; + break; + case MAV_PARAM_TYPE_UINT16: + factType = FactMetaData::valueTypeUint16; + break; + case MAV_PARAM_TYPE_INT16: + factType = FactMetaData::valueTypeInt16; + break; + case MAV_PARAM_TYPE_UINT32: + factType = FactMetaData::valueTypeUint32; + break; + case MAV_PARAM_TYPE_INT32: + factType = FactMetaData::valueTypeInt32; + break; + case MAV_PARAM_TYPE_REAL32: + factType = FactMetaData::valueTypeFloat; + break; + case MAV_PARAM_TYPE_REAL64: + factType = FactMetaData::valueTypeDouble; + break; + default: + factType = FactMetaData::valueTypeInt32; + qCritical() << "Unsupported fact type" << mavType; + break; + } + + Fact* fact = new Fact(componentId, parameterName, factType, this); + setMetaData = true; + + _mapParameterName2Variant[componentId][parameterName] = QVariant::fromValue(fact); + _mapFact2ParameterName[componentId][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, &ParameterLoader::_valueUpdated); + } + + Q_ASSERT(_mapParameterName2Variant[componentId].contains(parameterName)); + + qCDebug(ParameterLoaderLog) << "Updating fact value (component:" << componentId << "name:" << parameterName << value << ")"; + + Fact* fact = _mapParameterName2Variant[componentId][parameterName].value(); + Q_ASSERT(fact); + fact->_containerSetValue(value); + + if (setMetaData) { + _addMetaDataToFact(fact); + } +} + +/// Connected to Fact::valueUpdated +/// +/// Sets the new value into the Parameter Manager. Parameter is persisted after send. +void ParameterLoader::_valueUpdated(const QVariant& value) +{ + Fact* fact = qobject_cast(sender()); + Q_ASSERT(fact); + + int componentId = fact->componentId(); + + Q_ASSERT(_paramMgr); + Q_ASSERT(_mapFact2ParameterName.contains(componentId)); + Q_ASSERT(_mapFact2ParameterName[componentId].contains(fact)); + + QVariant typedValue; + switch (fact->type()) { + case FactMetaData::valueTypeInt8: + case FactMetaData::valueTypeInt16: + case FactMetaData::valueTypeInt32: + typedValue.setValue(QVariant(value.toInt())); + break; + + case FactMetaData::valueTypeUint8: + case FactMetaData::valueTypeUint16: + case FactMetaData::valueTypeUint32: + typedValue.setValue(value.toUInt()); + break; + + case FactMetaData::valueTypeFloat: + typedValue.setValue(value.toFloat()); + break; + + case FactMetaData::valueTypeDouble: + typedValue.setValue(value.toDouble()); + break; + } + + qCDebug(ParameterLoaderLog) << "Set parameter (componentId:" << componentId << "name:" << fact->name() << typedValue << ")"; + + _paramMgr->setParameter(componentId, fact->name(), typedValue); + _paramMgr->sendPendingParameters(true /* persistAfterSend */, false /* forceSend */); +} + +// Called when param mgr list is up to date +void ParameterLoader::_paramMgrParameterListUpToDate(void) +{ + if (!_parametersReady) { + _parametersReady = 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(); + + _determineDefaultComponentId(); + + // We should have all parameters now so we can signal ready + emit parametersReady(); + } +} + +void ParameterLoader::_addMetaDataToFact(Fact* fact) +{ + FactMetaData* metaData = new FactMetaData(this); + metaData->initFromTypeOnly(fact->type()); +} + +void ParameterLoader::refreshAllParameters(void) +{ + Q_ASSERT(_paramMgr); + _paramMgr->requestParameterList(); +} + +void ParameterLoader::_determineDefaultComponentId(void) +{ + if (_defaultComponentId == FactSystem::defaultComponentId) { + // We don't have a default component id yet. That means the plugin can't provide + // the param to trigger off of. Instead we use the most prominent component id in + // the set of parameters. Better than nothing! + + _defaultComponentId = -1; + foreach(int componentId, _mapParameterName2Variant.keys()) { + if (_mapParameterName2Variant[componentId].count() > _defaultComponentId) { + _defaultComponentId = componentId; + } + } + Q_ASSERT(_defaultComponentId != -1); + } +} + +/// Translates FactSystem::defaultComponentId to real component id if needed +int ParameterLoader::_actualComponentId(int componentId) +{ + if (componentId == FactSystem::defaultComponentId) { + componentId = _defaultComponentId; + Q_ASSERT(componentId != FactSystem::defaultComponentId); + } + + return componentId; +} + +void ParameterLoader::refreshParameter(int componentId, const QString& name) +{ + Q_ASSERT(_paramMgr); + + _paramMgr->requestParameterUpdate(_actualComponentId(componentId), name); +} + +void ParameterLoader::refreshParametersPrefix(int componentId, const QString& namePrefix) +{ + Q_ASSERT(_paramMgr); + + componentId = _actualComponentId(componentId); + Q_ASSERT(_mapFact2ParameterName.contains(componentId)); + foreach(QString name, _mapParameterName2Variant[componentId].keys()) { + if (name.startsWith(namePrefix)) { + refreshParameter(componentId, name); + } + } +} + +bool ParameterLoader::factExists(int componentId, const QString& name) +{ + componentId = _actualComponentId(componentId); + if (_mapParameterName2Variant.contains(componentId)) { + return _mapParameterName2Variant[componentId].contains(name); + } + return false; +} + +Fact* ParameterLoader::getFact(int componentId, const QString& name) +{ + componentId = _actualComponentId(componentId); + Q_ASSERT(_mapParameterName2Variant.contains(componentId)); + Q_ASSERT(_mapParameterName2Variant[componentId].contains(name)); + Fact* fact = _mapParameterName2Variant[componentId][name].value(); + Q_ASSERT(fact); + return fact; +} diff --git a/src/FactSystem/ParameterLoader.h b/src/FactSystem/ParameterLoader.h new file mode 100644 index 0000000000000000000000000000000000000000..6c1951059cd89a2db12670b9ed07c601d646e397 --- /dev/null +++ b/src/FactSystem/ParameterLoader.h @@ -0,0 +1,113 @@ +/*===================================================================== + + 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 PARAMETERLOADER_H +#define PARAMETERLOADER_H + +#include +#include +#include +#include + +#include "FactSystem.h" +#include "UASInterface.h" + +/// @file +/// @author Don Gagne + +Q_DECLARE_LOGGING_CATEGORY(ParameterLoaderLog) + +/// Connects to Parameter Manager to load/update Facts +class ParameterLoader : public QObject +{ + Q_OBJECT + +public: + /// @param uas Uas which this set of facts is associated with + ParameterLoader(UASInterface* uas, QObject* parent = NULL); + + ~ParameterLoader(); + + /// Returns true if the full set of facts are ready + bool parametersAreReady(void) { return _parametersReady; } + + /// Re-request the full set of parameters from the autopilot + void refreshAllParameters(void); + + /// Request a refresh on the specific parameter + void refreshParameter(int componentId, const QString& name); + + /// Request a refresh on all parameters that begin with the specified prefix + void refreshParametersPrefix(int componentId, const QString& namePrefix); + + /// Returns true if the specifed fact exists + bool factExists(int componentId, ///< fact component, -1=default component + const QString& name); ///< fact name + + /// Returns the specified Fact. + /// WARNING: Will assert if fact does not exists. If that possibily exists, check for existince first with + /// factExists. + Fact* getFact(int componentId, ///< fact component, -1=default component + const QString& name); ///< fact name + + /// Return the parameter for which the default component id is derived from. Return an empty + /// string is this is not available. + virtual QString getDefaultComponentIdParam(void) const = 0; + +signals: + /// Signalled when the full set of facts are ready + void parametersReady(void); + +protected: + /// Base implementation adds generic meta data based on variant type. Derived class can override to provide + /// more details meta data. + virtual void _addMetaDataToFact(Fact* fact); + +private slots: + void _parameterUpdate(int uas, int componentId, QString parameterName, int mavType, QVariant value); + void _valueUpdated(const QVariant& value); + void _paramMgrParameterListUpToDate(void); + +private: + static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk = false); + int _actualComponentId(int componentId); + void _determineDefaultComponentId(void); + + /// First mapping is by component id + /// Second mapping is parameter name, to Fact + QMap > _mapFact2ParameterName; + + int _uasId; ///< Id for uas which this set of Facts are associated with + + QGCUASParamManagerInterface* _paramMgr; + + /// First mapping id\s by component id + /// Second mapping is parameter name, to Fact* in QVariant + QMap _mapParameterName2Variant; + + bool _parametersReady; ///< All params received from param mgr + int _defaultComponentId; + QString _defaultComponentIdParam; +}; + +#endif \ No newline at end of file