diff --git a/src/Camera/QGCCameraControl.cc b/src/Camera/QGCCameraControl.cc index db28ecd8c74e727703987044ea96652b54b2841e..627fbefffeccc41fe0e1a53878de5356817ea5e9 100644 --- a/src/Camera/QGCCameraControl.cc +++ b/src/Camera/QGCCameraControl.cc @@ -28,6 +28,8 @@ static const char* kExclusion = "exclude"; static const char* kExclusions = "exclusions"; static const char* kLocale = "locale"; static const char* kLocalization = "localization"; +static const char* kMax = "max"; +static const char* kMin = "min"; static const char* kModel = "model"; static const char* kName = "name"; static const char* kOption = "option"; @@ -39,9 +41,11 @@ static const char* kParameterranges = "parameterranges"; static const char* kParameters = "parameters"; static const char* kReadOnly = "readonly"; static const char* kRoption = "roption"; +static const char* kStep = "step"; static const char* kStrings = "strings"; static const char* kTranslated = "translated"; static const char* kType = "type"; +static const char* kUnit = "unit"; static const char* kUpdate = "update"; static const char* kUpdates = "updates"; static const char* kValue = "value"; @@ -671,6 +675,61 @@ QGCCameraControl::_loadSettings(const QDomNodeList nodeList) qWarning() << QStringLiteral("Duplicate fact name:") << factName; delete metaData; } else { + { + //-- Check for Min Value + QString attr; + if(read_attribute(parameterNode, kMin, attr)) { + QVariant typedValue; + QString errorString; + if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) { + metaData->setRawMin(typedValue); + } else { + qWarning() << "Invalid min value for" << factName + << " type:" << metaData->type() + << " value:" << attr + << " error:" << errorString; + } + } + } + { + //-- Check for Max Value + QString attr; + if(read_attribute(parameterNode, kMax, attr)) { + QVariant typedValue; + QString errorString; + if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) { + metaData->setRawMax(typedValue); + } else { + qWarning() << "Invalid max value for" << factName + << " type:" << metaData->type() + << " value:" << attr + << " error:" << errorString; + } + } + } + { + //-- Check for Step Value + QString attr; + if(read_attribute(parameterNode, kStep, attr)) { + QVariant typedValue; + QString errorString; + if (metaData->convertAndValidateRaw(attr, true /* convertOnly */, typedValue, errorString)) { + metaData->setIncrement(typedValue.toDouble()); + } else { + qWarning() << "Invalid step value for" << factName + << " type:" << metaData->type() + << " value:" << attr + << " error:" << errorString; + } + } + } + { + //-- Check for Units + QString attr; + if(read_attribute(parameterNode, kUnit, attr)) { + metaData->setRawUnits(attr); + } + } qCDebug(CameraControlLog) << "New parameter:" << factName; _nameToFactMetaDataMap[factName] = metaData; Fact* pFact = new Fact(_compID, factName, factType, this); diff --git a/src/FactSystem/Fact.cc b/src/FactSystem/Fact.cc index 172262fd8d70fcc58a23191dc32fec0a7a92167d..6086ee381d11233939b2ed8c40b1396374f6f512 100644 --- a/src/FactSystem/Fact.cc +++ b/src/FactSystem/Fact.cc @@ -191,28 +191,30 @@ int Fact::enumIndex(void) { static const double accuracy = 1.0 / 1000000.0; if (_metaData) { - int index = 0; - foreach (QVariant enumValue, _metaData->enumValues()) { - if (enumValue == rawValue()) { - return index; - } - //-- Float comparissons don't always work - if(type() == FactMetaData::valueTypeFloat || type() == FactMetaData::valueTypeDouble) { - double diff = fabs(enumValue.toDouble() - rawValue().toDouble()); - if(diff < accuracy) { + //-- Only enums have an index + if(_metaData->enumValues().count()) { + int index = 0; + foreach (QVariant enumValue, _metaData->enumValues()) { + if (enumValue == rawValue()) { return index; } + //-- Float comparissons don't always work + if(type() == FactMetaData::valueTypeFloat || type() == FactMetaData::valueTypeDouble) { + double diff = fabs(enumValue.toDouble() - rawValue().toDouble()); + if(diff < accuracy) { + return index; + } + } + index ++; } - index ++; + // Current value is not in list, add it manually + _metaData->addEnumInfo(QString("Unknown: %1").arg(rawValue().toString()), rawValue()); + emit enumsChanged(); + return index; } - // Current value is not in list, add it manually - _metaData->addEnumInfo(QString("Unknown: %1").arg(rawValue().toString()), rawValue()); - emit enumsChanged(); - return index; } else { qWarning() << kMissingMetadata; } - return -1; } @@ -537,6 +539,22 @@ QString Fact::validate(const QString& cookedValue, bool convertOnly) } } +QVariant Fact::clamp(const QString& cookedValue) +{ + if (_metaData) { + QVariant typedValue; + if(_metaData->clampValue(cookedValue, typedValue)) { + return typedValue; + } else { + //-- If conversion failed, return current value + return rawValue(); + } + } else { + qWarning() << kMissingMetadata; + } + return QVariant(); +} + bool Fact::rebootRequired(void) const { if (_metaData) { diff --git a/src/FactSystem/Fact.h b/src/FactSystem/Fact.h index e3aa09b88cbcb902386dafaac4eba11a3449d4cd..b8693b86c3308cf70f5df2b21b39ccf23db5b167 100644 --- a/src/FactSystem/Fact.h +++ b/src/FactSystem/Fact.h @@ -70,6 +70,8 @@ public: /// Convert and validate value /// @param convertOnly true: validate type conversion only, false: validate against meta data as well Q_INVOKABLE QString validate(const QString& cookedValue, bool convertOnly); + /// Convert and clamp value + Q_INVOKABLE QVariant clamp(const QString& cookedValue); QVariant cookedValue (void) const; /// Value after translation QVariant rawValue (void) const { return _rawValue; } /// value prior to translation, careful diff --git a/src/FactSystem/FactMetaData.cc b/src/FactSystem/FactMetaData.cc index 34e2a8f8ccb9f44b7985a86bbac77936ee1d0443..a29bc63872f1269d3bb3b349b6fb0f588aa81be1 100644 --- a/src/FactSystem/FactMetaData.cc +++ b/src/FactSystem/FactMetaData.cc @@ -398,6 +398,67 @@ bool FactMetaData::convertAndValidateCooked(const QVariant& cookedValue, bool co return convertOk && errorString.isEmpty(); } +bool FactMetaData::clampValue(const QVariant& cookedValue, QVariant& typedValue) +{ + bool convertOk = false; + switch (type()) { + case FactMetaData::valueTypeInt8: + case FactMetaData::valueTypeInt16: + case FactMetaData::valueTypeInt32: + typedValue = QVariant(cookedValue.toInt(&convertOk)); + if (convertOk) { + if (cookedMin() > typedValue) { + typedValue = cookedMin(); + } else if(typedValue > cookedMax()) { + typedValue = cookedMax(); + } + } + break; + case FactMetaData::valueTypeUint8: + case FactMetaData::valueTypeUint16: + case FactMetaData::valueTypeUint32: + typedValue = QVariant(cookedValue.toUInt(&convertOk)); + if (convertOk) { + if (cookedMin() > typedValue) { + typedValue = cookedMin(); + } else if(typedValue > cookedMax()) { + typedValue = cookedMax(); + } + } + break; + case FactMetaData::valueTypeFloat: + typedValue = QVariant(cookedValue.toFloat(&convertOk)); + if (convertOk) { + if (cookedMin() > typedValue) { + typedValue = cookedMin(); + } else if(typedValue > cookedMax()) { + typedValue = cookedMax(); + } + } + break; + case FactMetaData::valueTypeElapsedTimeInSeconds: + case FactMetaData::valueTypeDouble: + typedValue = QVariant(cookedValue.toDouble(&convertOk)); + if (convertOk) { + if (cookedMin() > typedValue) { + typedValue = cookedMin(); + } else if(typedValue > cookedMax()) { + typedValue = cookedMax(); + } + } + break; + case FactMetaData::valueTypeString: + convertOk = true; + typedValue = QVariant(cookedValue.toString()); + break; + case FactMetaData::valueTypeBool: + convertOk = true; + typedValue = QVariant(cookedValue.toBool()); + break; + } + return convertOk; +} + void FactMetaData::setBitmaskInfo(const QStringList& strings, const QVariantList& values) { if (strings.count() != values.count()) { diff --git a/src/FactSystem/FactMetaData.h b/src/FactSystem/FactMetaData.h index 70751011685eb3a7a288334ff3e24a6f002a22e3..6f11c589b9509d5bdc63feda559a2b5135ae7b05 100644 --- a/src/FactSystem/FactMetaData.h +++ b/src/FactSystem/FactMetaData.h @@ -145,6 +145,12 @@ public: /// Same as convertAndValidateRaw except for cookedValue input bool convertAndValidateCooked(const QVariant& cookedValue, bool convertOnly, QVariant& typedValue, QString& errorString); + /// Converts the specified cooked value and clamps it (max/min) + /// @param cookedValue Value to convert, can be string + /// @param typeValue Converted value, correctly typed and clamped + /// @returns false: Convertion failed + bool clampValue(const QVariant& cookedValue, QVariant& typedValue); + static const int defaultDecimalPlaces = 3; ///< Default value for decimal places if not specified/known static const int unknownDecimalPlaces = -1; ///< Number of decimal places to specify is not known diff --git a/src/VideoStreaming/VideoReceiver.cc b/src/VideoStreaming/VideoReceiver.cc index c82b3d3e7c84a8d6a35fd8e24848a34156151670..beaa5b8cb0d85e35dbc1abac1178d95389943a2b 100644 --- a/src/VideoStreaming/VideoReceiver.cc +++ b/src/VideoStreaming/VideoReceiver.cc @@ -768,7 +768,10 @@ VideoReceiver::_updateTimer() } } if(_videoRunning) { - uint32_t timeout = qgcApp()->toolbox()->settingsManager()->videoSettings()->rtspTimeout()->rawValue().toUInt(); + uint32_t timeout = 1; + if(qgcApp()->toolbox() && qgcApp()->toolbox()->settingsManager()) { + timeout = qgcApp()->toolbox()->settingsManager()->videoSettings()->rtspTimeout()->rawValue().toUInt(); + } time_t elapsed = 0; time_t lastFrame = _videoSurface->lastFrame(); if(lastFrame != 0) {