PX4AirframeLoader.cc 6.71 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * 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 34
}

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

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

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

DonLakeFlyer's avatar
DonLakeFlyer committed
53 54 55 56
    if (AirframeComponentAirframes::get().count() != 0) {
        qCWarning(PX4AirframeLoaderLog) << "Internal error";
        return;
    }
Lorenz Meier's avatar
Lorenz Meier committed
57 58 59 60 61 62

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

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

    QFile xmlFile(airframeFilename);
DonLakeFlyer's avatar
DonLakeFlyer committed
72 73 74 75
    if (!xmlFile.exists()) {
        qCWarning(PX4AirframeLoaderLog) << "Internal error";
        return;
    }
76

Lorenz Meier's avatar
Lorenz Meier committed
77
    bool success = xmlFile.open(QIODevice::ReadOnly);
78

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

    QXmlStreamReader xml(xmlFile.readAll());
    xmlFile.close();
    if (xml.hasError()) {
Don Gagne's avatar
Don Gagne committed
87
        qCWarning(PX4AirframeLoaderLog) << "Badly formed XML" << xml.errorString();
Lorenz Meier's avatar
Lorenz Meier committed
88 89 90 91 92 93 94 95 96 97 98 99 100
        return;
    }

    QString         airframeGroup;
    QString         image;
    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
101
                    qCWarning(PX4AirframeLoaderLog) << "Badly formed XML";
Lorenz Meier's avatar
Lorenz Meier committed
102 103 104 105 106 107
                    return;
                }
                xmlState = XmlStateFoundAirframes;

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

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

126 127 128 129
            } 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
130 131 132 133 134 135 136 137 138 139

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

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