PX4AirframeLoader.cc 6.65 KB
Newer Older
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *   (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.
 *
 ****************************************************************************/
9 10 11 12 13


/// @file
///     @author Don Gagne <don@thegagnes.com>

14
#include "PX4AirframeLoader.h"
15 16 17
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "AirframeComponentAirframes.h"
18

19 20 21 22 23 24
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>

QGC_LOGGING_CATEGORY(PX4AirframeLoaderLog, "PX4AirframeLoaderLog")
25

26 27 28 29
bool PX4AirframeLoader::_airframeMetaDataLoaded = false;

PX4AirframeLoader::PX4AirframeLoader(AutoPilotPlugin* autopilot, UASInterface* uas, QObject* parent)
{
Lorenz Meier's avatar
Lorenz Meier committed
30 31 32
    Q_UNUSED(autopilot);
    Q_UNUSED(uas);
    Q_UNUSED(parent);
33
    Q_ASSERT(uas);
34 35
}

36 37 38 39 40 41 42
QString PX4AirframeLoader::aiframeMetaDataFile(void)
{
    QSettings settings;
    QDir parameterDir = QFileInfo(settings.fileName()).dir();
    return parameterDir.filePath("PX4AirframeFactMetaData.xml");
}

43 44 45
/// Load Airframe Fact meta data
///
/// The meta data comes from firmware airframes.xml file.
46
void PX4AirframeLoader::loadAirframeMetaData(void)
47
{
48 49 50 51 52 53
    if (_airframeMetaDataLoaded) {
        return;
    }

    qCDebug(PX4AirframeLoaderLog) << "Loading PX4 airframe fact meta data";

Lorenz Meier's avatar
Lorenz Meier committed
54 55 56 57 58 59 60
    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.
61
        airframeFilename = aiframeMetaDataFile();
Lorenz Meier's avatar
Lorenz Meier committed
62 63
    }
    if (airframeFilename.isEmpty() || !QFile(airframeFilename).exists()) {
64
        airframeFilename = ":/AutoPilotPlugins/PX4/AirframeFactMetaData.xml";
Lorenz Meier's avatar
Lorenz Meier committed
65 66 67 68 69 70
    }

    qCDebug(PX4AirframeLoaderLog) << "Loading meta data file:" << airframeFilename;

    QFile xmlFile(airframeFilename);
    Q_ASSERT(xmlFile.exists());
71

Lorenz Meier's avatar
Lorenz Meier committed
72 73 74
    bool success = xmlFile.open(QIODevice::ReadOnly);
    Q_UNUSED(success);
    Q_ASSERT(success);
75

Lorenz Meier's avatar
Lorenz Meier committed
76
    if (!success) {
Don Gagne's avatar
Don Gagne committed
77
        qCWarning(PX4AirframeLoaderLog) << "Failed opening airframe XML";
Lorenz Meier's avatar
Lorenz Meier committed
78 79 80 81 82 83
        return;
    }

    QXmlStreamReader xml(xmlFile.readAll());
    xmlFile.close();
    if (xml.hasError()) {
Don Gagne's avatar
Don Gagne committed
84
        qCWarning(PX4AirframeLoaderLog) << "Badly formed XML" << xml.errorString();
Lorenz Meier's avatar
Lorenz Meier committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98
        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) {
Don Gagne's avatar
Don Gagne committed
99
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
100 101 102 103 104 105
                    return;
                }
                xmlState = XmlStateFoundAirframes;

            } else if (elementName == "version") {
                if (xmlState != XmlStateFoundAirframes) {
Don Gagne's avatar
Don Gagne committed
106
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
107 108 109 110 111 112 113 114
                    return;
                }
                xmlState = XmlStateFoundVersion;

                bool convertOk;
                QString strVersion = xml.readElementText();
                int intVersion = strVersion.toInt(&convertOk);
                if (!convertOk) {
Don Gagne's avatar
Don Gagne committed
115
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
116 117 118 119 120 121 122 123
                    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;
                }

124 125 126 127
            } else if (elementName == "airframe_version_major") {
                // Just skip over for now
            } else if (elementName == "airframe_version_minor") {
                // Just skip over for now
Lorenz Meier's avatar
Lorenz Meier committed
128 129 130 131 132 133 134 135 136 137

            } 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")) {
Don Gagne's avatar
Don Gagne committed
138
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
139 140 141 142 143 144 145 146
                    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) {
Don Gagne's avatar
Don Gagne committed
147
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
148 149 150 151 152
                    return;
                }
                xmlState = XmlStateFoundAirframe;

                if (!xml.attributes().hasAttribute("name") || !xml.attributes().hasAttribute("id")) {
Don Gagne's avatar
Don Gagne committed
153
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167
                    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) {
Don Gagne's avatar
Don Gagne committed
168
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
                    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;
188
}