diff --git a/src/FirmwarePlugin/APM/APMGeoFenceManager.cc b/src/FirmwarePlugin/APM/APMGeoFenceManager.cc index a558227e1cb1cedc1975173c532625624e7ad7f9..1c7eae0aac09e17dd3eca5bc8f5a605e286412b5 100644 --- a/src/FirmwarePlugin/APM/APMGeoFenceManager.cc +++ b/src/FirmwarePlugin/APM/APMGeoFenceManager.cc @@ -82,6 +82,7 @@ void APMGeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, QmlOb // Total point count, +1 polygon close in last index, +1 for breach in index 0 _cWriteFencePoints = validatedPolygonCount ? validatedPolygonCount + 1 + 1 : 0; + qCDebug(GeoFenceManagerLog) << "APMGeoFenceManager::sendToVehicle validatedPolygonCount:_cWriteFencePoints" << validatedPolygonCount << _cWriteFencePoints; _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _fenceTotalParam)->setRawValue(_cWriteFencePoints); // FIXME: No validation of correct fence received @@ -89,7 +90,7 @@ void APMGeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, QmlOb _sendFencePoint(index); } - emit loadComplete(_breachReturnPoint, _polygon); + emit sendComplete(); } void APMGeoFenceManager::loadFromVehicle(void) @@ -326,7 +327,10 @@ void APMGeoFenceManager::_parametersReady(void) void APMGeoFenceManager::removeAll(void) { + qCDebug(GeoFenceManagerLog) << "APMGeoFenceManager::removeAll"; + QmlObjectListModel emptyPolygon; sendToVehicle(_breachReturnPoint, emptyPolygon); + emit removeAllComplete(); } diff --git a/src/FirmwarePlugin/APM/APMRallyPointManager.cc b/src/FirmwarePlugin/APM/APMRallyPointManager.cc index 0e44314d93e138fca67f63c3478036143c4dd476..6adef3d606b47787ccf3d6850f910edc03347c90 100644 --- a/src/FirmwarePlugin/APM/APMRallyPointManager.cc +++ b/src/FirmwarePlugin/APM/APMRallyPointManager.cc @@ -48,7 +48,7 @@ void APMRallyPointManager::sendToVehicle(const QList& rgPoints) _sendRallyPoint(index); } - emit loadComplete(_rgPoints); + emit sendComplete(); } void APMRallyPointManager::loadFromVehicle(void) @@ -60,7 +60,7 @@ void APMRallyPointManager::loadFromVehicle(void) _rgPoints.clear(); _cReadRallyPoints = _vehicle->parameterManager()->getParameter(FactSystem::defaultComponentId, _rallyTotalParam)->rawValue().toInt(); - qCDebug(GeoFenceManagerLog) << "APMGeoFenceManager::loadFromVehicle" << _cReadRallyPoints; + qCDebug(RallyPointManagerLog) << "APMRallyPointManager::loadFromVehicle - point count" << _cReadRallyPoints; if (_cReadRallyPoints == 0) { emit loadComplete(_rgPoints); return; @@ -152,7 +152,10 @@ bool APMRallyPointManager::rallyPointsSupported(void) const void APMRallyPointManager::removeAll(void) { + qCDebug(RallyPointManagerLog) << "APMRallyPointManager::removeAll"; + QList noRallyPoints; sendToVehicle(noRallyPoints); + emit removeAllComplete(); } diff --git a/src/MissionManager/GeoFenceController.cc b/src/MissionManager/GeoFenceController.cc index 41293a2921d4083abcee9c480d430d9d4f07afe4..3b8f6df847178e5770586dc0ce6a59a35115cf40 100644 --- a/src/MissionManager/GeoFenceController.cc +++ b/src/MissionManager/GeoFenceController.cc @@ -20,6 +20,7 @@ #include "JsonHelper.h" #include "QGCQGeoCoordinate.h" #include "AppSettings.h" +#include "PlanMasterController.h" #ifndef __mobile__ #include "MainWindow.h" @@ -39,6 +40,7 @@ GeoFenceController::GeoFenceController(PlanMasterController* masterController, Q , _geoFenceManager(_managerVehicle->geoFenceManager()) , _dirty(false) , _mapPolygon(this) + , _itemsRequested(false) { connect(_mapPolygon.qmlPathModel(), &QmlObjectListModel::countChanged, this, &GeoFenceController::_updateContainsItems); connect(_mapPolygon.qmlPathModel(), &QmlObjectListModel::dirtyChanged, this, &GeoFenceController::_polygonDirtyChanged); @@ -104,7 +106,9 @@ void GeoFenceController::managerVehicleChanged(Vehicle* managerVehicle) connect(_geoFenceManager, &GeoFenceManager::circleRadiusFactChanged, this, &GeoFenceController::circleRadiusFactChanged); connect(_geoFenceManager, &GeoFenceManager::polygonEnabledChanged, this, &GeoFenceController::polygonEnabledChanged); connect(_geoFenceManager, &GeoFenceManager::polygonSupportedChanged, this, &GeoFenceController::polygonSupportedChanged); - connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &GeoFenceController::_loadComplete); + connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &GeoFenceController::_managerLoadComplete); + connect(_geoFenceManager, &GeoFenceManager::sendComplete, this, &GeoFenceController::_managerSendComplete); + connect(_geoFenceManager, &GeoFenceManager::removeAllComplete, this, &GeoFenceController::_managerRemoveAllComplete); connect(_geoFenceManager, &GeoFenceManager::inProgressChanged, this, &GeoFenceController::syncInProgressChanged); _signalAll(); @@ -152,20 +156,40 @@ void GeoFenceController::removeAll(void) _mapPolygon.clear(); } +void GeoFenceController::removeAllFromVehicle(void) +{ + if (_masterController->offline()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::removeAllFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::removeAllFromVehicle called while syncInProgress"; + } else { + _geoFenceManager->removeAll(); + } +} + void GeoFenceController::loadFromVehicle(void) { - if (!syncInProgress()) { - _geoFenceManager->loadFromVehicle(); + if (_masterController->offline()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::loadFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::loadFromVehicle called while syncInProgress"; } else { - qCWarning(GeoFenceControllerLog) << "GeoFenceController::loadFromVehicle call while syncInProgress"; + _itemsRequested = true; + _geoFenceManager->loadFromVehicle(); } } void GeoFenceController::sendToVehicle(void) { - _geoFenceManager->sendToVehicle(_breachReturnPoint, _mapPolygon.pathModel()); - _mapPolygon.setDirty(false); - setDirty(false); + if (_masterController->offline()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::sendToVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::sendToVehicle called while syncInProgress"; + } else { + _geoFenceManager->sendToVehicle(_breachReturnPoint, _mapPolygon.pathModel()); + _mapPolygon.setDirty(false); + setDirty(false); + } } bool GeoFenceController::syncInProgress(void) const @@ -252,12 +276,32 @@ void GeoFenceController::_setReturnPointFromManager(QGeoCoordinate breachReturnP emit breachReturnPointChanged(_breachReturnPoint); } -void GeoFenceController::_loadComplete(const QGeoCoordinate& breachReturn, const QList& polygon) +void GeoFenceController::_managerLoadComplete(const QGeoCoordinate& breachReturn, const QList& polygon) { - _setReturnPointFromManager(breachReturn); - _setPolygonFromManager(polygon); - setDirty(false); - emit loadComplete(); + // Fly view always reloads on _loadComplete + // Plan view only reloads on _loadComplete if specifically requested + if (!_editMode || _itemsRequested) { + _setReturnPointFromManager(breachReturn); + _setPolygonFromManager(polygon); + setDirty(false); + _signalAll(); + emit loadComplete(); + } + _itemsRequested = false; +} + +void GeoFenceController::_managerSendComplete(void) +{ + // Fly view always reloads on manager sendComplete + if (!_editMode) { + showPlanFromManagerVehicle(); + } +} + +void GeoFenceController::_managerRemoveAllComplete(void) +{ + // Remove all from vehicle so we always update + showPlanFromManagerVehicle(); } bool GeoFenceController::containsItems(void) const @@ -270,7 +314,28 @@ void GeoFenceController::_updateContainsItems(void) emit containsItemsChanged(containsItems()); } -void GeoFenceController::removeAllFromVehicle(void) +bool GeoFenceController::showPlanFromManagerVehicle(void) { - _geoFenceManager->removeAll(); + qCDebug(GeoFenceControllerLog) << "showPlanFromManagerVehicle"; + if (_masterController->offline()) { + qCWarning(GeoFenceControllerLog) << "GeoFenceController::showPlanFromManagerVehicle called while offline"; + return true; // stops further propogation of showPlanFromManagerVehicle due to error + } else { + _itemsRequested = true; + if (!_managerVehicle->initialPlanRequestComplete()) { + // The vehicle hasn't completed initial load, we can just wait for newMissionItemsAvailable to be signalled automatically + qCDebug(GeoFenceControllerLog) << "showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal"; + return true; + } else if (syncInProgress()) { + // If the sync is already in progress, _loadComplete will be called automatically when it is done. So no need to do anything. + qCDebug(GeoFenceControllerLog) << "showPlanFromManagerVehicle: syncInProgress wait for signal"; + return true; + } else { + // Fake a _loadComplete with the current items + qCDebug(GeoFenceControllerLog) << "showPlanFromManagerVehicle: sync complete simulate signal"; + _itemsRequested = true; + _managerLoadComplete(_geoFenceManager->breachReturnPoint(), _geoFenceManager->polygon()); + return false; + } + } } diff --git a/src/MissionManager/GeoFenceController.h b/src/MissionManager/GeoFenceController.h index 00165354144dc203fd18ebc003b2ae3d4f1db989..3e8b01aeba60a46563a822c8bcd32932e3c6c6bd 100644 --- a/src/MissionManager/GeoFenceController.h +++ b/src/MissionManager/GeoFenceController.h @@ -56,6 +56,7 @@ public: void setDirty (bool dirty) final; bool containsItems (void) const final; void managerVehicleChanged (Vehicle* managerVehicle) final; + bool showPlanFromManagerVehicle (void) final; bool circleEnabled (void) const; Fact* circleRadiusFact (void) const; @@ -87,8 +88,10 @@ private slots: void _setDirty(void); void _setPolygonFromManager(const QList& polygon); void _setReturnPointFromManager(QGeoCoordinate breachReturnPoint); - void _loadComplete(const QGeoCoordinate& breachReturn, const QList& polygon); + void _managerLoadComplete(const QGeoCoordinate& breachReturn, const QList& polygon); void _updateContainsItems(void); + void _managerSendComplete(void); + void _managerRemoveAllComplete(void); private: void _init(void); @@ -98,6 +101,7 @@ private: bool _dirty; QGCMapPolygon _mapPolygon; QGeoCoordinate _breachReturnPoint; + bool _itemsRequested; static const char* _jsonFileTypeValue; static const char* _jsonBreachReturnKey; diff --git a/src/MissionManager/GeoFenceManager.cc b/src/MissionManager/GeoFenceManager.cc index 54e1593cd49e104a4a3e8afc5702cdd5578e8ca6..397262b49c86b094439c08b03c9064a1b68db6ce 100644 --- a/src/MissionManager/GeoFenceManager.cc +++ b/src/MissionManager/GeoFenceManager.cc @@ -43,5 +43,12 @@ void GeoFenceManager::sendToVehicle(const QGeoCoordinate& breachReturn, QmlObjec // No geofence support in unknown vehicle Q_UNUSED(breachReturn); Q_UNUSED(polygon); - emit loadComplete(QGeoCoordinate(), QList()); + emit sendComplete(); +} + + +void GeoFenceManager::removeAll(void) +{ + // No geofence support in unknown vehicle + emit removeAllComplete(); } diff --git a/src/MissionManager/GeoFenceManager.h b/src/MissionManager/GeoFenceManager.h index ffa82f0e365eb7108ac669c89ba0ce0454363ebf..d78fc499e94c0698e6060ccbe1b93d6bab66c215 100644 --- a/src/MissionManager/GeoFenceManager.h +++ b/src/MissionManager/GeoFenceManager.h @@ -35,13 +35,16 @@ public: virtual bool inProgress(void) const { return false; } /// Load the current settings from the vehicle + /// Signals loadComplete when done virtual void loadFromVehicle(void); /// Send the current settings to the vehicle + /// Signals sendComplete when done virtual void sendToVehicle(const QGeoCoordinate& breachReturn, QmlObjectListModel& polygon); /// Remove all fence related items from vehicle (does not affect paramters) - virtual void removeAll(void) { } + /// Signals removeAllComplete when done + virtual void removeAll(void); /// Returns true if this vehicle support polygon fence /// Signal: polygonSupportedChanged @@ -93,6 +96,8 @@ signals: void polygonSupportedChanged (bool polygonSupported); void polygonEnabledChanged (bool polygonEnabled); void breachReturnSupportedChanged (bool breachReturnSupported); + void removeAllComplete (void); + void sendComplete (void); protected: void _sendError(ErrorCode_t errorCode, const QString& errorMsg); diff --git a/src/MissionManager/MissionController.cc b/src/MissionManager/MissionController.cc index a943e35f1afea4926a2edb0de097575babcd41bd..d1e4f9bc98da97831e524649fabc82e481afa941 100644 --- a/src/MissionManager/MissionController.cc +++ b/src/MissionManager/MissionController.cc @@ -55,7 +55,7 @@ MissionController::MissionController(PlanMasterController* masterController, QOb , _visualItems(NULL) , _settingsItem(NULL) , _firstItemsFromVehicle(false) - , _missionItemsRequested(false) + , _itemsRequested(false) , _surveyMissionItemName(tr("Survey")) , _fwLandingMissionItemName(tr("Fixed Wing Landing")) , _appSettings(qgcApp()->toolbox()->settingsManager()->appSettings()) @@ -126,7 +126,7 @@ void MissionController::_init(void) { // We start with an empty mission _visualItems = new QmlObjectListModel(this); - _addMissionSettings(_controllerVehicle, _visualItems, false /* addToCenter */); + _addMissionSettings(_visualItems, false /* addToCenter */); _initAllVisualItems(); } @@ -135,7 +135,9 @@ void MissionController::_newMissionItemsAvailableFromVehicle(bool removeAllReque { qCDebug(MissionControllerLog) << "_newMissionItemsAvailableFromVehicle"; - if (!_editMode || removeAllRequested || _missionItemsRequested || _visualItems->count() == 1) { + // Fly view always reloads on _loadComplete + // Plan view only reloads on _loadComplete if specifically requested + if (!_editMode || removeAllRequested || _itemsRequested) { // Fly Mode (accept if): // - Always accepts new items from the vehicle so Fly view is kept up to date // Edit Mode (accept if): @@ -150,7 +152,7 @@ void MissionController::_newMissionItemsAvailableFromVehicle(bool removeAllReque int i = 0; if (_controllerVehicle->firmwarePlugin()->sendHomePositionToVehicle() && newMissionItems.count() != 0) { // First item is fake home position - _addMissionSettings(_controllerVehicle, newControllerMissionItems, false /* addToCenter */); + _addMissionSettings(newControllerMissionItems, false /* addToCenter */); MissionSettingsItem* settingsItem = newControllerMissionItems->value(0); if (!settingsItem) { qWarning() << "First item is not settings item"; @@ -171,11 +173,9 @@ void MissionController::_newMissionItemsAvailableFromVehicle(bool removeAllReque _visualItems = newControllerMissionItems; if (!_controllerVehicle->firmwarePlugin()->sendHomePositionToVehicle() || _visualItems->count() == 0) { - _addMissionSettings(_controllerVehicle, _visualItems, _editMode && _visualItems->count() > 0 /* addToCenter */); + _addMissionSettings(_visualItems, _editMode && _visualItems->count() > 0 /* addToCenter */); } - _missionItemsRequested = false; - if (_editMode) { MissionController::_scanForAdditionalSettings(_visualItems, _controllerVehicle); } @@ -183,18 +183,37 @@ void MissionController::_newMissionItemsAvailableFromVehicle(bool removeAllReque _initAllVisualItems(); emit newItemsFromVehicle(); } + _itemsRequested = false; } void MissionController::loadFromVehicle(void) { - _missionItemsRequested = true; - _managerVehicle->missionManager()->requestMissionItems(); + if (_masterController->offline()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::loadFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::loadFromVehicle called while syncInProgress"; + } else { + _itemsRequested = true; + _managerVehicle->missionManager()->loadFromVehicle(); + } } void MissionController::sendToVehicle(void) { - sendItemsToVehicle(_managerVehicle, _visualItems); - setDirty(false); + if (_masterController->offline()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::sendToVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::sendToVehicle called while syncInProgress"; + } else { + if (_visualItems->count() == 1) { + // This prevents us from sending a possibly bogus home position to the vehicle + QmlObjectListModel emptyModel; + sendItemsToVehicle(_managerVehicle, &emptyModel); + } else { + sendItemsToVehicle(_managerVehicle, _visualItems); + } + setDirty(false); + } } /// Converts from visual items to MissionItems @@ -202,6 +221,10 @@ void MissionController::sendToVehicle(void) /// @return true: Mission end action was added to end of list bool MissionController::_convertToMissionItems(QmlObjectListModel* visualMissionItems, QList& rgMissionItems, QObject* missionItemParent) { + if (visualMissionItems->count() == 0) { + return false; + } + bool endActionSet = false; int lastSeqNum = 0; @@ -366,7 +389,7 @@ void MissionController::removeAll(void) _visualItems->deleteLater(); _settingsItem = NULL; _visualItems = new QmlObjectListModel(this); - _addMissionSettings(_controllerVehicle, _visualItems, false /* addToCenter */); + _addMissionSettings(_visualItems, false /* addToCenter */); _initAllVisualItems(); setDirty(true); _resetMissionFlightStatus(); @@ -464,7 +487,7 @@ bool MissionController::_loadJsonMissionFileV1(const QJsonObject& json, QmlObjec return false; } } else { - _addMissionSettings(_controllerVehicle, visualItems, true /* addToCenter */); + _addMissionSettings(visualItems, true /* addToCenter */); } return true; @@ -661,7 +684,7 @@ bool MissionController::_loadTextMissionFile(QTextStream& stream, QmlObjectListM if (versionOk) { // Start with planned home in center - _addMissionSettings(_controllerVehicle, visualItems, true /* addToCenter */); + _addMissionSettings(visualItems, true /* addToCenter */); MissionSettingsItem* settingsItem = visualItems->value(0); while (!stream.atEnd()) { @@ -708,7 +731,7 @@ void MissionController::_initLoadedVisualItems(QmlObjectListModel* loadedVisualI _visualItems = loadedVisualItems; if (_visualItems->count() == 0) { - _addMissionSettings(_controllerVehicle, _visualItems, true /* addToCenter */); + _addMissionSettings(_visualItems, true /* addToCenter */); } MissionController::_scanForAdditionalSettings(_visualItems, _controllerVehicle); @@ -1353,6 +1376,8 @@ void MissionController::managerVehicleChanged(Vehicle* managerVehicle) _missionManager = _managerVehicle->missionManager(); connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &MissionController::_newMissionItemsAvailableFromVehicle); + connect(_missionManager, &MissionManager::sendComplete, this, &MissionController::_managerSendComplete); + connect(_missionManager, &MissionManager::removeAllComplete, this, &MissionController::_managerRemoveAllComplete); connect(_missionManager, &MissionManager::inProgressChanged, this, &MissionController::_inProgressChanged); connect(_missionManager, &MissionManager::progressPct, this, &MissionController::_progressPctChanged); connect(_missionManager, &MissionManager::currentIndexChanged, this, &MissionController::_currentMissionIndexChanged); @@ -1441,9 +1466,9 @@ double MissionController::_normalizeLon(double lon) } /// Add the Mission Settings complex item to the front of the items -void MissionController::_addMissionSettings(Vehicle* vehicle, QmlObjectListModel* visualItems, bool addToCenter) +void MissionController::_addMissionSettings(QmlObjectListModel* visualItems, bool addToCenter) { - MissionSettingsItem* settingsItem = new MissionSettingsItem(vehicle, visualItems); + MissionSettingsItem* settingsItem = new MissionSettingsItem(_controllerVehicle, visualItems); visualItems->insert(0, settingsItem); @@ -1480,7 +1505,7 @@ void MissionController::_addMissionSettings(Vehicle* vehicle, QmlObjectListModel } } } else { - settingsItem->setCoordinate(vehicle->homePosition()); + settingsItem->setCoordinate(_controllerVehicle->homePosition()); } } @@ -1575,8 +1600,14 @@ bool MissionController::containsItems(void) const void MissionController::removeAllFromVehicle(void) { - _missionItemsRequested = true; - _missionManager->removeAll(); + if (_masterController->offline()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::removeAllFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(MissionControllerLog) << "MissionControllerLog::removeAllFromVehicle called while syncInProgress"; + } else { + _itemsRequested = true; + _missionManager->removeAll(); + } } QStringList MissionController::complexMissionItemNames(void) const @@ -1644,3 +1675,42 @@ void MissionController::_visualItemsDirtyChanged(bool dirty) // We could connect signal to signal and not need this but this is handy for setting a breakpoint on emit dirtyChanged(dirty); } + +bool MissionController::showPlanFromManagerVehicle (void) +{ + qCDebug(MissionControllerLog) << "showPlanFromManagerVehicle"; + if (_masterController->offline()) { + qCWarning(MissionControllerLog) << "MissionController::showPlanFromManagerVehicle called while offline"; + return true; // stops further propogation of showPlanFromManagerVehicle due to error + } else { + if (!_managerVehicle->initialPlanRequestComplete()) { + // The vehicle hasn't completed initial load, we can just wait for newMissionItemsAvailable to be signalled automatically + qCDebug(MissionControllerLog) << "showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal"; + return true; + } else if (syncInProgress()) { + // If the sync is already in progress, newMissionItemsAvailable will be signalled automatically when it is done. So no need to do anything. + qCDebug(MissionControllerLog) << "showPlanFromManagerVehicle: syncInProgress wait for signal"; + return true; + } else { + // Fake a _newMissionItemsAvailable with the current items + qCDebug(MissionControllerLog) << "showPlanFromManagerVehicle: sync complete simulate signal"; + _itemsRequested = true; + _newMissionItemsAvailableFromVehicle(false /* removeAllRequested */); + return false; + } + } +} + +void MissionController::_managerSendComplete(void) +{ + // FLy view always reloads on send complete + if (!_editMode) { + showPlanFromManagerVehicle(); + } +} + +void MissionController::_managerRemoveAllComplete(void) +{ + // Remove all from vehicle so we always update + showPlanFromManagerVehicle(); +} diff --git a/src/MissionManager/MissionController.h b/src/MissionManager/MissionController.h index d4d8291357511b03dd52eca2ae1edf6509178b06..2721663bc6d28d862165b5cac6879b0301a80749 100644 --- a/src/MissionManager/MissionController.h +++ b/src/MissionManager/MissionController.h @@ -123,6 +123,7 @@ public: void setDirty (bool dirty) final; bool containsItems (void) const final; void managerVehicleChanged (Vehicle* managerVehicle) final; + bool showPlanFromManagerVehicle (void) final; // Property accessors @@ -178,6 +179,8 @@ private slots: void _cameraFeedback(QGeoCoordinate imageCoordinate, int index); void _progressPctChanged(double progressPct); void _visualItemsDirtyChanged(bool dirty); + void _managerSendComplete(void); + void _managerRemoveAllComplete(void); private: void _init(void); @@ -194,7 +197,7 @@ private: bool _findPreviousAltitude(int newIndex, double* prevAltitude, MAV_FRAME* prevFrame); static double _normalizeLat(double lat); static double _normalizeLon(double lon); - static void _addMissionSettings(Vehicle* vehicle, QmlObjectListModel* visualItems, bool addToCenter); + void _addMissionSettings(QmlObjectListModel* visualItems, bool addToCenter); bool _loadJsonMissionFile(const QByteArray& bytes, QmlObjectListModel* visualItems, QString& errorString); bool _loadJsonMissionFileV1(const QJsonObject& json, QmlObjectListModel* visualItems, QString& errorString); bool _loadJsonMissionFileV2(const QJsonObject& json, QmlObjectListModel* visualItems, QString& errorString); @@ -218,7 +221,7 @@ private: QmlObjectListModel _cameraPoints; CoordVectHashTable _linesTable; bool _firstItemsFromVehicle; - bool _missionItemsRequested; + bool _itemsRequested; MissionFlightStatus_t _missionFlightStatus; QString _surveyMissionItemName; QString _fwLandingMissionItemName; diff --git a/src/MissionManager/MissionManager.cc b/src/MissionManager/MissionManager.cc index f7134f5d4cb26d1713f544e32d17620e0660137f..85274f7df666fbc8ca150e3c3cec08b069910a8d 100644 --- a/src/MissionManager/MissionManager.cc +++ b/src/MissionManager/MissionManager.cc @@ -168,16 +168,16 @@ void MissionManager::writeArduPilotGuidedMissionItem(const QGeoCoordinate& gotoC emit inProgressChanged(true); } -void MissionManager::requestMissionItems(void) +void MissionManager::loadFromVehicle(void) { if (_vehicle->isOfflineEditingVehicle()) { return; } - qCDebug(MissionManagerLog) << "requestMissionItems read sequence"; + qCDebug(MissionManagerLog) << "loadFromVehicle read sequence"; if (inProgress()) { - qCDebug(MissionManagerLog) << "requestMissionItems called while transaction in progress"; + qCDebug(MissionManagerLog) << "loadFromVehicle called while transaction in progress"; return; } @@ -339,7 +339,6 @@ void MissionManager::_readTransactionComplete(void) _vehicle->sendMessageOnLink(_dedicatedLink, message); _finishTransaction(true); - emit newMissionItemsAvailable(false); } void MissionManager::_handleMissionCount(const mavlink_message_t& message) @@ -863,24 +862,35 @@ void MissionManager::_finishTransaction(bool success) { emit progressPct(1); - if (!success && _transactionInProgress == TransactionRead) { - // Read from vehicle failed, clear partial list - _clearAndDeleteMissionItems(); - emit newMissionItemsAvailable(false); - } - - if (_transactionInProgress == TransactionWrite) { - emit newMissionItemsAvailable(_missionItems.count() == 0); - } - _itemIndicesToRead.clear(); _itemIndicesToWrite.clear(); + // First thing we do is clear the transaction. This way inProgesss is off when we signal transaction complete. + TransactionType_t currentTransactionType = _transactionInProgress; + _transactionInProgress = TransactionNone; if (_transactionInProgress != TransactionNone) { _transactionInProgress = TransactionNone; emit inProgressChanged(false); } + switch (currentTransactionType) { + case TransactionRead: + if (!success) { + // Read from vehicle failed, clear partial list + _clearAndDeleteMissionItems(); + } + emit newMissionItemsAvailable(false); + break; + case TransactionWrite: + emit sendComplete(); + break; + case TransactionRemoveAll: + emit removeAllComplete(); + break; + default: + break; + } + if (_resumeMission) { _resumeMission = false; emit resumeMissionReady(); @@ -945,9 +955,8 @@ void MissionManager::removeAll(void) _lastCurrentIndex = -1; emit currentIndexChanged(-1); emit lastCurrentIndexChanged(-1); - emit newMissionItemsAvailable(true /* removeAllRequested */); - _transactionInProgress = TransactionClearAll; + _transactionInProgress = TransactionRemoveAll; _retryCount = 0; emit inProgressChanged(true); diff --git a/src/MissionManager/MissionManager.h b/src/MissionManager/MissionManager.h index dd040a6978594e40d8aa430e720630ffb6b9ac3f..8b47d6439e27d6cfa10ec24526ccd93804e24c28 100644 --- a/src/MissionManager/MissionManager.h +++ b/src/MissionManager/MissionManager.h @@ -43,10 +43,13 @@ public: /// Last current mission item reported while in Mission flight mode int lastCurrentIndex(void) const { return _lastCurrentIndex; } - void requestMissionItems(void); + /// Load the mission items from the vehicle + /// Signals newMissionItemsAvailable when done + void loadFromVehicle(void); /// Writes the specified set of mission items to the vehicle /// @param missionItems Items to send to vehicle + /// Signals sendComplete when done void writeMissionItems(const QList& missionItems); /// Writes the specified set mission items to the vehicle as an ArduPilot guided mode mission item. @@ -55,6 +58,7 @@ public: void writeArduPilotGuidedMissionItem(const QGeoCoordinate& gotoCoord, bool altChangeOnly); /// Removes all mission items from vehicle + /// Signals removeAllComplete when done void removeAll(void); /// Generates a new mission which starts from the specified index. It will include all the CMD_DO items @@ -86,6 +90,8 @@ signals: void resumeMissionReady(void); void cameraFeedback(QGeoCoordinate imageCoordinate, int index); void progressPct(double progressPercentPct); + void removeAllComplete (void); + void sendComplete (void); private slots: void _mavlinkMessageReceived(const mavlink_message_t& message); @@ -105,7 +111,7 @@ private: TransactionNone, TransactionRead, TransactionWrite, - TransactionClearAll + TransactionRemoveAll } TransactionType_t; void _startAckTimeout(AckType_t ack); diff --git a/src/MissionManager/MissionManagerTest.cc b/src/MissionManager/MissionManagerTest.cc index f6e94581c45a3454a8136dcc78af91cce2f8b3e4..99b16e382ecede1e474b2edadf0af862fd118cb9 100644 --- a/src/MissionManager/MissionManagerTest.cc +++ b/src/MissionManager/MissionManagerTest.cc @@ -120,7 +120,7 @@ void MissionManagerTest::_roundTripItems(MockLinkMissionItemHandler::FailureMode _mockLink->setMissionItemFailureMode(failureMode); // Read the items back from the vehicle - _missionManager->requestMissionItems(); + _missionManager->loadFromVehicle(); // requestMissionItems should emit inProgressChanged signal before returning so no need to wait for it QVERIFY(_missionManager->inProgress()); diff --git a/src/MissionManager/PlanElementController.cc b/src/MissionManager/PlanElementController.cc index 6c8bc65dd3fe7663312ff82f6873f934da10740c..0ec882bde185b7d7821056cf8b66d319ebf2c269 100644 --- a/src/MissionManager/PlanElementController.cc +++ b/src/MissionManager/PlanElementController.cc @@ -33,3 +33,8 @@ void PlanElementController::start(bool editMode) { _editMode = editMode; } + +void PlanElementController::managerVehicleChanged(Vehicle* managerVehicle) +{ + _managerVehicle = managerVehicle; +} diff --git a/src/MissionManager/PlanElementController.h b/src/MissionManager/PlanElementController.h index 2ac3d099deb52450f32e113066c100b08fa12604..090ea2a4617d967bfafd7aa00d17340ddebf33f3 100644 --- a/src/MissionManager/PlanElementController.h +++ b/src/MissionManager/PlanElementController.h @@ -35,19 +35,26 @@ public: /// @param editMode true: controller being used in Plan view, false: controller being used in Fly view virtual void start(bool editMode); - virtual void save(QJsonObject& json) = 0; - virtual bool load(const QJsonObject& json, QString& errorString) = 0; - virtual void loadFromVehicle(void) = 0; - virtual void sendToVehicle(void) = 0; - virtual void removeAll(void) = 0; ///< Removes all from controller only, synce required to remove from vehicle - virtual void removeAllFromVehicle(void) = 0; ///< Removes all from vehicle and controller + virtual void save (QJsonObject& json) = 0; + virtual bool load (const QJsonObject& json, QString& errorString) = 0; + virtual void loadFromVehicle (void) = 0; + virtual void removeAll (void) = 0; ///< Removes all from controller only + virtual bool showPlanFromManagerVehicle (void) = 0; /// true: controller is waiting for the current load to complete virtual bool containsItems (void) const = 0; virtual bool syncInProgress (void) const = 0; virtual bool dirty (void) const = 0; virtual void setDirty (bool dirty) = 0; - /// Called when a new manager vehicle has been set. Derived classes should override to implement custom behavior. + /// Sends the current plan element to the vehicle + /// Signals sendComplete when done + virtual void sendToVehicle(void) = 0; + + /// Removes all from vehicle and controller + /// Signals removeAllComplete when done + virtual void removeAllFromVehicle(void) = 0; + + /// Called when a new manager vehicle has been set. virtual void managerVehicleChanged(Vehicle* managerVehicle) = 0; signals: @@ -55,6 +62,8 @@ signals: void syncInProgressChanged (bool syncInProgress); void dirtyChanged (bool dirty); void vehicleChanged (Vehicle* vehicle); + void sendComplete (void); + void removeAllComplete (void); protected: PlanMasterController* _masterController; diff --git a/src/MissionManager/PlanMasterController.cc b/src/MissionManager/PlanMasterController.cc index 6156259a29a9efee960a5149e8e17e7f9a6eeb9f..adf1c89cbae0f10429fd82a2f0980c5d9232d668 100644 --- a/src/MissionManager/PlanMasterController.cc +++ b/src/MissionManager/PlanMasterController.cc @@ -18,6 +18,8 @@ #include #include +QGC_LOGGING_CATEGORY(PlanMasterControllerLog, "PlanMasterControllerLog") + const int PlanMasterController::_planFileVersion = 1; const char* PlanMasterController::_planFileType = "Plan"; const char* PlanMasterController::_jsonMissionObjectKey = "mission"; @@ -38,6 +40,7 @@ PlanMasterController::PlanMasterController(QObject* parent) , _loadRallyPoints(false) , _sendGeoFence(false) , _sendRallyPoints(false) + , _syncInProgress(false) { connect(&_missionController, &MissionController::dirtyChanged, this, &PlanMasterController::dirtyChanged); connect(&_geoFenceController, &GeoFenceController::dirtyChanged, this, &PlanMasterController::dirtyChanged); @@ -81,6 +84,8 @@ void PlanMasterController::_activeVehicleChanged(Vehicle* activeVehicle) return; } + qCDebug(PlanMasterControllerLog) << "_activeVehicleChanged" << activeVehicle; + bool newOffline = false; if (activeVehicle == NULL) { // Since there is no longer an active vehicle we use the offline controller vehicle as the manager vehicle @@ -96,8 +101,12 @@ void PlanMasterController::_activeVehicleChanged(Vehicle* activeVehicle) appSettings->offlineEditingVehicleType()->setRawValue(AppSettings::offlineEditingVehicleTypeFromVehicleType(_managerVehicle->vehicleType())); // We use these signals to sequence upload and download to the multiple controller/managers - connect(_managerVehicle->missionManager(), &MissionManager::newMissionItemsAvailable, this, &PlanMasterController::_loadSendMissionComplete); - connect(_managerVehicle->geoFenceManager(), &GeoFenceManager::loadComplete, this, &PlanMasterController::_loadSendGeoFenceCompelte); + connect(_managerVehicle->missionManager(), &MissionManager::newMissionItemsAvailable, this, &PlanMasterController::_loadMissionComplete); + connect(_managerVehicle->geoFenceManager(), &GeoFenceManager::loadComplete, this, &PlanMasterController::_loadGeoFenceComplete); + connect(_managerVehicle->rallyPointManager(), &RallyPointManager::loadComplete, this, &PlanMasterController::_loadRallyPointsComplete); + connect(_managerVehicle->missionManager(), &MissionManager::sendComplete, this, &PlanMasterController::_sendMissionComplete); + connect(_managerVehicle->geoFenceManager(), &GeoFenceManager::sendComplete, this, &PlanMasterController::_sendGeoFenceComplete); + connect(_managerVehicle->rallyPointManager(), &RallyPointManager::sendComplete, this, &PlanMasterController::_sendRallyPointsComplete); } if (newOffline != _offline) { _offline = newOffline; @@ -108,35 +117,77 @@ void PlanMasterController::_activeVehicleChanged(Vehicle* activeVehicle) _geoFenceController.managerVehicleChanged(_managerVehicle); _rallyPointController.managerVehicleChanged(_managerVehicle); - if (!_editMode && _offline) { - // Fly view has changed to a new active vehicle - loadFromVehicle(); + if (_editMode) { + if (!offline()) { + // We are in Plan view and we have a newly connected vehicle: + // - If there is no plan available in Plan view show the one from the vehicle + // - Otherwise leave the current plan alone + if (!containsItems()) { + qCDebug(PlanMasterControllerLog) << "_activeVehicleChanged: Plan view is empty so loading from manager"; + _showPlanFromManagerVehicle(); + } + } + } else { + if (offline()) { + // No more active vehicle, clear mission + qCDebug(PlanMasterControllerLog) << "_activeVehicleChanged: Fly view is offline clearing plan"; + removeAll(); + } else { + // Fly view has changed to a new active vehicle, update to show correct mission + qCDebug(PlanMasterControllerLog) << "_activeVehicleChanged: Fly view is online so loading from manager"; + _showPlanFromManagerVehicle(); + } } - - // Whenever manager changes we need to update syncInProgress - emit syncInProgressChanged(syncInProgress()); } void PlanMasterController::loadFromVehicle(void) { - if (!offline()) { + if (offline()) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::loadFromVehicle called while offline"; + } else if (!_editMode) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::loadFromVehicle called from Fly view"; + } else if (syncInProgress()) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::loadFromVehicle called while syncInProgress"; + } else { _loadGeoFence = true; + _syncInProgress = true; _missionController.loadFromVehicle(); setDirty(false); - } else { - qWarning() << "PlanMasterController::sendToVehicle called while offline"; } } -void PlanMasterController::_loadSendMissionComplete(void) +void PlanMasterController::_loadMissionComplete(void) { - if (_loadGeoFence) { + if (_editMode && _loadGeoFence) { _loadGeoFence = false; _loadRallyPoints = true; _geoFenceController.loadFromVehicle(); setDirty(false); - } else if (_sendGeoFence) { + } +} + +void PlanMasterController::_loadGeoFenceComplete(void) +{ + if (_editMode && _loadRallyPoints) { + _loadRallyPoints = false; + _rallyPointController.loadFromVehicle(); + setDirty(false); + } +} + +void PlanMasterController::_loadRallyPointsComplete(void) +{ + if (_editMode) { + _syncInProgress = false; + emit syncInProgressChanged(false); + } +} + +void PlanMasterController::_sendMissionComplete(void) +{ + if (_editMode && _sendGeoFence) { + qCDebug(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle start fence sendToVehicle"; _sendGeoFence = false; _sendRallyPoints = true; _geoFenceController.sendToVehicle(); @@ -144,26 +195,37 @@ void PlanMasterController::_loadSendMissionComplete(void) } } -void PlanMasterController::_loadSendGeoFenceCompelte(void) +void PlanMasterController::_sendGeoFenceComplete(void) { - if (_loadRallyPoints) { - _loadRallyPoints = false; - _rallyPointController.loadFromVehicle(); - setDirty(false); - } else if (_sendRallyPoints) { + if (_editMode && _sendRallyPoints) { + qCDebug(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle start rally sendToVehicle"; _sendRallyPoints = false; _rallyPointController.sendToVehicle(); } } +void PlanMasterController::_sendRallyPointsComplete(void) +{ + if (_editMode && _syncInProgress) { + qCDebug(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle rally point send complete"; + _syncInProgress = false; + emit syncInProgressChanged(false); + } +} + void PlanMasterController::sendToVehicle(void) { - if (!offline()) { + if (offline()) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle called while offline"; + } else if (!_editMode) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle called from Fly view"; + } else if (syncInProgress()) { + qCWarning(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle called while syncInProgress"; + } else { + qCDebug(PlanMasterControllerLog) << "PlanMasterController::sendToVehicle start mission sendToVehicle"; _sendGeoFence = true; _missionController.sendToVehicle(); setDirty(false); - } else { - qWarning() << "PlanMasterController::sendToVehicle called while offline"; } } @@ -293,11 +355,6 @@ bool PlanMasterController::containsItems(void) const return _missionController.containsItems() || _geoFenceController.containsItems() || _rallyPointController.containsItems(); } -bool PlanMasterController::syncInProgress(void) const -{ - return _missionController.syncInProgress() || _geoFenceController.syncInProgress() || _rallyPointController.syncInProgress(); -} - bool PlanMasterController::dirty(void) const { return _missionController.dirty() || _geoFenceController.dirty() || _rallyPointController.dirty(); @@ -341,3 +398,13 @@ void PlanMasterController::sendPlanToVehicle(Vehicle* vehicle, const QString& fi controller->loadFromFile(filename); delete controller; } + +void PlanMasterController::_showPlanFromManagerVehicle(void) +{ + // The crazy if structure is to handle the load propogating by itself through the system + if (!_missionController.showPlanFromManagerVehicle()) { + if (!_geoFenceController.showPlanFromManagerVehicle()) { + _rallyPointController.showPlanFromManagerVehicle(); + } + } +} diff --git a/src/MissionManager/PlanMasterController.h b/src/MissionManager/PlanMasterController.h index db4f69cba2250dbfc0dc4cc99ff04233ebbbdb1e..c7ab83ca8a8beedfc63a644eaa62be607dd62b8d 100644 --- a/src/MissionManager/PlanMasterController.h +++ b/src/MissionManager/PlanMasterController.h @@ -16,6 +16,9 @@ #include "RallyPointController.h" #include "Vehicle.h" #include "MultiVehicleManager.h" +#include "QGCLoggingCategory.h" + +Q_DECLARE_LOGGING_CATEGORY(PlanMasterControllerLog) /// Master controller for mission, fence, rally class PlanMasterController : public QObject @@ -64,7 +67,7 @@ public: bool offline (void) const { return _offline; } bool containsItems (void) const; - bool syncInProgress (void) const; + bool syncInProgress (void) const { return _syncInProgress; } bool dirty (void) const; void setDirty (bool dirty); QString fileExtension (void) const; @@ -83,10 +86,16 @@ signals: private slots: void _activeVehicleChanged(Vehicle* activeVehicle); - void _loadSendMissionComplete(void); - void _loadSendGeoFenceCompelte(void); + void _loadMissionComplete(void); + void _loadGeoFenceComplete(void); + void _loadRallyPointsComplete(void); + void _sendMissionComplete(void); + void _sendGeoFenceComplete(void); + void _sendRallyPointsComplete(void); private: + void _showPlanFromManagerVehicle(void); + MultiVehicleManager* _multiVehicleMgr; Vehicle* _controllerVehicle; Vehicle* _managerVehicle; @@ -99,6 +108,7 @@ private: bool _loadRallyPoints; bool _sendGeoFence; bool _sendRallyPoints; + bool _syncInProgress; static const int _planFileVersion; static const char* _planFileType; diff --git a/src/MissionManager/RallyPointController.cc b/src/MissionManager/RallyPointController.cc index 5807109c9283e5d4fe41448eb84094ebc414cdda..8b48dd9d4f8126af2c766139ac22f4e8778ba88c 100644 --- a/src/MissionManager/RallyPointController.cc +++ b/src/MissionManager/RallyPointController.cc @@ -23,6 +23,7 @@ #include "QGroundControlQmlGlobal.h" #include "SettingsManager.h" #include "AppSettings.h" +#include "PlanMasterController.h" #ifndef __mobile__ #include "QGCQFileDialog.h" @@ -41,6 +42,7 @@ RallyPointController::RallyPointController(PlanMasterController* masterControlle , _rallyPointManager(_managerVehicle->rallyPointManager()) , _dirty(false) , _currentRallyPoint(NULL) + , _itemsRequested(false) { connect(&_points, &QmlObjectListModel::countChanged, this, &RallyPointController::_updateContainsItems); @@ -67,7 +69,9 @@ void RallyPointController::managerVehicleChanged(Vehicle* managerVehicle) } _rallyPointManager = _managerVehicle->rallyPointManager(); - connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_loadComplete); + connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &RallyPointController::_managerLoadComplete); + connect(_rallyPointManager, &RallyPointManager::sendComplete, this, &RallyPointController::_managerSendComplete); + connect(_rallyPointManager, &RallyPointManager::removeAllComplete, this, &RallyPointController::_managerRemoveAllComplete); connect(_rallyPointManager, &RallyPointManager::inProgressChanged, this, &RallyPointController::syncInProgressChanged); emit rallyPointsSupportedChanged(rallyPointsSupported()); @@ -123,26 +127,42 @@ void RallyPointController::removeAll(void) setCurrentRallyPoint(NULL); } +void RallyPointController::removeAllFromVehicle(void) +{ + if (_masterController->offline()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::removeAllFromVehicle called while syncInProgress"; + } else { + _rallyPointManager->removeAll(); + } +} + void RallyPointController::loadFromVehicle(void) { - if (!syncInProgress()) { - _rallyPointManager->loadFromVehicle(); + if (_masterController->offline()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::loadFromVehicle called while syncInProgress"; } else { - qCWarning(RallyPointControllerLog) << "RallyPointController::loadFromVehicle call while syncInProgress"; + _itemsRequested = true; + _rallyPointManager->loadFromVehicle(); } } void RallyPointController::sendToVehicle(void) { - if (!syncInProgress()) { + if (_masterController->offline()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while offline"; + } else if (syncInProgress()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::sendToVehicle called while syncInProgress"; + } else { setDirty(false); QList rgPoints; for (int i=0; i<_points.count(); i++) { rgPoints.append(qobject_cast(_points[i])->coordinate()); } _rallyPointManager->sendToVehicle(rgPoints); - } else { - qCWarning(RallyPointControllerLog) << "RallyPointController::loadFromVehicle while syncInProgress"; } } @@ -164,17 +184,36 @@ QString RallyPointController::editorQml(void) const return _rallyPointManager->editorQml(); } -void RallyPointController::_loadComplete(const QList rgPoints) +void RallyPointController::_managerLoadComplete(const QList rgPoints) { - _points.clearAndDeleteContents(); - QObjectList pointList; - for (int i=0; iremoveAll(); + qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle"; + if (_masterController->offline()) { + qCWarning(RallyPointControllerLog) << "RallyPointController::showPlanFromManagerVehicle called while offline"; + return true; // stops further propogation of showPlanFromManagerVehicle due to error + } else { + if (!_managerVehicle->initialPlanRequestComplete()) { + // The vehicle hasn't completed initial load, we can just wait for newMissionItemsAvailable to be signalled automatically + qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: !initialPlanRequestComplete, wait for signal"; + return true; + } else if (syncInProgress()) { + // If the sync is already in progress, _loadComplete will be called automatically when it is done. So no need to do anything. + qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: syncInProgress wait for signal"; + return true; + } else { + // Fake a _loadComplete with the current items + qCDebug(RallyPointControllerLog) << "showPlanFromManagerVehicle: sync complete simulate signal"; + _itemsRequested = true; + _managerLoadComplete(_rallyPointManager->points()); + return false; + } + } } diff --git a/src/MissionManager/RallyPointController.h b/src/MissionManager/RallyPointController.h index 5007f50331fa95de3d13945486a4fecd5927af40..786f67f1704a95933b1c974174a3c1f1907cfb97 100644 --- a/src/MissionManager/RallyPointController.h +++ b/src/MissionManager/RallyPointController.h @@ -37,17 +37,18 @@ public: Q_INVOKABLE void addPoint(QGeoCoordinate point); Q_INVOKABLE void removePoint(QObject* rallyPoint); - void save (QJsonObject& json) final; - bool load (const QJsonObject& json, QString& errorString) final; - void loadFromVehicle (void) final; - void sendToVehicle (void) final; - void removeAll (void) final; - void removeAllFromVehicle (void) final; - bool syncInProgress (void) const final; - bool dirty (void) const final { return _dirty; } - void setDirty (bool dirty) final; - bool containsItems (void) const final; - void managerVehicleChanged (Vehicle* managerVehicle) final; + void save (QJsonObject& json) final; + bool load (const QJsonObject& json, QString& errorString) final; + void loadFromVehicle (void) final; + void sendToVehicle (void) final; + void removeAll (void) final; + void removeAllFromVehicle (void) final; + bool syncInProgress (void) const final; + bool dirty (void) const final { return _dirty; } + void setDirty (bool dirty) final; + bool containsItems (void) const final; + void managerVehicleChanged (Vehicle* managerVehicle) final; + bool showPlanFromManagerVehicle (void) final; bool rallyPointsSupported (void) const; QmlObjectListModel* points (void) { return &_points; } @@ -62,7 +63,9 @@ signals: void loadComplete(void); private slots: - void _loadComplete(const QList rgPoints); + void _managerLoadComplete(const QList rgPoints); + void _managerSendComplete(void); + void _managerRemoveAllComplete(void); void _setFirstPointCurrent(void); void _updateContainsItems(void); @@ -71,6 +74,7 @@ private: bool _dirty; QmlObjectListModel _points; QObject* _currentRallyPoint; + bool _itemsRequested; static const char* _jsonFileTypeValue; static const char* _jsonPointsKey; diff --git a/src/MissionManager/RallyPointManager.cc b/src/MissionManager/RallyPointManager.cc index 4b83624e47c83983d48f6edccf2ef0b9ad653049..2d1a391d855be918ffb0e2785e24612124432a49 100644 --- a/src/MissionManager/RallyPointManager.cc +++ b/src/MissionManager/RallyPointManager.cc @@ -41,5 +41,11 @@ void RallyPointManager::sendToVehicle(const QList& rgPoints) { // No support in generic vehicle Q_UNUSED(rgPoints); - emit loadComplete(QList()); + emit sendComplete(); +} + +void RallyPointManager::removeAll(void) +{ + // No support in generic vehicle + emit removeAllComplete(); } diff --git a/src/MissionManager/RallyPointManager.h b/src/MissionManager/RallyPointManager.h index 4b78b95726992f871046cb7b0bceebeb52d16932..a3f25337b7be83af38c6bd5a8a985b29fa4de163 100644 --- a/src/MissionManager/RallyPointManager.h +++ b/src/MissionManager/RallyPointManager.h @@ -33,12 +33,16 @@ public: virtual bool inProgress(void) const { return false; } /// Load the current settings from the vehicle + /// Signals loadComplete when done virtual void loadFromVehicle(void); /// Send the current settings to the vehicle + /// Signals sendComplete when done virtual void sendToVehicle(const QList& rgPoints); - virtual void removeAll(void) { }; + /// Remove all rally points from the vehicle + /// Signals removeAllCompleted when done + virtual void removeAll(void); virtual bool rallyPointsSupported(void) const { return false; } @@ -58,6 +62,8 @@ signals: void loadComplete (const QList rgPoints); void inProgressChanged (bool inProgress); void error (int errorCode, const QString& errorMsg); + void removeAllComplete (void); + void sendComplete (void); protected: void _sendError(ErrorCode_t errorCode, const QString& errorMsg); diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc index a4eb9e205fd4038f52f067875519a915289eafe2..57aa7bc8ef3ef3cfddfaf1ba3d38ad153ddc52bc 100644 --- a/src/Vehicle/Vehicle.cc +++ b/src/Vehicle/Vehicle.cc @@ -112,6 +112,7 @@ Vehicle::Vehicle(LinkInterface* link, , _supportsMissionItemInt(false) , _connectionLost(false) , _connectionLostEnabled(true) + , _initialPlanRequestComplete(false) , _missionManager(NULL) , _missionManagerInitialRequestSent(false) , _geoFenceManager(NULL) @@ -264,6 +265,7 @@ Vehicle::Vehicle(MAV_AUTOPILOT firmwareType, , _supportsMissionItemInt(false) , _connectionLost(false) , _connectionLostEnabled(true) + , _initialPlanRequestComplete(false) , _missionManager(NULL) , _missionManagerInitialRequestSent(false) , _geoFenceManager(NULL) @@ -313,7 +315,7 @@ void Vehicle::_commonInit(void) _missionManager = new MissionManager(this); connect(_missionManager, &MissionManager::error, this, &Vehicle::_missionManagerError); - connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_newMissionItemsAvailable); + connect(_missionManager, &MissionManager::newMissionItemsAvailable, this, &Vehicle::_missionLoadComplete); _parameterManager = new ParameterManager(this); connect(_parameterManager, &ParameterManager::parametersReadyChanged, this, &Vehicle::_parametersReady); @@ -321,10 +323,11 @@ void Vehicle::_commonInit(void) // GeoFenceManager needs to access ParameterManager so make sure to create after _geoFenceManager = _firmwarePlugin->newGeoFenceManager(this); connect(_geoFenceManager, &GeoFenceManager::error, this, &Vehicle::_geoFenceManagerError); - connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_newGeoFenceAvailable); + connect(_geoFenceManager, &GeoFenceManager::loadComplete, this, &Vehicle::_geoFenceLoadComplete); _rallyPointManager = _firmwarePlugin->newRallyPointManager(this); - connect(_rallyPointManager, &RallyPointManager::error, this, &Vehicle::_rallyPointManagerError); + connect(_rallyPointManager, &RallyPointManager::error, this, &Vehicle::_rallyPointManagerError); + connect(_rallyPointManager, &RallyPointManager::loadComplete, this, &Vehicle::_rallyPointLoadComplete); // Offline editing vehicle tracks settings changes for offline editing settings connect(_settingsManager->appSettings()->offlineEditingFirmwareType(), &Fact::rawValueChanged, this, &Vehicle::_offlineFirmwareTypeSettingChanged); @@ -704,7 +707,7 @@ void Vehicle::_handleAutopilotVersion(LinkInterface *link, mavlink_message_t& me qCDebug(VehicleLog) << "Vehicle supports MISSION_ITEM_INT"; _supportsMissionItemInt = true; _vehicleCapabilitiesKnown = true; - _startMissionRequest(); + _startPlanRequest(); } } @@ -742,7 +745,7 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message) if (ack.command == MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES && ack.result != MAV_RESULT_ACCEPTED) { // We aren't going to get a response back for capabilities, so stop waiting for it before we ask for mission items qCDebug(VehicleLog) << "Vehicle failed to responded to MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES with error. Starting mission request."; - _startMissionRequest(); + _startPlanRequest(); } if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) { @@ -1620,10 +1623,10 @@ void Vehicle::_mapTrajectoryStop() _mapTrajectoryTimer.stop(); } -void Vehicle::_startMissionRequest(void) +void Vehicle::_startPlanRequest(void) { if (!_missionManagerInitialRequestSent && _parameterManager->parametersReady() && _vehicleCapabilitiesKnown) { - qCDebug(VehicleLog) << "_startMissionRequest"; + qCDebug(VehicleLog) << "_startPlanRequest"; _missionManagerInitialRequestSent = true; if (_settingsManager->appSettings()->autoLoadMissions()->rawValue().toBool()) { QString missionAutoLoadDirPath = _settingsManager->appSettings()->missionSavePath(); @@ -1636,21 +1639,45 @@ void Vehicle::_startMissionRequest(void) } } } - _missionManager->requestMissionItems(); + _missionManager->loadFromVehicle(); } else { if (!_parameterManager->parametersReady()) { - qCDebug(VehicleLog) << "Delaying _startMissionRequest due to parameters not ready"; + qCDebug(VehicleLog) << "Delaying _startPlanRequest due to parameters not ready"; } else if (!_vehicleCapabilitiesKnown) { - qCDebug(VehicleLog) << "Delaying _startMissionRequest due to vehicle capabilities not know"; + qCDebug(VehicleLog) << "Delaying _startPlanRequest due to vehicle capabilities not know"; } } } +void Vehicle::_missionLoadComplete(void) +{ + // After the initial mission request completes we ask for the geofence + if (!_geoFenceManagerInitialRequestSent) { + _geoFenceManagerInitialRequestSent = true; + _geoFenceManager->loadFromVehicle(); + } +} + +void Vehicle::_geoFenceLoadComplete(void) +{ + // After geofence request completes we ask for the rally points + if (!_rallyPointManagerInitialRequestSent) { + _rallyPointManagerInitialRequestSent = true; + _rallyPointManager->loadFromVehicle(); + } +} + + +void Vehicle::_rallyPointLoadComplete(void) +{ + _initialPlanRequestComplete = true; +} + void Vehicle::_parametersReady(bool parametersReady) { if (parametersReady) { _setupAutoDisarmSignalling(); - _startMissionRequest(); + _startPlanRequest(); setJoystickEnabled(_joystickEnabled); } } @@ -2040,7 +2067,7 @@ void Vehicle::_sendMavCommandAgain(void) if (_mavCommandRetryCount++ > _mavCommandMaxRetryCount) { if (queuedCommand.command == MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES) { // We aren't going to get a response back for capabilities, so stop waiting for it before we ask for mission items - _startMissionRequest(); + _startPlanRequest(); } emit mavCommandResult(_id, queuedCommand.component, queuedCommand.command, MAV_RESULT_FAILED, true /* noResponsefromVehicle */); @@ -2175,24 +2202,6 @@ void Vehicle::motorTest(int motor, int percent, int timeoutSecs) } #endif -void Vehicle::_newMissionItemsAvailable(void) -{ - // After the initial mission request completes we ask for the geofence - if (!_geoFenceManagerInitialRequestSent) { - _geoFenceManagerInitialRequestSent = true; - _geoFenceManager->loadFromVehicle(); - } -} - -void Vehicle::_newGeoFenceAvailable(void) -{ - // After geofence request completes we ask for the rally points - if (!_rallyPointManagerInitialRequestSent) { - _rallyPointManagerInitialRequestSent = true; - _rallyPointManager->loadFromVehicle(); - } -} - QString Vehicle::brandImageIndoor(void) const { return _firmwarePlugin->brandImageIndoor(this); @@ -2261,7 +2270,7 @@ void Vehicle::setOfflineEditingDefaultComponentId(int defaultComponentId) void Vehicle::triggerCamera(void) { - sendMavCommand(FactSystem::defaultComponentId, + sendMavCommand(_defaultComponentId, MAV_CMD_DO_DIGICAM_CONTROL, true, // show errors 0.0, 0.0, 0.0, 0.0, // param 1-4 unused diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h index 4b9d4b2fb781503a58c5ecef18887cf53d022481..555f9f2b61e38508ad19155ec4eef60db7caaff8 100644 --- a/src/Vehicle/Vehicle.h +++ b/src/Vehicle/Vehicle.h @@ -669,6 +669,10 @@ public: /// @true: When flying a mission the vehicle is always facing towards the next waypoint bool vehicleYawsToNextWaypointInMission(void) const; + /// The vehicle is responsible for making the initial request for the Plan. + /// @return: true: initial request is complete, false: initial request is still in progress; + bool initialPlanRequestComplete(void) const { return _initialPlanRequestComplete; } + signals: void allLinksInactive(Vehicle* vehicle); void coordinateChanged(QGeoCoordinate coordinate); @@ -781,8 +785,9 @@ private slots: void _imageReady (UASInterface* uas); void _connectionLostTimeout(void); void _prearmErrorTimeout(void); - void _newMissionItemsAvailable(void); - void _newGeoFenceAvailable(void); + void _missionLoadComplete(void); + void _geoFenceLoadComplete(void); + void _rallyPointLoadComplete(void); void _sendMavCommandAgain(void); void _activeJoystickChanged(void); @@ -827,7 +832,7 @@ private: void _sendNextQueuedMavCommand(void); void _updatePriorityLink(void); void _commonInit(void); - void _startMissionRequest(void); + void _startPlanRequest(void); void _setupAutoDisarmSignalling(void); int _id; ///< Mavlink system id @@ -909,6 +914,8 @@ private: static const int _connectionLostTimeoutMSecs = 3500; // Signal connection lost after 3.5 seconds of missed heartbeat QTimer _connectionLostTimer; + bool _initialPlanRequestComplete; + MissionManager* _missionManager; bool _missionManagerInitialRequestSent;