diff --git a/QGCApplication.pro b/QGCApplication.pro index f1d3507..5bbb957 100644 --- a/QGCApplication.pro +++ b/QGCApplication.pro @@ -339,6 +339,7 @@ HEADERS += \ src/ViewWidgets/ParameterEditorWidget.h \ src/ViewWidgets/ViewWidgetController.h \ src/Waypoint.h \ + src/AutoPilotPlugins/PX4/PX4AirframeLoader.h !iOSBuild { HEADERS += \ @@ -470,6 +471,7 @@ SOURCES += \ src/ViewWidgets/ParameterEditorWidget.cc \ src/ViewWidgets/ViewWidgetController.cc \ src/Waypoint.cc \ + src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc !iOSBuild { SOURCES += \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 98f3572..c9b1729 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -137,9 +137,6 @@ src/ui/qmlcommon/qmldir src/ui/qmlcommon/QGCWaypoint.qml - - src/AutoPilotPlugins/PX4/ParameterFactMetaData.xml - resources/LeftArrow.svg resources/RightArrow.svg @@ -247,4 +244,8 @@ resources/audio/alert.wav + + src/AutoPilotPlugins/PX4/AirframeFactMetaData.xml + src/AutoPilotPlugins/PX4/ParameterFactMetaData.xml + diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.cc b/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.cc index b2024f8..fc34558 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.cc +++ b/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.cc @@ -26,86 +26,69 @@ #include "AirframeComponentAirframes.h" -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoStandardPlane[] = { - { "Multiplex Easystar 1/2", 2100 }, - { "Generic AERT", 2101 }, - { "3DR Skywalker", 2102 }, - { "Skyhunter (1800 mm)", 2103 }, - { "Generic AETR", 2104 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoSimulation[] = { - { "Plane (HilStar, X-Plane)", 1000 }, - { "Plane (Rascal, FlightGear)", 1004 }, - { "Quad X HIL", 1001 }, - { "Quad + HIL", 1003 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoFlyingWing[] = { - { "Z-84 Wing Wing (845 mm)", 3033 }, - { "TBS Caipirinha (850 mm)", 3100 }, - { "Bormatec Camflyer Q (800 mm)", 3030 }, - { "FX-61 Phantom FPV (1550 mm)", 3031 }, - { "FX-79 Buffalo (2000 mm)", 3034 }, - { "Skywalker X5 (1180 mm)", 3032 }, - { "Viper v2 (3000 mm)", 3035 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoQuadRotorX[] = { - { "DJI F330 8\" Quad", 4010 }, - { "DJI F450 10\" Quad", 4011 }, - { "X frame Quad UAVCAN", 4012 }, - { "AR.Drone Frame Quad", 4008 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoQuadRotorPlus[] = { - { "Generic 10\" Quad +", 5001 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoHexaRotorX[] = { - { "Standard 10\" Hexa X", 6001 }, - { "Coaxial 10\" Hexa X", 11001 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoHexaRotorPlus[] = { - { "Standard 10\" Hexa", 7001 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoOctoRotorX[] = { - { "Standard 10\" Octo", 8001 }, - { "Coaxial 10\" Octo", 12001 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoOctoRotorPlus[] = { - { "Standard 10\" Octo", 9001 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeInfo_t AirframeComponentAirframes::_rgAirframeInfoQuadRotorH[] = { - { "3DR Iris", 10016 }, - { "TBS Discovery", 10015 }, - { "SteadiDrone QU4D", 10017 }, - { NULL, 0 } -}; - -const AirframeComponentAirframes::AirframeType_t AirframeComponentAirframes::rgAirframeTypes[] = { - { "Standard Airplane", "qrc:/qmlimages/AirframeStandardPlane.png", AirframeComponentAirframes::_rgAirframeInfoStandardPlane }, - { "Flying Wing", "qrc:/qmlimages/AirframeFlyingWing.png", AirframeComponentAirframes::_rgAirframeInfoFlyingWing }, - { "QuadRotor X", "qrc:/qmlimages/AirframeQuadRotorX.png", AirframeComponentAirframes::_rgAirframeInfoQuadRotorX }, - { "QuadRotor +", "qrc:/qmlimages/AirframeQuadRotorPlus.png", AirframeComponentAirframes::_rgAirframeInfoQuadRotorPlus }, - { "HexaRotor X", "qrc:/qmlimages/AirframeHexaRotorX.png", AirframeComponentAirframes::_rgAirframeInfoHexaRotorX }, - { "HexaRotor +", "qrc:/qmlimages/AirframeHexaRotorPlus.png", AirframeComponentAirframes::_rgAirframeInfoHexaRotorPlus }, - { "OctoRotor X", "qrc:/qmlimages/AirframeOctoRotorX.png", AirframeComponentAirframes::_rgAirframeInfoOctoRotorX }, - { "OctoRotor +", "qrc:/qmlimages/AirframeOctoRotorPlus.png", AirframeComponentAirframes::_rgAirframeInfoOctoRotorPlus }, - { "QuadRotor H", "qrc:/qmlimages/AirframeQuadRotorH.png", AirframeComponentAirframes::_rgAirframeInfoQuadRotorH }, - { "Simulation", "qrc:/qmlimages/AirframeSimulation.png", AirframeComponentAirframes::_rgAirframeInfoSimulation }, - { NULL, NULL, NULL } -}; +QMap AirframeComponentAirframes::rgAirframeTypes; + +QMap& AirframeComponentAirframes::get() { + +#if 0 + // Set a single airframe to prevent the UI from going crazy + if (rgAirframeTypes.count() == 0) { + // Standard planes + AirframeType_t *standardPlane = new AirframeType_t; + standardPlane->name = "Standard Airplane"; + standardPlane->imageResource = "qrc:/qmlimages/AirframeStandardPlane.png"; + AirframeInfo_t *easystar = new AirframeInfo_t; + easystar->name = "Multiplex Easystar 1/2"; + easystar->autostartId = 2100; + standardPlane->rgAirframeInfo.append(easystar); + rgAirframeTypes.insert("StandardPlane", standardPlane); + qDebug() << "Adding plane config"; + + // Flying wings + } +#endif + + return rgAirframeTypes; +} + +void AirframeComponentAirframes::insert(QString& group, QString& image, QString& name, int id) +{ + AirframeType_t *g; + if (!rgAirframeTypes.contains(group)) { + g = new AirframeType_t; + g->name = group; + if (image.length() > 0) { + g->imageResource = QString("qrc:/qmlimages/").append(image); + } else { + g->imageResource = QString("qrc:/qmlimages/AirframeStandardPlane.png"); + } + qDebug() << "IMAGE:" << g->imageResource; + rgAirframeTypes.insert(group, g); + } else { + g = rgAirframeTypes.value(group); + } + + AirframeInfo_t *i = new AirframeInfo_t; + i->name = name; + i->autostartId = id; + + g->rgAirframeInfo.append(i); +} + +void AirframeComponentAirframes::clear() { + + // Run through all and delete them + for (int tindex = 0; tindex < AirframeComponentAirframes::get().count(); tindex++) { + + const AirframeComponentAirframes::AirframeType_t* pType = AirframeComponentAirframes::get().values().at(tindex); + + for (int index = 0; index < pType->rgAirframeInfo.count(); index++) { + const AirframeComponentAirframes::AirframeInfo_t* pInfo = pType->rgAirframeInfo.at(index); + delete pInfo; + } + + delete pType; + } + + rgAirframeTypes.clear(); +} diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.h b/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.h index 8c20e90..0a1116e 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.h +++ b/src/AutoPilotPlugins/PX4/AirframeComponentAirframes.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "UASInterface.h" #include "AutoPilotPlugin.h" @@ -39,30 +40,24 @@ class AirframeComponentAirframes { public: typedef struct { - const char* name; + QString name; int autostartId; } AirframeInfo_t; typedef struct { - const char* name; - const char* imageResource; - const AirframeInfo_t* rgAirframeInfo; + QString name; + QString imageResource; + QList rgAirframeInfo; } AirframeType_t; + + static QMap& get(); + static void clear(); + static void insert(QString& group, QString& image, QString& name, int id); -public: - static const AirframeType_t rgAirframeTypes[]; +protected: + static QMap rgAirframeTypes; private: - static const AirframeInfo_t _rgAirframeInfoStandardPlane[]; - static const AirframeInfo_t _rgAirframeInfoFlyingWing[]; - static const AirframeInfo_t _rgAirframeInfoQuadRotorX[]; - static const AirframeInfo_t _rgAirframeInfoQuadRotorPlus[]; - static const AirframeInfo_t _rgAirframeInfoOctoRotorX[]; - static const AirframeInfo_t _rgAirframeInfoOctoRotorPlus[]; - static const AirframeInfo_t _rgAirframeInfoHexaRotorX[]; - static const AirframeInfo_t _rgAirframeInfoHexaRotorPlus[]; - static const AirframeInfo_t _rgAirframeInfoQuadRotorH[]; - static const AirframeInfo_t _rgAirframeInfoSimulation[]; }; #endif diff --git a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc index 09cf480..c4790af 100644 --- a/src/AutoPilotPlugins/PX4/AirframeComponentController.cc +++ b/src/AutoPilotPlugins/PX4/AirframeComponentController.cc @@ -58,13 +58,20 @@ AirframeComponentController::AirframeComponentController(void) : bool autostartFound = false; _autostartId = getParameterFact(FactSystem::defaultComponentId, "SYS_AUTOSTART")->value().toInt(); + + - for (const AirframeComponentAirframes::AirframeType_t* pType=&AirframeComponentAirframes::rgAirframeTypes[0]; pType->name != NULL; pType++) { + for (int tindex = 0; tindex < AirframeComponentAirframes::get().count(); tindex++) { + + const AirframeComponentAirframes::AirframeType_t* pType = AirframeComponentAirframes::get().values().at(tindex); + AirframeType* airframeType = new AirframeType(pType->name, pType->imageResource, this); Q_CHECK_PTR(airframeType); - - int index = 0; - for (const AirframeComponentAirframes::AirframeInfo_t* pInfo=&pType->rgAirframeInfo[0]; pInfo->name != NULL; pInfo++) { + + for (int index = 0; index < pType->rgAirframeInfo.count(); index++) { + const AirframeComponentAirframes::AirframeInfo_t* pInfo = pType->rgAirframeInfo.at(index); + Q_CHECK_PTR(pInfo); + if (_autostartId == pInfo->autostartId) { Q_ASSERT(!autostartFound); autostartFound = true; @@ -73,7 +80,6 @@ AirframeComponentController::AirframeComponentController(void) : _currentVehicleIndex = index; } airframeType->addAirframe(pInfo->name, pInfo->autostartId); - index++; } _airframeTypes.append(QVariant::fromValue(airframeType)); diff --git a/src/AutoPilotPlugins/PX4/AirframeFactMetaData.xml b/src/AutoPilotPlugins/PX4/AirframeFactMetaData.xml new file mode 100644 index 0000000..d257142 --- /dev/null +++ b/src/AutoPilotPlugins/PX4/AirframeFactMetaData.xml @@ -0,0 +1,288 @@ + + + 1 + + + Simon Wilks <simon@px4.io> + Flying Wing + https://pixhawk.org/platforms/planes/bormatec_camflyer_q + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + left aileron + right aileron + throttle + + + Simon Wilks <simon@px4.io> + Flying Wing + https://pixhawk.org/platforms/planes/z-84_wing_wing + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + left aileron + right aileron + throttle + + + Thomas Gubler <thomas@px4.io>, Julian Oes <julian@px4.io> + Flying Wing + https://pixhawk.org/platforms/planes/skywalker_x5 + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + left aileron + right aileron + throttle + + + Simon Wilks <simon@px4.io> + Flying Wing + https://pixhawk.org/platforms/planes/z-84_wing_wing + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + left aileron + right aileron + throttle + + + Simon Wilks <simon@px4.io> + Flying Wing + + + Simon Wilks <simon@px4.io> + Flying Wing + + + Lorenz Meier <lorenz@px4.io> + Flying Wing + + + + + Anton Babushkin <anton@px4.io> + Hexarotor + + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + + + Lorenz Meier <lorenz@px4.io> + Hexarotor Coaxial + + + + + Anton Babushkin <anton@px4.io> + Hexarotor x + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + + + Anton Babushkin <anton@px4.io> + Octorotor + + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + + + Lorenz Meier <lorenz@px4.io> + Octorotor Coaxial + + + + + Anton Babushkin <anton@px4.io> + Octorotor x + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + + + Anton Babushkin <anton@px4.io> + Quadrotor + + + + + + Anton Babushkin <anton@px4.io>, Simon Wilks <simon@px4.io> + Quadrotor Wide + + + Anton Babushkin <anton@px4.io> + Quadrotor Wide + + + Thomas Gubler <thomas@px4.io> + Quadrotor Wide + + + Simon Wilks <simon@px4.io> + Quadrotor Wide + + + Anton Matosov <anton.matosov@gmail.com> + Quadrotor Wide + + + + + Lorenz Meier <lorenz@px4.io> + Quadrotor x + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + Lorenz Meier <lorenz@px4.io> + Quadrotor x + + + Lorenz Meier <lorenz@px4.io> + Quadrotor x + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + Lorenz Meier <lorenz@px4.io> + Quadrotor x + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + + + Pavel Kirienko <pavel@px4.io> + Quadrotor x + + + Thomas Gubler <thomas@px4.io> + Quadrotor x + + + + + Rover + + + + + Lorenz Meier <lorenz@px4.io> + Simulation + aileron + elevator + rudder + throttle + + + Anton Babushkin <anton@px4.io> + Simulation + + + Anton Babushkin <anton@px4.io> + Simulation + + + Thomas Gubler <thomas@px4.io> + Simulation + + + Thomas Gubler <thomas@px4.io> + Simulation + + + + + Lorenz Meier <lorenz@px4.io> + Standard Plane + + + Lorenz Meier <lorenz@px4.io> + Standard Plane + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + aileron + elevator + throttle + rudder + flaps + + + Lorenz Meier <lorenz@px4.io> + Standard Plane + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + aileron + elevator + throttle + rudder + flaps + + + Lorenz Meier <lorenz@px4.io> + Standard Plane + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + aileron + elevator + throttle + + + Lorenz Meier <lorenz@px4.io> + Standard Plane + feed-through of RC AUX1 channel + feed-through of RC AUX2 channel + feed-through of RC AUX3 channel + aileron + elevator + throttle + rudder + flaps + + + + + Trent Lukaczyk <aerialhedgehog@gmail.com> + Tricopter Y+ + + + + + Trent Lukaczyk <aerialhedgehog@gmail.com> + Tricopter Y- + + + + + Roman Bapst <roman@px4.io> + VTOL Tailsitter + + + Roman Bapst <roman@px4.io> + VTOL Tailsitter + + + Roman Bapst <roman@px4.io> + VTOL Tailsitter + + + + + Roman Bapst <roman@px4.io> + VTOL Tiltrotor + + + diff --git a/src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc b/src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc new file mode 100644 index 0000000..0f144de --- /dev/null +++ b/src/AutoPilotPlugins/PX4/PX4AirframeLoader.cc @@ -0,0 +1,255 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + 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 . + + ======================================================================*/ + +/// @file +/// @author Don Gagne + +#include "PX4AirframeLoader.h" +#include "QGCApplication.h" +#include "QGCLoggingCategory.h" +#include "AirframeComponentAirframes.h" + +#include +#include +#include +#include + +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); +} + +/// Load Airframe Fact meta data +/// +/// The meta data comes from firmware airframes.xml file. +void PX4AirframeLoader::loadAirframeFactMetaData(void) +{ + if (_airframeMetaDataLoaded) { + return; + } + + qCDebug(PX4AirframeLoaderLog) << "Loading PX4 airframe fact meta data"; + qDebug() << "LOADING 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. + QSettings settings; + QDir parameterDir = QFileInfo(settings.fileName()).dir(); + airframeFilename = parameterDir.filePath("PX4AirframeFactMetaData.xml"); + } + 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) { + qWarning() << "Failed opening airframe XML"; + return; + } + + QXmlStreamReader xml(xmlFile.readAll()); + xmlFile.close(); + if (xml.hasError()) { + qWarning() << "Badly formed XML" << xml.errorString(); + return; + } + + QString airframeGroup; + QString image; + QString errorString; + int xmlState = XmlStateNone; + bool badMetaData = true; + + while (!xml.atEnd()) { + if (xml.isStartElement()) { + QString elementName = xml.name().toString(); + + if (elementName == "airframes") { + if (xmlState != XmlStateNone) { + qWarning() << "Badly formed XML"; + return; + } + xmlState = XmlStateFoundAirframes; + + } else if (elementName == "version") { + if (xmlState != XmlStateFoundAirframes) { + qWarning() << "Badly formed XML"; + return; + } + xmlState = XmlStateFoundVersion; + + bool convertOk; + QString strVersion = xml.readElementText(); + int intVersion = strVersion.toInt(&convertOk); + if (!convertOk) { + qWarning() << "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_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")) { + qWarning() << "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) { + qWarning() << "Badly formed XML"; + return; + } + xmlState = XmlStateFoundAirframe; + + if (!xml.attributes().hasAttribute("name") || !xml.attributes().hasAttribute("id")) { + qWarning() << "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) { + qWarning() << "Badly formed XML"; + return; + } + + if (!badMetaData) { + + // We eventually want this, just not yet now +// if (elementName == "short_desc") { +// Q_ASSERT(metaData); +// QString text = xml.readElementText(); +// text = text.replace("\n", " "); +// qCDebug(PX4AirframeLoaderLog) << "Short description:" << text; +// metaData->setShortDescription(text); + +// } else if (elementName == "long_desc") { +// Q_ASSERT(metaData); +// QString text = xml.readElementText(); +// text = text.replace("\n", " "); +// qCDebug(PX4AirframeLoaderLog) << "Long description:" << text; +// metaData->setLongDescription(text); + +// } else if (elementName == "min") { +// Q_ASSERT(metaData); +// QString text = xml.readElementText(); +// qCDebug(PX4AirframeLoaderLog) << "Min:" << text; + +// QVariant varMin; +// if (metaData->convertAndValidate(text, true /* convertOnly */, varMin, errorString)) { +// metaData->setMin(varMin); +// } else { +// qCWarning(PX4AirframeLoaderLog) << "Invalid min value, name:" << metaData->name() << " type:" << metaData->type() << " min:" << text << " error:" << errorString; +// } + +// } else if (elementName == "max") { +// Q_ASSERT(metaData); +// QString text = xml.readElementText(); +// qCDebug(PX4AirframeLoaderLog) << "Max:" << text; + +// QVariant varMax; +// if (metaData->convertAndValidate(text, true /* convertOnly */, varMax, errorString)) { +// metaData->setMax(varMax); +// } else { +// qCWarning(PX4AirframeLoaderLog) << "Invalid max value, name:" << metaData->name() << " type:" << metaData->type() << " max:" << text << " error:" << errorString; +// } + +// } else if (elementName == "unit") { +// Q_ASSERT(metaData); +// QString text = xml.readElementText(); +// qCDebug(PX4AirframeLoaderLog) << "Unit:" << text; +// metaData->setUnits(text); + +// } else { + qDebug() << "Unknown element in XML: " << elementName; +// } + } + } + } else if (xml.isEndElement()) { + QString elementName = xml.name().toString(); + + if (elementName == "airframe") { + // Done loading this airframe, validate + + // Reset for next airframe + badMetaData = false; + xmlState = XmlStateFoundGroup; + } else if (elementName == "airframe_group") { + xmlState = XmlStateFoundVersion; + } else if (elementName == "airframes") { + xmlState = XmlStateFoundAirframes; + } + } + xml.readNext(); + } + + _airframeMetaDataLoaded = true; +} + +void PX4AirframeLoader::clearStaticData(void) +{ + AirframeComponentAirframes::clear(); + _airframeMetaDataLoaded = false; +} diff --git a/src/AutoPilotPlugins/PX4/PX4AirframeLoader.h b/src/AutoPilotPlugins/PX4/PX4AirframeLoader.h new file mode 100644 index 0000000..84d6e77 --- /dev/null +++ b/src/AutoPilotPlugins/PX4/PX4AirframeLoader.h @@ -0,0 +1,69 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2015 QGROUNDCONTROL PROJECT + + 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 . + + ======================================================================*/ + +#ifndef PX4AIRFRAMELOADER_H +#define PX4AIRFRAMELOADER_H + +#include +#include +#include +#include + +#include "ParameterLoader.h" +#include "FactSystem.h" +#include "UASInterface.h" +#include "AutoPilotPlugin.h" + +/// @file PX4AirframeLoader.h +/// @author Lorenz Meier + +Q_DECLARE_LOGGING_CATEGORY(PX4AirframeLoaderLog) + +/// Collection of Parameter Facts for PX4 AutoPilot + +class PX4AirframeLoader : QObject +{ + Q_OBJECT + +public: + /// @param uas Uas which this set of facts is associated with + PX4AirframeLoader(AutoPilotPlugin* autpilot,UASInterface* uas, QObject* parent = NULL); + + static void loadAirframeFactMetaData(void); + static void clearStaticData(void); + +private: + enum { + XmlStateNone, + XmlStateFoundAirframes, + XmlStateFoundVersion, + XmlStateFoundGroup, + XmlStateFoundAirframe, + XmlStateDone + }; + + static bool _airframeMetaDataLoaded; ///< true: parameter meta data already loaded + static QMap _mapParameterName2FactMetaData; ///< Maps from a parameter name to FactMetaData +}; + +#endif // PX4AIRFRAMELOADER_H diff --git a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc index c282deb..09ef2de 100644 --- a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc +++ b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc @@ -25,6 +25,7 @@ #include "AutoPilotPluginManager.h" #include "UASManager.h" #include "PX4ParameterLoader.h" +#include "PX4AirframeLoader.h" #include "FlightModesComponentController.h" #include "AirframeComponentController.h" #include "QGCMessageBox.h" @@ -81,13 +82,18 @@ PX4AutoPilotPlugin::PX4AutoPilotPlugin(UASInterface* uas, QObject* parent) : connect(_parameterFacts, &PX4ParameterLoader::parametersReady, this, &PX4AutoPilotPlugin::_pluginReadyPreChecks); connect(_parameterFacts, &PX4ParameterLoader::parameterListProgress, this, &PX4AutoPilotPlugin::parameterListProgress); + + _airframeFacts = new PX4AirframeLoader(this, uas, this); + Q_CHECK_PTR(_airframeFacts); PX4ParameterLoader::loadParameterFactMetaData(); + PX4AirframeLoader::loadAirframeFactMetaData(); } PX4AutoPilotPlugin::~PX4AutoPilotPlugin() { delete _parameterFacts; + delete _airframeFacts; } QList PX4AutoPilotPlugin::getModes(void) @@ -259,6 +265,7 @@ QString PX4AutoPilotPlugin::getShortModeText(uint8_t baseMode, uint32_t customMo void PX4AutoPilotPlugin::clearStaticData(void) { PX4ParameterLoader::clearStaticData(); + PX4AirframeLoader::clearStaticData(); } const QVariantList& PX4AutoPilotPlugin::vehicleComponents(void) diff --git a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h index d391e36..8f75ab0 100644 --- a/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h +++ b/src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h @@ -28,6 +28,7 @@ #include "AutoPilotPluginManager.h" #include "UASInterface.h" #include "PX4ParameterLoader.h" +#include "PX4AirframeLoader.h" #include "AirframeComponent.h" #include "RadioComponent.h" #include "FlightModesComponent.h" @@ -72,7 +73,8 @@ private: // Overrides from AutoPilotPlugin virtual ParameterLoader* _getParameterLoader(void) { return _parameterFacts; } - PX4ParameterLoader* _parameterFacts; + PX4ParameterLoader* _parameterFacts; + PX4AirframeLoader* _airframeFacts; QVariantList _components; AirframeComponent* _airframeComponent; RadioComponent* _radioComponent; diff --git a/src/VehicleSetup/FirmwareImage.cc b/src/VehicleSetup/FirmwareImage.cc index 1f49de6..b2ec91b 100644 --- a/src/VehicleSetup/FirmwareImage.cc +++ b/src/VehicleSetup/FirmwareImage.cc @@ -242,9 +242,8 @@ bool FirmwareImage::_px4Load(const QString& imageFilename) QSettings settings; QDir parameterDir = QFileInfo(settings.fileName()).dir(); QString parameterFilename = parameterDir.filePath("PX4ParameterFactMetaData.xml"); - qDebug() << parameterFilename; QFile parameterFile(parameterFilename); - + if (parameterFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qint64 bytesWritten = parameterFile.write(decompressedBytes); if (bytesWritten != decompressedBytes.count()) { @@ -259,6 +258,35 @@ bool FirmwareImage::_px4Load(const QString& imageFilename) emit statusMessage(QString("Unable to open parameter meta data file %1 for writing, error: %2").arg(parameterFilename).arg(parameterFile.errorString())); } } + + // Decompress the airframe xml and save to file + success = _decompressJsonValue(px4Json, // JSON object + bytes, // Raw bytes of JSON document + "airframe_xml_size", // key which holds byte size + "airframe_xml", // key which holds compress bytes + decompressedBytes); // Returned decompressed bytes + if (success) { + // We cache the airframe xml in the same location as settings and parameters + QSettings settings; + QDir airframeDir = QFileInfo(settings.fileName()).dir(); + QString airframeFilename = airframeDir.filePath("PX4AirframeFactMetaData.xml"); + qDebug() << airframeFilename; + QFile airframeFile(airframeFilename); + + if (airframeFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qint64 bytesWritten = airframeFile.write(decompressedBytes); + if (bytesWritten != decompressedBytes.count()) { + // FIXME: What about these warnings? + emit statusMessage(QString("Write failed for airframe meta data file, error: %1").arg(airframeFile.errorString())); + airframeFile.close(); + QFile::remove(airframeFilename); + } else { + airframeFile.close(); + } + } else { + emit statusMessage(QString("Unable to open airframe meta data file %1 for writing, error: %2").arg(airframeFilename).arg(airframeFile.errorString())); + } + } // Decompress the image and save to file _imageSize = px4Json.value(QString("image_size")).toInt();