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 connect(&_points, &QmlObjectListModel::dirtyChanged, this, &RallyPointController::_pointsDirtyChanged);
24}
25
30
32{
33 qCDebug(RallyPointControllerLog) << "start flyView" << flyView;
34
35 _managerVehicleChanged(_masterController->managerVehicle());
36 connect(_masterController, &PlanMasterController::managerVehicleChanged, this, &RallyPointController::_managerVehicleChanged);
37
39}
40
41void RallyPointController::_managerVehicleChanged(Vehicle* managerVehicle)
42{
43 if (_managerVehicle) {
44 _rallyPointManager->disconnect(this);
45 _managerVehicle->disconnect(this);
46 _managerVehicle = nullptr;
47 _rallyPointManager = nullptr;
48 }
49
50 _managerVehicle = managerVehicle;
51 if (!_managerVehicle) {
52 qWarning() << "RallyPointController::managerVehicleChanged managerVehicle=NULL";
53 return;
54 }
55
56 _rallyPointManager = _managerVehicle->rallyPointManager();
57 connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_managerLoadComplete);
58 connect(_rallyPointManager, &RallyPointManager::sendComplete, this, &RallyPointController::_managerSendComplete);
59 connect(_rallyPointManager, &RallyPointManager::removeAllComplete, this, &RallyPointController::_managerRemoveAllComplete);
61
62 (void) connect(_managerVehicle, &Vehicle::capabilityBitsChanged, this, [this](uint64_t capabilityBits) {
63 Q_UNUSED(capabilityBits);
65 });
66
68}
69
70bool RallyPointController::load(const QJsonObject& json, QString& errorString)
71{
72 removeAll();
73
74 errorString.clear();
75
76 if (json.contains(JsonParsing::jsonVersionKey) && json[JsonParsing::jsonVersionKey].toInt() == 1) {
77 // We just ignore old version 1 data
78 return true;
79 }
80
81 QList<JsonParsing::KeyValidateInfo> keyInfoList = {
82 { JsonParsing::jsonVersionKey, QJsonValue::Double, true },
83 { _jsonPointsKey, QJsonValue::Array, true },
84 };
85 if (!JsonParsing::validateKeys(json, keyInfoList, errorString)) {
86 return false;
87 }
88
89 QString errorStr;
90 QString errorMessage = tr("Rally: %1");
91
92 if (json[JsonParsing::jsonVersionKey].toInt() != _jsonCurrentVersion) {
93 errorString = tr("Rally Points supports version %1").arg(_jsonCurrentVersion);
94 return false;
95 }
96
97 QList<QGeoCoordinate> rgPoints;
98 if (!GeoJsonHelper::loadGeoCoordinateArray(json[_jsonPointsKey], true /* altitudeRequired */, rgPoints, errorStr)) {
99 errorString = errorMessage.arg(errorStr);
100 return false;
101 }
102
103 QObjectList pointList;
104 for (int i=0; i<rgPoints.count(); i++) {
105 pointList.append(new RallyPoint(rgPoints[i], this));
106 }
107 _points.swapObjectList(pointList);
108
109 setDirty(false);
110 _setFirstPointCurrent();
111
112 return true;
113}
114
115void RallyPointController::save(QJsonObject& json)
116{
117 json[JsonParsing::jsonVersionKey] = _jsonCurrentVersion;
118
119 QJsonArray rgPoints;
120 QJsonValue jsonPoint;
121 for (int i=0; i<_points.count(); i++) {
122 GeoJsonHelper::saveGeoCoordinate(qobject_cast<RallyPoint*>(_points[i])->coordinate(), true /* writeAltitude */, jsonPoint);
123 rgPoints.append(jsonPoint);
124 }
125 json[_jsonPointsKey] = QJsonValue(rgPoints);
126}
127
129{
130 _points.clearAndDeleteContents();
131 setDirty(true);
132 setCurrentRallyPoint(nullptr);
133}
134
136{
137 if (_masterController->offline()) {
138 qCCritical(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while offline";
139 } else if (syncInProgress()) {
140 qCCritical(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while syncInProgress";
141 } else {
142 _rallyPointManager->removeAll();
143 }
144}
145
147{
148 if (_masterController->offline()) {
149 qCCritical(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while offline";
150 } else if (syncInProgress()) {
151 qCCritical(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while syncInProgress";
152 } else {
153 _itemsRequested = true;
154 _rallyPointManager->loadFromVehicle();
155 }
156}
157
159{
160 if (_masterController->offline()) {
161 qCCritical(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while offline";
162 } else if (syncInProgress()) {
163 qCCritical(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while syncInProgress";
164 } else {
165 qCDebug(RallyPointControllerLog) << "RallyPointController::sendToVehicle";
166 setDirty(false);
167 QList<QGeoCoordinate> rgPoints;
168 for (int i=0; i<_points.count(); i++) {
169 rgPoints.append(qobject_cast<RallyPoint*>(_points[i])->coordinate());
170 }
171 _rallyPointManager->sendToVehicle(rgPoints);
172 }
173}
174
176{
177 return _rallyPointManager->inProgress();
178}
179
181{
182 if (dirty != _dirty) {
183 _dirty = dirty;
184 if (!dirty) {
185 _points.setDirty(false);
186 }
187 emit dirtyChanged(dirty);
188 }
189}
190
191void RallyPointController::_pointsDirtyChanged(bool dirty)
192{
193 if (dirty) {
194 setDirty(true);
195 }
196}
197
199{
200 return _rallyPointManager->editorQml();
201}
202
203void RallyPointController::_managerLoadComplete(void)
204{
205 // Fly view always reloads on _loadComplete
206 // Plan view only reloads if:
207 // - Load was specifically requested
208 // - There is no current Plan
209 if (_flyView || _itemsRequested || isEmpty()) {
210 _points.clearAndDeleteContents();
211 QObjectList pointList;
212 for (int i=0; i<_rallyPointManager->points().count(); i++) {
213 pointList.append(new RallyPoint(_rallyPointManager->points()[i], this));
214 }
215 _points.swapObjectList(pointList);
216 setDirty(false);
217 _setFirstPointCurrent();
218 emit loadComplete();
219 }
220 _itemsRequested = false;
221}
222
223void RallyPointController::_managerSendComplete(bool error)
224{
225 // Fly view always reloads after send
226 if (!error && _flyView) {
228 }
229}
230
231void RallyPointController::_managerRemoveAllComplete(bool error)
232{
233 if (!error) {
234 // Remove all from vehicle so we always update
236 }
237}
238
239void RallyPointController::addPoint(QGeoCoordinate point)
240{
241 double defaultAlt;
242 if (_points.count()) {
243 defaultAlt = qobject_cast<RallyPoint*>(_points[_points.count() - 1])->coordinate().altitude();
244 } else {
246 defaultAlt = SettingsManager::instance()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble();
247 }
248 else {
250 }
251 }
252 point.setAltitude(defaultAlt);
253 RallyPoint* newPoint = new RallyPoint(point, this);
254 _points.append(newPoint);
255 setCurrentRallyPoint(newPoint);
256 setDirty(true);
257}
258
260{
261 return _managerVehicle->capabilityBits() & MAV_PROTOCOL_CAPABILITY_MISSION_RALLY;
262}
263
264void RallyPointController::removePoint(QObject* rallyPoint)
265{
266 int foundIndex = 0;
267 for (foundIndex=0; foundIndex<_points.count(); foundIndex++) {
268 if (_points[foundIndex] == rallyPoint) {
269 _points.removeOne(rallyPoint);
270 rallyPoint->deleteLater();
271 }
272 }
273
274 if (_points.count()) {
275 int newIndex = qMin(foundIndex, _points.count() - 1);
276 newIndex = qMax(newIndex, 0);
277 setCurrentRallyPoint(_points[newIndex]);
278 } else {
279 setCurrentRallyPoint(nullptr);
280 }
281}
282
284{
285 if (_currentRallyPoint != rallyPoint) {
286 _currentRallyPoint = rallyPoint;
287 emit currentRallyPointChanged(rallyPoint);
288 }
289}
290
291void RallyPointController::_setFirstPointCurrent(void)
292{
293 setCurrentRallyPoint(_points.count() ? _points[0] : nullptr);
294}
295
297{
298 return _points.count() > 0;
299}
300
302{
303 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle _flyView" << _flyView;
304 if (_masterController->offline()) {
305 qCCritical(RallyPointControllerLog) << "RallyPointController::showPlanFromManagerVehicle called while offline";
306 return true; // stops further propagation of showPlanFromManagerVehicle due to error
307 } else {
308 if (!_managerVehicle->initialPlanRequestComplete()) {
309 // The vehicle hasn't completed initial load, we can just wait for loadComplete to be signalled automatically
310 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal";
311 return true;
312 } else if (syncInProgress()) {
313 // If the sync is already in progress, _loadComplete will be called automatically when it is done. So no need to do anything.
314 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: syncInProgress wait for signal";
315 return true;
316 } else {
317 qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: sync complete";
318 _itemsRequested = true;
319 _managerLoadComplete();
320 return false;
321 }
322 }
323}
324
326{
327 return _points.count() == 0;
328}
QString errorString
Error error
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void dirtyChanged(bool dirty)
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.
void setDirty(bool dirty) override final
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:97
static SettingsManager * instance()
AppSettings * appSettings() const
void capabilityBitsChanged(uint64_t capabilityBits)
uint64_t capabilityBits() const
Definition Vehicle.h:727
RallyPointManager * rallyPointManager()
Definition Vehicle.h:594
bool initialPlanRequestComplete() const
Definition Vehicle.h:733
bool fixedWing() const
Definition Vehicle.cc:1755
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:14