WimaController.cc 41.3 KB
Newer Older
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1
#include "WimaController.h"
2

3 4 5 6 7 8 9 10 11 12
const char* WimaController::wimaFileExtension           = "wima";
const char* WimaController::areaItemsName               = "AreaItems";
const char* WimaController::missionItemsName            = "MissionItems";
const char* WimaController::settingsGroup               = "WimaController";
const char* WimaController::enableWimaControllerName    = "EnableWimaController";
const char* WimaController::overlapWaypointsName        = "OverlapWaypoints";
const char* WimaController::maxWaypointsPerPhaseName    = "MaxWaypointsPerPhase";
const char* WimaController::startWaypointIndexName      = "StartWaypointIndex";
const char* WimaController::showAllMissionItemsName     = "ShowAllMissionItems";
const char* WimaController::showCurrentMissionItemsName = "ShowCurrentMissionItems";
13
const char* WimaController::flightSpeedName             = "FlightSpeed";
14
const char* WimaController::arrivalReturnSpeedName      = "ArrivalReturnSpeed";
15
const char* WimaController::altitudeName                = "Altitude";
16
const char* WimaController::reverseName                 = "Reverse";
17

18
WimaController::WimaController(QObject *parent)
19 20 21 22 23 24 25 26 27 28 29
    : QObject                   (parent)
    , _container                (nullptr)
    , _joinedArea               (this)
    , _measurementArea          (this)
    , _serviceArea              (this)
    , _corridor                 (this)
    , _localPlanDataValid       (false)
    , _metaDataMap              (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/WimaController.SettingsGroup.json"), this))
    , _enableWimaController     (settingsGroup, _metaDataMap[enableWimaControllerName])
    , _overlapWaypoints         (settingsGroup, _metaDataMap[overlapWaypointsName])
    , _maxWaypointsPerPhase     (settingsGroup, _metaDataMap[maxWaypointsPerPhaseName])
30
    , _nextPhaseStartWaypointIndex       (settingsGroup, _metaDataMap[startWaypointIndexName])
31
    , _showAllMissionItems      (settingsGroup, _metaDataMap[showAllMissionItemsName])
32 33
    , _showCurrentMissionItems  (settingsGroup, _metaDataMap[showCurrentMissionItemsName])    
    , _flightSpeed              (settingsGroup, _metaDataMap[flightSpeedName])
34
    , _arrivalReturnSpeed       (settingsGroup, _metaDataMap[arrivalReturnSpeedName])
35
    , _altitude                 (settingsGroup, _metaDataMap[altitudeName])
36
    , _reverse                  (settingsGroup, _metaDataMap[reverseName])
Valentin Platzgummer's avatar
Valentin Platzgummer committed
37
    , _endWaypointIndex         (0)
38 39
    , _startWaypointIndex       (0)
    , _uploadOverrideRequired   (false)
40 41 42
    , _measurementPathLength              (-1)
    , _arrivalPathLength        (-1)
    , _returnPathLength         (-1)
43 44
    , _phaseDistance            (-1)
    , _phaseDuration            (-1)
45 46
    , _phaseDistanceBuffer      (-1)
    , _phaseDurationBuffer      (-1)
47
    , _vehicleHasLowBattery     (false)
48
    , _lowBatteryHandlingTriggered(false)
49
    , _executingSmartRTL        (false)
50

51 52 53
{
    _showAllMissionItems.setRawValue(true);
    _showCurrentMissionItems.setRawValue(true);
54 55 56
    connect(&_overlapWaypoints,             &Fact::rawValueChanged, this, &WimaController::updateNextWaypoint);
    connect(&_maxWaypointsPerPhase,         &Fact::rawValueChanged, this, &WimaController::recalcCurrentPhase);
    connect(&_nextPhaseStartWaypointIndex,  &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
57
    connect(&_flightSpeed,                  &Fact::rawValueChanged, this, &WimaController::updateflightSpeed);
58
    connect(&_arrivalReturnSpeed,           &Fact::rawValueChanged, this, &WimaController::updateArrivalReturnSpeed);
59
    connect(&_altitude,                     &Fact::rawValueChanged, this, &WimaController::updateAltitude);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
60
    connect(&_reverse,                      &Fact::rawValueChanged, this, &WimaController::reverseChangedHandler);
61

62
    // setup low battery handling
63 64
    connect(&_checkBatteryTimer, &QTimer::timeout, this, &WimaController::checkBatteryLevel);
    _checkBatteryTimer.setInterval(500);
65 66 67
    Fact *enableLowBatteryHandling = qgcApp()->toolbox()->settingsManager()->wimaSettings()->enableLowBatteryHandling();
    connect(enableLowBatteryHandling, &Fact::rawValueChanged, this, &WimaController::enableDisableLowBatteryHandling);
    enableDisableLowBatteryHandling(enableLowBatteryHandling->rawValue());
68 69
}

70
QmlObjectListModel* WimaController::visualItems()
71
{
72
    return &_visualItems;
73 74
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
75 76 77 78
QStringList WimaController::loadNameFilters() const
{
    QStringList filters;

79
    filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension) <<
Valentin Platzgummer's avatar
Valentin Platzgummer committed
80 81
               tr("All Files (*.*)");
    return filters;
82 83 84 85 86
}

QStringList WimaController::saveNameFilters() const
{
    QStringList filters;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
87

88 89
    filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension);
    return filters;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
90 91
}

92
WimaDataContainer *WimaController::dataContainer()
93
{
94
    return _container;
95 96
}

97 98 99 100 101
QmlObjectListModel *WimaController::missionItems()
{
    return &_missionItems;
}

102 103 104 105 106
QmlObjectListModel *WimaController::currentMissionItems()
{
    return &_currentMissionItems;
}

107 108 109 110 111
QVariantList WimaController::waypointPath()
{
    return  _waypointPath;
}

112 113 114 115 116
QVariantList WimaController::currentWaypointPath()
{
    return _currentWaypointPath;
}

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
Fact *WimaController::enableWimaController()
{
    return &_enableWimaController;
}

Fact *WimaController::overlapWaypoints()
{
    return &_overlapWaypoints;
}

Fact *WimaController::maxWaypointsPerPhase()
{
    return &_maxWaypointsPerPhase;
}

Fact *WimaController::showAllMissionItems()
{
    return &_showAllMissionItems;
}

Fact *WimaController::showCurrentMissionItems()
{
    return &_showCurrentMissionItems;
}

142 143 144 145 146
Fact *WimaController::flightSpeed()
{
    return &_flightSpeed;
}

147 148 149 150 151
Fact *WimaController::arrivalReturnSpeed()
{
    return &_arrivalReturnSpeed;
}

152 153 154 155 156
Fact *WimaController::altitude()
{
    return &_altitude;
}

157 158 159 160 161
Fact *WimaController::reverse()
{
    return &_reverse;
}

162 163 164 165 166
bool WimaController::uploadOverrideRequired() const
{
    return _uploadOverrideRequired;
}

167 168 169 170 171 172 173 174 175 176
double WimaController::phaseDistance() const
{
    return _phaseDistance;
}

double WimaController::phaseDuration() const
{
    return _phaseDuration;
}

177 178 179 180 181
bool WimaController::vehicleHasLowBattery() const
{
    return _vehicleHasLowBattery;
}

182 183
Fact *WimaController::startWaypointIndex()
{
184
    return &_nextPhaseStartWaypointIndex;
185 186
}

187 188 189 190 191 192 193 194 195 196 197 198
void WimaController::setMasterController(PlanMasterController *masterC)
{
    _masterController = masterC;
    emit masterControllerChanged();
}

void WimaController::setMissionController(MissionController *missionC)
{
    _missionController = missionC;
    emit missionControllerChanged();
}

199 200 201 202 203 204
/*!
 * \fn void WimaController::setDataContainer(WimaDataContainer *container)
 * Sets the pointer to the \c WimaDataContainer, which is meant to exchange data between the \c WimaController and the \c WimaPlaner.
 *
 * \sa WimaPlaner, WimaDataContainer, WimaPlanData
 */
205 206
void WimaController::setDataContainer(WimaDataContainer *container)
{
207 208
    if (container != nullptr) {
        if (_container != nullptr) {
209
           disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
210 211
        }

212
        _container = container;
213
        connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
214 215 216 217 218

        emit dataContainerChanged();
    }
}

219 220 221 222 223 224 225 226 227
void WimaController::setUploadOverrideRequired(bool overrideRequired)
{
    if (_uploadOverrideRequired != overrideRequired) {
        _uploadOverrideRequired = overrideRequired;

        emit uploadOverrideRequiredChanged();
    }
}

228 229
void WimaController::nextPhase()
{
230
    calcNextPhase();
231 232
}

233
void WimaController::previousPhase()
Valentin Platzgummer's avatar
Valentin Platzgummer committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
{    
    bool reverseBool = _reverse.rawValue().toBool();
    if (!reverseBool){
        int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt();
        if (startIndex > 0) {
            _nextPhaseStartWaypointIndex.setRawValue(1+std::max(_startWaypointIndex
                                                              - _maxWaypointsPerPhase.rawValue().toInt()
                                                              + _overlapWaypoints.rawValue().toInt(), 0));
        }
    }
    else {
        int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt();
        if (startIndex <= _missionItems.count()) {
            _nextPhaseStartWaypointIndex.setRawValue(1+std::min(_startWaypointIndex
                                                              + _maxWaypointsPerPhase.rawValue().toInt()
                                                              - _overlapWaypoints.rawValue().toInt(), _missionItems.count()-1));
        }
251
    }
252 253 254 255
}

void WimaController::resetPhase()
{
Valentin Platzgummer's avatar
Valentin Platzgummer committed
256 257 258 259 260 261 262
    bool reverseBool = _reverse.rawValue().toBool();
    if (!reverseBool) {
        _nextPhaseStartWaypointIndex.setRawValue(int(1));
    }
    else {
        _nextPhaseStartWaypointIndex.setRawValue(_missionItems.count());
    }
263 264
}

265
bool WimaController::uploadToVehicle()
266
{
267 268
    if (   !_serviceArea.containsCoordinate(_masterController->managerVehicle()->coordinate())
        && _currentMissionItems.count() > 0) {
269 270 271 272 273 274 275 276 277 278
        setUploadOverrideRequired(true);
        return false;
    }

    return forceUploadToVehicle();
}

bool WimaController::forceUploadToVehicle()
{
    setUploadOverrideRequired(false);
279
    if (_currentMissionItems.count() < 1)
280
        return false;
281 282 283 284 285 286 287

    _missionController->removeAll();
    // set homeposition of settingsItem
    QmlObjectListModel* visuals = _missionController->visualItems();
    MissionSettingsItem* settingsItem = visuals->value<MissionSettingsItem *>(0);
    if (settingsItem == nullptr) {
        qWarning("WimaController::updateCurrentMissionItems(): nullptr");
288
        return false;
289 290 291 292 293 294 295
    }
    settingsItem->setCoordinate(_takeoffLandPostion);

    // copy mission items from _currentMissionItems to _missionController
    for (int i = 0; i < _currentMissionItems.count(); i++){
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
        _missionController->insertSimpleMissionItem(*item, visuals->count());
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
        if (item->command() == MAV_CMD_DO_CHANGE_SPEED) {
        }
    }

    for (int i = 0; i < _missionController->visualItems()->count(); i++){
        SimpleMissionItem *item =  _missionController->visualItems()->value<SimpleMissionItem*>(i);
        if (item == nullptr)
            continue;
        if (item->command() == MAV_CMD_DO_CHANGE_SPEED) {
        }
    }
    for (int i = 0; i < _missionController->visualItems()->count(); i++){
        SimpleMissionItem *item =  _missionController->visualItems()->value<SimpleMissionItem*>(i);
        if (item == nullptr)
            continue;
311 312
    }

313
    _masterController->sendToVehicle();
314 315

    return true;
316
}
317

318 319 320
void WimaController::removeFromVehicle()
{
    _masterController->removeAllFromVehicle();
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
    _missionController->removeAll();
}

bool WimaController::checkSmartRTLPreCondition()
{
    QString errorString;
    bool retValue = _checkSmartRTLPreCondition(errorString);
    if (retValue == false) {
        qgcApp()->showMessage(errorString);
        return false;
    }
    return true;
}

bool WimaController::calcReturnPath()
{
    QString errorString;
    bool retValue = _calcReturnPath(errorString);
    if (retValue == false) {
        qgcApp()->showMessage(errorString);
        return false;
    }
    return true;
344 345
}

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
bool WimaController::executeSmartRTL()
{
    QString errorString;
    bool retValue = _executeSmartRTL(errorString);
    if (!retValue) {
        qgcApp()->showMessage(errorString);
    }

    return retValue;
}

bool WimaController::initSmartRTL()
{
    masterController()->managerVehicle()->pauseVehicle();
    QString errorString;
    bool retValue = calcReturnPath();
    if (!retValue)
        return false;
364
    emit uploadAndExecuteConfirmRequired();
365 366 367
    return true;
}

368 369 370 371 372 373
void WimaController::removeVehicleTrajectoryHistory()
{
    Vehicle *managerVehicle = masterController()->managerVehicle();
    managerVehicle->trajectoryPoints()->clear();
}

374
void WimaController::saveToCurrent()
375
{
376

377 378
}

379 380
void WimaController::saveToFile(const QString& filename)
{
381
    QString file = filename;
382 383
}

384
bool WimaController::loadFromCurrent()
385
{
386
    return true;
387 388 389 390
}

bool WimaController::loadFromFile(const QString &filename)
{
391
    QString file = filename;
392
    return true;
393 394 395
}


396

397
QJsonDocument WimaController::saveToJson(FileType fileType)
398
{
399 400 401 402
    if(fileType)
    {

    }
403
    return QJsonDocument();
404 405
}

406
bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordinate &destination, QVector<QGeoCoordinate> &path)
407 408 409
{
    using namespace GeoUtilities;
    using namespace PolygonCalculus;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
410
    QVector<QPointF> path2D;
411 412 413 414 415 416 417 418 419 420
    bool retVal = PolygonCalculus::shortestPath(
                                   toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)),
                                   /*start point*/ QPointF(0,0),
                                   /*destination*/ toCartesian2D(destination, start),
                                   /*shortest path*/ path2D);
    path.append(toGeo(path2D, /*origin*/ start));

    return  retVal;
}

421
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVector<QGeoCoordinate> &coordinateList)
422 423 424 425
{
    return extractCoordinateList(missionItems, coordinateList, 0, missionItems.count()-1);
}

426
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVector<QGeoCoordinate> &coordinateList, int startIndex, int endIndex)
427 428 429 430 431 432 433 434 435 436 437 438
{
    if (   startIndex >= 0
        && startIndex < missionItems.count()
        && endIndex >= 0
        && endIndex < missionItems.count()) {
        if (startIndex > endIndex) {
            if (!extractCoordinateList(missionItems, coordinateList, startIndex, missionItems.count()-1))
                return false;
            if (!extractCoordinateList(missionItems, coordinateList, 0, endIndex))
                return false;
        } else {
            for (int i = startIndex; i <= endIndex; i++) {
439
                SimpleMissionItem *mItem = missionItems.value<SimpleMissionItem *>(i);
440 441 442 443 444 445 446 447 448 449 450 451 452 453

                if (mItem == nullptr) {
                    coordinateList.clear();
                    return false;
                }
                coordinateList.append(mItem->coordinate());
            }
        }
    } else
        return false;

    return true;
}

454
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList)
455 456 457 458
{
    return extractCoordinateList(missionItems, coordinateList, 0 , missionItems.count()-1);
}

459
bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex)
460
{
461
    QVector<QGeoCoordinate> geoCoordintateList;
462 463 464

    bool retValue = extractCoordinateList(missionItems, geoCoordintateList, startIndex, endIndex);

465 466 467
    if (!retValue)
        return false;

468 469
    for (int i = 0; i < geoCoordintateList.size(); i++) {
        QGeoCoordinate vertex = geoCoordintateList[i];
Valentin Platzgummer's avatar
Valentin Platzgummer committed
470 471
        if (   (qFuzzyIsNull(vertex.latitude()) && qFuzzyIsNull(vertex.longitude()))
            || !vertex.isValid())
472 473 474
            geoCoordintateList.removeAt(i);
    }

475 476 477 478 479 480
    for (auto coordinate : geoCoordintateList)
        coordinateList.append(QVariant::fromValue(coordinate));

    return true;
}

481 482 483 484 485 486 487
/*!
 * \fn void WimaController::containerDataValidChanged(bool valid)
 * Pulls plan data generated by \c WimaPlaner from the \c _container if the data is valid (\a valid equals true).
 * Is connected to the dataValidChanged() signal of the \c WimaDataContainer.
 *
 * \sa WimaDataContainer, WimaPlaner, WimaPlanData
 */
488
bool WimaController::fetchContainerData()
489
{
490
    // fetch only if valid, return true on sucess
491

492 493
    // reset visual items
    _visualItems.clear();
494 495
    _missionItems.clearAndDeleteContents();
    _currentMissionItems.clearAndDeleteContents();
496 497
    _waypointPath.clear();
    _currentWaypointPath.clear();
498

499 500 501 502
    emit visualItemsChanged();
    emit missionItemsChanged();
    emit currentMissionItemsChanged();
    emit currentWaypointPathChanged();
503

504
    _localPlanDataValid = false;
505

506 507 508 509
    if (_container == nullptr) {
        qWarning("WimaController::fetchContainerData(): No container assigned!");
        return false;
    }
510

511
    WimaPlanData planData = _container->pull();
512

513 514
    // extract list with WimaAreas
    QList<const WimaAreaData*> areaList = planData.areaList();
515

516 517 518 519
    int areaCounter = 0;
    int numAreas = 4; // extract only numAreas Areas, if there are more they are invalid and ignored
    for (int i = 0; i < areaList.size(); i++) {
        const WimaAreaData *areaData = areaList[i];
520

521 522 523 524
        if (areaData->type() == WimaServiceAreaData::typeString) { // is it a service area?
            _serviceArea = *qobject_cast<const WimaServiceAreaData*>(areaData);
            areaCounter++;
            _visualItems.append(&_serviceArea);
525

526 527
            continue;
        }
528

529 530 531 532
        if (areaData->type() == WimaMeasurementAreaData::typeString) { // is it a measurement area?
            _measurementArea =  *qobject_cast<const WimaMeasurementAreaData*>(areaData);
            areaCounter++;
            _visualItems.append(&_measurementArea);
533

534
            continue;
535
        }
536

537 538 539 540
        if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
            _corridor =  *qobject_cast<const WimaCorridorData*>(areaData);
            areaCounter++;
            //_visualItems.append(&_corridor); // not needed
541

542 543
            continue;
        }
544

545 546 547 548
        if (areaData->type() == WimaJoinedAreaData::typeString) { // is it a corridor?
            _joinedArea =  *qobject_cast<const WimaJoinedAreaData*>(areaData);
            areaCounter++;
            _visualItems.append(&_joinedArea);
549

550 551
            continue;
        }
552

553 554 555
        if (areaCounter >= numAreas)
            break;
    }
556

557
    // extract mission items
558
    QList<MissionItem> tempMissionItems = planData.missionItems();
559 560
    if (tempMissionItems.size() < 1)
        return false;
561

562 563 564
    // create mission items
    _missionController->removeAll();
    QmlObjectListModel* missionControllerVisualItems = _missionController->visualItems();
565

566 567
    // create SimpleMissionItem by using _missionController
    for ( int i = 0; i < tempMissionItems.size(); i++) {
568
        _missionController->insertSimpleMissionItem(tempMissionItems[i], missionControllerVisualItems->count());
569 570 571 572 573 574 575
    }
    // copy mission items from _missionController to _missionItems
    for ( int i = 1; i < missionControllerVisualItems->count(); i++) {
        SimpleMissionItem *visualItem     = qobject_cast<SimpleMissionItem *>((*missionControllerVisualItems)[i]);
        if (visualItem == nullptr) {
            qWarning("WimaController::fetchContainerData(): Nullptr at SimpleMissionItem!");
            return false;
576
        }
577 578 579 580 581
        SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
        _missionItems.append(visualItemCopy);
    }
    if (areaCounter != numAreas)
        return false;
582

583 584
    if (!setTakeoffLandPosition())
        return false;
585

586
    updateWaypointPath();
587

588 589
    // set _nextPhaseStartWaypointIndex to 1
    disconnect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
590 591
    bool reverse = _reverse.rawValue().toBool();
    _nextPhaseStartWaypointIndex.setRawValue(reverse? _missionItems.count() : int(1));
592
    connect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
593

594 595
    if(!calcNextPhase())
        return false;
596 597

    emit visualItemsChanged();
598
    emit missionItemsChanged();
599

600 601
    _localPlanDataValid = true;
    return true;
602 603
}

604
bool WimaController::calcNextPhase()
605
{
Valentin Platzgummer's avatar
Valentin Platzgummer committed
606 607 608
    if (_missionItems.count() < 1) {
        _startWaypointIndex = 0;
        _endWaypointIndex = 0;
609
        return false;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
610
    }
611

612
    _currentMissionItems.clearAndDeleteContents();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
613

Valentin Platzgummer's avatar
Valentin Platzgummer committed
614 615 616 617
    bool reverse = _reverse.rawValue().toBool(); // Reverses the phase direction. Phases go from high to low waypoint numbers, if true.
    int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt()-1;
    if (!reverse) {
        if (startIndex > _missionItems.count()-1)
618 619 620
            return false;
    }
    else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
621
        if (startIndex < 0)
622
            return false;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
623 624
    }    
    _startWaypointIndex = startIndex;
625

Valentin Platzgummer's avatar
Valentin Platzgummer committed
626
    int maxWaypointsPerPhase = _maxWaypointsPerPhase.rawValue().toInt();
627
    // determine end waypoint index
Valentin Platzgummer's avatar
Valentin Platzgummer committed
628 629 630
    bool lastMissionPhaseReached = false;
    if (!reverse) {
        _endWaypointIndex = std::min(_startWaypointIndex + maxWaypointsPerPhase - 1, _missionItems.count()-1);
631
        if (_endWaypointIndex == _missionItems.count() - 1)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
632
            lastMissionPhaseReached = true;
633 634
    }
    else {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
635
        _endWaypointIndex = std::max(_startWaypointIndex - maxWaypointsPerPhase + 1, 0);
636
        if (_endWaypointIndex == 0)
Valentin Platzgummer's avatar
Valentin Platzgummer committed
637
            lastMissionPhaseReached = true;
638 639
    }

640

641
    // extract waypoints
642
    QVector<QGeoCoordinate> CSWpList; // list with potential waypoints (from _missionItems), for _currentMissionItems
643

Valentin Platzgummer's avatar
Valentin Platzgummer committed
644
    if (!reverse) {
645
        if (!extractCoordinateList(_missionItems, CSWpList, _startWaypointIndex, _endWaypointIndex)) {
646 647 648 649
            qWarning("WimaController::calcNextPhase(): error on waypoint extraction.");
            return false;
        }
    } else {
650
        if (!extractCoordinateList(_missionItems, CSWpList, _endWaypointIndex, _startWaypointIndex)) {
651 652 653 654 655
            qWarning("WimaController::calcNextPhase(): error on waypoint extraction.");
            return false;
        }

        // reverse path
656 657
        QVector<QGeoCoordinate> reversePath;
        for (QGeoCoordinate c : CSWpList)
658
            reversePath.prepend(c);
659 660
        CSWpList.clear();
        CSWpList.append(reversePath);
661
    }
662

663

664 665 666 667 668 669
    // calculate phase length
    _measurementPathLength = 0;
    for (int i = 0; i < CSWpList.size()-1; ++i)
        _measurementPathLength += CSWpList[i].distanceTo(CSWpList[i+1]);


670
    // set start waypoint index for next phase
Valentin Platzgummer's avatar
Valentin Platzgummer committed
671
    if (!lastMissionPhaseReached) {
672
        disconnect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
673
        if (!reverse) {
674 675 676 677 678 679 680 681 682
            int untruncated = std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0);
            int truncated   = std::min(untruncated , _missionItems.count()-1);
            _nextPhaseStartWaypointIndex.setRawValue(truncated  + 1);
        }
        else {
            int untruncated = std::min(_endWaypointIndex - 1 + _overlapWaypoints.rawValue().toInt(), _missionItems.count()-1);
            int truncated   = std::max(untruncated , 0);
            _nextPhaseStartWaypointIndex.setRawValue(truncated  + 1);
        }
683
        connect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
684
    }
685 686

    // calculate path from home to first waypoint
687
    QVector<QGeoCoordinate> arrivalPath;
688 689 690 691
    if (!_takeoffLandPostion.isValid()){
        qWarning("WimaController::calcNextPhase(): _takeoffLandPostion not valid.");
        return false;
    }
692
    if ( !calcShortestPath(_takeoffLandPostion, CSWpList.first(), arrivalPath) ) {
693 694
        qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
        return false;
695
    }
696 697 698 699 700 701

    // calculate arrival path length
    _arrivalPathLength = 0;
    for (int i = 0; i < arrivalPath.size()-1; ++i)
        _arrivalPathLength += arrivalPath[i].distanceTo(arrivalPath[i+1]);

702
    arrivalPath.removeFirst();
703 704

    // calculate path from last waypoint to home
705 706
    QVector<QGeoCoordinate> returnPath;
    if ( !calcShortestPath(CSWpList.last(), _takeoffLandPostion, returnPath) ) {
707 708
        qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint.");
        return false;
709 710 711 712 713 714 715
    }

    // calculate arrival path length
    _returnPathLength = 0;
    for (int i = 0; i < returnPath.size()-1; ++i)
        _returnPathLength += returnPath[i].distanceTo(returnPath[i+1]);

716 717
    returnPath.removeFirst();
    returnPath.removeLast();
718

719

720

721 722 723
    // create Mission Items
    _missionController->removeAll();
    QmlObjectListModel* missionControllerVisuals = _missionController->visualItems();
724 725 726 727

    // set homeposition of settingsItem
    MissionSettingsItem* settingsItem = missionControllerVisuals->value<MissionSettingsItem *>(0);
    if (settingsItem == nullptr) {
728 729
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
730 731 732
    }
    settingsItem->setCoordinate(_takeoffLandPostion);

733
    // set takeoff position for first mission item (bug)
734
    missionController()->insertSimpleMissionItem(_takeoffLandPostion, 1);
735 736 737 738
    SimpleMissionItem *takeoffItem = missionControllerVisuals->value<SimpleMissionItem*>(1);
    if (takeoffItem == nullptr) {
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
739
    }
740
    takeoffItem->setCoordinate(_takeoffLandPostion);
741

742
    // create change speed item, after take off
743 744 745 746 747 748
    _missionController->insertSimpleMissionItem(_takeoffLandPostion, 2);
    SimpleMissionItem *speedItem = missionControllerVisuals->value<SimpleMissionItem*>(2);
    if (speedItem == nullptr) {
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
749
    speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED);// set coordinate must be after setCommand (setCommand sets coordinate to zero)
750
    speedItem->setCoordinate(_takeoffLandPostion);
751 752 753 754 755 756 757 758 759 760 761 762 763 764
    speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble());

    // insert arrival path
    for (auto coordinate : arrivalPath)
        _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());

    // create change speed item, after arrival path
    int index = missionControllerVisuals->count();
    _missionController->insertSimpleMissionItem(CSWpList.first(), index);
    speedItem = missionControllerVisuals->value<SimpleMissionItem*>(index);
    if (speedItem == nullptr) {
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
765
    speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); // set coordinate must be after setCommand (setCommand sets coordinate to zero)
766
    speedItem->setCoordinate(CSWpList.first());
767 768
    speedItem->missionItem().setParam2(_flightSpeed.rawValue().toDouble());

769 770 771 772 773 774 775 776 777 778 779 780
    // insert Circular Survey coordinates
    for (auto coordinate : CSWpList)
        _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());

    // create change speed item, after circular survey
    index = missionControllerVisuals->count();
    _missionController->insertSimpleMissionItem(CSWpList.last(), index);
    speedItem = missionControllerVisuals->value<SimpleMissionItem*>(index);
    if (speedItem == nullptr) {
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
781 782
    speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); // set coordinate must be after setCommand (setCommand sets coordinate to zero)
    speedItem->setCoordinate(CSWpList.last());
783 784 785 786 787
    speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble());

    // insert return path coordinates
    for (auto coordinate : returnPath)
        _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());
788 789

    // set land command for last mission item
790 791 792
    index = missionControllerVisuals->count();
    _missionController->insertSimpleMissionItem(_takeoffLandPostion, index);
    SimpleMissionItem *landItem = missionControllerVisuals->value<SimpleMissionItem*>(index);
793
    if (landItem == nullptr) {
794 795
        qWarning("WimaController::calcNextPhase(): nullptr");
        return false;
796
    }
797
    _missionController->setLandCommand(*landItem);
798

799
    // copy to _currentMissionItems
800 801 802
    for ( int i = 1; i < missionControllerVisuals->count(); i++) {
        SimpleMissionItem *visualItem     = missionControllerVisuals->value<SimpleMissionItem*>(i);
        if (visualItem == nullptr) {
803
            qWarning("WimaController::calcNextPhase(): Nullptr at SimpleMissionItem!");
804
            _currentMissionItems.clear();
805
            return false;
806
        }
807

808
        SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
809 810
        _currentMissionItems.append(visualItemCopy);
    }
811

812 813 814 815 816 817
    double dist = 0;
    double time = 0;
    if (!_missionController->distanceTimeToMissionEnd(dist, time, 1, false))
        qWarning("WimaController::calcNextPhase: distanceTimeToMissionEnd returned false!");
    _setPhaseDistance(dist);
    _setPhaseDuration(time);
818
    _missionController->removeAll(); // remove items from _missionController, will be added on upload
819
    updateAltitude();
820

821
    updateCurrentPath();
822
    emit currentMissionItemsChanged();
823 824

    return true;
825
}
826

827 828 829
void WimaController::updateWaypointPath()
{
    _waypointPath.clear();
830
    extractCoordinateList(_missionItems, _waypointPath, 0, _missionItems.count()-1);
831

832 833 834 835 836
    emit waypointPathChanged();
}
void WimaController::updateCurrentPath()
{
    _currentWaypointPath.clear();
837
    extractCoordinateList(_currentMissionItems, _currentWaypointPath, 0, _currentMissionItems.count()-1);
838

839 840
    emit currentWaypointPathChanged();
}
841

842 843 844
void WimaController::updateNextWaypoint()
{
    if (_endWaypointIndex < _missionItems.count()-2) {
845 846 847
        disconnect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
        _nextPhaseStartWaypointIndex.setRawValue(1 + std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0));
        connect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
848 849 850
    }
}

851 852
void WimaController::recalcCurrentPhase()
{
853 854 855 856
    disconnect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
    _nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);    
    connect(&_nextPhaseStartWaypointIndex,   &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
    calcNextPhase();
857 858 859 860 861 862 863 864 865
}

bool WimaController::setTakeoffLandPosition()
{
    _takeoffLandPostion.setAltitude(0);
    _takeoffLandPostion.setLongitude(_serviceArea.center().longitude());
    _takeoffLandPostion.setLatitude(_serviceArea.center().latitude());

    return true;
866 867
}

868
void WimaController::updateflightSpeed()
869
{
870 871 872 873 874 875 876 877 878
    int speedItemCounter = 0;
    for (int i = 0; i < _currentMissionItems.count(); i++) {
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
        if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) {
            speedItemCounter++;
            if (speedItemCounter == 2) {
                item->missionItem().setParam2(_flightSpeed.rawValue().toDouble());
            }
        }
879
    }
880

881 882 883 884
    _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble()
                      + (_arrivalPathLength + _returnPathLength)
                      / _arrivalReturnSpeed.rawValue().toDouble());

885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
    if (speedItemCounter != 3)
        qWarning("WimaController::updateflightSpeed(): internal error.");
}

void WimaController::updateArrivalReturnSpeed()
{
    int speedItemCounter = 0;
    for (int i = 0; i < _currentMissionItems.count(); i++) {
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
        if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) {
            speedItemCounter++;
            if (speedItemCounter != 2) {
                item->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble());
            }
        }
900
    }
901

902 903 904 905
    _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble()
                      + (_arrivalPathLength + _returnPathLength)
                      / _arrivalReturnSpeed.rawValue().toDouble());

906 907 908
    if (speedItemCounter != 3)
        qWarning("WimaController::updateArrivalReturnSpeed(): internal error.");

909 910 911 912 913 914 915 916 917 918 919 920 921 922
}

void WimaController::updateAltitude()
{
    for (int i = 0; i < _currentMissionItems.count(); i++) {
        SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
        if (item == nullptr) {
            qWarning("WimaController::updateAltitude(): nullptr");
            return;
        }
        item->altitude()->setRawValue(_altitude.rawValue().toDouble());
    }
}

923 924
void WimaController::checkBatteryLevel()
{
925 926 927 928 929
    Vehicle *managerVehicle     = masterController()->managerVehicle();
    WimaSettings* wimaSettings  = qgcApp()->toolbox()->settingsManager()->wimaSettings();
    int batteryThreshold        = wimaSettings->lowBatteryThreshold()->rawValue().toInt();
    bool enabled                = _enableWimaController.rawValue().toBool();
    unsigned int minTime        = wimaSettings->minimalRemainingMissionTime()->rawValue().toUInt();
930

931
    static short attemptCounter = 0;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
932

Valentin Platzgummer's avatar
Valentin Platzgummer committed
933
    if (managerVehicle != nullptr && enabled == true) {
934 935 936 937 938 939 940 941
        Fact *battery1percentRemaining = managerVehicle->battery1FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName);
        Fact *battery2percentRemaining = managerVehicle->battery2FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName);


        if (battery1percentRemaining->rawValue().toDouble() < batteryThreshold
                && battery2percentRemaining->rawValue().toDouble() < batteryThreshold) {
            _setVehicleHasLowBattery(true);
            if (!_lowBatteryHandlingTriggered) {
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

                if (_missionController->remainingTime() <= minTime) {
                    _lowBatteryHandlingTriggered = true;
                }
                else {
                    QString errorString;
                    attemptCounter++;
                    if (_checkSmartRTLPreCondition(errorString) == true) {

                        managerVehicle->pauseVehicle();
                        if (_calcReturnPath(errorString)) {
                            _lowBatteryHandlingTriggered = true;
                            attemptCounter = 0;
                            emit returnBatteryLowConfirmRequired();
                        } else {
                            if (attemptCounter > 3) {
                                qgcApp()->showMessage(tr("Battery level is low. Smart RTL not possible."));
                                qgcApp()->showMessage(errorString);
                            }
                        }
                    }
                    if (attemptCounter > 3) { // try 3 times, somtimes vehicle is outside joined area
964 965
                        _lowBatteryHandlingTriggered = true;
                        attemptCounter = 0;
966 967 968 969 970 971 972 973 974 975 976 977
                    }
                }
            }
        }
        else {
            _setVehicleHasLowBattery(false);
            _lowBatteryHandlingTriggered = false;
        }

    }
}

978 979 980 981 982 983 984
void WimaController::smartRTLCleanUp(bool flying)
{

    if ( !flying) { // vehicle has landed
        if (_executingSmartRTL) {
            _executingSmartRTL = false;
            _loadCurrentMissionItemsFromBuffer();
985 986
            _setPhaseDistance(_phaseDistanceBuffer);
            _setPhaseDuration(_phaseDurationBuffer);
987
            _showAllMissionItems.setRawValue(true);
988 989
            _missionController->removeAllFromVehicle();
            _missionController->removeAll();
990 991 992 993 994
            disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp);
        }
    }
}

995 996 997 998 999 1000 1001 1002 1003
void WimaController::enableDisableLowBatteryHandling(QVariant enable)
{
    if (enable.toBool()) {
        _checkBatteryTimer.start();
    } else {
        _checkBatteryTimer.stop();
    }
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
1004 1005 1006 1007 1008 1009 1010 1011 1012
void WimaController::reverseChangedHandler()
{
    disconnect(&_nextPhaseStartWaypointIndex,  &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
    _nextPhaseStartWaypointIndex.setRawValue(_endWaypointIndex+1);
    connect(&_nextPhaseStartWaypointIndex,  &Fact::rawValueChanged, this, &WimaController::calcNextPhase);

    calcNextPhase();
}

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
void WimaController::_setPhaseDistance(double distance)
{
    if (!qFuzzyCompare(distance, _phaseDistance)) {
        _phaseDistance = distance;

        emit phaseDistanceChanged();
    }
}

void WimaController::_setPhaseDuration(double duration)
{
    if (!qFuzzyCompare(duration, _phaseDuration)) {
        _phaseDuration = duration;

        emit phaseDurationChanged();
    }
}

1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
bool WimaController::_checkSmartRTLPreCondition(QString &errorString)
{
    if (!_localPlanDataValid) {
        errorString.append(tr("No WiMA data available. Please define at least a measurement and a service area."));
        return false;
    }
    Vehicle *managerVehicle = masterController()->managerVehicle();
   if (!managerVehicle->flying()) {
        errorString.append(tr("Vehicle is not flying. Smart RTL not available."));
        return false;
   }
1042 1043

   return true;
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
}

bool WimaController::_calcReturnPath(QString &errorSring)
{
    // it is assumed that checkSmartRTLPreCondition() was called first and true was returned


    Vehicle *managerVehicle = masterController()->managerVehicle();

    QGeoCoordinate currentVehiclePosition = managerVehicle->coordinate();
    // check if vehicle inside _joinedArea, this statement is not inside checkSmartRTLPreCondition() because during checkSmartRTLPreCondition() vehicle is not paused yet
    if (!_joinedArea.containsCoordinate(currentVehiclePosition)) {
        errorSring.append(tr("Vehicle not inside joined area. Action not supported."));
        return false;
    }

    // calculate return path
1061
    QVector<QGeoCoordinate> returnPath;
1062 1063 1064 1065 1066 1067 1068 1069
    calcShortestPath(currentVehiclePosition, _takeoffLandPostion, returnPath);
    // successful?
    if (returnPath.isEmpty()) {
        errorSring.append(tr("Not able to calculate return path."));
        return false;
    }
    // qWarning() << "returnPath.size()" << returnPath.size();

1070
    _saveCurrentMissionItemsToBuffer();
1071 1072 1073
    _phaseDistanceBuffer = _phaseDistance;
    _phaseDurationBuffer = _phaseDuration;

1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102

    // create Mission Items
    removeFromVehicle();
    QmlObjectListModel* missionControllerVisuals = _missionController->visualItems();

    // set homeposition of settingsItem
    MissionSettingsItem* settingsItem = missionControllerVisuals->value<MissionSettingsItem *>(0);
    if (settingsItem == nullptr) {
        qWarning("WimaController: nullptr");
        return false;
    }
    settingsItem->setCoordinate(_takeoffLandPostion);

    // copy from returnPath to _missionController
    QGeoCoordinate speedItemCoordinate = returnPath.first();
    for (auto coordinate : returnPath) {
        _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count());
    }
    //qWarning() << "missionControllerVisuals->count()" << missionControllerVisuals->count();

    // create speed item
    int speedItemIndex = 1;
    _missionController->insertSimpleMissionItem(speedItemCoordinate, speedItemIndex);
    SimpleMissionItem *speedItem = missionControllerVisuals->value<SimpleMissionItem*>(speedItemIndex);
    if (speedItem == nullptr) {
        qWarning("WimaController: nullptr");
        return false;
    }
    speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED);
1103 1104
    speedItem->setCoordinate(speedItemCoordinate);
    speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble());
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

    // set second item command to ordinary waypoint (is takeoff)
    SimpleMissionItem *secondItem = missionControllerVisuals->value<SimpleMissionItem*>(2);
    if (secondItem == nullptr) {
        qWarning("WimaController: nullptr");
        return false;
    }
    secondItem->setCoordinate(speedItemCoordinate);
    secondItem->setCommand(MAV_CMD_NAV_WAYPOINT);


    // set land command for last mission item
    SimpleMissionItem *landItem = missionControllerVisuals->value<SimpleMissionItem*>(missionControllerVisuals->count()-1);
    if (landItem == nullptr) {
        qWarning("WimaController: nullptr");
        return false;
    }
    _missionController->setLandCommand(*landItem);

    // copy to _currentMissionItems
    //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
    for ( int i = 1; i < missionControllerVisuals->count(); i++) {
        SimpleMissionItem *visualItem     = missionControllerVisuals->value<SimpleMissionItem*>(i);
        if (visualItem == nullptr) {
            qWarning("WimaController: Nullptr at SimpleMissionItem!");
            _currentMissionItems.clear();
            return false;
        }

        SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this);
        _currentMissionItems.append(visualItemCopy);
    }
    //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();

1139 1140
    _setPhaseDistance(-1);
    _setPhaseDuration(-1);
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
    _missionController->removeAll(); // remove items from _missionController, will be added on upload
    updateAltitude();

    updateCurrentPath();
    emit currentMissionItemsChanged();


    //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count();
    _showAllMissionItems.setRawValue(false);
    managerVehicle->trajectoryPoints()->clear();

    return true;
}

void WimaController::_setVehicleHasLowBattery(bool batteryLow)
{
    if (_vehicleHasLowBattery != batteryLow) {
        _vehicleHasLowBattery = batteryLow;

        emit vehicleHasLowBatteryChanged();
    }
}

1164 1165
bool WimaController::_executeSmartRTL(QString &errorSring)
{
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1166
    Q_UNUSED(errorSring)
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
    _executingSmartRTL = true;
    connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp);
    forceUploadToVehicle();
    masterController()->managerVehicle()->startMission();

    return true;
}

void WimaController::_loadCurrentMissionItemsFromBuffer()
{
    _currentMissionItems.clear();
    int numItems = _missionItemsBuffer.count();
    for (int i = 0; i < numItems; i++)
        _currentMissionItems.append(_missionItemsBuffer.removeAt(0));
1181 1182

    updateCurrentPath();
1183 1184 1185 1186 1187 1188
}


void WimaController::_saveCurrentMissionItemsToBuffer()
{
    _missionItemsBuffer.clear();
1189 1190
    int numCurrentMissionItems = _currentMissionItems.count();
    for (int i = 0; i < numCurrentMissionItems; i++)
1191 1192 1193
        _missionItemsBuffer.append(_currentMissionItems.removeAt(0));
}

1194 1195