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