-
Lorenz Meier authoredLorenz Meier authored
PX4AirframeLoader.cc 6.65 KiB
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/// @file
/// @author Don Gagne <don@thegagnes.com>
#include "PX4AirframeLoader.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "AirframeComponentAirframes.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
QGC_LOGGING_CATEGORY(PX4AirframeLoaderLog, "PX4AirframeLoaderLog")
bool PX4AirframeLoader::_airframeMetaDataLoaded = false;
PX4AirframeLoader::PX4AirframeLoader(AutoPilotPlugin* autopilot, UASInterface* uas, QObject* parent)
{
Q_UNUSED(autopilot);
Q_UNUSED(uas);
Q_UNUSED(parent);
Q_ASSERT(uas);
}
QString PX4AirframeLoader::aiframeMetaDataFile(void)
{
QSettings settings;
QDir parameterDir = QFileInfo(settings.fileName()).dir();
return parameterDir.filePath("PX4AirframeFactMetaData.xml");
}
/// Load Airframe Fact meta data
///
/// The meta data comes from firmware airframes.xml file.
void PX4AirframeLoader::loadAirframeMetaData(void)
{
if (_airframeMetaDataLoaded) {
return;
}
qCDebug(PX4AirframeLoaderLog) << "Loading PX4 airframe fact meta data";
Q_ASSERT(AirframeComponentAirframes::get().count() == 0);
QString airframeFilename;
// We want unit test builds to always use the resource based meta data to provide repeatable results
if (!qgcApp()->runningUnitTests()) {
// First look for meta data that comes from a firmware download. Fall back to resource if not there.
airframeFilename = aiframeMetaDataFile();
}
if (airframeFilename.isEmpty() || !QFile(airframeFilename).exists()) {
airframeFilename = ":/AutoPilotPlugins/PX4/AirframeFactMetaData.xml";
}
qCDebug(PX4AirframeLoaderLog) << "Loading meta data file:" << airframeFilename;
QFile xmlFile(airframeFilename);
Q_ASSERT(xmlFile.exists());
bool success = xmlFile.open(QIODevice::ReadOnly);
Q_UNUSED(success);
Q_ASSERT(success);
if (!success) {
qCWarning(PX4AirframeLoaderLog) << "Failed opening airframe XML";
return;
}
QXmlStreamReader xml(xmlFile.readAll());
xmlFile.close();
if (xml.hasError()) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML" << xml.errorString();
return;
}
QString airframeGroup;
QString image;
QString errorString;
int xmlState = XmlStateNone;
while (!xml.atEnd()) {
if (xml.isStartElement()) {
QString elementName = xml.name().toString();
if (elementName == "airframes") {
if (xmlState != XmlStateNone) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
xmlState = XmlStateFoundAirframes;
} else if (elementName == "version") {
if (xmlState != XmlStateFoundAirframes) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
xmlState = XmlStateFoundVersion;
bool convertOk;
QString strVersion = xml.readElementText();
int intVersion = strVersion.toInt(&convertOk);
if (!convertOk) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
if (intVersion < 1) {
// We can't read these old files
qDebug() << "Airframe version stamp too old, skipping load. Found:" << intVersion << "Want: 3 File:" << airframeFilename;
return;
}
} else if (elementName == "airframe_version_major") {
// Just skip over for now
} else if (elementName == "airframe_version_minor") {
// Just skip over for now
} else if (elementName == "airframe_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" << airframeFilename;
return;
}
xmlState = XmlStateFoundGroup;
if (!xml.attributes().hasAttribute("name") || !xml.attributes().hasAttribute("image")) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
airframeGroup = xml.attributes().value("name").toString();
image = xml.attributes().value("image").toString();
qCDebug(PX4AirframeLoaderLog) << "Found group: " << airframeGroup;
} else if (elementName == "airframe") {
if (xmlState != XmlStateFoundGroup) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
xmlState = XmlStateFoundAirframe;
if (!xml.attributes().hasAttribute("name") || !xml.attributes().hasAttribute("id")) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
QString name = xml.attributes().value("name").toString();
QString id = xml.attributes().value("id").toString();
qCDebug(PX4AirframeLoaderLog) << "Found airframe name:" << name << " type:" << airframeGroup << " id:" << id;
// Now that we know type we can airframe meta data object and add it to the system
AirframeComponentAirframes::insert(airframeGroup, image, name, id.toInt());
} else {
// We should be getting meta data now
if (xmlState != XmlStateFoundAirframe) {
qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
return;
}
}
} else if (xml.isEndElement()) {
QString elementName = xml.name().toString();
if (elementName == "airframe") {
// Reset for next airframe
xmlState = XmlStateFoundGroup;
} else if (elementName == "airframe_group") {
xmlState = XmlStateFoundVersion;
} else if (elementName == "airframes") {
xmlState = XmlStateFoundAirframes;
}
}
xml.readNext();
}
_airframeMetaDataLoaded = true;
}