6#include <QtCore/QDebug>
7#include <QtCore/QXmlStreamReader>
22QVariant PX4ParameterMetaData::_stringToTypedVariant(
const QString&
string,
FactMetaData::ValueType_t type,
bool* convertOk)
26 QMetaType::Type convertTo = QMetaType::Int;
32 convertTo = QMetaType::UInt;
38 convertTo = QMetaType::Int;
41 convertTo = QMetaType::Float;
45 convertTo = QMetaType::Double;
48 qWarning() << kInvalidConverstion;
49 convertTo = QMetaType::QString;
52 qWarning() << kInvalidConverstion;
53 convertTo = QMetaType::Bool;
56 qWarning() << kInvalidConverstion;
57 convertTo = QMetaType::QByteArray;
61 *convertOk = var.convert(QMetaType(convertTo));
68 qCDebug(PX4ParameterMetaDataLog) <<
"PX4ParameterMetaData::loadParameterFactMetaDataFile" << metaDataFile;
70 if (_parameterMetaDataLoaded) {
71 qWarning() <<
"Internal error: parameter meta data loaded more than once";
74 _parameterMetaDataLoaded =
true;
76 qCDebug(PX4ParameterMetaDataLog) <<
"Loading parameter meta data:" << metaDataFile;
78 QFile xmlFile(metaDataFile);
80 if (!xmlFile.exists()) {
81 qWarning() <<
"Internal error: metaDataFile mission" << metaDataFile;
85 if (!xmlFile.open(QIODevice::ReadOnly)) {
86 qWarning() <<
"Internal error: Unable to open parameter file:" << metaDataFile << xmlFile.errorString();
90 QXmlStreamReader xml(xmlFile.readAll());
93 qWarning() <<
"Badly formed XML" << xml.errorString();
100 int xmlState = XmlStateNone;
101 bool badMetaData =
true;
103 while (!xml.atEnd()) {
104 if (xml.isStartElement()) {
105 QString elementName = xml.name().toString();
107 if (elementName ==
"parameters") {
108 if (xmlState != XmlStateNone) {
109 qWarning() <<
"Badly formed XML";
112 xmlState = XmlStateFoundParameters;
114 }
else if (elementName ==
"version") {
115 if (xmlState != XmlStateFoundParameters) {
116 qWarning() <<
"Badly formed XML";
119 xmlState = XmlStateFoundVersion;
122 QString strVersion = xml.readElementText();
123 int intVersion = strVersion.toInt(&convertOk);
125 qWarning() <<
"Badly formed XML";
128 if (intVersion <= 2) {
130 qDebug() <<
"Parameter version stamp too old, skipping load. Found:" << intVersion <<
"Want: 3 File:" << metaDataFile;
134 }
else if (elementName ==
"parameter_version_major") {
136 }
else if (elementName ==
"parameter_version_minor") {
139 }
else if (elementName ==
"group") {
140 if (xmlState != XmlStateFoundVersion) {
142 qDebug() <<
"Parameter version stamp not found, skipping load" << metaDataFile;
145 xmlState = XmlStateFoundGroup;
147 if (!xml.attributes().hasAttribute(
"name")) {
148 qWarning() <<
"Badly formed XML";
151 factGroup = xml.attributes().value(
"name").toString();
152 qCDebug(PX4ParameterMetaDataLog) <<
"Found group: " << factGroup;
154 }
else if (elementName ==
"parameter") {
155 if (xmlState != XmlStateFoundGroup) {
156 qWarning() <<
"Badly formed XML";
159 xmlState = XmlStateFoundParameter;
161 if (!xml.attributes().hasAttribute(
"name") || !xml.attributes().hasAttribute(
"type")) {
162 qWarning() <<
"Badly formed XML";
166 QString name = xml.attributes().value(
"name").toString();
167 QString type = xml.attributes().value(
"type").toString();
168 QString strDefault = xml.attributes().value(
"default").toString();
170 QString category = xml.attributes().value(
"category").toString();
171 if (category.isEmpty()) {
172 category = QStringLiteral(
"Standard");
175 bool volatileValue =
false;
176 bool readOnly =
false;
177 QString volatileStr = xml.attributes().value(
"volatile").toString();
178 if (volatileStr.compare(QStringLiteral(
"true")) == 0) {
179 volatileValue =
true;
182 if (!volatileValue) {
183 QString readOnlyStr = xml.attributes().value(
"readonly").toString();
184 if (readOnlyStr.compare(QStringLiteral(
"true")) == 0) {
189 qCDebug(PX4ParameterMetaDataLog) <<
"Found parameter name:" << name <<
" type:" << type <<
" default:" << strDefault;
195 qWarning() <<
"Parameter meta data with bad type:" << type <<
" name:" << name;
201 if (_mapParameterName2FactMetaData.contains(name)) {
203 qCWarning(PX4ParameterMetaDataLog) <<
"Duplicate parameter found:" << name;
206 _mapParameterName2FactMetaData[name] = metaData;
208 _mapParameterName2FactMetaData[name] = metaData;
215 if (xml.attributes().hasAttribute(
"default") && !strDefault.isEmpty()) {
221 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid default value, name:" << name <<
" type:" << type <<
" default:" << strDefault <<
" error:" <<
errorString;
228 if (xmlState != XmlStateFoundParameter) {
229 qWarning() <<
"Badly formed XML";
235 if (elementName ==
"short_desc") {
236 QString text = xml.readElementText();
237 text = text.replace(
"\n",
" ");
238 qCDebug(PX4ParameterMetaDataLog) <<
"Short description:" << text;
241 }
else if (elementName ==
"long_desc") {
242 QString text = xml.readElementText();
243 text = text.replace(
"\n",
" ");
244 qCDebug(PX4ParameterMetaDataLog) <<
"Long description:" << text;
247 }
else if (elementName ==
"min") {
248 QString text = xml.readElementText();
249 qCDebug(PX4ParameterMetaDataLog) <<
"Min:" << text;
255 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid min value, name:" << metaData->
name() <<
" type:" << metaData->
type() <<
" min:" << text <<
" error:" <<
errorString;
258 }
else if (elementName ==
"max") {
259 QString text = xml.readElementText();
260 qCDebug(PX4ParameterMetaDataLog) <<
"Max:" << text;
267 if (!metaData->
name().startsWith(
"VTQ_TELEM_IDS_")) {
268 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid max value, name:" << metaData->
name() <<
" type:" << metaData->
type() <<
" max:" << text <<
" error:" <<
errorString;
272 }
else if (elementName ==
"unit") {
273 QString text = xml.readElementText();
274 qCDebug(PX4ParameterMetaDataLog) <<
"Unit:" << text;
277 }
else if (elementName ==
"decimal") {
278 QString text = xml.readElementText();
279 qCDebug(PX4ParameterMetaDataLog) <<
"Decimal:" << text;
282 QVariant varDecimals = QVariant(text).toUInt(&convertOk);
286 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid decimals value, name:" << metaData->
name() <<
" type:" << metaData->
type() <<
" decimals:" << text <<
" error: invalid number";
289 }
else if (elementName ==
"reboot_required") {
290 QString text = xml.readElementText();
291 qCDebug(PX4ParameterMetaDataLog) <<
"RebootRequired:" << text;
292 if (text.compare(
"true", Qt::CaseInsensitive) == 0) {
296 }
else if (elementName ==
"values") {
299 }
else if (elementName ==
"value") {
300 QString enumValueStr = xml.attributes().value(
"code").toString();
301 QString enumString = xml.readElementText();
302 qCDebug(PX4ParameterMetaDataLog) <<
"parameter value:"
303 <<
"value desc:" << enumString <<
"code:" << enumValueStr;
306 QString enumErrorString;
310 qCDebug(PX4ParameterMetaDataLog) <<
"Invalid enum value, name:" << metaData->
name()
311 <<
" type:" << metaData->
type() <<
" value:" << enumValueStr
312 <<
" error:" << enumErrorString;
314 }
else if (elementName ==
"increment") {
317 QString text = xml.readElementText();
318 increment = text.toDouble(&ok);
322 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid value for increment, name:" << metaData->
name() <<
" increment:" << text;
325 }
else if (elementName ==
"boolean") {
332 }
else if (elementName ==
"bitmask") {
335 }
else if (elementName ==
"bit") {
337 unsigned char bit = xml.attributes().value(
"index").toString().toUInt(&ok);
339 QString bitDescription = xml.readElementText();
340 qCDebug(PX4ParameterMetaDataLog) <<
"parameter value:"
341 <<
"index:" << bit <<
"description:" << bitDescription;
344 QVariant bitmaskRawValue = 1 << bit;
345 QVariant bitmaskValue;
346 QString bitmaskErrorString;
350 qCDebug(PX4ParameterMetaDataLog) <<
"Invalid bitmask value, name:" << metaData->
name()
351 <<
" type:" << metaData->
type() <<
" value:" << bitmaskValue
352 <<
" error:" << bitmaskErrorString;
355 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid value for bitmask bit, name:" << metaData->
name() <<
" bit:" << bit;
359 qCDebug(PX4ParameterMetaDataLog) <<
"Unknown element in XML: " << elementName;
362 qWarning() <<
"Internal error";
366 }
else if (xml.isEndElement()) {
367 QString elementName = xml.name().toString();
369 if (elementName ==
"parameter") {
375 qCWarning(PX4ParameterMetaDataLog) <<
"Invalid default value, name:" << metaData->
name() <<
" type:" << metaData->
type() <<
" default:" << metaData->
rawDefaultValue() <<
" error:" <<
errorString;
382 xmlState = XmlStateFoundGroup;
383 }
else if (elementName ==
"group") {
384 xmlState = XmlStateFoundVersion;
385 }
else if (elementName ==
"parameters") {
386 xmlState = XmlStateFoundParameters;
392#ifdef GENERATE_PARAMETER_JSON
393 _generateParameterJson();
397#ifdef GENERATE_PARAMETER_JSON
398void _jsonWriteLine(QFile& file,
int indent,
const QString& line)
403 file.write(line.toLocal8Bit().constData());
407void PX4ParameterMetaData::_generateParameterJson()
409 qCDebug(PX4ParameterMetaDataLog) <<
"PX4ParameterMetaData::_generateParameterJson";
412 QFile jsonFile(QDir(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).absoluteFilePath(
"parameter.json"));
413 jsonFile.open(QFile::WriteOnly | QFile::Truncate | QFile::Text);
415 _jsonWriteLine(jsonFile, indentLevel++,
"{");
416 _jsonWriteLine(jsonFile, indentLevel,
"\"version\": 1,");
417 _jsonWriteLine(jsonFile, indentLevel,
"\"uid\": 1,");
418 _jsonWriteLine(jsonFile, indentLevel,
"\"scope\": \"Firmware\",");
419 _jsonWriteLine(jsonFile, indentLevel++,
"\"parameters\": [");
422 for (
const QString& paramName: _mapParameterName2FactMetaData.keys()) {
423 const FactMetaData* metaData = _mapParameterName2FactMetaData[paramName];
424 _jsonWriteLine(jsonFile, indentLevel++,
"{");
425 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"name\": \"%1\",").arg(paramName));
426 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"type\": \"%1\",").arg(metaData->
typeToString(metaData->
type())));
427 if (!metaData->
group().isEmpty()) {
428 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"group\": \"%1\",").arg(metaData->
group()));
430 if (!metaData->
category().isEmpty()) {
431 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"category\": \"%1\",").arg(metaData->
category()));
435 text.replace(
"\"",
"\\\"");
436 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"shortDescription\": \"%1\",").arg(text));
440 text.replace(
"\"",
"\\\"");
441 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"longDescription\": \"%1\",").arg(text));
443 if (!metaData->
rawUnits().isEmpty()) {
444 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"units\": \"%1\",").arg(metaData->
rawUnits()));
447 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"defaultValue\": %1,").arg(metaData->
rawDefaultValue().toDouble()));
450 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"increment\": %1,").arg(metaData->
rawIncrement()));
453 _jsonWriteLine(jsonFile, indentLevel++,
"\"values\": [");
454 for (
int i=0; i<metaData->
enumValues().count(); i++) {
455 _jsonWriteLine(jsonFile, indentLevel++,
"{");
456 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"value\": %1,").arg(metaData->
enumValues()[i].toDouble()));
458 text.replace(
"\"",
"\\\"");
459 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"description\": \"%1\"").arg(text));
460 _jsonWriteLine(jsonFile, --indentLevel, QStringLiteral(
"}%1").arg(i == metaData->
enumValues().count() - 1 ?
"" :
","));
462 _jsonWriteLine(jsonFile, --indentLevel,
"],");
465 _jsonWriteLine(jsonFile, indentLevel,
"\"rebootRequired\": true,");
468 _jsonWriteLine(jsonFile, indentLevel,
"\"volatile\": true,");
470 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"decimalPlaces\": %1,").arg(metaData->
decimalPlaces()));
471 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"minValue\": %1,").arg(metaData->
rawMin().toDouble()));
472 _jsonWriteLine(jsonFile, indentLevel, QStringLiteral(
"\"maxValue\": %1").arg(metaData->
rawMax().toDouble()));
473 _jsonWriteLine(jsonFile, --indentLevel, QStringLiteral(
"}%1").arg(++keyIndex == _mapParameterName2FactMetaData.keys().count() ?
"" :
","));
476 _jsonWriteLine(jsonFile, --indentLevel,
"]");
477 _jsonWriteLine(jsonFile, --indentLevel,
"}");
483 Q_UNUSED(vehicleType)
485 if (!_mapParameterName2FactMetaData.contains(name)) {
486 qCDebug(PX4ParameterMetaDataLog) <<
"No metaData for " << name <<
"using generic metadata";
488 _mapParameterName2FactMetaData[name] = metaData;
491 return _mapParameterName2FactMetaData[name];
496 QFile xmlFile(metaDataFile);
502 if (!xmlFile.exists()) {
503 _outputFileWarning(metaDataFile, QStringLiteral(
"Does not exist"), QString());
507 if (!xmlFile.open(QIODevice::ReadOnly)) {
508 _outputFileWarning(metaDataFile, QStringLiteral(
"Unable to open file"), xmlFile.errorString());
512 QXmlStreamReader xml(xmlFile.readAll());
514 if (xml.hasError()) {
515 _outputFileWarning(metaDataFile, QStringLiteral(
"Badly formed XML"), xml.errorString());
519 while (!xml.atEnd() && (majorVersion == -1 || minorVersion == -1)) {
520 if (xml.isStartElement()) {
521 QString elementName = xml.name().toString();
523 if (elementName ==
"parameter_version_major") {
525 QString strVersion = xml.readElementText();
526 majorVersion = strVersion.toInt(&convertOk);
528 _outputFileWarning(metaDataFile, QStringLiteral(
"Unable to convert parameter_version_major value to int"), QString());
531 }
else if (elementName ==
"parameter_version_minor") {
533 QString strVersion = xml.readElementText();
534 minorVersion = strVersion.toInt(&convertOk);
536 _outputFileWarning(metaDataFile, QStringLiteral(
"Unable to convert parameter_version_minor value to int"), QString());
544 if (majorVersion == -1) {
545 _outputFileWarning(metaDataFile, QStringLiteral(
"parameter_version_major is missing"), QString());
547 if (minorVersion == -1) {
548 _outputFileWarning(metaDataFile, QStringLiteral(
"parameter_version_minor tag is missing"), QString());
552void PX4ParameterMetaData::_outputFileWarning(
const QString& metaDataFile,
const QString& error1,
const QString& error2)
554 qWarning() << QStringLiteral(
"Internal Error: Parameter meta data file '%1'. %2. error: %3").arg(metaDataFile).arg(error1).arg(error2);
#define QGC_LOGGING_CATEGORY(name, categoryStr)