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

Valentin Platzgummer's avatar
Valentin Platzgummer committed
3
#include "utilities.h"
4

5
#include "Snake/QNemoHeartbeat.h"
6
#include "Snake/QNemoProgress.h"
7

8
#include "QVector3D"
9
#include <QScopedPointer>
10
#include <QtConcurrentRun>
11

12 13
#include <memory>

14
#define SMART_RTL_MAX_ATTEMPTS 3       // times
15
#define SMART_RTL_ATTEMPT_INTERVAL 200 // ms
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#define EVENT_TIMER_INTERVAL 50        // ms

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";
const char *WimaController::flightSpeedName = "FlightSpeed";
const char *WimaController::arrivalReturnSpeedName = "ArrivalReturnSpeed";
const char *WimaController::altitudeName = "Altitude";
const char *WimaController::snakeTileWidthName = "SnakeTileWidth";
const char *WimaController::snakeTileHeightName = "SnakeTileHeight";
const char *WimaController::snakeMinTileAreaName = "SnakeMinTileArea";
const char *WimaController::snakeLineDistanceName = "SnakeLineDistance";
const char *WimaController::snakeMinTransectLengthName =
    "SnakeMinTransectLength";
Valentin Platzgummer's avatar
Valentin Platzgummer committed
37

Valentin Platzgummer's avatar
Valentin Platzgummer committed
38 39 40
WimaController::StatusMap WimaController::_nemoStatusMap{
    std::make_pair<int, QString>(0, "No Heartbeat"),
    std::make_pair<int, QString>(1, "Connected"),
41 42
    std::make_pair<int, QString>(-1, "Timeout"),
    std::make_pair<int, QString>(-2, "Error")};
43

44
WimaController::WimaController(QObject *parent)
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
    : QObject(parent), _joinedArea(), _measurementArea(), _serviceArea(),
      _corridor(), _localPlanDataValid(false),
      _areaInterface(&_measurementArea, &_serviceArea, &_corridor,
                     &_joinedArea),
      _WMSettings(), _defaultWM(_WMSettings, _areaInterface),
      _snakeWM(_WMSettings, _areaInterface),
      _rtlWM(_WMSettings, _areaInterface),
      _currentWM(&_defaultWM), _WMList{&_defaultWM, &_snakeWM, &_rtlWM},
      _metaDataMap(FactMetaData::createMapFromJsonFile(
          QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)),
      _enableWimaController(settingsGroup,
                            _metaDataMap[enableWimaControllerName]),
      _overlapWaypoints(settingsGroup, _metaDataMap[overlapWaypointsName]),
      _maxWaypointsPerPhase(settingsGroup,
                            _metaDataMap[maxWaypointsPerPhaseName]),
      _nextPhaseStartWaypointIndex(settingsGroup,
                                   _metaDataMap[startWaypointIndexName]),
      _showAllMissionItems(settingsGroup,
                           _metaDataMap[showAllMissionItemsName]),
      _showCurrentMissionItems(settingsGroup,
                               _metaDataMap[showCurrentMissionItemsName]),
      _flightSpeed(settingsGroup, _metaDataMap[flightSpeedName]),
      _arrivalReturnSpeed(settingsGroup, _metaDataMap[arrivalReturnSpeedName]),
      _altitude(settingsGroup, _metaDataMap[altitudeName]),
      _snakeTileWidth(settingsGroup, _metaDataMap[snakeTileWidthName]),
      _snakeTileHeight(settingsGroup, _metaDataMap[snakeTileHeightName]),
      _snakeMinTileArea(settingsGroup, _metaDataMap[snakeMinTileAreaName]),
      _snakeLineDistance(settingsGroup, _metaDataMap[snakeLineDistanceName]),
      _snakeMinTransectLength(settingsGroup,
                              _metaDataMap[snakeMinTransectLengthName]),
      _lowBatteryHandlingTriggered(false), _measurementPathLength(-1),
      _currentDM(&_emptyDM),
      _batteryLevelTicker(EVENT_TIMER_INTERVAL, 1000 /*ms*/) {

  // Set up facts.
  _showAllMissionItems.setRawValue(true);
  _showCurrentMissionItems.setRawValue(true);
  connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
          &WimaController::_updateOverlap);
  connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
          &WimaController::_updateMaxWaypoints);
  connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
          &WimaController::_setStartIndex);
  connect(&_flightSpeed, &Fact::rawValueChanged, this,
          &WimaController::_updateflightSpeed);
  connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this,
          &WimaController::_updateArrivalReturnSpeed);
  connect(&_altitude, &Fact::rawValueChanged, this,
          &WimaController::_updateAltitude);

  // Init waypoint managers.
  bool value;
  size_t overlap = _overlapWaypoints.rawValue().toUInt(&value);
  Q_ASSERT(value);
  size_t N = _maxWaypointsPerPhase.rawValue().toUInt(&value);
  Q_ASSERT(value);
  size_t startIdx = _nextPhaseStartWaypointIndex.rawValue().toUInt(&value);
  Q_ASSERT(value);
  (void)value;
  for (auto manager : _WMList) {
    manager->setOverlap(overlap);
    manager->setN(N);
    manager->setStartIndex(startIdx);
  }

  // Periodic.
  connect(&_eventTimer, &QTimer::timeout, this,
          &WimaController::_eventTimerHandler);
  _eventTimer.start(EVENT_TIMER_INTERVAL);

  // Snake Data Manager.
  connect(_currentDM, &SnakeDataManager::finished, this,
          &WimaController::_DMFinishedHandler);
  connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
          &WimaController::_progressChangedHandler);
  connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
          &WimaController::nemoStatusChanged);
  connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
          &WimaController::nemoStatusStringChanged);

  connect(this, &QObject::destroyed, &this->_snakeDM, &SnakeDataManager::quit);
  connect(this, &QObject::destroyed, &this->_emptyDM, &SnakeDataManager::quit);

  connect(&_enableSnake, &Fact::rawValueChanged, this,
          &WimaController::_enableSnakeChangedHandler);
  _enableSnakeChangedHandler();

  // Snake Waypoint Manager.
  connect(&_enableSnake, &Fact::rawValueChanged, this,
          &WimaController::_switchToSnakeWaypointManager);
  _switchToSnakeWaypointManager(_enableSnake.rawValue());
136 137
}

138
PlanMasterController *WimaController::masterController() {
139
  return _masterController;
140 141 142
}

MissionController *WimaController::missionController() {
143
  return _missionController;
144 145
}

146
QmlObjectListModel *WimaController::visualItems() { return &_areas; }
147 148

QmlObjectListModel *WimaController::missionItems() {
149
  return const_cast<QmlObjectListModel *>(&_currentWM->missionItems());
150 151 152
}

QmlObjectListModel *WimaController::currentMissionItems() {
153
  return const_cast<QmlObjectListModel *>(&_currentWM->currentMissionItems());
154 155
}

156 157
QVariantList WimaController::waypointPath() {
  return const_cast<QVariantList &>(_currentWM->waypointsVariant());
158 159
}

160 161
QVariantList WimaController::currentWaypointPath() {
  return const_cast<QVariantList &>(_currentWM->currentWaypointsVariant());
162 163
}

164
Fact *WimaController::enableWimaController() { return &_enableWimaController; }
165

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

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

Fact *WimaController::startWaypointIndex() {
171
  return &_nextPhaseStartWaypointIndex;
172 173
}

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

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

180
Fact *WimaController::flightSpeed() { return &_flightSpeed; }
181

182
Fact *WimaController::arrivalReturnSpeed() { return &_arrivalReturnSpeed; }
183

184
Fact *WimaController::altitude() { return &_altitude; }
185

186 187
QmlObjectListModel *WimaController::snakeTiles() {
  return const_cast<QmlObjectListModel *>(this->_snakeDM.tiles());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
188 189
}

190 191
QVariantList WimaController::snakeTileCenterPoints() {
  return _currentDM->tileCenterPoints();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
192 193
}

194 195
QVector<int> WimaController::nemoProgress() {
  return _currentDM->nemoProgress().progress();
196 197
}

198 199 200
double WimaController::phaseDistance() const {
  qWarning() << "using phaseDistance dummy";
  return 0.0;
201 202
}

203 204 205
double WimaController::phaseDuration() const {
  qWarning() << "using phaseDuration dummy";
  return 0.0;
206 207
}

208
int WimaController::nemoStatus() const { return _currentDM->nemoStatus(); }
209

210 211
QString WimaController::nemoStatusString() const {
  return _nemoStatusMap.at(nemoStatus());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
212 213
}

214 215
bool WimaController::snakeCalcInProgress() const {
  return _currentDM->calcInProgress();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
216 217
}

218 219 220 221
void WimaController::setMasterController(PlanMasterController *masterC) {
  _masterController = masterC;
  _WMSettings.setMasterController(masterC);
  emit masterControllerChanged();
222 223
}

224 225 226 227
void WimaController::setMissionController(MissionController *missionC) {
  _missionController = missionC;
  _WMSettings.setMissionController(missionC);
  emit missionControllerChanged();
228 229
}

230
void WimaController::nextPhase() { _calcNextPhase(); }
231

232 233 234 235
void WimaController::previousPhase() {
  if (!_currentWM->previous()) {
    Q_ASSERT(false);
  }
236

237 238 239 240
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
241 242
}

243 244 245 246
void WimaController::resetPhase() {
  if (!_currentWM->reset()) {
    Q_ASSERT(false);
  }
247

248 249 250 251
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
252 253
}

254 255 256 257 258 259 260
void WimaController::requestSmartRTL() {
  QString errorString("Smart RTL requested. ");
  if (!_checkSmartRTLPreCondition(errorString)) {
    qgcApp()->showMessage(errorString);
    return;
  }
  emit smartRTLRequestConfirm();
261 262
}

263 264 265 266 267 268 269 270
bool WimaController::upload() {
  auto &currentMissionItems = _defaultWM.currentMissionItems();
  if (!_serviceArea.containsCoordinate(
          _masterController->managerVehicle()->coordinate()) &&
      currentMissionItems.count() > 0) {
    emit forceUploadConfirm();
    return false;
  }
271

272
  return forceUpload();
273 274
}

275 276 277 278
bool WimaController::forceUpload() {
  auto &currentMissionItems = _defaultWM.currentMissionItems();
  if (currentMissionItems.count() < 1)
    return false;
279

280 281 282 283 284 285 286 287 288 289
  _missionController->removeAll();
  // Set homeposition of settingsItem.
  QmlObjectListModel *visuals = _missionController->visualItems();
  MissionSettingsItem *settingsItem = visuals->value<MissionSettingsItem *>(0);
  if (settingsItem == nullptr) {
    Q_ASSERT(false);
    qWarning("WimaController::updateCurrentMissionItems(): nullptr");
    return false;
  }
  settingsItem->setCoordinate(_WMSettings.homePosition());
290

291 292 293 294 295
  // Copy mission items to _missionController.
  for (int i = 1; i < currentMissionItems.count(); i++) {
    auto *item = currentMissionItems.value<const SimpleMissionItem *>(i);
    _missionController->insertSimpleMissionItem(*item, visuals->count());
  }
296

297
  _masterController->sendToVehicle();
298

299
  return true;
300
}
301

302 303 304
void WimaController::removeFromVehicle() {
  _masterController->removeAllFromVehicle();
  _missionController->removeAll();
305 306
}

307 308 309
void WimaController::executeSmartRTL() {
  forceUpload();
  masterController()->managerVehicle()->startMission();
310 311
}

312
void WimaController::initSmartRTL() { _initSmartRTL(); }
313

314 315 316
void WimaController::removeVehicleTrajectoryHistory() {
  Vehicle *managerVehicle = masterController()->managerVehicle();
  managerVehicle->trajectoryPoints()->clear();
317 318
}

Valentin Platzgummer's avatar
Valentin Platzgummer committed
319 320
bool WimaController::_calcShortestPath(const QGeoCoordinate &start,
                                       const QGeoCoordinate &destination,
321 322 323 324 325 326 327 328 329
                                       QVector<QGeoCoordinate> &path) {
  using namespace GeoUtilities;
  using namespace PolygonCalculus;
  QPolygonF polygon2D;
  toCartesianList(_joinedArea.coordinateList(), /*origin*/ start, polygon2D);
  QPointF start2D(0, 0);
  QPointF end2D;
  toCartesian(destination, start, end2D);
  QVector<QPointF> path2D;
330

331 332 333
  bool retVal =
      PolygonCalculus::shortestPath(polygon2D, start2D, end2D, path2D);
  toGeoList(path2D, /*origin*/ start, path);
334

335 336
  return retVal;
}
337

338 339 340 341 342
bool WimaController::setWimaPlanData(const WimaPlanData &planData) {
  // reset visual items
  _areas.clear();
  _defaultWM.clear();
  _snakeWM.clear();
343

344 345 346 347 348
  emit visualItemsChanged();
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit waypointPathChanged();
  emit currentWaypointPathChanged();
349

350
  _localPlanDataValid = false;
351

352 353
  // extract list with WimaAreas
  QList<const WimaAreaData *> areaList = planData.areaList();
354

355 356 357 358 359
  int areaCounter = 0;
  const 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];
360

361 362 363 364 365
    if (areaData->type() ==
        WimaServiceAreaData::typeString) { // is it a service area?
      _serviceArea = *qobject_cast<const WimaServiceAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_serviceArea);
366

367
      continue;
368
    }
369

370 371 372 373 374 375
    if (areaData->type() ==
        WimaMeasurementAreaData::typeString) { // is it a measurement area?
      _measurementArea =
          *qobject_cast<const WimaMeasurementAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_measurementArea);
376

377
      continue;
378
    }
379

380 381 382 383
    if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor?
      _corridor = *qobject_cast<const WimaCorridorData *>(areaData);
      areaCounter++;
      //_visualItems.append(&_corridor); // not needed
384

385
      continue;
386
    }
387

388 389 390 391 392
    if (areaData->type() ==
        WimaJoinedAreaData::typeString) { // is it a corridor?
      _joinedArea = *qobject_cast<const WimaJoinedAreaData *>(areaData);
      areaCounter++;
      _areas.append(&_joinedArea);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
393

394
      continue;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
395 396
    }

397 398 399
    if (areaCounter >= numAreas)
      break;
  }
400

401 402 403 404
  if (areaCounter != numAreas) {
    Q_ASSERT(false);
    return false;
  }
405

406
  emit visualItemsChanged();
407

408 409 410 411 412 413
  // extract mission items
  QList<MissionItem> tempMissionItems = planData.missionItems();
  if (tempMissionItems.size() < 1) {
    qWarning("WimaController: Mission items from WimaPlaner empty!");
    return false;
  }
414

415 416 417
  for (auto item : tempMissionItems) {
    _defaultWM.push_back(item.coordinate());
  }
418

419 420
  _WMSettings.setHomePosition(QGeoCoordinate(
      _serviceArea.center().latitude(), _serviceArea.center().longitude(), 0));
421

422 423 424 425
  if (!_defaultWM.reset()) {
    Q_ASSERT(false);
    return false;
  }
426

427 428 429 430
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit waypointPathChanged();
  emit currentWaypointPathChanged();
431

432 433 434 435 436
  // Update Snake Data Manager
  _snakeDM.setMeasurementArea(_measurementArea.coordinateList());
  _snakeDM.setServiceArea(_serviceArea.coordinateList());
  _snakeDM.setCorridor(_corridor.coordinateList());
  _currentDM->start();
437

438 439
  _localPlanDataValid = true;
  return true;
440
}
441

442
WimaController *WimaController::thisPointer() { return this; }
443

444 445 446 447 448
bool WimaController::_calcNextPhase() {
  if (!_currentWM->next()) {
    Q_ASSERT(false);
    return false;
  }
449

450 451 452 453
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
454

455
  return true;
456 457
}

458 459 460 461 462 463
bool WimaController::_setStartIndex() {
  bool value;
  _currentWM->setStartIndex(
      _nextPhaseStartWaypointIndex.rawValue().toUInt(&value) - 1);
  Q_ASSERT(value);
  (void)value;
464

465 466 467 468
  if (!_currentWM->update()) {
    Q_ASSERT(false);
    return false;
  }
469

470 471 472 473
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
474

475
  return true;
476 477
}

478 479 480 481
void WimaController::_recalcCurrentPhase() {
  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }
482

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateOverlap() {
  bool value;
  _currentWM->setOverlap(_overlapWaypoints.rawValue().toUInt(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    assert(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateMaxWaypoints() {
  bool value;
  _currentWM->setN(_maxWaypointsPerPhase.rawValue().toUInt(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateflightSpeed() {
  bool value;
  _WMSettings.setFlightSpeed(_flightSpeed.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateArrivalReturnSpeed() {
  bool value;
  _WMSettings.setArrivalReturnSpeed(
      _arrivalReturnSpeed.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_updateAltitude() {
  bool value;
  _WMSettings.setAltitude(_altitude.rawValue().toDouble(&value));
  Q_ASSERT(value);
  (void)value;

  if (!_currentWM->update()) {
    Q_ASSERT(false);
  }

  emit missionItemsChanged();
  emit currentMissionItemsChanged();
  emit currentWaypointPathChanged();
  emit waypointPathChanged();
}

void WimaController::_checkBatteryLevel() {
  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();

  if (managerVehicle != nullptr && enabled == true) {
    Fact *battery1percentRemaining =
        managerVehicle->battery1FactGroup()->getFact(
            VehicleBatteryFactGroup::_percentRemainingFactName);
    Fact *battery2percentRemaining =
        managerVehicle->battery2FactGroup()->getFact(
            VehicleBatteryFactGroup::_percentRemainingFactName);

    if (battery1percentRemaining->rawValue().toDouble() < batteryThreshold &&
        battery2percentRemaining->rawValue().toDouble() < batteryThreshold) {
      if (!_lowBatteryHandlingTriggered) {
        _lowBatteryHandlingTriggered = true;
        if (!(_missionController->remainingTime() <= minTime)) {
          requestSmartRTL();
594
        }
595 596 597
      }
    } else {
      _lowBatteryHandlingTriggered = false;
598
    }
599
  }
600 601
}

602 603 604 605 606 607 608 609 610 611
void WimaController::_eventTimerHandler() {
  // Battery level check necessary?
  Fact *enableLowBatteryHandling = qgcApp()
                                       ->toolbox()
                                       ->settingsManager()
                                       ->wimaSettings()
                                       ->enableLowBatteryHandling();
  if (enableLowBatteryHandling->rawValue().toBool() &&
      _batteryLevelTicker.ready())
    _checkBatteryLevel();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
612 613
}

614 615 616 617 618 619 620 621
void WimaController::_smartRTLCleanUp(bool flying) {
  if (!flying) { // vehicle has landed
    _switchWaypointManager(_defaultWM);
    _missionController->removeAllFromVehicle();
    _missionController->removeAll();
    disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged,
               this, &WimaController::_smartRTLCleanUp);
  }
622 623
}

624 625 626 627
void WimaController::_setPhaseDistance(double distance) {
  (void)distance;
  //    if (!qFuzzyCompare(distance, _phaseDistance)) {
  //        _phaseDistance = distance;
628

629 630
  //        emit phaseDistanceChanged();
  //    }
631 632
}

633 634 635 636
void WimaController::_setPhaseDuration(double duration) {
  (void)duration;
  //    if (!qFuzzyCompare(duration, _phaseDuration)) {
  //        _phaseDuration = duration;
637

638 639
  //        emit phaseDurationChanged();
  //    }
640 641
}

642 643 644 645 646 647
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;
  }
648

649
  return _rtlWM.checkPrecondition(errorString);
650 651
}

652 653 654 655
void WimaController::_switchWaypointManager(
    WaypointManager::ManagerBase &manager) {
  if (_currentWM != &manager) {
    _currentWM = &manager;
Valentin Platzgummer's avatar
Valentin Platzgummer committed
656

657 658 659 660 661 662
    disconnect(&_overlapWaypoints, &Fact::rawValueChanged, this,
               &WimaController::_updateOverlap);
    disconnect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
               &WimaController::_updateMaxWaypoints);
    disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
               &WimaController::_setStartIndex);
663

664 665 666
    _maxWaypointsPerPhase.setRawValue(_currentWM->N());
    _overlapWaypoints.setRawValue(_currentWM->overlap());
    _nextPhaseStartWaypointIndex.setRawValue(_currentWM->startIndex());
Valentin Platzgummer's avatar
Valentin Platzgummer committed
667

668 669 670 671 672 673
    connect(&_overlapWaypoints, &Fact::rawValueChanged, this,
            &WimaController::_updateOverlap);
    connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this,
            &WimaController::_updateMaxWaypoints);
    connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this,
            &WimaController::_setStartIndex);
674

675
    emit missionItemsChanged();
676 677
    emit currentMissionItemsChanged();
    emit waypointPathChanged();
678
    emit currentWaypointPathChanged();
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
    qWarning()
        << "WimaController::_switchWaypointManager: statistics update missing.";
  }
}

void WimaController::_initSmartRTL() {
  QString errorString;
  static int attemptCounter = 0;
  attemptCounter++;

  if (_checkSmartRTLPreCondition(errorString)) {
    _masterController->managerVehicle()->pauseVehicle();
    connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this,
            &WimaController::_smartRTLCleanUp);
    if (_rtlWM.update()) { // Calculate return path.
      _switchWaypointManager(_rtlWM);
      attemptCounter = 0;
      emit smartRTLPathConfirm();
      return;
    }
  } else if (attemptCounter > SMART_RTL_MAX_ATTEMPTS) {
    errorString.append(
        tr("Smart RTL: No success after maximum number of attempts."));
    qgcApp()->showMessage(errorString);
    attemptCounter = 0;
  } else {
    _smartRTLTimer.singleShot(SMART_RTL_ATTEMPT_INTERVAL, this,
                              &WimaController::_initSmartRTL);
  }
}

void WimaController::_DMFinishedHandler() {
  if (!_snakeDM.success()) {
    // qgcApp()->showMessage(r.errorMessage);
    return;
  }

  // Copy waypoints to waypoint manager.
  _snakeWM.clear();
  auto waypoints = _snakeDM.waypoints();
  if (waypoints.size() < 1) {
    return;
  }
  for (auto &vertex : waypoints) {
    _snakeWM.push_back(vertex);
  }

  // Do update.
  auto fut = QtConcurrent::run([this] {
    this->_snakeWM.update(); // this can take a while (ca. 200ms)

    emit this->missionItemsChanged();
    emit this->currentMissionItemsChanged();
    emit this->currentWaypointPathChanged();
    emit this->waypointPathChanged();
  });
  (void)fut;
}

void WimaController::_switchToSnakeWaypointManager(QVariant variant) {
  if (variant.value<bool>()) {
    _switchWaypointManager(_snakeWM);
  } else {
    _switchWaypointManager(_defaultWM);
  }
}

void WimaController::_switchDataManager(SnakeDataManager &dataManager) {
  if (_currentDM != &dataManager) {

    disconnect(_currentDM, &SnakeDataManager::finished, this,
               &WimaController::_DMFinishedHandler);
    disconnect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
               &WimaController::_progressChangedHandler);
    disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
               &WimaController::nemoStatusChanged);
    disconnect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
               &WimaController::nemoStatusStringChanged);

    _currentDM = &dataManager;

    connect(_currentDM, &SnakeDataManager::finished, this,
            &WimaController::_DMFinishedHandler);
    connect(_currentDM, &SnakeDataManager::nemoProgressChanged, this,
            &WimaController::_progressChangedHandler);
    connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
            &WimaController::nemoStatusChanged);
    connect(_currentDM, &SnakeDataManager::nemoStatusChanged, this,
            &WimaController::nemoStatusStringChanged);

    emit snakeConnectionStatusChanged();
    emit snakeCalcInProgressChanged();
    emit snakeTilesChanged();
    emit snakeTileCenterPointsChanged();
    emit nemoProgressChanged();
    emit nemoStatusChanged();
    emit nemoStatusStringChanged();
  }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
778 779
}

780 781 782
void WimaController::_progressChangedHandler() {
  emit this->nemoProgressChanged();
  this->_currentDM->start();
783
}
784

785 786 787 788 789 790 791 792 793 794
void WimaController::_enableSnakeChangedHandler() {
  if (this->_enableSnake.rawValue().toBool()) {
    this->_snakeDM.enableRosBridge();
    _switchDataManager(_snakeDM);
    _currentDM->start();
  } else {
    this->_snakeDM.disableRosBride();
    _switchDataManager(_emptyDM);
  }
}