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+= \
src/AutoPilotPlugins/PX4/SensorsComponentController.h \
src/AutoPilotPlugins/PX4/SafetyComponent.h \
src/AutoPilotPlugins/PX4/PowerComponent.h \
src/AutoPilotPlugins/PX4/PX4ParameterFacts.h \
src/AutoPilotPlugins/PX4/PX4ParameterLoader.h \
SOURCES += \
src/VehicleSetup/SetupView.cc \
......@@ -637,7 +637,7 @@ SOURCES += \
src/AutoPilotPlugins/PX4/SensorsComponentController.cc \
src/AutoPilotPlugins/PX4/SafetyComponent.cc \
src/AutoPilotPlugins/PX4/PowerComponent.cc \
src/AutoPilotPlugins/PX4/PX4ParameterFacts.cc \
src/AutoPilotPlugins/PX4/PX4ParameterLoader.cc \
# Fact System code
......
......@@ -25,7 +25,7 @@
#include "AutoPilotPluginManager.h"
#include "UASManager.h"
#include "QGCUASParamManagerInterface.h"
#include "PX4ParameterFacts.h"
#include "PX4ParameterLoader.h"
#include "FlightModesComponentController.h"
#include "AirframeComponentController.h"
#include "QGCMessageBox.h"
......@@ -79,12 +79,12 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) :
qmlRegisterType<FlightModesComponentController>("QGroundControl.Controllers", 1, 0, "FlightModesComponentController");
qmlRegisterType<AirframeComponentController>("QGroundControl.Controllers", 1, 0, "AirframeComponentController");
_parameterFacts = new PX4ParameterFacts(uas, this);
_parameterFacts = new PX4ParameterLoader(uas, this);
Q_CHECK_PTR(_parameterFacts);
connect(_parameterFacts, &PX4ParameterFacts::parametersReady, this, &PX4AutoPilotPlugin::_pluginReadyPreChecks);
connect(_parameterFacts, &PX4ParameterLoader::parametersReady, this, &PX4AutoPilotPlugin::_pluginReadyPreChecks);
PX4ParameterFacts::loadParameterFactMetaData();
PX4ParameterLoader::loadParameterFactMetaData();
}
PX4AutoPilotPlugin::~PX4AutoPilotPlugin()
......@@ -187,7 +187,7 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo
void PX4AutoPilotPlugin::clearStaticData(void)
{
PX4ParameterFacts::clearStaticData();
PX4ParameterLoader::clearStaticData();
}
const QVariantList& PX4AutoPilotPlugin::vehicleComponents(void)
......
......@@ -27,7 +27,7 @@
#include "AutoPilotPlugin.h"
#include "AutoPilotPluginManager.h"
#include "UASInterface.h"
#include "PX4ParameterFacts.h"
#include "PX4ParameterLoader.h"
#include "AirframeComponent.h"
#include "RadioComponent.h"
#include "FlightModesComponent.h"
......@@ -71,7 +71,7 @@ private:
// Overrides from AutoPilotPlugin
virtual ParameterLoader* _getParameterLoader(void) { return _parameterFacts; }
PX4ParameterFacts* _parameterFacts;
PX4ParameterLoader* _parameterFacts;
QVariantList _components;
AirframeComponent* _airframeComponent;
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);
}
}
This diff is collapsed.
......@@ -21,8 +21,8 @@
======================================================================*/
#ifndef PX4PARAMETERFACTS_H
#define PX4PARAMETERFACTS_H
#ifndef PX4PARAMETERLOADER_H
#define PX4PARAMETERLOADER_H
#include <QObject>
#include <QMap>
......@@ -36,17 +36,17 @@
/// @file
/// @author Don Gagne <don@thegagnes.com>
Q_DECLARE_LOGGING_CATEGORY(PX4ParameterFactsMetaDataLog)
Q_DECLARE_LOGGING_CATEGORY(PX4ParameterLoaderLog)
/// Collection of Parameter Facts for PX4 AutoPilot
class PX4ParameterFacts : public ParameterLoader
class PX4ParameterLoader : public ParameterLoader
{
Q_OBJECT
public:
/// @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
virtual QString getDefaultComponentIdParam(void) const { return QString("SYS_AUTOSTART"); }
......@@ -55,12 +55,20 @@ public:
static void clearStaticData(void);
private:
// Overrides from FactLoader
enum {
XmlStateNone,
XmlStateFoundParameters,
XmlStateFoundVersion,
XmlStateFoundGroup,
XmlStateFoundParameter,
XmlStateDone
};
// Overrides from ParameterLoader
virtual void _addMetaDataToFact(Fact* fact);
// Class methods
static void _initMetaData(FactMetaData* metaData);
static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool failOk = false);
static QVariant _stringToTypedVariant(const QString& string, FactMetaData::ValueType_t type, bool* convertOk);
static bool _parameterMetaDataLoaded; ///< true: parameter meta data already loaded
static QMap<QString, FactMetaData*> _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData
......
......@@ -94,7 +94,10 @@ QString Fact::valueString(void) const
QVariant Fact::defaultValue(void)
{
Q_ASSERT(_metaData);
return _metaData->defaultValue;
if (!_metaData->defaultValueAvailable()) {
qDebug() << "Access to unavailable default value";
}
return _metaData->defaultValue();
}
FactMetaData::ValueType_t Fact::type(void)
......@@ -104,53 +107,57 @@ FactMetaData::ValueType_t Fact::type(void)
QString Fact::shortDescription(void)
{
if (_metaData) {
return _metaData->shortDescription;
} else {
return QString("");
}
Q_ASSERT(_metaData);
return _metaData->shortDescription();
}
QString Fact::longDescription(void)
{
if (_metaData) {
return _metaData->longDescription;
} else {
return QString("");
}
Q_ASSERT(_metaData);
return _metaData->longDescription();
}
QString Fact::units(void)
{
if (_metaData) {
return _metaData->units;
} else {
return QString("");
}
Q_ASSERT(_metaData);
return _metaData->units();
}
QVariant Fact::min(void)
{
Q_ASSERT(_metaData);
return _metaData->min;
return _metaData->min();
}
QVariant Fact::max(void)
{
Q_ASSERT(_metaData);
return _metaData->max;
return _metaData->max();
}
QString Fact::group(void)
{
if (_metaData) {
return _metaData->group;
} else {
return "Default Group";
}
Q_ASSERT(_metaData);
return _metaData->group();
}
void Fact::setMetaData(FactMetaData* 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
{
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:
//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);
......@@ -70,6 +55,8 @@ public:
QString valueString(void) const;
void setValue(const QVariant& value);
QVariant defaultValue(void);
bool defaultValueAvailable(void);
bool valueEqualsDefault(void);
FactMetaData::ValueType_t type(void);
QString shortDescription(void);
QString longDescription(void);
......
......@@ -188,3 +188,21 @@ QString FactBinder::group(void)
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
Q_PROPERTY(QVariant valueString READ valueString NOTIFY valueChanged)
Q_PROPERTY(QString units READ units 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(QString shortDescription READ shortDescription NOTIFY metaDataChanged)
Q_PROPERTY(QString longDescription READ longDescription NOTIFY metaDataChanged)
......@@ -66,6 +68,8 @@ public:
QString units(void) const;
QVariant defaultValue(void);
bool defaultValueAvailable(void);
bool valueEqualsDefault(void);
FactMetaData::ValueType_t type(void);
QString shortDescription(void);
QString longDescription(void);
......
......@@ -28,13 +28,108 @@
#include "FactMetaData.h"
FactMetaData::FactMetaData(QObject* parent) :
QObject(parent)
#include <QDebug>
#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)
{
initFromTypeOnly(valueTypeInt32);
if (max > _maxForType()) {
qWarning() << "Attempt to set max above allowable value";
_max = _maxForType();
} else {
_max = max;
}
}
void FactMetaData::initFromTypeOnly(ValueType_t initType)
QVariant FactMetaData::_minForType(void)
{
type = initType;
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();
}
QVariant FactMetaData::_maxForType(void)
{
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
Q_OBJECT
public:
FactMetaData(QObject* parent = NULL);
typedef enum {
valueTypeUint8,
valueTypeInt8,
......@@ -54,17 +52,41 @@ public:
valueTypeDouble
} ValueType_t;
/// Initialize the meta data given only the type.
void initFromTypeOnly(ValueType_t initType);
QString group;
ValueType_t type;
QVariant defaultValue;
QString shortDescription;
QString longDescription;
QString units;
QVariant min;
QVariant max;
FactMetaData(ValueType_t type, QObject* parent = NULL);
// 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; }