PX4AirframeLoader.cc 7.02 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 53 54 55
QString PX4AirframeLoader::aiframeMetaDataFile(void)
{
    QSettings settings;
    QDir parameterDir = QFileInfo(settings.fileName()).dir();
    return parameterDir.filePath("PX4AirframeFactMetaData.xml");
}

56 57 58
/// Load Airframe Fact meta data
///
/// The meta data comes from firmware airframes.xml file.
59
void PX4AirframeLoader::loadAirframeMetaData(void)
60
{
61 62 63 64 65 66
    if (_airframeMetaDataLoaded) {
        return;
    }

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

Lorenz Meier's avatar
Lorenz Meier committed
67 68 69 70 71 72 73
    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.
74
        airframeFilename = aiframeMetaDataFile();
Lorenz Meier's avatar
Lorenz Meier committed
75 76
    }
    if (airframeFilename.isEmpty() || !QFile(airframeFilename).exists()) {
77
        airframeFilename = ":/AutoPilotPlugins/PX4/AirframeFactMetaData.xml";
Lorenz Meier's avatar
Lorenz Meier committed
78 79 80 81 82 83
    }

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

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

Lorenz Meier's avatar
Lorenz Meier committed
85 86 87
    bool success = xmlFile.open(QIODevice::ReadOnly);
    Q_UNUSED(success);
    Q_ASSERT(success);
88

Lorenz Meier's avatar
Lorenz Meier committed
89
    if (!success) {
Don Gagne's avatar
Don Gagne committed
90
        qCWarning(PX4AirframeLoaderLog) << "Failed opening airframe XML";
Lorenz Meier's avatar
Lorenz Meier committed
91 92 93 94 95 96
        return;
    }

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

            } else if (elementName == "version") {
                if (xmlState != XmlStateFoundAirframes) {
Don Gagne's avatar
Don Gagne committed
119
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
120 121 122 123 124 125 126 127
                    return;
                }
                xmlState = XmlStateFoundVersion;

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

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