QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RallyPointController.cc
Go to the documentation of this file.
2#include "RallyPoint.h"
3#include "Vehicle.h"
4#include "GeoJsonHelper.h"
5#include "JsonParsing.h"
6#include "SettingsManager.h"
7#include "AppSettings.h"
9#include "RallyPointManager.h"
10#include "Vehicle.h"
11#include "QGCLoggingCategory.h"
12
13#include <QtCore/QJsonArray>
14
15QGC_LOGGING_CATEGORY(RallyPointControllerLog, "PlanManager.RallyPointController")
16
18 : PlanElementController (masterController, parent)
19 , _managerVehicle (masterController->managerVehicle())
20 , _rallyPointManager (masterController->managerVehicle()->rallyPointManager())
21{
23}
24
29
31{
32 qCDebug(RallyPointControllerLog) << "start flyView" << flyView;
33
34 _managerVehicleChanged(_masterController->managerVehicle());
35 connect(_masterController, &PlanMasterController::managerVehicleChanged, this, &RallyPointController::_managerVehicleChanged);
36
38}
39
40void RallyPointController::_managerVehicleChanged(Vehicle* managerVehicle)
41{
42 if (_managerVehicle) {
43 _rallyPointManager->disconnect(this);
44 _managerVehicle->disconnect(this);
45 _managerVehicle = nullptr;
46 _rallyPointManager = nullptr;
47 }
48
49 _managerVehicle = managerVehicle;
50 if (!_managerVehicle) {
51 qWarning() << "RallyPointController::managerVehicleChanged managerVehicle=NULL";
52 return;
53 }
54
55 _rallyPointManager = _managerVehicle->rallyPointManager();
56 connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_managerLoadComplete);
57 connect(_rallyPointManager, &RallyPointManager::sendComplete, this, &RallyPointController::_managerSendComplete);
58 connect(_rallyPointManager, &RallyPointManager::removeAllComplete, this, &RallyPointController::_managerRemoveAllComplete);
60
61 (void) connect(_managerVehicle, &Vehicle::capabilityBitsChanged, this, [this](uint64_t capabilityBits) {
62 Q_UNUSED(capabilityBits);
64 });
65
67}
68
69bool RallyPointController::load(const QJsonObject& json, QString& errorString)
70{
71 removeAll();
72
73 errorString.clear();
74
75 if (json.contains(JsonParsing::jsonVersionKey) && json[JsonParsing::jsonVersionKey].toInt() == 1) {
76 // We just ignore old version 1 data
77 return true;
78 }
79
80 QList<JsonParsing::KeyValidateInfo> keyInfoList = {
81 { JsonParsing::jsonVersionKey, QJsonValue::Double, true },
82 { _jsonPointsKey, QJsonValue::Array, true },
83 };
84 if (!JsonParsing::validateKeys(json, keyInfoList, errorString)) {
85 return false;
86 }
87
88 QString errorStr;
89 QString errorMessage = tr("Rally: %1");
90
91 if (json[JsonParsing::jsonVersionKey].toInt() != _jsonCurrentVersion) {
92 errorString = tr("Rally Points supports version %1").arg(_jsonCurrentVersion);
93 return false;
94 }
95
96 QList<QGeoCoordinate> rgPoints;
97 if (!GeoJsonHelper::loadGeoCoordinateArray(json[_jsonPointsKey], true /* altitudeRequired */, rgPoints, errorStr)) {
98 errorString = errorMessage.arg(errorStr);
99 return false;
100 }
101
102 QObjectList pointList;
103 for (int i=0; i<rgPoints.count(); i++) {
104 pointList.append(new RallyPoint(rgPoints[i], this));
105 }
106 _points.swapObjectList(pointList);
107
108 setDirty(false);
109 _setFirstPointCurrent();
110
111 return true;
112}
113
114void RallyPointController::save(QJsonObject& json)
115{
116 json[JsonParsing::jsonVersionKey] = _jsonCurrentVersion;
117
118 QJsonArray rgPoints;
119 QJsonValue jsonPoint;
120 for (int i=0; i<_points.count(); i++) {
121 GeoJsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
122 rgPoints.append(jsonPoint);
123 }
124 json[_jsonPointsKey] = QJsonValue(rgPoints);
125}
126
128{
129 _points.clearAndDeleteContents();
130 setDirty(true);
131 setCurrentRallyPoint(nullptr);
132}
133
135{
136 if (_masterController->offline()) {
137 qCCritical(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while offline";
138 } else if (syncInProgress()) {
139 qCCritical(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while syncInProgress";
140 } else {
141 _rallyPointManager->removeAll();
142 }
143}
144
146{
147 if (_masterController->offline()) {
148 qCCritical(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while offline";
149 } else if (syncInProgress()) {
150 qCCritical(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while syncInProgress";
151 } else {
152 _itemsRequested = true;
153 _rallyPointManager->loadFromVehicle();
154 }
155}
156
158{
159 if (_masterController->offline()) {
160 qCCritical(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while offline";
161 } else if (syncInProgress()) {
162 qCCritical(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while syncInProgress";
163 } else {
164 qCDebug(RallyPointControllerLog) << "RallyPointController::sendToVehicle";
165 setDirty(false);
166 QList<QGeoCoordinate> rgPoints;
167 for (int i=0; i<_points.count(); i++) {
168 rgPoints.append(qobject_cast<RallyPoint*>(_points[i])->coordinate());
169 }
170 _rallyPointManager->sendToVehicle(rgPoints);
171 }
172}
173
175{
176 return _rallyPointManager->inProgress();
177}
178
180{
181 if (dirty != _dirty) {
182 _dirty = dirty;
183 emit dirtyChanged(dirty);
184 }
185}
186
188{
189 return _rallyPointManager->editorQml();
190}
191
192void RallyPointController::_managerLoadComplete(void)
193{
194 // Fly view always reloads on _loadComplete
195 // Plan view only reloads if:
196 // - Load was specifically requested
197 // - There is no current Plan
198 if (_flyView || _itemsRequested || isEmpty()) {
199 _points.clearAndDeleteContents();
200 QObjectList pointList;
201 for (int i=0; i<_rallyPointManager->points().count(); i++) {
202 pointList.append(new RallyPoint(_rallyPointManager->points()[i], this));
203 }
204 _points.swapObjectList(pointList);
205 setDirty(false);
206 _setFirstPointCurrent();
207 emit loadComplete();
208 }
209 _itemsRequested = false;
210}
211
212void RallyPointController::_managerSendComplete(bool error)
213{
214 // Fly view always reloads after send
215 if (!error && _flyView) {
217 }
218}
219
220void RallyPointController::_managerRemoveAllComplete(bool error)
221{
222 if (!error) {
223 // Remove all from vehicle so we always update
225 }
226}
227
228void RallyPointController::addPoint(QGeoCoordinate point)
229{
230 double defaultAlt;
231 if (_points.count()) {
232 defaultAlt = qobject_cast<RallyPoint*>(_points[_points.count() - 1])->coordinate().altitude();
233 } else {
235 defaultAlt = SettingsManager::instance()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble();
236 }
237 else {
239 }
240 }
241 point.setAltitude(defaultAlt);
242 RallyPoint* newPoint = new RallyPoint(point, this);
243 _points.append(newPoint);
244 setCurrentRallyPoint(newPoint);
245 setDirty(true);
246}
247
249{
250 return _managerVehicle->capabilityBits() & MAV_PROTOCOL_CAPABILITY_MISSION_RALLY;
251}
252
253void RallyPointController::removePoint(QObject* rallyPoint)
254{
255 int foundIndex = 0;
256 for (foundIndex=0; foundIndex<_points.count(); foundIndex++) {
257 if (_points[foundIndex] == rallyPoint) {
258 _points.removeOne(rallyPoint);
259 rallyPoint->deleteLater();
260 }
261 }
262
263 if (_points.count()) {
264 int newIndex = qMin(foundIndex, _points.count() - 1);
265 newIndex = qMax(newIndex, 0);
266 setCurrentRallyPoint(_points[newIndex]);
267 } else {
268 setCurrentRallyPoint(nullptr);
269 }
270}
271
273{
274 if (_currentRallyPoint != rallyPoint) {
275 _currentRallyPoint = rallyPoint;
276 emit currentRallyPointChanged(rallyPoint);
277 }
278}
279
280void RallyPointController::_setFirstPointCurrent(void)
281{
282 setCurrentRallyPoint(_points.count() ? _points[0] : nullptr);
283}
284
286{
287 return _points.count() > 0;
288}
289
291{
292 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle _flyView" << _flyView;
293 if (_masterController->offline()) {
294 qCCritical(RallyPointControllerLog) << "RallyPointController::showPlanFromManagerVehicle called while offline";
295 return true; // stops further propagation of showPlanFromManagerVehicle due to error
296 } else {
297 if (!_managerVehicle->initialPlanRequestComplete()) {
298 // The vehicle hasn't completed initial load, we can just wait for loadComplete to be signalled automatically
299 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal";
300 return true;
301 } else if (syncInProgress()) {
302 // If the sync is already in progress, _loadComplete will be called automatically when it is done. So no need to do anything.
303 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: syncInProgress wait for signal";
304 return true;
305 } else {
306 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: sync complete";
307 _itemsRequested = true;
308 _managerLoadComplete();
309 return false;
310 }
311 }
312}
313
315{
316 return _points.count() == 0;
317}
QString errorString
Error error
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void countChanged(int count)
This is the abstract base clas for Plan Element controllers.
void supportedChanged(bool supported)
void syncInProgressChanged(bool syncInProgress)
PlanMasterController * _masterController
virtual void start(bool flyView)
Should be called immediately upon Component.onCompleted.
void dirtyChanged(bool dirty)
void loadFromVehicle(void)
bool inProgress(void) const
Master controller for mission, fence, rally.
Vehicle * controllerVehicle(void)
void managerVehicleChanged(Vehicle *managerVehicle)
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
QObject * removeOne(const QObject *object) override final
int count() const override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
QObjectList swapObjectList(const QObjectList &newlist)
bool containsItems(void) const final
void save(QJsonObject &json) final
void loadComplete(void)
Q_INVOKABLE void addPoint(QGeoCoordinate point)
bool supported(void) const final
true: controller is waiting for the current load to complete
void setDirty(bool dirty) final
QString editorQml(void) const
bool showPlanFromManagerVehicle(void) final
bool syncInProgress(void) const final
void setCurrentRallyPoint(QObject *rallyPoint)
bool dirty(void) const final
void start(bool flyView) final
Should be called immediately upon Component.onCompleted.
void removeAllFromVehicle(void) final
bool load(const QJsonObject &json, QString &errorString) final
Q_INVOKABLE void removePoint(QObject *rallyPoint)
void removeAll(void) final
Removes all from controller only.
void currentRallyPointChanged(QObject *rallyPoint)
void loadFromVehicle(void) final
void inProgressChanged(bool inProgress)
void sendToVehicle(const QList< QGeoCoordinate > &rgPoints)
void loadComplete(void)
void sendComplete(bool error)
QList< QGeoCoordinate > points(void) const
void removeAllComplete(bool error)
QString editorQml(void) const
This class is used to encapsulate the QGeoCoordinate associated with a Rally Point into a QObject suc...
Definition RallyPoint.h:12
static double getDefaultFactAltitude()
Definition RallyPoint.cc:89
static SettingsManager * instance()
AppSettings * appSettings() const
void capabilityBitsChanged(uint64_t capabilityBits)
uint64_t capabilityBits() const
Definition Vehicle.h:697
RallyPointManager * rallyPointManager()
Definition Vehicle.h:572
bool initialPlanRequestComplete() const
Definition Vehicle.h:703
bool fixedWing() const
Definition Vehicle.cc:1738
bool loadGeoCoordinateArray(const QJsonValue &jsonValue, bool altitudeRequired, QVariantList &rgVarPoints, QString &errorString)
Loads a list of QGeoCoordinates (QGC plan format) from a json array.
void saveGeoCoordinate(const QGeoCoordinate &coordinate, bool writeAltitude, QJsonValue &jsonValue)
Saves a QGeoCoordinate as [lat, lon, alt] array (QGC plan format).
bool validateKeys(const QJsonObject &jsonObject, const QList< KeyValidateInfo > &keyInfo, QString &errorString)
Validates that all required keys are present and that listed keys have the expected type.
constexpr const char * jsonVersionKey
Definition JsonParsing.h:12