SimpleMissionItem.cc 27.5 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 149

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

    _syncFrameToAltitudeRelativeToHome();
150 151 152

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

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
168
    // Values from these facts must propagate back and forth between the real object storage
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    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);
186
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::abbreviationChanged);
187
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesCoordinateChanged);
188
    connect(&_missionItem._commandFact, &Fact::valueChanged, this, &SimpleMissionItem::specifiesAltitudeOnlyChanged);
189 190 191 192 193 194 195 196 197
    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);
198

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

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

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

        enumStrings.clear();
        enumValues.clear();
215 216 217 218
        MissionCommandTree* commandTree = qgcApp()->toolbox()->missionCommandTree();
        foreach (const MAV_CMD command, commandTree->allCommandIds()) {
            enumStrings.append(commandTree->rawName(command));
            enumValues.append(QVariant((int)command));
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 254
        }
        _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()
{    
}

255
void SimpleMissionItem::save(QJsonArray&  missionItems)
256
{
257 258 259 260 261 262 263 264 265 266 267
    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();
    }
268 269 270 271 272 273 274
}

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

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

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

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

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

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

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

332 333 334 335 336 337 338 339 340 341 342 343
QString SimpleMissionItem::abbreviation() const
{
    if (homePosition())
        return QStringLiteral("H");

    switch(command()) {
    default:
        return QString::number(sequenceNumber());
    case MavlinkQmlSingleton::MAV_CMD_NAV_TAKEOFF:
        return QStringLiteral("T");
    case MavlinkQmlSingleton::MAV_CMD_NAV_LAND:
        return QStringLiteral("L");
344 345 346 347
    case MavlinkQmlSingleton::MAV_CMD_NAV_VTOL_TAKEOFF:
        return QStringLiteral("VT");
    case MavlinkQmlSingleton::MAV_CMD_NAV_VTOL_LAND:
        return QStringLiteral("VL");
348 349 350
    }
}

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

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

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

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

411
            if (paramInfo && paramInfo->enumStrings().count() == 0) {
412 413 414 415 416 417 418 419 420 421 422 423
                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);
            }
        }

424
        if (uiInfo->specifiesCoordinate() || uiInfo->specifiesAltitudeOnly()) {
425
            _missionItem._param7Fact._setName("Altitude");
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
            _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);
441
    } else if ((specifiesCoordinate() || specifiesAltitudeOnly()) && !_homePositionSpecialCase) {
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
        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++) {
467
            const MissionCmdParamInfo* paramInfo = _commandTree->getUIInfo(_vehicle, command)->getParamInfo(i);
468

469
            if (paramInfo && paramInfo->enumStrings().count() != 0) {
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
                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
{
488 489
    const MissionCommandUIInfo* uiInfo = _commandTree->getUIInfo(_vehicle, (MAV_CMD)command());
    if (uiInfo && uiInfo->friendlyEdit()) {
490 491 492 493
        if (!_missionItem.autoContinue()) {
            return false;
        }

494
        if (specifiesCoordinate() || specifiesAltitudeOnly()) {
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
            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)
{
519
    if (!_homePositionSpecialCase || (_dirty != dirty)) {
520
        _dirty = dirty;
521 522
        _cameraSection->setDirty(false);
        emit dirtyChanged(dirty);
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
    }
}

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
557
    _missionItem.setParam7(qgcApp()->toolbox()->settingsManager()->appSettings()->defaultMissionItemAltitude()->rawValue().toDouble());
558 559

    MAV_CMD command = (MAV_CMD)this->command();
560 561 562 563 564 565 566 567
    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());
            }
568 569 570
        }
    }

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

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

    _missionItem.setAutoContinue(true);
586
    _missionItem.setFrame((specifiesCoordinate() || specifiesAltitudeOnly()) ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_MISSION);
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    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
{
612
    return _commandTree->getUIInfo(_vehicle, (MAV_CMD)command())->category();
613 614 615 616 617 618
}

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

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

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

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

double SimpleMissionItem::specifiedGimbalYaw(void)
{
    return _cameraSection->available() ? _cameraSection->specifiedGimbalYaw() : missionItem().specifiedGimbalYaw();
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 678

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
679 680 681 682
    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);
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

    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);
}