Commit 5053bebc authored by Don Gagne's avatar Don Gagne

Merge pull request #1471 from DonLakeFlyer/MoreMetaData

Full meta data support in fact system
parents 6042ff09 6760bc95
...@@ -613,7 +613,7 @@ HEADERS+= \ ...@@ -613,7 +613,7 @@ HEADERS+= \
src/AutoPilotPlugins/PX4/SensorsComponentController.h \ src/AutoPilotPlugins/PX4/SensorsComponentController.h \
src/AutoPilotPlugins/PX4/SafetyComponent.h \ src/AutoPilotPlugins/PX4/SafetyComponent.h \
src/AutoPilotPlugins/PX4/PowerComponent.h \ src/AutoPilotPlugins/PX4/PowerComponent.h \
src/AutoPilotPlugins/PX4/PX4ParameterFacts.h \ src/AutoPilotPlugins/PX4/PX4ParameterLoader.h \
SOURCES += \ SOURCES += \
src/VehicleSetup/SetupView.cc \ src/VehicleSetup/SetupView.cc \
...@@ -637,7 +637,7 @@ SOURCES += \ ...@@ -637,7 +637,7 @@ SOURCES += \
src/AutoPilotPlugins/PX4/SensorsComponentController.cc \ src/AutoPilotPlugins/PX4/SensorsComponentController.cc \
src/AutoPilotPlugins/PX4/SafetyComponent.cc \ src/AutoPilotPlugins/PX4/SafetyComponent.cc \
src/AutoPilotPlugins/PX4/PowerComponent.cc \ src/AutoPilotPlugins/PX4/PowerComponent.cc \
src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc \ src/AutoPilotPlugins/PX4/PX4ParameterLoader.cc \
# Fact System code # Fact System code
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "AutoPilotPluginManager.h" #include "AutoPilotPluginManager.h"
#include "UASManager.h" #include "UASManager.h"
#include "QGCUASParamManagerInterface.h" #include "QGCUASParamManagerInterface.h"
#include "PX4ParameterFacts.h" #include "PX4ParameterLoader.h"
#include "FlightModesComponentController.h" #include "FlightModesComponentController.h"
#include "AirframeComponentController.h" #include "AirframeComponentController.h"
#include "QGCMessageBox.h" #include "QGCMessageBox.h"
...@@ -79,12 +79,12 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) : ...@@ -79,12 +79,12 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) :
qmlRegisterType<FlightModesComponentController>("QGroundControl.Controllers", 1, 0, "FlightModesComponentController"); qmlRegisterType<FlightModesComponentController>("QGroundControl.Controllers", 1, 0, "FlightModesComponentController");
qmlRegisterType<AirframeComponentController>("QGroundControl.Controllers", 1, 0, "AirframeComponentController"); qmlRegisterType<AirframeComponentController>("QGroundControl.Controllers", 1, 0, "AirframeComponentController");
_parameterFacts = new PX4ParameterFacts(uas, this); _parameterFacts = new PX4ParameterLoader(uas, this);
Q_CHECK_PTR(_parameterFacts); Q_CHECK_PTR(_parameterFacts);
connect(_parameterFacts, &PX4ParameterFacts::parametersReady, this, &PX4AutoPilotPlugin::_pluginReadyPreChecks); connect(_parameterFacts, &PX4ParameterLoader::parametersReady, this, &PX4AutoPilotPlugin::_pluginReadyPreChecks);
PX4ParameterFacts::loadParameterFactMetaData(); PX4ParameterLoader::loadParameterFactMetaData();
} }
PX4AutoPilotPlugin::~PX4AutoPilotPlugin() PX4AutoPilotPlugin::~PX4AutoPilotPlugin()
...@@ -187,7 +187,7 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo ...@@ -187,7 +187,7 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo
void PX4AutoPilotPlugin::clearStaticData(void) void PX4AutoPilotPlugin::clearStaticData(void)
{ {
PX4ParameterFacts::clearStaticData(); PX4ParameterLoader::clearStaticData();
} }
const QVariantList& PX4AutoPilotPlugin::vehicleComponents(void) const QVariantList& PX4AutoPilotPlugin::vehicleComponents(void)
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "AutoPilotPlugin.h" #include "AutoPilotPlugin.h"
#include "AutoPilotPluginManager.h" #include "AutoPilotPluginManager.h"
#include "UASInterface.h" #include "UASInterface.h"
#include "PX4ParameterFacts.h" #include "PX4ParameterLoader.h"
#include "AirframeComponent.h" #include "AirframeComponent.h"
#include "RadioComponent.h" #include "RadioComponent.h"
#include "FlightModesComponent.h" #include "FlightModesComponent.h"
...@@ -71,7 +71,7 @@ private: ...@@ -71,7 +71,7 @@ private:
// Overrides from AutoPilotPlugin // Overrides from AutoPilotPlugin
virtual ParameterLoader* _getParameterLoader(void) { return _parameterFacts; } virtual ParameterLoader* _getParameterLoader(void) { return _parameterFacts; }
PX4ParameterFacts* _parameterFacts; PX4ParameterLoader* _parameterFacts;
QVariantList _components; QVariantList _components;
AirframeComponent* _airframeComponent; AirframeComponent* _airframeComponent;
RadioComponent* _radioComponent; RadioComponent* _radioComponent;
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "PX4ParameterFacts.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
QGC_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog, "PX4ParameterFactsMetaDataLog")
bool PX4ParameterFacts::_parameterMetaDataLoaded = false;
QMap<QString, FactMetaData*> PX4ParameterFacts::_mapParameterName2FactMetaData;
PX4ParameterFacts::PX4ParameterFacts(UASInterface* uas, QObject* parent) :
ParameterLoader(uas, parent)
{
Q_ASSERT(uas);
}
/// This will fill in missing meta data such as range info
void PX4ParameterFacts::_initMetaData(FactMetaData* metaData)
{
switch (metaData->type) {
case FactMetaData::valueTypeUint8:
metaData->min = QVariant(std::numeric_limits<quint8>::min());
metaData->max = QVariant(std::numeric_limits<quint8>::max());
break;
case FactMetaData::valueTypeInt8:
metaData->min = QVariant(std::numeric_limits<qint8>::min());
metaData->max = QVariant(std::numeric_limits<qint8>::max());
break;
case FactMetaData::valueTypeUint16:
metaData->min = QVariant(std::numeric_limits<quint16>::min());
metaData->max = QVariant(std::numeric_limits<quint16>::max());
break;
case FactMetaData::valueTypeInt16:
metaData->min = QVariant(std::numeric_limits<qint16>::min());
metaData->max = QVariant(std::numeric_limits<qint16>::max());
break;
case FactMetaData::valueTypeUint32:
metaData->min = QVariant(std::numeric_limits<quint32>::min());
metaData->max = QVariant(std::numeric_limits<quint32>::max());
break;
case FactMetaData::valueTypeInt32:
metaData->min = QVariant(std::numeric_limits<qint32>::min());
metaData->max = QVariant(std::numeric_limits<qint32>::max());
break;
case FactMetaData::valueTypeFloat:
metaData->min = QVariant(std::numeric_limits<float>::min());
metaData->max = QVariant(std::numeric_limits<float>::max());
break;
case FactMetaData::valueTypeDouble:
metaData->min = QVariant(std::numeric_limits<double>::min());
metaData->max = QVariant(std::numeric_limits<double>::max());
break;
}
}
/// Converts a string to a typed QVariant
/// @param type Type for Fact which dictates the QVariant type as well
/// @param failOk - true: Don't assert if convert fails
/// @return Returns the correctly type QVariant
QVariant PX4ParameterFacts::_stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk)
{
QVariant var(string);
bool convertOk;
Q_UNUSED(convertOk);
switch (type) {
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeUint16:
case FactMetaData::valueTypeUint32:
convertOk = var.convert(QVariant::UInt);
if (!failOk) {
Q_ASSERT(convertOk);
}
break;
case FactMetaData::valueTypeInt8:
case FactMetaData::valueTypeInt16:
case FactMetaData::valueTypeInt32:
convertOk = var.convert(QVariant::Int);
if (!failOk) {
qDebug() << string;
Q_ASSERT(convertOk);
}
break;
case FactMetaData::valueTypeFloat:
case FactMetaData::valueTypeDouble:
convertOk = var.convert(QVariant::Double);
if (!failOk) {
qDebug() << string;
Q_ASSERT(convertOk);
}
break;
}
return var;
}
/// Load Parameter Fact meta data
///
/// The meta data comes from firmware parameters.xml file.
void PX4ParameterFacts::loadParameterFactMetaData(void)
{
if (_parameterMetaDataLoaded) {
return;
}
_parameterMetaDataLoaded = true;
qCDebug(PX4ParameterFactsMetaDataLog) << "Loading PX4 parameter fact meta data";
Q_ASSERT(_mapParameterName2FactMetaData.count() == 0);
// First look for meta data that comes from a firmware download. Fall back to resource if not there.
QSettings settings;
QDir parameterDir = QFileInfo(settings.fileName()).dir();
QString parameterFilename = parameterDir.filePath("PX4ParameterFactMetaData.xml");
if (!QFile(parameterFilename).exists()) {
parameterFilename = ":/AutoPilotPlugins/PX4/ParameterFactMetaData.xml";
}
QFile xmlFile(parameterFilename);
Q_ASSERT(xmlFile.exists());
bool success = xmlFile.open(QIODevice::ReadOnly);
Q_UNUSED(success);
Q_ASSERT(success);
QXmlStreamReader xml(xmlFile.readAll());
xmlFile.close();
QString factGroup;
FactMetaData* metaData = NULL;
while (!xml.atEnd()) {
if (xml.isStartElement()) {
QString elementName = xml.name().toString();
if (elementName == "parameters") {
// Just move to next state
} else if (elementName == "group") {
factGroup = xml.attributes().value("name").toString();
qCDebug(PX4ParameterFactsMetaDataLog) << "Found group: " << factGroup;
} else if (elementName == "parameter") {
metaData = new FactMetaData();
Q_CHECK_PTR(metaData);
metaData->group = factGroup;
} else if (elementName == "code") {
Q_ASSERT(metaData);
QString name = xml.readElementText();
qCDebug(PX4ParameterFactsMetaDataLog) << "Found parameter: " << name;
// FIXME: Change the parameter build scheme in Firmware to get rid of ifdef dup problem
if (!_mapParameterName2FactMetaData.contains(name)) {
_mapParameterName2FactMetaData[name] = metaData;
}
} else if (elementName == "type") {
Q_ASSERT(metaData);
QString type = xml.readElementText();
// Convert type from string to FactMetaData::ValueType_t
struct String2Type {
const char* strType;
FactMetaData::ValueType_t type;
};
static const struct String2Type rgString2Type[] = {
{ "FLOAT", FactMetaData::valueTypeFloat },
{ "INT32", FactMetaData::valueTypeInt32 },
};
static const size_t crgString2Type = sizeof(rgString2Type) / sizeof(rgString2Type[0]);
bool found = false;
for (size_t i=0; i<crgString2Type; i++) {
const struct String2Type* info = &rgString2Type[i];
if (type == info->strType) {
found = true;
metaData->type = info->type;
break;
}
}
Q_UNUSED(found);
Q_ASSERT(found);
qCDebug(PX4ParameterFactsMetaDataLog) << "Type:" << type << metaData->type;
_initMetaData(metaData);
} else if (elementName == "short_desc") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
metaData->shortDescription = text;
} else if (elementName == "long_desc") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
metaData->longDescription = text;
} else if (elementName == "default") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
// FIXME: failOk=true Is a hack to handle enum values in default value. Need
// to implement enums in the meta data.
metaData->defaultValue = _stringToTypedVariant(text, metaData->type, true /* failOk */);
} else if (elementName == "min") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
metaData->min = _stringToTypedVariant(text, metaData->type);
} else if (elementName == "max") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
metaData->max = _stringToTypedVariant(text, metaData->type);
metaData->shortDescription = text;
} else if (elementName == "unit") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
metaData->units = text;
}
} else if (xml.isEndElement() && xml.name() == "parameter") {
metaData = NULL;
}
xml.readNext();
}
}
void PX4ParameterFacts::clearStaticData(void)
{
foreach(QString parameterName, _mapParameterName2FactMetaData.keys()) {
delete _mapParameterName2FactMetaData[parameterName];
}
_mapParameterName2FactMetaData.clear();
_parameterMetaDataLoaded = false;
}
/// Override from FactLoad which connects the meta data to the fact
void PX4ParameterFacts::_addMetaDataToFact(Fact* fact)
{
if (_mapParameterName2FactMetaData.contains(fact->name())) {
fact->setMetaData(_mapParameterName2FactMetaData[fact->name()]);
} else {
// Use generic meta data
ParameterLoader::_addMetaDataToFact(fact);
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "PX4ParameterLoader.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
QGC_LOGGING_CATEGORY(PX4ParameterLoaderLog, "PX4ParameterLoaderLog")
bool PX4ParameterLoader::_parameterMetaDataLoaded = false;
QMap<QString, FactMetaData*> PX4ParameterLoader::_mapParameterName2FactMetaData;
PX4ParameterLoader::PX4ParameterLoader(UASInterface* uas, QObject* parent) :
ParameterLoader(uas, parent)
{
Q_ASSERT(uas);
}
/// Converts a string to a typed QVariant
/// @param string String to convert
/// @param type Type for Fact which dictates the QVariant type as well
/// @param convertOk Returned: true: conversion success, false: conversion failure
/// @return Returns the correctly type QVariant
QVariant PX4ParameterLoader::_stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool* convertOk)
{
QVariant var(string);
int convertTo = QVariant::Int; // keep compiler warning happy
switch (type) {
case FactMetaData::valueTypeUint8:
case FactMetaData::valueTypeUint16:
case FactMetaData::valueTypeUint32:
convertTo = QVariant::UInt;
break;
case FactMetaData::valueTypeInt8:
case FactMetaData::valueTypeInt16:
case FactMetaData::valueTypeInt32:
convertTo = QVariant::Int;
break;
case FactMetaData::valueTypeFloat:
convertTo = QMetaType::Float;
break;
case FactMetaData::valueTypeDouble:
convertTo = QVariant::Double;
break;
}
*convertOk = var.convert(convertTo);
return var;
}
/// Load Parameter Fact meta data
///
/// The meta data comes from firmware parameters.xml file.
void PX4ParameterLoader::loadParameterFactMetaData(void)
{
if (_parameterMetaDataLoaded) {
return;
}
_parameterMetaDataLoaded = true;
qCDebug(PX4ParameterLoaderLog) << "Loading PX4 parameter fact meta data";
Q_ASSERT(_mapParameterName2FactMetaData.count() == 0);
// First look for meta data that comes from a firmware download. Fall back to resource if not there.
QSettings settings;
QDir parameterDir = QFileInfo(settings.fileName()).dir();
QString parameterFilename = parameterDir.filePath("PX4ParameterFactMetaData.xml");
if (!QFile(parameterFilename).exists()) {
parameterFilename = ":/AutoPilotPlugins/PX4/ParameterFactMetaData.xml";
}
qCDebug(PX4ParameterLoaderLog) << "Loading parameter meta data:" << parameterFilename;
QFile xmlFile(parameterFilename);
Q_ASSERT(xmlFile.exists());
bool success = xmlFile.open(QIODevice::ReadOnly);
Q_UNUSED(success);
Q_ASSERT(success);
QXmlStreamReader xml(xmlFile.readAll());
xmlFile.close();
if (xml.hasError()) {
qWarning() << "Badly formed XML" << xml.errorString();
return;
}
QString factGroup;
FactMetaData* metaData = NULL;
int xmlState = XmlStateNone;
bool badMetaData = true;
while (!xml.atEnd()) {
if (xml.isStartElement()) {
QString elementName = xml.name().toString();
if (elementName == "parameters") {
if (xmlState != XmlStateNone) {
qWarning() << "Badly formed XML";
return;
}
xmlState = XmlStateFoundParameters;
} else if (elementName == "version") {
if (xmlState != XmlStateFoundParameters) {
qWarning() << "Badly formed XML";
return;
}
xmlState = XmlStateFoundVersion;
bool convertOk;
QString strVersion = xml.readElementText();
int intVersion = strVersion.toInt(&convertOk);
if (!convertOk) {
qWarning() << "Badly formed XML";
return;
}
if (intVersion <= 2) {
// We can't read these old files
qDebug() << "Parameter version stamp too old, skipping load" << parameterFilename;
return;
}
} else if (elementName == "group") {
if (xmlState != XmlStateFoundVersion) {
// We didn't get a version stamp, assume older version we can't read
qDebug() << "Parameter version stamp not found, skipping load" << parameterFilename;
return;
}
xmlState = XmlStateFoundGroup;
if (!xml.attributes().hasAttribute("name")) {
qWarning() << "Badly formed XML";
return;
}
factGroup = xml.attributes().value("name").toString();
qCDebug(PX4ParameterLoaderLog) << "Found group: " << factGroup;
} else if (elementName == "parameter") {
if (xmlState != XmlStateFoundGroup) {
qWarning() << "Badly formed XML";
return;
}
xmlState = XmlStateFoundParameter;
if (!xml.attributes().hasAttribute("name") || !xml.attributes().hasAttribute("type")) {
qWarning() << "Badly formed XML";
return;
}
QString name = xml.attributes().value("name").toString();
QString type = xml.attributes().value("type").toString();
QString strDefault = xml.attributes().value("default").toString();
qCDebug(PX4ParameterLoaderLog) << "Found parameter name:" << name << " type:" << type << " default:" << strDefault;
// Convert type from string to FactMetaData::ValueType_t
struct String2Type {
const char* strType;
FactMetaData::ValueType_t type;
};
static const struct String2Type rgString2Type[] = {
{ "FLOAT", FactMetaData::valueTypeFloat },
{ "INT32", FactMetaData::valueTypeInt32 },
};
static const size_t crgString2Type = sizeof(rgString2Type) / sizeof(rgString2Type[0]);
bool found = false;
FactMetaData::ValueType_t foundType;
for (size_t i=0; i<crgString2Type; i++) {
const struct String2Type* info = &rgString2Type[i];
if (type == info->strType) {
found = true;
foundType = info->type;
break;
}
}
if (!found) {
qWarning() << "Parameter meta data with bad type:" << type << " name:" << name;
return;
}
// Now that we know type we can create meta data object and add it to the system
metaData = new FactMetaData(foundType);
Q_CHECK_PTR(metaData);
if (_mapParameterName2FactMetaData.contains(name)) {
// We can't trust the meta dafa since we have dups
qDebug() << "Duplicate parameter found:" << name;
badMetaData = true;
// Reset to default meta data
_mapParameterName2FactMetaData[name] = metaData;
} else {
_mapParameterName2FactMetaData[name] = metaData;
metaData->setGroup(factGroup);
if (xml.attributes().hasAttribute("default")) {
bool convertOk;
QVariant varDefault = _stringToTypedVariant(strDefault, metaData->type(), &convertOk);
if (convertOk) {
metaData->setDefaultValue(varDefault);
} else {
// Non-fatal
qDebug() << "Parameter meta data with bad default value, name:" << name << " type:" << type << " default:" << strDefault;
}
}
}
} else {
// We should be getting meta data now
if (xmlState != XmlStateFoundParameter) {
qWarning() << "Badly formed XML";
return;
}
if (!badMetaData) {
if (elementName == "short_desc") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
qCDebug(PX4ParameterLoaderLog) << "Short description:" << text;
metaData->setShortDescription(text);
} else if (elementName == "long_desc") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
qCDebug(PX4ParameterLoaderLog) << "Long description:" << text;
metaData->setLongDescription(text);
} else if (elementName == "min") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
qCDebug(PX4ParameterLoaderLog) << "Min:" << text;
bool convertOk;
QVariant varMin = _stringToTypedVariant(text, metaData->type(), &convertOk);
if (convertOk) {
metaData->setMin(varMin);
} else {
// Non-fatal
qDebug() << "Parameter meta data with bad min value:" << text;
}
} else if (elementName == "max") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
qCDebug(PX4ParameterLoaderLog) << "Max:" << text;
bool convertOk;
QVariant varMax = _stringToTypedVariant(text, metaData->type(), &convertOk);
if (convertOk) {
metaData->setMax(varMax);
} else {
// Non-fatal
qDebug() << "Parameter meta data with bad max value:" << text;
}
} else if (elementName == "unit") {
Q_ASSERT(metaData);
QString text = xml.readElementText();
qCDebug(PX4ParameterLoaderLog) << "Unit:" << text;
metaData->setUnits(text);
} else {
qDebug() << "Unknown element in XML: " << elementName;
}
}
}
} else if (xml.isEndElement()) {
QString elementName = xml.name().toString();
if (elementName == "parameter") {
// Done loading this one parameter
metaData = NULL;
badMetaData = false;
xmlState = XmlStateFoundGroup;
} else if (elementName == "group") {
xmlState = XmlStateFoundVersion;
} else if (elementName == "parameters") {
xmlState = XmlStateFoundParameters;
}
}
xml.readNext();
}
}
void PX4ParameterLoader::clearStaticData(void)
{
foreach(QString parameterName, _mapParameterName2FactMetaData.keys()) {
delete _mapParameterName2FactMetaData[parameterName];
}
_mapParameterName2FactMetaData.clear();
_parameterMetaDataLoaded = false;
}
/// Override from FactLoad which connects the meta data to the fact
void PX4ParameterLoader::_addMetaDataToFact(Fact* fact)
{
if (_mapParameterName2FactMetaData.contains(fact->name())) {
fact->setMetaData(_mapParameterName2FactMetaData[fact->name()]);
} else {
// Use generic meta data
ParameterLoader::_addMetaDataToFact(fact);
}
}
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
======================================================================*/ ======================================================================*/
#ifndef PX4PARAMETERFACTS_H #ifndef PX4PARAMETERLOADER_H
#define PX4PARAMETERFACTS_H #define PX4PARAMETERLOADER_H
#include <QObject> #include <QObject>
#include <QMap> #include <QMap>
...@@ -36,17 +36,17 @@ ...@@ -36,17 +36,17 @@
/// @file /// @file
/// @author Don Gagne <don@thegagnes.com> /// @author Don Gagne <don@thegagnes.com>
Q_DECLARE_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog) Q_DECLARE_LOGGING_CATEGORY(PX4ParameterLoaderLog)
/// Collection of Parameter Facts for PX4 AutoPilot /// Collection of Parameter Facts for PX4 AutoPilot
class PX4ParameterFacts : public ParameterLoader class PX4ParameterLoader : public ParameterLoader
{ {
Q_OBJECT Q_OBJECT
public: public:
/// @param uas Uas which this set of facts is associated with /// @param uas Uas which this set of facts is associated with
PX4ParameterFacts(UASInterface* uas, QObject* parent = NULL); PX4ParameterLoader(UASInterface* uas, QObject* parent = NULL);
/// Override from ParameterLoader /// Override from ParameterLoader
virtual QString getDefaultComponentIdParam(void) const { return QString("SYS_AUTOSTART"); } virtual QString getDefaultComponentIdParam(void) const { return QString("SYS_AUTOSTART"); }
...@@ -55,12 +55,20 @@ public: ...@@ -55,12 +55,20 @@ public:
static void clearStaticData(void); static void clearStaticData(void);
private: private:
// Overrides from FactLoader enum {
XmlStateNone,
XmlStateFoundParameters,
XmlStateFoundVersion,
XmlStateFoundGroup,
XmlStateFoundParameter,
XmlStateDone
};
// Overrides from ParameterLoader
virtual void _addMetaDataToFact(Fact* fact); virtual void _addMetaDataToFact(Fact* fact);
// Class methods // Class methods
static void _initMetaData(FactMetaData* metaData); static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool* convertOk);
static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk = false);
static bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded static bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded
static QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData static QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -94,7 +94,10 @@ QString Fact::valueString(void) const ...@@ -94,7 +94,10 @@ QString Fact::valueString(void) const
QVariant Fact::defaultValue(void) QVariant Fact::defaultValue(void)
{ {
Q_ASSERT(_metaData); Q_ASSERT(_metaData);
return _metaData->defaultValue; if (!_metaData->defaultValueAvailable()) {
qDebug() << "Access to unavailable default value";
}
return _metaData->defaultValue();
} }
FactMetaData::ValueType_t Fact::type(void) FactMetaData::ValueType_t Fact::type(void)
...@@ -104,53 +107,57 @@ FactMetaData::ValueType_t Fact::type(void) ...@@ -104,53 +107,57 @@ FactMetaData::ValueType_t Fact::type(void)
QString Fact::shortDescription(void) QString Fact::shortDescription(void)
{ {
if (_metaData) { Q_ASSERT(_metaData);
return _metaData->shortDescription; return _metaData->shortDescription();
} else {
return QString("");
}
} }
QString Fact::longDescription(void) QString Fact::longDescription(void)
{ {
if (_metaData) { Q_ASSERT(_metaData);
return _metaData->longDescription; return _metaData->longDescription();
} else {
return QString("");
}
} }
QString Fact::units(void) QString Fact::units(void)
{ {
if (_metaData) { Q_ASSERT(_metaData);
return _metaData->units; return _metaData->units();
} else {
return QString("");
}
} }
QVariant Fact::min(void) QVariant Fact::min(void)
{ {
Q_ASSERT(_metaData); Q_ASSERT(_metaData);
return _metaData->min; return _metaData->min();
} }
QVariant Fact::max(void) QVariant Fact::max(void)
{ {
Q_ASSERT(_metaData); Q_ASSERT(_metaData);
return _metaData->max; return _metaData->max();
} }
QString Fact::group(void) QString Fact::group(void)
{ {
if (_metaData) { Q_ASSERT(_metaData);
return _metaData->group; return _metaData->group();
} else {
return "Default Group";
}
} }
void Fact::setMetaData(FactMetaData* metaData) void Fact::setMetaData(FactMetaData* metaData)
{ {
_metaData = metaData; _metaData = metaData;
} }
bool Fact::valueEqualsDefault(void)
{
Q_ASSERT(_metaData);
if (_metaData->defaultValueAvailable()) {
return _metaData->defaultValue() == value();
} else {
return false;
}
}
bool Fact::defaultValueAvailable(void)
{
Q_ASSERT(_metaData);
return _metaData->defaultValueAvailable();
}
\ No newline at end of file
...@@ -43,21 +43,6 @@ class Fact : public QObject ...@@ -43,21 +43,6 @@ class Fact : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(int componentId READ componentId CONSTANT)
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged USER true)
Q_PROPERTY(QVariant valueString READ valueString NOTIFY valueChanged)
Q_PROPERTY(QVariant defaultValue READ defaultValue CONSTANT)
Q_PROPERTY(FactMetaData::ValueType_t type READ type CONSTANT)
Q_PROPERTY(QString shortDescription READ shortDescription CONSTANT)
Q_PROPERTY(QString longDescription READ longDescription CONSTANT)
Q_PROPERTY(QString units READ units CONSTANT)
Q_PROPERTY(QVariant min READ min CONSTANT)
Q_PROPERTY(QVariant max READ max CONSTANT)
Q_PROPERTY(QString group READ group CONSTANT)
Q_ENUMS(FactMetaData::ValueType_t)
public: public:
//Fact(int componentId, QString name = "", FactMetaData::ValueType_t type = FactMetaData::valueTypeInt32, QObject* parent = NULL); //Fact(int componentId, QString name = "", FactMetaData::ValueType_t type = FactMetaData::valueTypeInt32, QObject* parent = NULL);
Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent = NULL); Fact(int componentId, QString name, FactMetaData::ValueType_t type, QObject* parent = NULL);
...@@ -70,6 +55,8 @@ public: ...@@ -70,6 +55,8 @@ public:
QString valueString(void) const; QString valueString(void) const;
void setValue(const QVariant& value); void setValue(const QVariant& value);
QVariant defaultValue(void); QVariant defaultValue(void);
bool defaultValueAvailable(void);
bool valueEqualsDefault(void);
FactMetaData::ValueType_t type(void); FactMetaData::ValueType_t type(void);
QString shortDescription(void); QString shortDescription(void);
QString longDescription(void); QString longDescription(void);
......
...@@ -188,3 +188,21 @@ QString FactBinder::group(void) ...@@ -188,3 +188,21 @@ QString FactBinder::group(void)
return QString(); return QString();
} }
} }
bool FactBinder::defaultValueAvailable(void)
{
if (_fact) {
return _fact->defaultValueAvailable();
} else {
return false;
}
}
bool FactBinder::valueEqualsDefault(void)
{
if (_fact) {
return _fact->valueEqualsDefault();
} else {
return false;
}
}
...@@ -44,6 +44,8 @@ class FactBinder : public QObject ...@@ -44,6 +44,8 @@ class FactBinder : public QObject
Q_PROPERTY(QVariant valueString READ valueString NOTIFY valueChanged) Q_PROPERTY(QVariant valueString READ valueString NOTIFY valueChanged)
Q_PROPERTY(QString units READ units NOTIFY metaDataChanged) Q_PROPERTY(QString units READ units NOTIFY metaDataChanged)
Q_PROPERTY(QVariant defaultValue READ defaultValue NOTIFY metaDataChanged) Q_PROPERTY(QVariant defaultValue READ defaultValue NOTIFY metaDataChanged)
Q_PROPERTY(bool defaultValueAvailable READ defaultValueAvailable NOTIFY metaDataChanged)
Q_PROPERTY(bool valueEqualsDefault READ valueEqualsDefault NOTIFY valueChanged)
Q_PROPERTY(FactMetaData::ValueType_t type READ type NOTIFY metaDataChanged) Q_PROPERTY(FactMetaData::ValueType_t type READ type NOTIFY metaDataChanged)
Q_PROPERTY(QString shortDescription READ shortDescription NOTIFY metaDataChanged) Q_PROPERTY(QString shortDescription READ shortDescription NOTIFY metaDataChanged)
Q_PROPERTY(QString longDescription READ longDescription NOTIFY metaDataChanged) Q_PROPERTY(QString longDescription READ longDescription NOTIFY metaDataChanged)
...@@ -64,14 +66,16 @@ public: ...@@ -64,14 +66,16 @@ public:
QString valueString(void) const; QString valueString(void) const;
QString units(void) const; QString units(void) const;
QVariant defaultValue(void); QVariant defaultValue(void);
FactMetaData::ValueType_t type(void); bool defaultValueAvailable(void);
QString shortDescription(void); bool valueEqualsDefault(void);
QString longDescription(void); FactMetaData::ValueType_t type(void);
QVariant min(void); QString shortDescription(void);
QVariant max(void); QString longDescription(void);
QString group(void); QVariant min(void);
QVariant max(void);
QString group(void);
signals: signals:
void nameChanged(void); void nameChanged(void);
......
...@@ -28,13 +28,108 @@ ...@@ -28,13 +28,108 @@
#include "FactMetaData.h" #include "FactMetaData.h"
FactMetaData::FactMetaData(QObject* parent) : #include <QDebug>
QObject(parent)
#include <limits>
FactMetaData::FactMetaData(ValueType_t type, QObject* parent) :
QObject(parent),
_group("Default Group"),
_type(type),
_defaultValue(0),
_defaultValueAvailable(false),
_min(_minForType()),
_max(_maxForType())
{
}
QVariant FactMetaData::defaultValue(void)
{
if (_defaultValueAvailable) {
return _defaultValue;
} else {
qWarning() << "Attempt to access unavailable default value";
return QVariant(0);
}
}
void FactMetaData::setDefaultValue(const QVariant& defaultValue)
{
if (_min <= defaultValue && defaultValue <= _max) {
_defaultValue = defaultValue;
_defaultValueAvailable = true;
} else {
qWarning() << "Attempt to set default value which is outside min/max range";
}
}
void FactMetaData::setMin(const QVariant& min)
{
if (min > _minForType()) {
_min = min;
} else {
qWarning() << "Attempt to set min below allowable value";
_min = _minForType();
}
}
void FactMetaData::setMax(const QVariant& max)
{
if (max > _maxForType()) {
qWarning() << "Attempt to set max above allowable value";
_max = _maxForType();
} else {
_max = max;
}
}
QVariant FactMetaData::_minForType(void)
{ {
initFromTypeOnly(valueTypeInt32); switch (_type) {
case valueTypeUint8:
return QVariant(std::numeric_limits<unsigned char>::min());
case valueTypeInt8:
return QVariant(std::numeric_limits<signed char>::min());
case valueTypeUint16:
return QVariant(std::numeric_limits<unsigned short int>::min());
case valueTypeInt16:
return QVariant(std::numeric_limits<short int>::min());
case valueTypeUint32:
return QVariant(std::numeric_limits<unsigned int>::min());
case valueTypeInt32:
return QVariant(std::numeric_limits<int>::min());
case valueTypeFloat:
return QVariant(-std::numeric_limits<float>::max());
case valueTypeDouble:
return QVariant(-std::numeric_limits<double>::max());
}
// Make windows compiler happy, even switch is full cased
return QVariant();
} }
void FactMetaData::initFromTypeOnly(ValueType_t initType) QVariant FactMetaData::_maxForType(void)
{ {
type = initType; switch (_type) {
case valueTypeUint8:
return QVariant(std::numeric_limits<unsigned char>::max());
case valueTypeInt8:
return QVariant(std::numeric_limits<signed char>::max());
case valueTypeUint16:
return QVariant(std::numeric_limits<unsigned short int>::max());
case valueTypeInt16:
return QVariant(std::numeric_limits<short int>::max());
case valueTypeUint32:
return QVariant(std::numeric_limits<unsigned int>::max());
case valueTypeInt32:
return QVariant(std::numeric_limits<int>::max());
case valueTypeFloat:
return QVariant(std::numeric_limits<float>::max());
case valueTypeDouble:
return QVariant(std::numeric_limits<double>::max());
}
// Make windows compiler happy, even switch is full cased
return QVariant();
} }
...@@ -41,8 +41,6 @@ class FactMetaData : public QObject ...@@ -41,8 +41,6 @@ class FactMetaData : public QObject
Q_OBJECT Q_OBJECT
public: public:
FactMetaData(QObject* parent = NULL);
typedef enum { typedef enum {
valueTypeUint8, valueTypeUint8,
valueTypeInt8, valueTypeInt8,
...@@ -54,17 +52,41 @@ public: ...@@ -54,17 +52,41 @@ public:
valueTypeDouble valueTypeDouble
} ValueType_t; } ValueType_t;
/// Initialize the meta data given only the type. FactMetaData(ValueType_t type, QObject* parent = NULL);
void initFromTypeOnly(ValueType_t initType);
// Property accessors
QString group(void) { return _group; }
ValueType_t type(void) { return _type; }
QVariant defaultValue(void);
bool defaultValueAvailable(void) { return _defaultValueAvailable; }
QString shortDescription(void) { return _shortDescription; }
QString longDescription(void) { return _longDescription;}
QString units(void) { return _units; }
QVariant min(void) { return _min; }
QVariant max(void) { return _max; }
// Property setters
void setGroup(const QString& group) { _group = group; }
void setDefaultValue(const QVariant& defaultValue);
void setShortDescription(const QString& shortDescription) { _shortDescription = shortDescription; }
void setLongDescription(const QString& longDescription) { _longDescription = longDescription;}
void setUnits(const QString& units) { _units = units; }
void setMin(const QVariant& max);
void setMax(const QVariant& max);
QString group; private:
ValueType_t type; QVariant _minForType(void);
QVariant defaultValue; QVariant _maxForType(void);
QString shortDescription;
QString longDescription; QString _group;
QString units; ValueType_t _type;
QVariant min; QVariant _defaultValue;
QVariant max; bool _defaultValueAvailable;
QString _shortDescription;
QString _longDescription;
QString _units;
QVariant _min;
QVariant _max;
}; };
#endif #endif
\ No newline at end of file
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
/// additional meta data associated with a Fact such as description, min/max ranges and so forth. /// additional meta data associated with a Fact such as description, min/max ranges and so forth.
/// The FactValidator object is a QML validator which validates input according to the FactMetaData /// The FactValidator object is a QML validator which validates input according to the FactMetaData
/// settings. Client code can then use this system to expose sets of Facts to QML code. An example /// settings. Client code can then use this system to expose sets of Facts to QML code. An example
/// of this is the PX4ParameterFacts onbject which is part of the PX4 AutoPilot plugin. It exposes /// of this is the PX4ParameterLoader onbject which is part of the PX4 AutoPilot plugin. It exposes
/// the firmware parameters to QML such that you can bind QML ui elements directly to parameters. /// the firmware parameters to QML such that you can bind QML ui elements directly to parameters.
class FactSystem : public QGCSingleton class FactSystem : public QGCSingleton
......
...@@ -199,8 +199,8 @@ void ParameterLoader::_paramMgrParameterListUpToDate(void) ...@@ -199,8 +199,8 @@ void ParameterLoader::_paramMgrParameterListUpToDate(void)
void ParameterLoader::_addMetaDataToFact(Fact* fact) void ParameterLoader::_addMetaDataToFact(Fact* fact)
{ {
FactMetaData* metaData = new FactMetaData(this); FactMetaData* metaData = new FactMetaData(fact->type(), this);
metaData->initFromTypeOnly(fact->type()); fact->setMetaData(metaData);
} }
void ParameterLoader::refreshAllParameters(void) void ParameterLoader::refreshAllParameters(void)
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
/// @author Don Gagne <don@thegagnes.com> /// @author Don Gagne <don@thegagnes.com>
import QtQuick 2.3 import QtQuick 2.3
import QtQuick.Controls 1.2 import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import QGroundControl.Controls 1.0 import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0 import QGroundControl.Palette 1.0
...@@ -161,6 +162,99 @@ Rectangle { ...@@ -161,6 +162,99 @@ Rectangle {
text: modelFact.valueString + " " + modelFact.units text: modelFact.valueString + " " + modelFact.units
width: __charWidth.contentWidth * 20 width: __charWidth.contentWidth * 20
height: contentHeight height: contentHeight
color: modelFact.valueEqualsDefault ? __qgcPal.text : "orange"
Menu {
id: rightClickMenu
visible: false
MenuItem {
id: resetToDefaultMenuItem
text: "Reset to default"
enabled: modelFact.defaultValueAvailable
onTriggered: modelFact.value = modelFact.defaultValue
}
MenuItem {
text: "Set RC to Param..."
onTriggered: __controller.setRCToParam(modelData)
}
MenuItem {
text: "Properties..."
onTriggered: propertiesDialog.open()
}
}
Dialog {
id: propertiesDialog
visible: false
title: "Parameter Properties"
contentItem: Rectangle {
color: __qgcPal.window
implicitWidth: 500
implicitHeight: longDescription.y + longDescription.height + 20
Grid {
id: grid
x: 10
y: 10
columns: 2
spacing: 5
QGCLabel {
text: "Parameter:"
}
QGCLabel {
text: modelFact.name
}
QGCLabel {
text: "Group:"
}
QGCLabel {
text: modelFact.group
}
QGCLabel {
text: "Units:"
}
QGCLabel {
text: modelFact.units ? modelFact.units : "none"
}
QGCLabel {
text: "Default value:"
}
QGCLabel {
text: modelFact.defaultValueAvailable ? modelFact.defaultValue : "none"
}
QGCLabel {
text: "Minimum value:"
}
QGCLabel {
text: modelFact.min
}
QGCLabel {
text: "Maximum value:"
}
QGCLabel {
text: modelFact.max
}
QGCLabel {
text: "Description:"
}
QGCLabel {
text: modelFact.shortDescription ? modelFact.shortDescription : "none"
}
QGCLabel {
text: "Description (long):"
}
QGCLabel {
id: longDescription
width: 500 - 20 - x
wrapMode: Text.WordWrap
text: modelFact.longDescription ? modelFact.longDescription : "none"
}
}
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
...@@ -171,7 +265,7 @@ Rectangle { ...@@ -171,7 +265,7 @@ Rectangle {
editor.checked = true editor.checked = true
editor.focus = true editor.focus = true
} else if (mouse.button == Qt.RightButton) { } else if (mouse.button == Qt.RightButton) {
__controller.setRCToParam(modelData) rightClickMenu.popup()
} }
} }
} }
......
...@@ -56,7 +56,7 @@ Rectangle { ...@@ -56,7 +56,7 @@ Rectangle {
id: infoLabel id: infoLabel
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "Click a parameter value to modify. Right-click to set an RC to Param mapping. Use caution when modifying parameters here since the values are not checked for validity." text: "Click a parameter value to modify. Right-click for additional options. Values which have been modified from the default are shown in orange. Use caution when modifying parameters here since the values are not checked for validity."
} }
ParameterEditor { ParameterEditor {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment