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