QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
APMAirframeComponentController.cc
Go to the documentation of this file.
5#include "ParameterManager.h"
6#include "QGCApplication.h"
7#include "QGCFileDownload.h"
9#include "Vehicle.h"
10
11#include <QtCore/QJsonObject>
12#include <QtCore/QJsonParseError>
13#include <QtCore/QVariant>
14#include <QtGui/QCursor>
15#include <QtGui/QGuiApplication>
16
17QGC_LOGGING_CATEGORY(APMAirframeComponentControllerLog, "AutoPilotPlugins.APMAirframeComponentController")
18
19/*===========================================================================*/
20
22 : FactPanelController(parent)
23 , _frameClassFact(getParameterFact(ParameterManager::defaultComponentId, QStringLiteral("FRAME_CLASS"), false /* reportMissing */))
24 , _frameTypeFact(getParameterFact(ParameterManager::defaultComponentId, QStringLiteral("FRAME_TYPE"), false /* reportMissing */))
25 , _frameClassModel(new QmlObjectListModel(this))
26{
27 // qCDebug(APMAirframeComponentControllerLog) << Q_FUNC_INFO << this;
28
29 _fillFrameClasses();
30}
31
32APMAirframeComponentController::~APMAirframeComponentController()
33{
34 // qCDebug(APMAirframeComponentControllerLog) << Q_FUNC_INFO << this;
35}
36
37void APMAirframeComponentController::_fillFrameClasses()
38{
39 FirmwarePlugin *const fwPlugin = _vehicle->firmwarePlugin();
40
41 if (qobject_cast<ArduCopterFirmwarePlugin*>(fwPlugin)) {
42 static const QList<int> frameTypeNotSupported = {
49 };
50
51 for (qsizetype i = 1; i < _frameClassFact->enumStrings().count(); i++) {
52 const QString frameClassName = _frameClassFact->enumStrings()[i];
53 const int frameClass = _frameClassFact->enumValues()[i].toInt();
54
55 if (frameClass == FRAME_CLASS_HELI) {
56 // Heli requires it's own firmware variant. You can't switch to Heli from a Copter variant firmware.
57 continue;
58 }
59
60 _frameClassModel->append(new APMFrameClass(frameClassName, true /* copter */, frameClass, _frameTypeFact, _frameClassModel));
61 }
62 } else if (qobject_cast<ArduRoverFirmwarePlugin*>(fwPlugin)) {
63 for (qsizetype i = 1; i < _frameClassFact->enumStrings().count(); i++) {
64 const QString frameClassName = _frameClassFact->enumStrings()[i];
65 const int frameClass = _frameClassFact->enumValues()[i].toInt();
66 _frameClassModel->append(new APMFrameClass(frameClassName, false /* copter */, frameClass, _frameTypeFact, _frameClassModel));
67 }
68 }
69}
70
71void APMAirframeComponentController::_loadParametersFromDownloadFile(const QString &downloadedParamFile)
72{
73 QFile parametersFile(downloadedParamFile);
74 if (!parametersFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
75 qCWarning(APMAirframeComponentControllerLog) << "Unable to open downloaded parameter file" << downloadedParamFile << parametersFile.errorString();
76 QGuiApplication::restoreOverrideCursor();
77 return;
78 }
79
80 QTextStream reader(&parametersFile);
81 while (!reader.atEnd()) {
82 const QString line = reader.readLine().trimmed();
83 if (line.isEmpty() || (line.at(0) == QChar('#'))) {
84 continue;
85 }
86
87 const QStringList aux = line.split(',');
88 if (parameterExists(-1, aux.at(0))) {
89 Fact *const param = getParameterFact(-1, aux.at(0));
90 param->setRawValue(QVariant::fromValue(aux.at(1)));
91 }
92 }
93 QGuiApplication::restoreOverrideCursor();
95}
96
97void APMAirframeComponentController::loadParameters(const QString &paramFile)
98{
99 QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
100
101 QGCFileDownload *const downloader = new QGCFileDownload(this);
102 (void) connect(downloader, &QGCFileDownload::finished, downloader, &QObject::deleteLater);
103 (void) connect(downloader, &QGCFileDownload::finished, this, &APMAirframeComponentController::_githubJsonDownloadComplete);
104 const QString paramFileUrl = QStringLiteral("https://api.github.com/repos/ArduPilot/ardupilot/contents/Tools/Frame_params/%1?ref=master");
105 if (!downloader->start(paramFileUrl.arg(paramFile))) {
106 qgcApp()->showAppMessage(tr("Param file github json download failed to start: %1").arg(downloader->errorString()));
107 QGuiApplication::restoreOverrideCursor();
108 downloader->deleteLater();
109 }
110}
111
112void APMAirframeComponentController::_githubJsonDownloadComplete(bool success, const QString &localFile, const QString &errorMsg)
113{
114 if (success) {
115 QFile jsonFile(localFile);
116 if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
117 qCWarning(APMAirframeComponentControllerLog) << "Unable to open github json file" << localFile << jsonFile.errorString();
118 QGuiApplication::restoreOverrideCursor();
119 return;
120 }
121 const QByteArray bytes = jsonFile.readAll();
122 jsonFile.close();
123
124 QJsonParseError jsonParseError;
125 const QJsonDocument doc = QJsonDocument::fromJson(bytes, &jsonParseError);
126 if (jsonParseError.error != QJsonParseError::NoError) {
127 qCWarning(APMAirframeComponentControllerLog) << "Unable to open json document" << localFile << jsonParseError.errorString();
128 QGuiApplication::restoreOverrideCursor();
129 return;
130 }
131
132 QGCFileDownload *const downloader = new QGCFileDownload(this);
133 (void) connect(downloader, &QGCFileDownload::finished, downloader, &QObject::deleteLater);
134 (void) connect(downloader, &QGCFileDownload::finished, this, &APMAirframeComponentController::_paramFileDownloadComplete);
135 const QJsonObject json = doc.object();
136 if (!downloader->start(json[QLatin1String("download_url")].toString())) {
137 qgcApp()->showAppMessage(tr("Param file download failed to start: %1").arg(downloader->errorString()));
138 QGuiApplication::restoreOverrideCursor();
139 downloader->deleteLater();
140 }
141 } else if (!errorMsg.isEmpty()) {
142 qgcApp()->showAppMessage(tr("Param file github json download failed: %1").arg(errorMsg));
143 QGuiApplication::restoreOverrideCursor();
144 }
145}
146
147void APMAirframeComponentController::_paramFileDownloadComplete(bool success, const QString &localFile, const QString &errorMsg)
148{
149 if (success) {
150 _loadParametersFromDownloadFile(localFile);
151 } else if (!errorMsg.isEmpty()) {
152 qgcApp()->showAppMessage(tr("Param file download failed: %1").arg(errorMsg));
153 QGuiApplication::restoreOverrideCursor();
154 }
155}
156
157/*===========================================================================*/
158
159APMFrameClass::APMFrameClass(const QString &name, bool copter, int frameClass, Fact *frameTypeFact, QObject *parent)
160 : QObject(parent)
161 , _name(name)
162 , _copter(copter)
163 , _frameClass(frameClass)
164 , _frameTypeFact(frameTypeFact)
165{
166 if (frameTypeFact) {
167 (void) connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::imageResourceChanged);
168 (void) connect(frameTypeFact, &Fact::rawValueChanged, this, &APMFrameClass::frameTypeChanged);
169 }
170
171 if (copter) {
172 QList<int> rgSupportedFrameTypes;
173
174 for (const FrameToImageInfo &pFrameToImageInfo : _rgFrameToImageCopter) {
175 if (pFrameToImageInfo.frameClass == frameClass) {
176 if (_defaultFrameType == -1) {
177 // Default frame type/icon is the first item found to match frameClass
178 _defaultFrameType = pFrameToImageInfo.frameType;
179 _imageResourceDefault = QStringLiteral("/qmlimages/Airframe/%1").arg(pFrameToImageInfo.imageResource);
180 }
181
182 if (pFrameToImageInfo.frameType != -1) {
183 // The list includes the supported frame types for the class
184 rgSupportedFrameTypes.append(pFrameToImageInfo.frameType);
185 }
186 }
187 }
188
189 if (_imageResourceDefault.isEmpty()) {
190 _imageResourceDefault = QStringLiteral("/qmlimages/Airframe/AirframeUnknown.svg");
191 }
192
193 // Filter the enums
194 for (const int frameType: rgSupportedFrameTypes) {
195 const int index = frameTypeFact->enumValues().indexOf(frameType);
196 if (index != -1) {
197 _frameTypeEnumValues.append(frameType);
198 _frameTypeEnumStrings.append(frameTypeFact->enumStrings()[index]);
199 }
200 }
201 } else {
202 _imageResourceDefault = imageResource();
203 }
204
205 // If the frameClass is not in the list then frame type is not supported
206 _frameTypeSupported = _defaultFrameType != -1;
207}
208
209APMFrameClass::~APMFrameClass()
210{
211
212}
213
214int APMFrameClass::frameType() const
215{
216 return _frameTypeFact->rawValue().toInt();
217}
218
219QString APMFrameClass::imageResource() const
220{
221 int frameType = _frameTypeFact ? _frameTypeFact->rawValue().toInt() : -1;
222
223 QString imageResource;
224 if (_copter) {
225 imageResource = _findImageResourceCopter(_frameClass, frameType);
226 } else {
227 imageResource = _findImageResourceRover(_frameClass, frameType);
228 }
229
230 return QStringLiteral("/qmlimages/Airframe/%1").arg(imageResource);
231}
232
233
234QString APMFrameClass::_findImageResourceCopter(int frameClass, int &frameType)
235{
236 for (const FrameToImageInfo &pFrameToImageInfo : _rgFrameToImageCopter) {
237 if (((pFrameToImageInfo.frameClass == frameClass) && (frameType == -1)) ||
238 ((pFrameToImageInfo.frameClass == frameClass) && (pFrameToImageInfo.frameType == frameType))) {
239 frameType = pFrameToImageInfo.frameType;
240 return pFrameToImageInfo.imageResource;
241 }
242 }
243
244 return QStringLiteral("AirframeUnknown");
245}
246
247QString APMFrameClass::_findImageResourceRover(int frameClass, int frameType)
248{
249 Q_UNUSED(frameType);
250
251 static const QList<FrameToImageInfo> s_rgFrameToImageRover = {
252 { FRAME_CLASS_ROVER, -1, "Rover" },
253 { FRAME_CLASS_BOAT, -1, "Boat" },
254 };
255
256 for (const FrameToImageInfo &pFrameToImageInfo : s_rgFrameToImageRover) {
257 if (pFrameToImageInfo.frameClass == frameClass) {
258 return pFrameToImageInfo.imageResource;
259 }
260 }
261
262 return QStringLiteral("AirframeUnknown");
263}
#define FRAME_CLASS_BOAT
#define FRAME_CLASS_BICOPTER
#define FRAME_CLASS_HELI
#define FRAME_CLASS_ROVER
#define FRAME_CLASS_COAXCOPTER
#define FRAME_CLASS_HELI_DUAL
#define FRAME_CLASS_HELIQUAD
#define FRAME_CLASS_SINGLECOPTER
#define qgcApp()
Unified file download utility with decompression, verification, and QML support.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
MVC Controller for APMAirframeComponent.qml.
void frameTypeChanged()
void imageResourceChanged()
Used for handling missing Facts from C++ code.
A Fact is used to hold a single value within the system.
Definition Fact.h:19
void rawValueChanged(const QVariant &value)
void refreshAllParameters(uint8_t componentID=MAV_COMP_ID_ALL)
Re-request the full set of parameters from the autopilot.
void finished(bool success, const QString &localPath, const QString &errorMessage)
bool start(const QString &remoteUrl)
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
Definition Vehicle.h:444
ParameterManager * parameterManager()
Definition Vehicle.h:578