CameraSection.cc 26.1 KB
Newer Older
1 2
/****************************************************************************
 *
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9 10 11
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "CameraSection.h"
#include "SimpleMissionItem.h"
12
#include "FirmwarePlugin.h"
13
#include "PlanMasterController.h"
14 15 16

QGC_LOGGING_CATEGORY(CameraSectionLog, "CameraSectionLog")

17 18 19 20 21 22
const char* CameraSection::_gimbalPitchName =                   "GimbalPitch";
const char* CameraSection::_gimbalYawName =                     "GimbalYaw";
const char* CameraSection::_cameraActionName =                  "CameraAction";
const char* CameraSection::_cameraPhotoIntervalDistanceName =   "CameraPhotoIntervalDistance";
const char* CameraSection::_cameraPhotoIntervalTimeName =       "CameraPhotoIntervalTime";
const char* CameraSection::_cameraModeName =                    "CameraMode";
23 24 25

QMap<QString, FactMetaData*> CameraSection::_metaDataMap;

26 27 28 29 30 31
CameraSection::CameraSection(PlanMasterController* masterController, QObject* parent)
    : Section                           (masterController, parent)
    , _available                        (false)
    , _settingsSpecified                (false)
    , _specifyGimbal                    (false)
    , _specifyCameraMode                (false)
32 33 34 35 36
    , _gimbalYawFact                    (0, _gimbalYawName,                     FactMetaData::valueTypeDouble)
    , _gimbalPitchFact                  (0, _gimbalPitchName,                   FactMetaData::valueTypeDouble)
    , _cameraActionFact                 (0, _cameraActionName,                  FactMetaData::valueTypeDouble)
    , _cameraPhotoIntervalDistanceFact  (0, _cameraPhotoIntervalDistanceName,   FactMetaData::valueTypeDouble)
    , _cameraPhotoIntervalTimeFact      (0, _cameraPhotoIntervalTimeName,       FactMetaData::valueTypeUint32)
37
    , _cameraModeFact                   (0, _cameraModeName,                    FactMetaData::valueTypeUint32)
38
    , _dirty                            (false)
39 40
{
    if (_metaDataMap.isEmpty()) {
41
        _metaDataMap = FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraSection.FactMetaData.json"), Q_NULLPTR /* metaDataParent */);
42 43 44 45 46 47 48
    }

    _gimbalPitchFact.setMetaData                    (_metaDataMap[_gimbalPitchName]);
    _gimbalYawFact.setMetaData                      (_metaDataMap[_gimbalYawName]);
    _cameraActionFact.setMetaData                   (_metaDataMap[_cameraActionName]);
    _cameraPhotoIntervalDistanceFact.setMetaData    (_metaDataMap[_cameraPhotoIntervalDistanceName]);
    _cameraPhotoIntervalTimeFact.setMetaData        (_metaDataMap[_cameraPhotoIntervalTimeName]);
49
    _cameraModeFact.setMetaData                     (_metaDataMap[_cameraModeName]);
50 51 52 53 54 55

    _gimbalPitchFact.setRawValue                    (_gimbalPitchFact.rawDefaultValue());
    _gimbalYawFact.setRawValue                      (_gimbalYawFact.rawDefaultValue());
    _cameraActionFact.setRawValue                   (_cameraActionFact.rawDefaultValue());
    _cameraPhotoIntervalDistanceFact.setRawValue    (_cameraPhotoIntervalDistanceFact.rawDefaultValue());
    _cameraPhotoIntervalTimeFact.setRawValue        (_cameraPhotoIntervalTimeFact.rawDefaultValue());
56
    _cameraModeFact.setRawValue                     (_cameraModeFact.rawDefaultValue());
57

58 59
    connect(this,                               &CameraSection::specifyGimbalChanged,       this, &CameraSection::_specifyChanged);
    connect(this,                               &CameraSection::specifyCameraModeChanged,   this, &CameraSection::_specifyChanged);
60

61
    connect(&_cameraActionFact,                 &Fact::valueChanged,                        this, &CameraSection::_cameraActionChanged);
DonLakeFlyer's avatar
DonLakeFlyer committed
62

63 64
    connect(&_gimbalPitchFact,                  &Fact::valueChanged,                        this, &CameraSection::_dirtyIfSpecified);
    connect(&_gimbalYawFact,                    &Fact::valueChanged,                        this, &CameraSection::_dirtyIfSpecified);
65 66 67 68 69 70 71
    connect(&_cameraPhotoIntervalDistanceFact,  &Fact::valueChanged,                        this, &CameraSection::_setDirty);
    connect(&_cameraPhotoIntervalTimeFact,      &Fact::valueChanged,                        this, &CameraSection::_setDirty);
    connect(&_cameraModeFact,                   &Fact::valueChanged,                        this, &CameraSection::_setDirty);
    connect(this,                               &CameraSection::specifyGimbalChanged,       this, &CameraSection::_setDirty);
    connect(this,                               &CameraSection::specifyCameraModeChanged,   this, &CameraSection::_setDirty);

    connect(&_gimbalYawFact,                    &Fact::valueChanged,                        this, &CameraSection::_updateSpecifiedGimbalYaw);
72
    connect(&_gimbalPitchFact,                  &Fact::valueChanged,                        this, &CameraSection::_updateSpecifiedGimbalPitch);
73 74 75 76 77 78 79
}

void CameraSection::setSpecifyGimbal(bool specifyGimbal)
{
    if (specifyGimbal != _specifyGimbal) {
        _specifyGimbal = specifyGimbal;
        emit specifyGimbalChanged(specifyGimbal);
80 81
        emit specifiedGimbalYawChanged(specifiedGimbalYaw());
        emit specifiedGimbalPitchChanged(specifiedGimbalPitch());
82 83 84
    }
}

85 86 87 88 89 90 91 92
void CameraSection::setSpecifyCameraMode(bool specifyCameraMode)
{
    if (specifyCameraMode != _specifyCameraMode) {
        _specifyCameraMode = specifyCameraMode;
        emit specifyCameraModeChanged(specifyCameraMode);
    }
}

93
int CameraSection::itemCount(void) const
94 95 96 97 98 99
{
    int itemCount = 0;

    if (_specifyGimbal) {
        itemCount++;
    }
100 101 102
    if (_specifyCameraMode) {
        itemCount++;
    }
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    if (_cameraActionFact.rawValue().toInt() != CameraActionNone) {
        itemCount++;
    }

    return itemCount;
}

void CameraSection::setDirty(bool dirty)
{
    if (_dirty != dirty) {
        _dirty = dirty;
        emit dirtyChanged(_dirty);
    }
}

118
void CameraSection::appendSectionItems(QList<MissionItem*>& items, QObject* missionItemParent, int& nextSequenceNumber)
119
{
120
    // IMPORTANT NOTE: If anything changes here you must also change CameraSection::scanForSection
121

DonLakeFlyer's avatar
DonLakeFlyer committed
122 123 124 125
    if (_specifyCameraMode) {
        MissionItem* item = new MissionItem(nextSequenceNumber++,
                                            MAV_CMD_SET_CAMERA_MODE,
                                            MAV_FRAME_MISSION,
126
                                            0,                                              // Reserved (Set to 0)
DonLakeFlyer's avatar
DonLakeFlyer committed
127
                                            _cameraModeFact.rawValue().toDouble(),
128 129 130
                                            qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(),    // reserved
                                            true,                                           // autoContinue
                                            false,                                          // isCurrentItem
DonLakeFlyer's avatar
DonLakeFlyer committed
131 132 133 134
                                            missionItemParent);
        items.append(item);
    }

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    if (_specifyGimbal) {
        MissionItem* item = new MissionItem(nextSequenceNumber++,
                                            MAV_CMD_DO_MOUNT_CONTROL,
                                            MAV_FRAME_MISSION,
                                            _gimbalPitchFact.rawValue().toDouble(),
                                            0,                                      // Gimbal roll
                                            _gimbalYawFact.rawValue().toDouble(),
                                            0, 0, 0,                                // param 4-6 not used
                                            MAV_MOUNT_MODE_MAVLINK_TARGETING,
                                            true,                                   // autoContinue
                                            false,                                  // isCurrentItem
                                            missionItemParent);
        items.append(item);
    }

    if (_cameraActionFact.rawValue().toInt() != CameraActionNone) {
151
        MissionItem* item = nullptr;
152 153 154 155 156 157

        switch (_cameraActionFact.rawValue().toInt()) {
        case TakePhotosIntervalTime:
            item = new MissionItem(nextSequenceNumber++,
                                   MAV_CMD_IMAGE_START_CAPTURE,
                                   MAV_FRAME_MISSION,
Gus Grubba's avatar
Gus Grubba committed
158
                                   0,                                               // Reserved (Set to 0)
159 160
                                   _cameraPhotoIntervalTimeFact.rawValue().toInt(), // Interval
                                   0,                                               // Unlimited photo count
161
                                   qQNaN(), qQNaN(), qQNaN(), qQNaN(),              // reserved
162 163 164 165 166 167 168 169 170 171
                                   true,                                            // autoContinue
                                   false,                                           // isCurrentItem
                                   missionItemParent);
            break;

        case TakePhotoIntervalDistance:
            item = new MissionItem(nextSequenceNumber++,
                                   MAV_CMD_DO_SET_CAM_TRIGG_DIST,
                                   MAV_FRAME_MISSION,
                                   _cameraPhotoIntervalDistanceFact.rawValue().toDouble(),  // Trigger distance
172 173 174
                                   0,                                                       // No shutter integartion
                                   1,                                                       // Trigger immediately
                                   0, 0, 0, 0,                                              // param 4-7 not used
175 176 177 178 179 180 181 182 183
                                   true,                                                    // autoContinue
                                   false,                                                   // isCurrentItem
                                   missionItemParent);
            break;

        case TakeVideo:
            item = new MissionItem(nextSequenceNumber++,
                                   MAV_CMD_VIDEO_START_CAPTURE,
                                   MAV_FRAME_MISSION,
184 185 186 187 188
                                   0,                                               // Reserved (Set to 0)
                                   VIDEO_CAPTURE_STATUS_INTERVAL,                   // CAMERA_CAPTURE_STATUS (default to every 5 seconds)
                                   qQNaN(), qQNaN(), qQNaN(), qQNaN(),  qQNaN(),    // reserved
                                   true,                                            // autoContinue
                                   false,                                           // isCurrentItem
189 190
                                   missionItemParent);
            break;
191 192

        case StopTakingVideo:
193
            appendStopTakingVideo(items, nextSequenceNumber, missionItemParent);
194 195 196
            break;

        case StopTakingPhotos:
197
            appendStopTakingPhotos(items, nextSequenceNumber, missionItemParent);
198
            break;
DonLakeFlyer's avatar
DonLakeFlyer committed
199 200

        case TakePhoto:
201 202 203
            item = new MissionItem(nextSequenceNumber++,
                                   MAV_CMD_IMAGE_START_CAPTURE,
                                   MAV_FRAME_MISSION,
204 205 206 207 208 209 210
                                   0,                           // Reserved (Set to 0)
                                   0,                           // Interval (none)
                                   1,                           // Take 1 photo
                                   0,                           // No sequence number specified
                                   qQNaN(), qQNaN(), qQNaN(),   // reserved
                                   true,                        // autoContinue
                                   false,                       // isCurrentItem
211
                                   missionItemParent);
DonLakeFlyer's avatar
DonLakeFlyer committed
212
            break;
213 214 215 216 217 218 219
        }
        if (item) {
            items.append(item);
        }
    }
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
void CameraSection::appendStopTakingPhotos(QList<MissionItem*>& items, int& seqNum, QObject* missionItemParent)
{
    MissionItem* item = new MissionItem(seqNum++,
                           MAV_CMD_DO_SET_CAM_TRIGG_DIST,
                           MAV_FRAME_MISSION,
                           0,                               // Trigger distance = 0 means stop
                           0, 0, 0, 0, 0, 0,                // param 2-7 not used
                           true,                            // autoContinue
                           false,                           // isCurrentItem
                           missionItemParent);
    items.append(item);
    item = new MissionItem(seqNum++,
                           MAV_CMD_IMAGE_STOP_CAPTURE,
                           MAV_FRAME_MISSION,
                           0,                                                       // Reserved (Set to 0)
                           qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(),    // reserved
                           true,                                                    // autoContinue
                           false,                                                   // isCurrentItem
                           missionItemParent);
    items.append(item);
}

void CameraSection::appendStopTakingVideo(QList<MissionItem*>& items, int& seqNum, QObject* missionItemParent)
{
    MissionItem* item = new MissionItem(seqNum++,
                           MAV_CMD_VIDEO_STOP_CAPTURE,
                           MAV_FRAME_MISSION,
                           0,                                                       // Reserved (Set to 0)
                           qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(), qQNaN(),    // reserved
                           true,                                                    // autoContinue
                           false,                                                   // isCurrentItem
                           missionItemParent);
    items.append(item);
}

255
bool CameraSection::_scanGimbal(QmlObjectListModel* visualItems, int scanIndex)
256
{
257 258 259
    if (scanIndex > visualItems->count() -1) {
        return false;
    }
260 261
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
262
        MissionItem& missionItem = item->missionItem();
263 264
        if ((MAV_CMD)item->command() == MAV_CMD_DO_MOUNT_CONTROL) {
            if (missionItem.param2() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == MAV_MOUNT_MODE_MAVLINK_TARGETING) {
265 266 267 268
                setSpecifyGimbal(true);
                gimbalPitch()->setRawValue(missionItem.param1());
                gimbalYaw()->setRawValue(missionItem.param3());
                visualItems->removeAt(scanIndex)->deleteLater();
269
                return true;
270
            }
271 272
        }
    }
273

274 275 276 277 278
    return false;
}

bool CameraSection::_scanTakePhoto(QmlObjectListModel* visualItems, int scanIndex)
{
279 280 281
    if (scanIndex > visualItems->count() -1) {
        return false;
    }
282 283 284 285
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_IMAGE_START_CAPTURE) {
286
            if (missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 1) {
287
                cameraAction()->setRawValue(TakePhoto);
288
                visualItems->removeAt(scanIndex)->deleteLater();
289
                return true;
290
            }
291 292
        }
    }
293

294 295
    return false;
}
296

297 298
bool CameraSection::_scanTakePhotosIntervalTime(QmlObjectListModel* visualItems, int scanIndex)
{
299 300 301
    if (scanIndex > visualItems->count() -1) {
        return false;
    }
302 303 304 305
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_IMAGE_START_CAPTURE) {
306
            if (missionItem.param1() == 0 && missionItem.param2() >= 1 && missionItem.param3() == 0) {
307 308 309 310 311 312 313 314 315 316 317
                cameraAction()->setRawValue(TakePhotosIntervalTime);
                cameraPhotoIntervalTime()->setRawValue(missionItem.param2());
                visualItems->removeAt(scanIndex)->deleteLater();
                return true;
            }
        }
    }

    return false;
}

318
bool CameraSection::scanStopTakingPhotos(QmlObjectListModel* visualItems, int scanIndex, bool removeScannedItems)
319
{
320 321 322
    if (scanIndex < 0 || scanIndex > visualItems->count() -1) {
        return false;
    }
323 324 325 326 327 328
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
            if (missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) {
                if (scanIndex < visualItems->count() - 1) {
329 330
                    SimpleMissionItem* nextItem = visualItems->value<SimpleMissionItem*>(scanIndex + 1);
                    if (nextItem) {
331
                        MissionItem& nextMissionItem = nextItem->missionItem();
332
                        if (nextMissionItem.command() == MAV_CMD_IMAGE_STOP_CAPTURE && nextMissionItem.param1() == 0) {
333 334 335 336
                            if (removeScannedItems) {
                                visualItems->removeAt(scanIndex)->deleteLater();
                                visualItems->removeAt(scanIndex)->deleteLater();
                            }
337
                            return true;
338 339 340
                        }
                    }
                }
341 342 343
            }
        }
    }
344

345 346 347
    return false;
}

348
bool CameraSection::_scanTriggerStartDistance(QmlObjectListModel* visualItems, int scanIndex)
349
{
350 351 352
    if (scanIndex < 0 || scanIndex > visualItems->count() -1) {
        return false;
    }
353 354 355 356
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
357 358 359 360 361 362 363 364 365 366 367 368 369 370
            if (missionItem.param1() > 0 && missionItem.param2() == 0 && missionItem.param3() == 1 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) {
                cameraAction()->setRawValue(TakePhotoIntervalDistance);
                cameraPhotoIntervalDistance()->setRawValue(missionItem.param1());
                visualItems->removeAt(scanIndex)->deleteLater();
                return true;
            }
        }
    }

    return false;
}

bool CameraSection::_scanTriggerStopDistance(QmlObjectListModel* visualItems, int scanIndex)
{
371 372 373
    if (scanIndex < 0 || scanIndex > visualItems->count() -1) {
        return false;
    }
374 375 376 377 378
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_DO_SET_CAM_TRIGG_DIST) {
            if (missionItem.param1() == 0 && missionItem.param2() == 0 && missionItem.param3() == 0 && missionItem.param4() == 0 && missionItem.param5() == 0 && missionItem.param6() == 0 && missionItem.param7() == 0) {
379 380 381 382
                cameraAction()->setRawValue(TakePhotoIntervalDistance);
                cameraPhotoIntervalDistance()->setRawValue(missionItem.param1());
                visualItems->removeAt(scanIndex)->deleteLater();
                return true;
383
            }
384 385 386 387 388
        }
    }

    return false;
}
389

390 391
bool CameraSection::_scanTakeVideo(QmlObjectListModel* visualItems, int scanIndex)
{
392 393 394
    if (scanIndex > visualItems->count() -1) {
        return false;
    }
395 396 397 398
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_VIDEO_START_CAPTURE) {
399
            if (missionItem.param1() == 0 && missionItem.param2() == VIDEO_CAPTURE_STATUS_INTERVAL) {
400 401
                cameraAction()->setRawValue(TakeVideo);
                visualItems->removeAt(scanIndex)->deleteLater();
402
                return true;
403
            }
404 405
        }
    }
406

407 408 409
    return false;
}

410
bool CameraSection::scanStopTakingVideo(QmlObjectListModel* visualItems, int scanIndex, bool removeScannedItems)
411
{
412 413 414
    if (scanIndex < 0 || scanIndex > visualItems->count() -1) {
        return false;
    }
415 416 417 418
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_VIDEO_STOP_CAPTURE) {
419
            if (missionItem.param1() == 0) {
420 421 422
                if (removeScannedItems) {
                    visualItems->removeAt(scanIndex)->deleteLater();
                }
423
                return true;
424
            }
425 426
        }
    }
427

428 429 430 431 432
    return false;
}

bool CameraSection::_scanSetCameraMode(QmlObjectListModel* visualItems, int scanIndex)
{
433 434 435
    if (scanIndex < 0 || scanIndex > visualItems->count() -1) {
        return false;
    }
436 437 438 439
    SimpleMissionItem* item = visualItems->value<SimpleMissionItem*>(scanIndex);
    if (item) {
        MissionItem& missionItem = item->missionItem();
        if ((MAV_CMD)item->command() == MAV_CMD_SET_CAMERA_MODE) {
440
            // We specifically don't test param 5/6/7 since we don't have NaN persistence for those fields
441
            if (missionItem.param1() == 0 && (missionItem.param2() == CAMERA_MODE_IMAGE || missionItem.param2() == CAMERA_MODE_VIDEO || missionItem.param2() == CAMERA_MODE_IMAGE_SURVEY) && qIsNaN(missionItem.param3())) {
442 443 444
                setSpecifyCameraMode(true);
                cameraMode()->setRawValue(missionItem.param2());
                visualItems->removeAt(scanIndex)->deleteLater();
445
                return true;
446
            }
447 448
        }
    }
449

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
    return false;
}

bool CameraSection::scanForSection(QmlObjectListModel* visualItems, int scanIndex)
{
    bool foundGimbal = false;
    bool foundCameraAction = false;
    bool foundCameraMode = false;

    qCDebug(CameraSectionLog) << "CameraSection::scanForCameraSection visualItems->count():scanIndex;" << visualItems->count() << scanIndex;

    if (!_available || scanIndex >= visualItems->count()) {
        return false;
    }

    // Scan through the initial mission items for possible mission settings

    while (visualItems->count() > scanIndex) {
        if (!foundGimbal && _scanGimbal(visualItems, scanIndex)) {
            foundGimbal = true;
            continue;
        }
        if (!foundCameraAction && _scanTakePhoto(visualItems, scanIndex)) {
            foundCameraAction = true;
            continue;
        }
        if (!foundCameraAction && _scanTakePhotosIntervalTime(visualItems, scanIndex)) {
            foundCameraAction = true;
            continue;
        }
480 481
        if (!foundCameraAction && scanStopTakingPhotos(visualItems, scanIndex, true /* removeScannedItems */)) {
            cameraAction()->setRawValue(StopTakingPhotos);
482 483 484
            foundCameraAction = true;
            continue;
        }
485 486 487 488 489
        if (!foundCameraAction && _scanTriggerStartDistance(visualItems, scanIndex)) {
            foundCameraAction = true;
            continue;
        }
        if (!foundCameraAction && _scanTriggerStopDistance(visualItems, scanIndex)) {
490 491 492 493 494 495 496
            foundCameraAction = true;
            continue;
        }
        if (!foundCameraAction && _scanTakeVideo(visualItems, scanIndex)) {
            foundCameraAction = true;
            continue;
        }
497 498
        if (!foundCameraAction && scanStopTakingVideo(visualItems, scanIndex, true /* removeScannedItems */)) {
            cameraAction()->setRawValue(StopTakingVideo);
499 500 501 502 503 504
            foundCameraAction = true;
            continue;
        }
        if (!foundCameraMode && _scanSetCameraMode(visualItems, scanIndex)) {
            foundCameraMode = true;
            continue;
505
        }
506
        break;
507 508
    }

509
    qCDebug(CameraSectionLog) << "CameraSection::scanForCameraSection foundGimbal:foundCameraAction:foundCameraMode;" << foundGimbal << foundCameraAction << foundCameraMode;
510

511
    _settingsSpecified = foundGimbal || foundCameraAction || foundCameraMode;
512 513
    emit settingsSpecifiedChanged(_settingsSpecified);

514
    return _settingsSpecified;
515 516 517 518 519 520 521
}

void CameraSection::_setDirty(void)
{
    setDirty(true);
}

522
void CameraSection::_setDirtyAndUpdateItemCount(void)
523
{
524
    emit itemCountChanged(itemCount());
525 526 527 528 529 530 531 532 533 534
    setDirty(true);
}

void CameraSection::setAvailable(bool available)
{
    if (_available != available) {
        _available = available;
        emit availableChanged(available);
    }
}
DonLakeFlyer's avatar
DonLakeFlyer committed
535 536 537 538 539 540

double CameraSection::specifiedGimbalYaw(void) const
{
    return _specifyGimbal ? _gimbalYawFact.rawValue().toDouble() : std::numeric_limits<double>::quiet_NaN();
}

541 542 543 544 545
double CameraSection::specifiedGimbalPitch(void) const
{
    return _specifyGimbal ? _gimbalPitchFact.rawValue().toDouble() : std::numeric_limits<double>::quiet_NaN();
}

DonLakeFlyer's avatar
DonLakeFlyer committed
546 547
void CameraSection::_updateSpecifiedGimbalYaw(void)
{
548 549 550 551 552 553 554 555 556 557
    if (_specifyGimbal) {
        emit specifiedGimbalYawChanged(specifiedGimbalYaw());
    }
}

void CameraSection::_updateSpecifiedGimbalPitch(void)
{
    if (_specifyGimbal) {
        emit specifiedGimbalPitchChanged(specifiedGimbalPitch());
    }
DonLakeFlyer's avatar
DonLakeFlyer committed
558
}
559 560 561

void CameraSection::_updateSettingsSpecified(void)
{
562
    bool newSettingsSpecified = _specifyGimbal || _specifyCameraMode || _cameraActionFact.rawValue().toInt() != CameraActionNone;
563 564 565 566 567 568
    if (newSettingsSpecified != _settingsSpecified) {
        _settingsSpecified = newSettingsSpecified;
        emit settingsSpecifiedChanged(newSettingsSpecified);
    }
}

569
void CameraSection::_specifyChanged(void)
570 571 572 573 574 575 576 577 578 579
{
    _setDirtyAndUpdateItemCount();
    _updateSettingsSpecified();
}

void CameraSection::_cameraActionChanged(void)
{
    _setDirtyAndUpdateItemCount();
    _updateSettingsSpecified();
}
580 581 582

bool CameraSection::cameraModeSupported(void) const
{
583
    return _specifyCameraMode || _masterController->controllerVehicle()->firmwarePlugin()->supportedMissionCommands(QGCMAVLink::VehicleClassGeneric).contains(MAV_CMD_SET_CAMERA_MODE);
584
}
585 586 587 588 589 590 591 592

void CameraSection::_dirtyIfSpecified(void)
{
    // We only set the dirty bit if specify gimbal it set. This allows us to change defaults without affecting dirty.
    if (_specifyGimbal) {
        setDirty(true);
    }
}