PX4AirframeLoader.cc 6.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*=====================================================================

 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>

27
#include "PX4AirframeLoader.h"
28 29 30
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "AirframeComponentAirframes.h"
31

32 33 34 35 36 37
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>

QGC_LOGGING_CATEGORY(PX4AirframeLoaderLog, "PX4AirframeLoaderLog")
38

39 40 41 42
bool PX4AirframeLoader::_airframeMetaDataLoaded = false;

PX4AirframeLoader::PX4AirframeLoader(AutoPilotPlugin* autopilot, UASInterface* uas, QObject* parent)
{
Lorenz Meier's avatar
Lorenz Meier committed
43 44 45
    Q_UNUSED(autopilot);
    Q_UNUSED(uas);
    Q_UNUSED(parent);
46
    Q_ASSERT(uas);
47 48
}

49 50 51 52
/// Load Airframe Fact meta data
///
/// The meta data comes from firmware airframes.xml file.
void PX4AirframeLoader::loadAirframeFactMetaData(void)
53
{
54 55 56 57 58 59
    if (_airframeMetaDataLoaded) {
        return;
    }

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

Lorenz Meier's avatar
Lorenz Meier committed
60 61 62 63 64 65 66 67 68 69 70 71
    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.
        QSettings settings;
        QDir parameterDir = QFileInfo(settings.fileName()).dir();
        airframeFilename = parameterDir.filePath("PX4AirframeFactMetaData.xml");
    }
    if (airframeFilename.isEmpty() || !QFile(airframeFilename).exists()) {
72
        airframeFilename = ":/AutoPilotPlugins/PX4/AirframeFactMetaData.xml";
Lorenz Meier's avatar
Lorenz Meier committed
73 74 75 76 77 78
    }

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

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

Lorenz Meier's avatar
Lorenz Meier committed
80 81 82
    bool success = xmlFile.open(QIODevice::ReadOnly);
    Q_UNUSED(success);
    Q_ASSERT(success);
83

Lorenz Meier's avatar
Lorenz Meier committed
84
    if (!success) {
Don Gagne's avatar
Don Gagne committed
85
        qCWarning(PX4AirframeLoaderLog) << "Failed opening airframe XML";
Lorenz Meier's avatar
Lorenz Meier committed
86 87 88 89 90 91
        return;
    }

    QXmlStreamReader xml(xmlFile.readAll());
    xmlFile.close();
    if (xml.hasError()) {
Don Gagne's avatar
Don Gagne committed
92
        qCWarning(PX4AirframeLoaderLog) << "Badly formed XML" << xml.errorString();
Lorenz Meier's avatar
Lorenz Meier committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106
        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
107
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
108 109 110 111 112 113
                    return;
                }
                xmlState = XmlStateFoundAirframes;

            } else if (elementName == "version") {
                if (xmlState != XmlStateFoundAirframes) {
Don Gagne's avatar
Don Gagne committed
114
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
115 116 117 118 119 120 121 122
                    return;
                }
                xmlState = XmlStateFoundVersion;

                bool convertOk;
                QString strVersion = xml.readElementText();
                int intVersion = strVersion.toInt(&convertOk);
                if (!convertOk) {
Don Gagne's avatar
Don Gagne committed
123
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
                    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_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
142
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
143 144 145 146 147 148 149 150
                    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
151
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
152 153 154 155 156
                    return;
                }
                xmlState = XmlStateFoundAirframe;

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