diff --git a/src/JsonHelper.cc b/src/JsonHelper.cc index e6ee750e0f44769d45351262b46c9207a8457830..8d44bcb09c68b0e3791de3abb073976314b964cc 100644 --- a/src/JsonHelper.cc +++ b/src/JsonHelper.cc @@ -102,6 +102,10 @@ bool JsonHelper::validateKeyTypes(const QJsonObject& jsonObject, const QStringLi QString valueKey = keys[i]; if (jsonObject.contains(valueKey)) { const QJsonValue& jsonValue = jsonObject[valueKey]; + if (types[i] == QJsonValue::Null && jsonValue.type() == QJsonValue::Double) { + // Null type signals a NaN on a double value + continue; + } if (jsonValue.type() != types[i]) { errorString = QObject::tr("Incorrect value type - key:type:expected %1:%2:%3").arg(valueKey).arg(_jsonValueTypeToString(jsonValue.type())).arg(_jsonValueTypeToString(types[i])); return false; @@ -342,3 +346,12 @@ void JsonHelper::savePolygon(QmlObjectListModel& list, QJsonArray& polygonArray) polygonArray.append(jsonValue); } } + +double JsonHelper::possibleNaNJsonValue(const QJsonValue& value) +{ + if (value.type() == QJsonValue::Null) { + return std::numeric_limits::quiet_NaN(); + } else { + return value.toDouble(); + } +} diff --git a/src/JsonHelper.h b/src/JsonHelper.h index dd6f7aa329e454fd767603471345d350780593eb..8f88dceab43ae08fd85e888edd44fc049c8826c1 100644 --- a/src/JsonHelper.h +++ b/src/JsonHelper.h @@ -34,20 +34,30 @@ public: /// jsonFileTypeKey - Required and checked to be equal to expectedFileType /// jsonVersionKey - Required and checked to be below supportedMajorVersion, supportedMinorVersion /// jsonGroundStationKey - Required and checked to be string type - /// @return false: validation failed - static bool validateQGCJsonFile(const QJsonObject& jsonObject, ///< root json object + /// @return false: validation failed, errorString set + static bool validateQGCJsonFile(const QJsonObject& jsonObject, ///< json object to validate const QString& expectedFileType, ///< correct file type for file int minSupportedVersion, ///< minimum supported version int maxSupportedVersion, ///< maximum supported major version int &version, ///< returned file version QString& errorString); ///< returned error string if validation fails - static bool validateRequiredKeys(const QJsonObject& jsonObject, const QStringList& keys, QString& errorString); - static bool validateKeyTypes(const QJsonObject& jsonObject, const QStringList& keys, const QList& types, QString& errorString); + /// Validates that the specified keys are in the object + /// @return false: validation failed, errorString set + static bool validateRequiredKeys(const QJsonObject& jsonObject, ///< json object to validate + const QStringList& keys, ///< keys which are required to be present + QString& errorString); ///< returned error string if validation fails + + /// Validates the types of specified keys are in the object + /// @return false: validation failed, errorString set + static bool validateKeyTypes(const QJsonObject& jsonObject, ///< json object to validate + const QStringList& keys, ///< keys to validate + const QList& types, ///< required type for each key, QJsonValue::Null specifies double with possible NaN + QString& errorString); ///< returned error string if validation fails typedef struct { const char* key; ///< json key name - QJsonValue::Type type; ///< type of key + QJsonValue::Type type; ///< required type for key, QJsonValue::Null specifies double with possible NaN bool required; ///< true: key must be present } KeyValidateInfo; @@ -96,6 +106,8 @@ public: static bool parseEnum(const QJsonObject& jsonObject, QStringList& enumStrings, QStringList& enumValues, QString& errorString); + /// Returns NaN if the value is null, or it not the double value + static double possibleNaNJsonValue(const QJsonValue& value); static const char* jsonVersionKey; static const char* jsonGroundStationKey; diff --git a/src/MissionManager/MavCmdInfoCommon.json b/src/MissionManager/MavCmdInfoCommon.json index 8ba01705bb4d55a6087ec9b62de666abd26f2928..1d6cc1f38b5ebdf607adecf767fd8c0414c7c6ee 100644 --- a/src/MissionManager/MavCmdInfoCommon.json +++ b/src/MissionManager/MavCmdInfoCommon.json @@ -54,6 +54,7 @@ "label": "Heading", "units": "radians", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -75,6 +76,7 @@ "label": "Heading", "units": "radians", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -101,6 +103,7 @@ "label": "Heading", "units": "radians", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -157,6 +160,7 @@ "label": "Heading", "units": "radians", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -178,6 +182,7 @@ "label": "Heading", "units": "radians", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -316,6 +321,7 @@ "label": "Heading", "units": "deg", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, @@ -331,6 +337,7 @@ "label": "Heading", "units": "deg", "nanUnchanged": true, + "default": null, "decimalPlaces": 2 } }, diff --git a/src/MissionManager/MissionCommandUIInfo.cc b/src/MissionManager/MissionCommandUIInfo.cc index 8e9b1e3bb1260b60497c9b8b946ae84b59ee9808..ad63a6b1d77006ce0e45f9e87ea6ffe017f8e1ee 100644 --- a/src/MissionManager/MissionCommandUIInfo.cc +++ b/src/MissionManager/MissionCommandUIInfo.cc @@ -334,7 +334,7 @@ bool MissionCommandUIInfo::loadJsonInfo(const QJsonObject& jsonObject, bool requ // Validate key types QList types; - types << QJsonValue::Double << QJsonValue::Double << QJsonValue::String << QJsonValue::String << QJsonValue::String << QJsonValue::String << QJsonValue::Bool; + types << QJsonValue::Null << QJsonValue::Double << QJsonValue::String << QJsonValue::String << QJsonValue::String << QJsonValue::String << QJsonValue::Bool; if (!JsonHelper::validateKeyTypes(jsonObject, allParamKeys, types, internalError)) { errorString = _loadErrorString(internalError); return false; @@ -358,7 +358,15 @@ bool MissionCommandUIInfo::loadJsonInfo(const QJsonObject& jsonObject, bool requ paramInfo->_nanUnchanged = paramObject.value(_nanUnchangedJsonKey).toBool(false); if (paramObject.contains(_defaultJsonKey)) { - paramInfo->_defaultValue = paramObject.value(_defaultJsonKey).toDouble(0.0); + if (paramInfo->_nanUnchanged) { + paramInfo->_defaultValue = JsonHelper::possibleNaNJsonValue(paramObject[_defaultJsonKey]); + } else { + if (paramObject[_defaultJsonKey].type() == QJsonValue::Null) { + errorString = QString("Param %1 default value was null/NaN but NaN is not allowed"); + return false; + } + paramInfo->_defaultValue = paramObject.value(_defaultJsonKey).toDouble(0.0); + } } else { paramInfo->_defaultValue = paramInfo->_nanUnchanged ? std::numeric_limits::quiet_NaN() : 0; } diff --git a/src/MissionManager/MissionItem.cc b/src/MissionManager/MissionItem.cc index 80f9effb6263bb291b28bf5ae4b7943d7253b85b..c5bc12c030490bf4bb2d6f2c4708ed4a04a26891 100644 --- a/src/MissionManager/MissionItem.cc +++ b/src/MissionManager/MissionItem.cc @@ -260,6 +260,13 @@ bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& err return false; } + for (int i=0; i<4; i++) { + if (rgParams[i].type() != QJsonValue::Double && rgParams[i].type() != QJsonValue::Null) { + errorString = tr("Param %1 incorrect type %2, must be double or null").arg(i+1).arg(rgParams[i].type()); + return false; + } + } + // Make sure to set these first since they can signal other changes setFrame((MAV_FRAME)v2Json[_jsonFrameKey].toInt()); setCommand((MAV_CMD)v2Json[_jsonCommandKey].toInt()); @@ -280,10 +287,10 @@ bool MissionItem::load(const QJsonObject& json, int sequenceNumber, QString& err setSequenceNumber(sequenceNumber); setAutoContinue(v2Json[_jsonAutoContinueKey].toBool()); - setParam1(rgParams[0].toDouble()); - setParam2(rgParams[1].toDouble()); - setParam3(rgParams[2].toDouble()); - setParam4(rgParams[3].toDouble()); + setParam1(JsonHelper::possibleNaNJsonValue(rgParams[0])); + setParam2(JsonHelper::possibleNaNJsonValue(rgParams[1])); + setParam3(JsonHelper::possibleNaNJsonValue(rgParams[2])); + setParam4(JsonHelper::possibleNaNJsonValue(rgParams[3])); return true; }