|
|
|
/*=====================================================================
|
|
|
|
|
|
|
|
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(AutoPilotPlugin* autopilot, UASInterface* uas, QObject* parent) :
|
|
|
|
ParameterLoader(autopilot, 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. Found:" << intVersion << "Want: 3 File:" << 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
|
|
|
|
qCDebug(PX4ParameterLoaderLog) << "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
|
|
|
|
qCDebug(PX4ParameterLoaderLog) << "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);
|
|
|
|
}
|
|
|
|
}
|