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


11 12 13
#include <QStringList>
#include <QDebug>

14
#include "SimpleMissionItem.h"
15 16 17
#include "FirmwarePluginManager.h"
#include "QGCApplication.h"
#include "JsonHelper.h"
18 19
#include "MissionCommandTree.h"
#include "MissionCommandUIInfo.h"
20
#include "QGroundControlQmlGlobal.h"
21
#include "SettingsManager.h"
22

Don Gagne's avatar
Don Gagne committed
23 24 25 26 27 28
FactMetaData* SimpleMissionItem::_altitudeMetaData =        NULL;
FactMetaData* SimpleMissionItem::_commandMetaData =         NULL;
FactMetaData* SimpleMissionItem::_defaultParamMetaData =    NULL;
FactMetaData* SimpleMissionItem::_frameMetaData =           NULL;
FactMetaData* SimpleMissionItem::_latitudeMetaData =        NULL;
FactMetaData* SimpleMissionItem::_longitudeMetaData =       NULL;
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

struct EnumInfo_s {
    const char *    label;
    MAV_FRAME       frame;
};

static const struct EnumInfo_s _rgMavFrameInfo[] = {
{ "MAV_FRAME_GLOBAL",                   MAV_FRAME_GLOBAL },
{ "MAV_FRAME_LOCAL_NED",                MAV_FRAME_LOCAL_NED },
{ "MAV_FRAME_MISSION",                  MAV_FRAME_MISSION },
{ "MAV_FRAME_GLOBAL_RELATIVE_ALT",      MAV_FRAME_GLOBAL_RELATIVE_ALT },
{ "MAV_FRAME_LOCAL_ENU",                MAV_FRAME_LOCAL_ENU },
{ "MAV_FRAME_GLOBAL_INT",               MAV_FRAME_GLOBAL_INT },
{ "MAV_FRAME_GLOBAL_RELATIVE_ALT_INT",  MAV_FRAME_GLOBAL_RELATIVE_ALT_INT },
{ "MAV_FRAME_LOCAL_OFFSET_NED",         MAV_FRAME_LOCAL_OFFSET_NED },
{ "MAV_FRAME_BODY_NED",                 MAV_FRAME_BODY_NED },
{ "MAV_FRAME_BODY_OFFSET_NED",          MAV_FRAME_BODY_OFFSET_NED },
{ "MAV_FRAME_GLOBAL_TERRAIN_ALT",       MAV_FRAME_GLOBAL_TERRAIN_ALT },
{ "MAV_FRAME_GLOBAL_TERRAIN_ALT_INT",   MAV_FRAME_GLOBAL_TERRAIN_ALT_INT },
};
49 50

SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, QObject* parent)
51 52
    : VisualMissionItem(vehicle, parent)
    , _rawEdit(false)
53 54
    , _dirty(false)
    , _cameraSection(NULL)
55
    , _commandTree(qgcApp()->toolbox()->missionCommandTree())
56 57 58 59 60 61 62 63 64 65 66
    , _altitudeRelativeToHomeFact   (0, "Altitude is relative to home", FactMetaData::valueTypeUint32)
    , _supportedCommandFact         (0, "Command:",                     FactMetaData::valueTypeUint32)
    , _param1MetaData(FactMetaData::valueTypeDouble)
    , _param2MetaData(FactMetaData::valueTypeDouble)
    , _param3MetaData(FactMetaData::valueTypeDouble)
    , _param4MetaData(FactMetaData::valueTypeDouble)
    , _param5MetaData(FactMetaData::valueTypeDouble)
    , _param6MetaData(FactMetaData::valueTypeDouble)
    , _param7MetaData(FactMetaData::valueTypeDouble)
    , _syncingAltitudeRelativeToHomeAndFrame    (false)
    , _syncingHeadingDegreesAndParam4           (false)
67
{
Don Gagne's avatar
Don Gagne committed
68
    _editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");
69

70
    _altitudeRelativeToHomeFact.setRawValue(true);
71

72 73
    _setupMetaData();
    _connectSignals();
74
    _updateCameraSection();
75 76

    setDefaultsForCommand();
77

DonLakeFlyer's avatar
DonLakeFlyer committed
78
    connect(&_missionItem, &MissionItem::specifiedFlightSpeedChanged, this, &SimpleMissionItem::specifiedFlightSpeedChanged);
79 80 81 82

    connect(this, &SimpleMissionItem::sequenceNumberChanged,    this, &SimpleMissionItem::lastSequenceNumberChanged);
    connect(this, &SimpleMissionItem::cameraSectionChanged,     this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(this, &SimpleMissionItem::cameraSectionChanged,     this, &SimpleMissionItem::_updateLastSequenceNumber);
83 84
}

85 86 87 88 89
SimpleMissionItem::SimpleMissionItem(Vehicle* vehicle, const MissionItem& missionItem, QObject* parent)
    : VisualMissionItem(vehicle, parent)
    , _missionItem(missionItem)
    , _rawEdit(false)
    , _dirty(false)
90
    , _cameraSection(NULL)
91
    , _commandTree(qgcApp()->toolbox()->missionCommandTree())
92 93 94 95 96 97 98 99 100 101 102
    , _altitudeRelativeToHomeFact   (0, "Altitude is relative to home", FactMetaData::valueTypeUint32)
    , _supportedCommandFact         (0, "Command:",                     FactMetaData::valueTypeUint32)
    , _param1MetaData(FactMetaData::valueTypeDouble)
    , _param2MetaData(FactMetaData::valueTypeDouble)
    , _param3MetaData(FactMetaData::valueTypeDouble)
    , _param4MetaData(FactMetaData::valueTypeDouble)
    , _param5MetaData(FactMetaData::valueTypeDouble)
    , _param6MetaData(FactMetaData::valueTypeDouble)
    , _param7MetaData(FactMetaData::valueTypeDouble)
    , _syncingAltitudeRelativeToHomeAndFrame    (false)
    , _syncingHeadingDegreesAndParam4           (false)
103
{
Don Gagne's avatar
Don Gagne committed
104 105
    _editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");

106 107 108 109
    _altitudeRelativeToHomeFact.setRawValue(true);

    _setupMetaData();
    _connectSignals();
110
    _updateCameraSection();
111

112
    _syncFrameToAltitudeRelativeToHome();
113 114 115
}

SimpleMissionItem::SimpleMissionItem(const SimpleMissionItem& other, QObject* parent)
116 117 118 119
    : VisualMissionItem(other, parent)
    , _missionItem(other._vehicle)
    , _rawEdit(false)
    , _dirty(false)
120
    , _cameraSection(NULL)
121
    , _commandTree(qgcApp()->toolbox()->missionCommandTree())
122 123 124 125 126 127 128 129
    , _altitudeRelativeToHomeFact   (0, "Altitude is relative to home", FactMetaData::valueTypeUint32)
    , _supportedCommandFact         (0, "Command:",                     FactMetaData::valueTypeUint32)
    , _param1MetaData(FactMetaData::valueTypeDouble)
    , _param2MetaData(FactMetaData::valueTypeDouble)
    , _param3MetaData(FactMetaData::valueTypeDouble)
    , _param4MetaData(FactMetaData::valueTypeDouble)
    , _syncingAltitudeRelativeToHomeAndFrame    (false)
    , _syncingHeadingDegreesAndParam4           (false)
130
{
Don Gagne's avatar
Don Gagne committed
131 132
    _editorQml = QStringLiteral("qrc:/qml/SimpleItemEditor.qml");

133 134
    _setupMetaData();
    _connectSignals();
135
    _updateCameraSection();
136

137
    *this = other;
138 139 140 141
}

const SimpleMissionItem& SimpleMissionItem::operator=(const SimpleMissionItem& other)
{
142
    VisualMissionItem::operator=(other);
143 144 145 146 147 148

    setRawEdit(other._rawEdit);
    setDirty(other._dirty);
    setHomePositionSpecialCase(other._homePositionSpecialCase);

    _syncFrameToAltitudeRelativeToHome();
149 150 151

    return *this;
}
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

void SimpleMissionItem::_connectSignals(void)
{
    // Connect to change signals to track dirty state
    connect(&_missionItem._param1Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param2Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param3Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param4Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param5Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param6Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._param7Fact,  &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._frameFact,   &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem._commandFact, &Fact::valueChanged,                    this, &SimpleMissionItem::_setDirtyFromSignal);
    connect(&_missionItem,              &MissionItem::sequenceNumberChanged,    this, &SimpleMissionItem::_setDirtyFromSignal);

Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
167
    // Values from these facts must propagate back and forth between the real object storage
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    connect(&_altitudeRelativeToHomeFact,   &Fact::valueChanged,    this, &SimpleMissionItem::_syncAltitudeRelativeToHomeToFrame);
    connect(&_missionItem._frameFact,       &Fact::valueChanged,    this, &SimpleMissionItem::_syncFrameToAltitudeRelativeToHome);

    // These are coordinate parameters, they must emit coordinateChanged signal
    connect(&_missionItem._param5Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);
    connect(&_missionItem._param6Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);
    connect(&_missionItem._param7Fact, &Fact::valueChanged, this, &SimpleMissionItem::_sendCoordinateChanged);

    // The following changes may also change friendlyEditAllowed
    connect(&_missionItem._autoContinueFact,    &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);
    connect(&_missionItem._commandFact,         &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);
    connect(&_missionItem._frameFact,           &Fact::valueChanged, this, &SimpleMissionItem::_sendFriendlyEditAllowedChanged);

    // A command change triggers a number of other changes as well.
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::setDefaultsForCommand);
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::commandNameChanged);
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::commandDescriptionChanged);
185
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::abbreviationChanged);
186
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesCoordinateChanged);
187
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesAltitudeOnlyChanged);
188 189 190 191 192 193 194 195 196
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::isStandaloneCoordinateChanged);

    // Whenever these properties change the ui model changes as well
    connect(this, &SimpleMissionItem::commandChanged, this, &SimpleMissionItem::_sendUiModelChanged);
    connect(this, &SimpleMissionItem::rawEditChanged, this, &SimpleMissionItem::_sendUiModelChanged);

    // These fact signals must alway signal out through SimpleMissionItem signals
    connect(&_missionItem._commandFact,     &Fact::valueChanged, this, &SimpleMissionItem::_sendCommandChanged);
    connect(&_missionItem._frameFact,       &Fact::valueChanged, this, &SimpleMissionItem::_sendFrameChanged);
197

Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
198
    // Sequence number is kept in mission iteem, so we need to propagate signal up as well
199
    connect(&_missionItem, &MissionItem::sequenceNumberChanged, this, &SimpleMissionItem::sequenceNumberChanged);
200 201 202 203 204 205 206 207 208
}

void SimpleMissionItem::_setupMetaData(void)
{
    QStringList enumStrings;
    QVariantList enumValues;

    if (!_altitudeMetaData) {
        _altitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
209
        _altitudeMetaData->setRawUnits("m");
210 211 212 213
        _altitudeMetaData->setDecimalPlaces(2);

        enumStrings.clear();
        enumValues.clear();
214 215 216 217
        MissionCommandTree* commandTree = qgcApp()->toolbox()->missionCommandTree();
        foreach (const MAV_CMD command, commandTree->allCommandIds()) {
            enumStrings.append(commandTree->rawName(command));
            enumValues.append(QVariant((int)command));
218 219 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
        }
        _commandMetaData = new FactMetaData(FactMetaData::valueTypeUint32);
        _commandMetaData->setEnumInfo(enumStrings, enumValues);

        _defaultParamMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
        _defaultParamMetaData->setDecimalPlaces(7);

        enumStrings.clear();
        enumValues.clear();
        for (size_t i=0; i<sizeof(_rgMavFrameInfo)/sizeof(_rgMavFrameInfo[0]); i++) {
            const struct EnumInfo_s* mavFrameInfo = &_rgMavFrameInfo[i];

            enumStrings.append(mavFrameInfo->label);
            enumValues.append(QVariant(mavFrameInfo->frame));
        }
        _frameMetaData = new FactMetaData(FactMetaData::valueTypeUint32);
        _frameMetaData->setEnumInfo(enumStrings, enumValues);

        _latitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
        _latitudeMetaData->setRawUnits("deg");
        _latitudeMetaData->setDecimalPlaces(7);

        _longitudeMetaData = new FactMetaData(FactMetaData::valueTypeDouble);
        _longitudeMetaData->setRawUnits("deg");
        _longitudeMetaData->setDecimalPlaces(7);

    }

    _missionItem._commandFact.setMetaData(_commandMetaData);
    _missionItem._frameFact.setMetaData(_frameMetaData);
}

SimpleMissionItem::~SimpleMissionItem()
{    
}

254
void SimpleMissionItem::save(QJsonArray&  missionItems)
255
{
256 257 258 259 260 261 262 263 264 265 266
    QList<MissionItem*> items;

    appendMissionItems(items, this);

    for (int i=0; i<items.count(); i++) {
        MissionItem* item = items[i];
        QJsonObject saveObject;
        item->save(saveObject);
        missionItems.append(saveObject);
        item->deleteLater();
    }
267 268 269 270 271 272 273
}

bool SimpleMissionItem::load(QTextStream &loadStream)
{
    return _missionItem.load(loadStream);
}

Don Gagne's avatar
Don Gagne committed
274
bool SimpleMissionItem::load(const QJsonObject& json, int sequenceNumber, QString& errorString)
275
{
Don Gagne's avatar
Don Gagne committed
276
    return _missionItem.load(json, sequenceNumber, errorString);
277 278 279 280
}

bool SimpleMissionItem::isStandaloneCoordinate(void) const
{
281 282 283
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo) {
        return uiInfo->isStandaloneCoordinate();
284 285 286 287 288 289 290
    } else {
        return false;
    }
}

bool SimpleMissionItem::specifiesCoordinate(void) const
{
291 292 293
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo) {
        return uiInfo->specifiesCoordinate();
294 295 296 297 298
    } else {
        return false;
    }
}

299 300 301 302 303 304 305 306 307 308
bool SimpleMissionItem::specifiesAltitudeOnly(void) const
{
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo) {
        return uiInfo->specifiesAltitudeOnly();
    } else {
        return false;
    }
}

309 310
QString SimpleMissionItem::commandDescription(void) const
{
311 312 313
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo) {
        return uiInfo->description();
314 315 316 317 318 319 320 321
    } else {
        qWarning() << "Should not ask for command description on unknown command";
        return commandName();
    }
}

QString SimpleMissionItem::commandName(void) const
{
322 323 324
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo) {
        return uiInfo->friendlyName();
325 326
    } else {
        qWarning() << "Request for command name on unknown command";
327
        return tr("Unknown: %1").arg(command());
328 329 330
    }
}

331 332 333 334 335 336 337
QString SimpleMissionItem::abbreviation() const
{
    if (homePosition())
        return QStringLiteral("H");

    switch(command()) {
    default:
338
        return QString();
339
    case MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF:
340
        return QStringLiteral("Takeoff");
341
    case MavlinkQmlSingleton::MAV_CMD_NAV_LAND:
342
        return QStringLiteral("Land");
343
    case MavlinkQmlSingleton::MAV_CMD_NAV_VTOL_TAKEOFF:
344
        return QStringLiteral("VTOL Takeoff");
345
    case MavlinkQmlSingleton::MAV_CMD_NAV_VTOL_LAND:
346
        return QStringLiteral("VTOL Land");
347 348 349
    }
}

350 351 352
void SimpleMissionItem::_clearParamMetaData(void)
{
    _param1MetaData.setRawUnits("");
353
    _param1MetaData.setDecimalPlaces(FactMetaData::unknownDecimalPlaces);
354
    _param1MetaData.setBuiltInTranslator();
355
    _param2MetaData.setRawUnits("");
356
    _param2MetaData.setDecimalPlaces(FactMetaData::unknownDecimalPlaces);
357
    _param2MetaData.setBuiltInTranslator();
358
    _param3MetaData.setRawUnits("");
359
    _param3MetaData.setDecimalPlaces(FactMetaData::unknownDecimalPlaces);
360
    _param3MetaData.setBuiltInTranslator();
361
    _param4MetaData.setRawUnits("");
362
    _param4MetaData.setDecimalPlaces(FactMetaData::unknownDecimalPlaces);
363
    _param4MetaData.setBuiltInTranslator();
364 365 366 367 368 369 370
}

QmlObjectListModel* SimpleMissionItem::textFieldFacts(void)
{
    QmlObjectListModel* model = new QmlObjectListModel(this);
    
    if (rawEdit()) {
371
        _missionItem._param1Fact._setName("Param1");
372 373
        _missionItem._param1Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param1Fact);
374
        _missionItem._param2Fact._setName("Param2");
375 376
        _missionItem._param2Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param2Fact);
377
        _missionItem._param3Fact._setName("Param3");
378 379
        _missionItem._param3Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param3Fact);
380
        _missionItem._param4Fact._setName("Param4");
381 382
        _missionItem._param4Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param4Fact);
383
        _missionItem._param5Fact._setName("Lat/X");
384 385
        _missionItem._param5Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param5Fact);
386
        _missionItem._param6Fact._setName("Lon/Y");
387 388
        _missionItem._param6Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param6Fact);
389
        _missionItem._param7Fact._setName("Alt/Z");
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
        _missionItem._param7Fact.setMetaData(_defaultParamMetaData);
        model->append(&_missionItem._param7Fact);
    } else {
        _clearParamMetaData();

        MAV_CMD command;
        if (_homePositionSpecialCase) {
            command = MAV_CMD_NAV_LAST;
        } else {
            command = _missionItem.command();
        }

        Fact*           rgParamFacts[7] =       { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
        FactMetaData*   rgParamMetaData[7] =    { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };

405 406
        const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);

407
        for (int i=1; i<=7; i++) {
408
            const MissionCmdParamInfo* paramInfo = uiInfo->getParamInfo(i);
409

410
            if (paramInfo && paramInfo->enumStrings().count() == 0) {
411 412 413 414 415 416 417 418 419 420 421 422
                Fact*               paramFact =     rgParamFacts[i-1];
                FactMetaData*       paramMetaData = rgParamMetaData[i-1];

                paramFact->_setName(paramInfo->label());
                paramMetaData->setDecimalPlaces(paramInfo->decimalPlaces());
                paramMetaData->setEnumInfo(paramInfo->enumStrings(), paramInfo->enumValues());
                paramMetaData->setRawUnits(paramInfo->units());
                paramFact->setMetaData(paramMetaData);
                model->append(paramFact);
            }
        }

423
        if (uiInfo->specifiesCoordinate() || uiInfo->specifiesAltitudeOnly()) {
424
            _missionItem._param7Fact._setName("Altitude");
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
            _missionItem._param7Fact.setMetaData(_altitudeMetaData);
            model->append(&_missionItem._param7Fact);
        }
    }
    
    return model;
}

QmlObjectListModel* SimpleMissionItem::checkboxFacts(void)
{
    QmlObjectListModel* model = new QmlObjectListModel(this);
    

    if (rawEdit()) {
        model->append(&_missionItem._autoContinueFact);
440
    } else if ((specifiesCoordinate() || specifiesAltitudeOnly()) && !_homePositionSpecialCase) {
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
        model->append(&_altitudeRelativeToHomeFact);
    }

    return model;
}

QmlObjectListModel* SimpleMissionItem::comboboxFacts(void)
{
    QmlObjectListModel* model = new QmlObjectListModel(this);

    if (rawEdit()) {
        model->append(&_missionItem._commandFact);
        model->append(&_missionItem._frameFact);
    } else {
        Fact*           rgParamFacts[7] =       { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
        FactMetaData*   rgParamMetaData[7] =    { &_param1MetaData, &_param2MetaData, &_param3MetaData, &_param4MetaData, &_param5MetaData, &_param6MetaData, &_param7MetaData };

        MAV_CMD command;
        if (_homePositionSpecialCase) {
            command = MAV_CMD_NAV_LAST;
        } else {
            command = (MAV_CMD)this->command();
        }

        for (int i=1; i<=7; i++) {
466
            const MissionCmdParamInfo* paramInfo = _commandTree->getUIInfo(_vehicle, command)->getParamInfo(i);
467

468
            if (paramInfo && paramInfo->enumStrings().count() != 0) {
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
                Fact*               paramFact =     rgParamFacts[i-1];
                FactMetaData*       paramMetaData = rgParamMetaData[i-1];

                paramFact->_setName(paramInfo->label());
                paramMetaData->setDecimalPlaces(paramInfo->decimalPlaces());
                paramMetaData->setEnumInfo(paramInfo->enumStrings(), paramInfo->enumValues());
                paramMetaData->setRawUnits(paramInfo->units());
                paramFact->setMetaData(paramMetaData);
                model->append(paramFact);
            }
        }
    }

    return model;
}

bool SimpleMissionItem::friendlyEditAllowed(void) const
{
487 488
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo && uiInfo->friendlyEdit()) {
489 490 491 492
        if (!_missionItem.autoContinue()) {
            return false;
        }

493
        if (specifiesCoordinate() || specifiesAltitudeOnly()) {
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
            return _missionItem.frame() == MAV_FRAME_GLOBAL || _missionItem.frame() == MAV_FRAME_GLOBAL_RELATIVE_ALT;
        }

        return true;
    }

    return false;
}

bool SimpleMissionItem::rawEdit(void) const
{
    return _rawEdit || !friendlyEditAllowed();
}

void SimpleMissionItem::setRawEdit(bool rawEdit)
{
    if (this->rawEdit() != rawEdit) {
        _rawEdit = rawEdit;
        emit rawEditChanged(this->rawEdit());
    }
}

void SimpleMissionItem::setDirty(bool dirty)
{
518
    if (!_homePositionSpecialCase || (_dirty != dirty)) {
519
        _dirty = dirty;
520 521
        _cameraSection->setDirty(false);
        emit dirtyChanged(dirty);
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
    }
}

void SimpleMissionItem::_setDirtyFromSignal(void)
{
    setDirty(true);
}

void SimpleMissionItem::_sendCoordinateChanged(void)
{
    emit coordinateChanged(coordinate());
}

void SimpleMissionItem::_syncAltitudeRelativeToHomeToFrame(const QVariant& value)
{
    if (!_syncingAltitudeRelativeToHomeAndFrame) {
        _syncingAltitudeRelativeToHomeAndFrame = true;
        _missionItem.setFrame(value.toBool() ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL);
        _syncingAltitudeRelativeToHomeAndFrame = false;
    }
}

void SimpleMissionItem::_syncFrameToAltitudeRelativeToHome(void)
{
    if (!_syncingAltitudeRelativeToHomeAndFrame) {
        _syncingAltitudeRelativeToHomeAndFrame = true;
        _altitudeRelativeToHomeFact.setRawValue(relativeAltitude());
        _syncingAltitudeRelativeToHomeAndFrame = false;
    }
}

void SimpleMissionItem::setDefaultsForCommand(void)
{
    // We set these global defaults first, then if there are param defaults they will get reset
556
    _missionItem.setParam7(qgcApp()->toolbox()->settingsManager()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble());
557 558

    MAV_CMD command = (MAV_CMD)this->command();
559 560 561 562 563 564 565 566
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, command);
    if (uiInfo) {
        for (int i=1; i<=7; i++) {
            const MissionCmdParamInfo* paramInfo = uiInfo->getParamInfo(i);
            if (paramInfo) {
                Fact* rgParamFacts[7] = { &_missionItem._param1Fact, &_missionItem._param2Fact, &_missionItem._param3Fact, &_missionItem._param4Fact, &_missionItem._param5Fact, &_missionItem._param6Fact, &_missionItem._param7Fact };
                rgParamFacts[paramInfo->param()-1]->setRawValue(paramInfo->defaultValue());
            }
567 568 569
        }
    }

570 571
    switch (command) {
    case MAV_CMD_NAV_WAYPOINT:
572 573 574
        // We default all acceptance radius to 0. This allows flight controller to be in control of
        // accept radius.
        _missionItem.setParam2(0);
575 576 577 578 579
        break;

    case MAV_CMD_NAV_LAND:
        _missionItem.setParam7(0);
        break;
Donald Gagne's avatar
Donald Gagne committed
580 581
    default:
        break;
582 583 584
    }

    _missionItem.setAutoContinue(true);
585
    _missionItem.setFrame((specifiesCoordinate() || specifiesAltitudeOnly()) ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_MISSION);
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
    setRawEdit(false);
}

void SimpleMissionItem::_sendUiModelChanged(void)
{
    emit uiModelChanged();
}

void SimpleMissionItem::_sendFrameChanged(void)
{
    emit frameChanged(_missionItem.frame());
}

void SimpleMissionItem::_sendCommandChanged(void)
{
    emit commandChanged(command());
}

void SimpleMissionItem::_sendFriendlyEditAllowedChanged(void)
{
    emit friendlyEditAllowedChanged(friendlyEditAllowed());
}

QString SimpleMissionItem::category(void) const
{
611
    return _commandTree->getUIInfo(_vehicle, (MAV_CMD)command())->category();
612 613 614 615 616 617
}

void SimpleMissionItem::setCommand(MavlinkQmlSingleton::Qml_MAV_CMD command)
{
    if ((MAV_CMD)command != _missionItem.command()) {
        _missionItem.setCommand((MAV_CMD)command);
618
        _updateCameraSection();
619 620 621 622 623 624 625 626 627
    }
}

void SimpleMissionItem::setCoordinate(const QGeoCoordinate& coordinate)
{
    if (_missionItem.coordinate() != coordinate) {
        _missionItem.setCoordinate(coordinate);
    }
}
628 629 630

void SimpleMissionItem::setSequenceNumber(int sequenceNumber)
{
631 632 633 634 635 636
    if (_missionItem.sequenceNumber() != sequenceNumber) {
        _missionItem.setSequenceNumber(sequenceNumber);
        emit sequenceNumberChanged(sequenceNumber);
        // This is too likely to ignore
        emit abbreviationChanged();
    }
637
}
638

DonLakeFlyer's avatar
DonLakeFlyer committed
639
double SimpleMissionItem::specifiedFlightSpeed(void)
640
{
DonLakeFlyer's avatar
DonLakeFlyer committed
641 642 643 644 645 646
    return missionItem().specifiedFlightSpeed();
}

double SimpleMissionItem::specifiedGimbalYaw(void)
{
    return _cameraSection->available() ? _cameraSection->specifiedGimbalYaw() : missionItem().specifiedGimbalYaw();
647
}
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677

void SimpleMissionItem::scanForSections(QmlObjectListModel* visualItems, int scanIndex, Vehicle* vehicle)
{
    Q_UNUSED(vehicle);

    qDebug() << "SimpleMissionItem::scanForSections" << scanIndex << _cameraSection->available();

    if (_cameraSection->available()) {
        bool sectionFound = _cameraSection->scanForCameraSection(visualItems, scanIndex);
        qDebug() << sectionFound;
    }
}

void SimpleMissionItem::_updateCameraSection(void)
{
    if (_cameraSection) {
        // Remove previous section
        _cameraSection->deleteLater();
        _cameraSection = NULL;
    }

    // Add new section
    _cameraSection = new CameraSection(this);
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo && uiInfo->cameraSection()) {
        _cameraSection->setAvailable(true);
    }

    connect(_cameraSection, &CameraSection::dirtyChanged,               this, &SimpleMissionItem::_cameraSectionDirtyChanged);
    connect(_cameraSection, &CameraSection::availableChanged,           this, &SimpleMissionItem::_updateLastSequenceNumber);
DonLakeFlyer's avatar
DonLakeFlyer committed
678 679 680 681
    connect(_cameraSection, &CameraSection::missionItemCountChanged,    this, &SimpleMissionItem::_updateLastSequenceNumber);    
    connect(_cameraSection, &CameraSection::availableChanged,           this, &SimpleMissionItem::specifiedGimbalYawChanged);
    connect(_cameraSection, &CameraSection::specifyGimbalChanged,       this, &SimpleMissionItem::specifiedGimbalYawChanged);
    connect(_cameraSection, &CameraSection::specifiedGimbalYawChanged,  this, &SimpleMissionItem::specifiedGimbalYawChanged);
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

    emit cameraSectionChanged(_cameraSection);
}

int SimpleMissionItem::lastSequenceNumber(void) const
{
    return sequenceNumber() + (_cameraSection ? _cameraSection->missionItemCount() : 0);
}

void SimpleMissionItem::_updateLastSequenceNumber(void)
{
    emit lastSequenceNumberChanged(lastSequenceNumber());
}

void SimpleMissionItem::_cameraSectionDirtyChanged(bool dirty)
{
    if (dirty) {
        setDirty(true);
    }
}

void SimpleMissionItem::appendMissionItems(QList<MissionItem*>& items, QObject* missionItemParent)
{
    int seqNum = sequenceNumber();

    items.append(new MissionItem(missionItem(), missionItemParent));
    seqNum++;

    _cameraSection->appendMissionItems(items, missionItemParent, seqNum);
}