diff --git a/src/MissionManager/MissionItem.cc b/src/MissionManager/MissionItem.cc index c5bc12c030490bf4bb2d6f2c4708ed4a04a26891..7696e0439d22ba9f2fa5b2c652ae5af516cb4a06 100644 --- a/src/MissionManager/MissionItem.cc +++ b/src/MissionManager/MissionItem.cc @@ -162,12 +162,8 @@ void MissionItem::save(QJsonObject& json) const json[_jsonAutoContinueKey] = autoContinue(); json[_jsonDoJumpIdKey] = _sequenceNumber; - QJsonArray rgParams = { param1(), param2(), param3(), param4() }; + QJsonArray rgParams = { param1(), param2(), param3(), param4(), param5(), param6(), param7() }; json[_jsonParamsKey] = rgParams; - - QJsonValue coordinateValue; - JsonHelper::saveGeoCoordinate(QGeoCoordinate(param5(), param6(), param7()), true /* writeAltitude */, coordinateValue); - json[_jsonCoordinateKey] = coordinateValue; } bool MissionItem::load(QTextStream &loadStream) @@ -229,10 +225,46 @@ bool MissionItem::_convertJsonV1ToV2(const QJsonObject& json, QJsonObject& v2Jso return true; } +bool MissionItem::_convertJsonV2ToV3(QJsonObject& json, QString& errorString) +{ + // V2 format: param 5/6/7 stored in GeoCoordinate + // V3 format: param 5/6/7 stored in params array + + if (!json.contains(_jsonCoordinateKey)) { + // Already V3 format + return true; + } + + QList keyInfoList = { + { _jsonCoordinateKey, QJsonValue::Array, true }, + }; + if (!JsonHelper::validateKeys(json, keyInfoList, errorString)) { + return false; + } + + QGeoCoordinate coordinate; + if (!JsonHelper::loadGeoCoordinate(json[_jsonCoordinateKey], true /* altitudeRequired */, coordinate, errorString)) { + return false; + } + + QJsonArray rgParam = json[_jsonParamsKey].toArray(); + rgParam.append(coordinate.latitude()); + rgParam.append(coordinate.longitude()); + rgParam.append(coordinate.altitude()); + json[_jsonParamsKey] = rgParam; + + json.remove(_jsonCoordinateKey); + + return true; +} + bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& errorString) { - QJsonObject v2Json; - if (!_convertJsonV1ToV2(json, v2Json, errorString)) { + QJsonObject convertedJson; + if (!_convertJsonV1ToV2(json, convertedJson, errorString)) { + return false; + } + if (!_convertJsonV2ToV3(convertedJson, errorString)) { return false; } @@ -242,21 +274,20 @@ bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& err { _jsonCommandKey, QJsonValue::Double, true }, { _jsonParamsKey, QJsonValue::Array, true }, { _jsonAutoContinueKey, QJsonValue::Bool, true }, - { _jsonCoordinateKey, QJsonValue::Array, true }, { _jsonDoJumpIdKey, QJsonValue::Double, false }, }; - if (!JsonHelper::validateKeys(v2Json, keyInfoList, errorString)) { + if (!JsonHelper::validateKeys(convertedJson, keyInfoList, errorString)) { return false; } - if (v2Json[VisualMissionItem::jsonTypeKey] != VisualMissionItem::jsonTypeSimpleItemValue) { - errorString = tr("Type found: %1 must be: %2").arg(v2Json[VisualMissionItem::jsonTypeKey].toString()).arg(VisualMissionItem::jsonTypeSimpleItemValue); + if (convertedJson[VisualMissionItem::jsonTypeKey] != VisualMissionItem::jsonTypeSimpleItemValue) { + errorString = tr("Type found: %1 must be: %2").arg(convertedJson[VisualMissionItem::jsonTypeKey].toString()).arg(VisualMissionItem::jsonTypeSimpleItemValue); return false; } - QJsonArray rgParams = v2Json[_jsonParamsKey].toArray(); - if (rgParams.count() != 4) { - errorString = tr("%1 key must contains 4 values").arg(_jsonParamsKey); + QJsonArray rgParams = convertedJson[_jsonParamsKey].toArray(); + if (rgParams.count() != 7) { + errorString = tr("%1 key must contains 7 values").arg(_jsonParamsKey); return false; } @@ -268,29 +299,24 @@ bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& err } // Make sure to set these first since they can signal other changes - setFrame((MAV_FRAME)v2Json[_jsonFrameKey].toInt()); - setCommand((MAV_CMD)v2Json[_jsonCommandKey].toInt()); - - QGeoCoordinate coordinate; - if (!JsonHelper::loadGeoCoordinate(v2Json[_jsonCoordinateKey], true /* altitudeRequired */, coordinate, errorString)) { - return false; - } - setParam5(coordinate.latitude()); - setParam6(coordinate.longitude()); - setParam7(coordinate.altitude()); + setFrame((MAV_FRAME)convertedJson[_jsonFrameKey].toInt()); + setCommand((MAV_CMD)convertedJson[_jsonCommandKey].toInt()); _doJumpId = -1; - if (v2Json.contains(_jsonDoJumpIdKey)) { - _doJumpId = v2Json[_jsonDoJumpIdKey].toInt(); + if (convertedJson.contains(_jsonDoJumpIdKey)) { + _doJumpId = convertedJson[_jsonDoJumpIdKey].toInt(); } setIsCurrentItem(false); setSequenceNumber(sequenceNumber); - setAutoContinue(v2Json[_jsonAutoContinueKey].toBool()); + setAutoContinue(convertedJson[_jsonAutoContinueKey].toBool()); setParam1(JsonHelper::possibleNaNJsonValue(rgParams[0])); setParam2(JsonHelper::possibleNaNJsonValue(rgParams[1])); setParam3(JsonHelper::possibleNaNJsonValue(rgParams[2])); setParam4(JsonHelper::possibleNaNJsonValue(rgParams[3])); + setParam5(JsonHelper::possibleNaNJsonValue(rgParams[4])); + setParam6(JsonHelper::possibleNaNJsonValue(rgParams[5])); + setParam7(JsonHelper::possibleNaNJsonValue(rgParams[6])); return true; } diff --git a/src/MissionManager/MissionItem.h b/src/MissionManager/MissionItem.h index da2693319e6e43c2e56f4f5286249e2d3ddd809d..78e07593aac0604214d072b890350fb6a60a2f52 100644 --- a/src/MissionManager/MissionItem.h +++ b/src/MissionManager/MissionItem.h @@ -114,6 +114,7 @@ private slots: private: bool _convertJsonV1ToV2(const QJsonObject& json, QJsonObject& v2Json, QString& errorString); + bool _convertJsonV2ToV3(QJsonObject& json, QString& errorString); int _sequenceNumber; int _doJumpId; @@ -134,10 +135,12 @@ private: static const char* _jsonFrameKey; static const char* _jsonCommandKey; static const char* _jsonAutoContinueKey; - static const char* _jsonCoordinateKey; static const char* _jsonParamsKey; static const char* _jsonDoJumpIdKey; + // Deprecated V2 format keys + static const char* _jsonCoordinateKey; + // Deprecated V1 format keys static const char* _jsonParam1Key; static const char* _jsonParam2Key; diff --git a/src/MissionManager/MissionItemTest.cc b/src/MissionManager/MissionItemTest.cc index 812dda95c1c561017fa0a5347df10cbdabd5465b..fd4ab52f65faf3bfead644157a578f046cd9d2fb 100644 --- a/src/MissionManager/MissionItemTest.cc +++ b/src/MissionManager/MissionItemTest.cc @@ -241,20 +241,30 @@ void MissionItemTest::_testFactSignals(void) QCOMPARE(arguments.at(0).toDouble(), 8.0); } -void MissionItemTest::_checkExpectedMissionItem(const MissionItem& missionItem) +void MissionItemTest::_checkExpectedMissionItem(const MissionItem& missionItem, bool allNaNs) { QCOMPARE(missionItem.sequenceNumber(), _seq); QCOMPARE(missionItem.isCurrentItem(), false); QCOMPARE(missionItem.frame(), (MAV_FRAME)3); QCOMPARE(missionItem.command(), (MAV_CMD)80); - QCOMPARE(missionItem.param1(), 10.0); - QCOMPARE(missionItem.param2(), 20.0); - QCOMPARE(missionItem.param3(), 30.0); - QCOMPARE(missionItem.param4(), 40.0); - QCOMPARE(missionItem.param5(), -10.0); - QCOMPARE(missionItem.param6(), -20.0); - QCOMPARE(missionItem.param7(), -30.0); QCOMPARE(missionItem.autoContinue(), true); + if (allNaNs) { + QVERIFY(qIsNaN(missionItem.param1())); + QVERIFY(qIsNaN(missionItem.param2())); + QVERIFY(qIsNaN(missionItem.param3())); + QVERIFY(qIsNaN(missionItem.param4())); + QVERIFY(qIsNaN(missionItem.param5())); + QVERIFY(qIsNaN(missionItem.param6())); + QVERIFY(qIsNaN(missionItem.param7())); + } else { + QCOMPARE(missionItem.param1(), 10.0); + QCOMPARE(missionItem.param2(), 20.0); + QCOMPARE(missionItem.param3(), 30.0); + QCOMPARE(missionItem.param4(), 40.0); + QCOMPARE(missionItem.param5(), -10.0); + QCOMPARE(missionItem.param6(), -20.0); + QCOMPARE(missionItem.param7(), -30.0); + } } void MissionItemTest::_testLoadFromStream(void) @@ -285,21 +295,9 @@ void MissionItemTest::_testLoadFromJsonV1(void) { MissionItem missionItem; QString errorString; - QJsonArray coordinateArray; - coordinateArray << -10.0 << -20.0 <<-30.0; - QJsonObject jsonObject; - jsonObject.insert(MissionItem::_jsonAutoContinueKey, true); - jsonObject.insert(MissionItem::_jsonCommandKey, 80); - jsonObject.insert(MissionItem::_jsonFrameKey, 3); - jsonObject.insert(MissionItem::_jsonParam1Key, 10); - jsonObject.insert(MissionItem::_jsonParam2Key, 20); - jsonObject.insert(MissionItem::_jsonParam3Key, 30); - jsonObject.insert(MissionItem::_jsonParam4Key, 40); - jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue); - jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray); + QJsonObject jsonObject = _createV1Json(); - - // We only need to test the differences between V1 and V2 + // V1 format has param 1-4 in seperate items instead of in params array QStringList removeKeys; removeKeys << MissionItem::_jsonParam1Key << MissionItem::_jsonParam2Key << MissionItem::_jsonParam3Key << MissionItem::_jsonParam4Key; @@ -313,7 +311,11 @@ void MissionItemTest::_testLoadFromJsonV1(void) // Test good load - QVERIFY(missionItem.load(jsonObject, _seq, errorString)); + bool success = missionItem.load(jsonObject, _seq, errorString); + if (!success) { + qDebug() << errorString; + } + QVERIFY(success); _checkExpectedMissionItem(missionItem); } @@ -321,27 +323,12 @@ void MissionItemTest::_testLoadFromJsonV2(void) { MissionItem missionItem; QString errorString; - QJsonArray coordinateArray; - coordinateArray << -10.0 << -20.0 <<-30.0; - QJsonObject jsonObject; - jsonObject.insert(MissionItem::_jsonAutoContinueKey, true); - jsonObject.insert(MissionItem::_jsonCommandKey, 80); - jsonObject.insert(MissionItem::_jsonFrameKey, 3); - jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue); - jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray); - - QJsonArray rgParams = { 10, 20, 30, 40 }; - jsonObject.insert(MissionItem::_jsonParamsKey, rgParams); + QJsonObject jsonObject = _createV2Json(); // Test missing key detection QStringList removeKeys; - removeKeys << MissionItem::_jsonAutoContinueKey << - MissionItem::_jsonCommandKey << - MissionItem::_jsonFrameKey << - MissionItem::_jsonParamsKey << - VisualMissionItem::jsonTypeKey << - MissionItem::_jsonCoordinateKey; + removeKeys << MissionItem::_jsonCoordinateKey; foreach(const QString& removeKey, removeKeys) { QJsonObject badObject = jsonObject; badObject.remove(removeKey); @@ -388,11 +375,50 @@ void MissionItemTest::_testLoadFromJsonV2(void) QVERIFY(!errorString.isEmpty()); qDebug() << errorString; - // Test bad type + // Test good load + bool result = missionItem.load(jsonObject, _seq, errorString); + if (!result) { + qDebug() << errorString; + QVERIFY(result); + } + _checkExpectedMissionItem(missionItem); +} + +void MissionItemTest::_testLoadFromJsonV3(void) +{ + MissionItem missionItem; + QString errorString; + QJsonObject jsonObject = _createV3Json(); + + // Test missing key detection + + QStringList removeKeys; + removeKeys << MissionItem::_jsonAutoContinueKey << + MissionItem::_jsonCommandKey << + MissionItem::_jsonFrameKey << + MissionItem::_jsonParamsKey << + VisualMissionItem::jsonTypeKey; + foreach(const QString& removeKey, removeKeys) { + QJsonObject badObject = jsonObject; + badObject.remove(removeKey); + QCOMPARE(missionItem.load(badObject, _seq, errorString), false); + QVERIFY(!errorString.isEmpty()); + qDebug() << errorString; + } + + // Bad type + QJsonObject badObject = jsonObject; + badObject[VisualMissionItem::jsonTypeKey] = "foo"; + QCOMPARE(missionItem.load(badObject, _seq, errorString), false); + QVERIFY(!errorString.isEmpty()); + qDebug() << errorString; + + // Incorrect param count badObject = jsonObject; - badObject.remove("type"); - badObject["type"] = "foo"; + QJsonArray rgParam = badObject[MissionItem::_jsonParamsKey].toArray(); + rgParam.removeFirst(); + badObject[MissionItem::_jsonParamsKey] = rgParam; QCOMPARE(missionItem.load(badObject, _seq, errorString), false); QVERIFY(!errorString.isEmpty()); qDebug() << errorString; @@ -407,6 +433,20 @@ void MissionItemTest::_testLoadFromJsonV2(void) _checkExpectedMissionItem(missionItem); } +void MissionItemTest::_testLoadFromJsonV3NaN(void) +{ + MissionItem missionItem; + QString errorString; + QJsonObject jsonObject = _createV3Json(true /* allNaNs */); + + bool result = missionItem.load(jsonObject, _seq, errorString); + if (!result) { + qDebug() << errorString; + QVERIFY(result); + } + _checkExpectedMissionItem(missionItem, true /* allNaNs */); +} + void MissionItemTest::_testSimpleLoadFromJson(void) { // We specifically test SimpleMissionItem loading as well since it has additional @@ -434,36 +474,75 @@ void MissionItemTest::_testSimpleLoadFromJson(void) void MissionItemTest::_testSaveToJson(void) { MissionItem missionItem; + QString errorString; - missionItem.setSequenceNumber(_seq); - missionItem.setIsCurrentItem(true); - missionItem.setFrame((MAV_FRAME)3); - missionItem.setCommand((MAV_CMD)80); - missionItem.setParam1(10.1234567); - missionItem.setParam2(20.1234567); - missionItem.setParam3(30.1234567); - missionItem.setParam4(40.1234567); - missionItem.setParam5(-10.1234567); - missionItem.setParam6(-20.1234567); - missionItem.setParam7(-30.1234567); - missionItem.setAutoContinue(true); - - // Round trip item - QJsonObject jsonObject; - QString errorString; + QJsonObject jsonObject = _createV3Json(false /* allNaNs */); + QVERIFY(missionItem.load(jsonObject, _seq, errorString)); missionItem.save(jsonObject); + QCOMPARE(jsonObject.contains(MissionItem::_jsonCoordinateKey), false); QVERIFY(missionItem.load(jsonObject, _seq, errorString)); + _checkExpectedMissionItem(missionItem, false /* allNaNs */); - QCOMPARE(missionItem.sequenceNumber(), _seq); - QCOMPARE(missionItem.isCurrentItem(), false); - QCOMPARE(missionItem.frame(), (MAV_FRAME)3); - QCOMPARE(missionItem.command(), (MAV_CMD)80); - QCOMPARE(missionItem.param1(), 10.1234567); - QCOMPARE(missionItem.param2(), 20.1234567); - QCOMPARE(missionItem.param3(), 30.1234567); - QCOMPARE(missionItem.param4(), 40.1234567); - QCOMPARE(missionItem.param5(), -10.1234567); - QCOMPARE(missionItem.param6(), -20.1234567); - QCOMPARE(missionItem.param7(), -30.1234567); - QCOMPARE(missionItem.autoContinue(), true); + jsonObject = _createV3Json(true /* allNaNs */); + QVERIFY(missionItem.load(jsonObject, _seq, errorString)); + missionItem.save(jsonObject); + QVERIFY(missionItem.load(jsonObject, _seq, errorString)); + _checkExpectedMissionItem(missionItem, true /* allNaNs */); +} + +QJsonObject MissionItemTest::_createV1Json(void) +{ + QJsonObject jsonObject; + QJsonArray coordinateArray; + + coordinateArray << -10.0 << -20.0 <<-30.0; + jsonObject.insert(MissionItem::_jsonAutoContinueKey, true); + jsonObject.insert(MissionItem::_jsonCommandKey, 80); + jsonObject.insert(MissionItem::_jsonFrameKey, 3); + jsonObject.insert(MissionItem::_jsonParam1Key, 10); + jsonObject.insert(MissionItem::_jsonParam2Key, 20); + jsonObject.insert(MissionItem::_jsonParam3Key, 30); + jsonObject.insert(MissionItem::_jsonParam4Key, 40); + jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue); + jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray); + + return jsonObject; +} + +QJsonObject MissionItemTest::_createV2Json(void) +{ + QJsonObject jsonObject; + QJsonArray coordinateArray; + + coordinateArray << -10.0 << -20.0 <<-30.0; + jsonObject.insert(MissionItem::_jsonAutoContinueKey, true); + jsonObject.insert(MissionItem::_jsonCommandKey, 80); + jsonObject.insert(MissionItem::_jsonFrameKey, 3); + jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue); + jsonObject.insert(MissionItem::_jsonCoordinateKey, coordinateArray); + + QJsonArray rgParams = { 10, 20, 30, 40 }; + jsonObject.insert(MissionItem::_jsonParamsKey, rgParams); + + return jsonObject; +} + +QJsonObject MissionItemTest::_createV3Json(bool allNaNs) +{ + QJsonObject jsonObject; + + jsonObject.insert(MissionItem::_jsonAutoContinueKey, true); + jsonObject.insert(MissionItem::_jsonCommandKey, 80); + jsonObject.insert(MissionItem::_jsonFrameKey, 3); + jsonObject.insert(VisualMissionItem::jsonTypeKey, VisualMissionItem::jsonTypeSimpleItemValue); + + if (allNaNs) { + QJsonArray rgParams = { NAN, NAN, NAN, NAN, NAN, NAN, NAN }; + jsonObject.insert(MissionItem::_jsonParamsKey, rgParams); + } else { + QJsonArray rgParams = { 10, 20, 30, 40, -10, -20, -30 }; + jsonObject.insert(MissionItem::_jsonParamsKey, rgParams); + } + + return jsonObject; } diff --git a/src/MissionManager/MissionItemTest.h b/src/MissionManager/MissionItemTest.h index 2c477249189e9979e8b301d222c5abbe5c9fba3d..7a4d6fad659259e00fa59a24f239de8bfc9d9476 100644 --- a/src/MissionManager/MissionItemTest.h +++ b/src/MissionManager/MissionItemTest.h @@ -35,11 +35,16 @@ private slots: void _testSimpleLoadFromStream(void); void _testLoadFromJsonV1(void); void _testLoadFromJsonV2(void); + void _testLoadFromJsonV3(void); + void _testLoadFromJsonV3NaN(void); void _testSimpleLoadFromJson(void); void _testSaveToJson(void); private: - void _checkExpectedMissionItem(const MissionItem& missionItem); + void _checkExpectedMissionItem(const MissionItem& missionItem, bool allNaNs = false); + QJsonObject _createV1Json(void); + QJsonObject _createV2Json(void); + QJsonObject _createV3Json(bool allNaNs = false); int _seq = 10; Vehicle* _offlineVehicle;