diff --git a/src/FactSystem/Fact.cc b/src/FactSystem/Fact.cc index 18ffe8682655628267d9c82a38d285af1560dee9..c5046bbf5029fbd8ca17b6e12aad1593b1af0d29 100644 --- a/src/FactSystem/Fact.cc +++ b/src/FactSystem/Fact.cc @@ -147,15 +147,20 @@ void Fact::setCookedValue(const QVariant& value) } } -void Fact::setEnumStringValue(const QString& value) +int Fact::valueIndex(const QString& value) { if (_metaData) { - int index = _metaData->enumStrings().indexOf(value); - if (index != -1) { - setCookedValue(_metaData->enumValues()[index]); - } - } else { - qWarning() << kMissingMetadata << name(); + return _metaData->enumStrings().indexOf(value); + } + qWarning() << kMissingMetadata << name(); + return -1; +} + +void Fact::setEnumStringValue(const QString& value) +{ + int index = valueIndex(value); + if (index != -1) { + setCookedValue(_metaData->enumValues()[index]); } } diff --git a/src/FactSystem/Fact.h b/src/FactSystem/Fact.h index 7faf62cb34abf134dfd947694cde48b3d0af1047..1490595d061e87c232396c7babf49d264814881c 100644 --- a/src/FactSystem/Fact.h +++ b/src/FactSystem/Fact.h @@ -138,6 +138,7 @@ public: void setCookedValue (const QVariant& value); void setEnumIndex (int index); void setEnumStringValue (const QString& value); + int valueIndex (const QString& value); // The following methods allow you to defer sending of the valueChanged signals in order to implement // rate limited signalling for ui performance. Used by FactGroup for example. diff --git a/src/Taisync/TaisyncManager.cc b/src/Taisync/TaisyncManager.cc index 49b775e8b7e021a93b7f7395294dc2d40a218179..e5b6a877bee01157366bee614a4272da930b5afd 100644 --- a/src/Taisync/TaisyncManager.cc +++ b/src/Taisync/TaisyncManager.cc @@ -13,13 +13,12 @@ #include "QGCApplication.h" #include "VideoManager.h" +static const char *kTAISYNC_GROUP = "Taisync"; static const char *kRADIO_MODE = "RadioMode"; -static const char *kRadioModeValues[] = { - "auto", - "manual" -}; - static const char *kRADIO_CHANNEL = "RadioChannel"; +static const char *kVIDEO_OUTPUT = "VideoOutput"; +static const char *kVIDEO_MODE = "VideoMode"; +static const char *kVIDEO_RATE = "VideoRate"; //----------------------------------------------------------------------------- TaisyncManager::TaisyncManager(QGCApplication* app, QGCToolbox* toolbox) @@ -27,20 +26,6 @@ TaisyncManager::TaisyncManager(QGCApplication* app, QGCToolbox* toolbox) { connect(&_workTimer, &QTimer::timeout, this, &TaisyncManager::_checkTaisync); _workTimer.setSingleShot(true); - _decodeList.append(tr("Stream")); - _decodeList.append(tr("HDMI Port")); - _rateList.append(tr("Low")); - _rateList.append(tr("Medium")); - _rateList.append(tr("High")); -} - -//----------------------------------------------------------------------------- -void -TaisyncManager::_radioSettingsChanged(QVariant) -{ - if(_taiSettings) { - _taiSettings->setRadioSettings(kRadioModeValues[_radioMode->rawValue().toInt()], _radioChannel->enumStringValue()); - } } //----------------------------------------------------------------------------- @@ -97,6 +82,25 @@ TaisyncManager::_reset() } } +//----------------------------------------------------------------------------- +FactMetaData* +TaisyncManager::_createMetadata(const char* name, QStringList enums) +{ + FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, name, this); + QQmlEngine::setObjectOwnership(metaData, QQmlEngine::CppOwnership); + metaData->setShortDescription(name); + metaData->setLongDescription(name); + metaData->setRawDefaultValue(QVariant(0)); + metaData->setHasControl(true); + metaData->setReadOnly(false); + for(int i = 0; i < enums.size(); i++) { + metaData->addEnumInfo(enums[i], QVariant(i)); + } + metaData->setRawMin(0); + metaData->setRawMin(enums.size() - 1); + return metaData; +} + //----------------------------------------------------------------------------- void TaisyncManager::setToolbox(QGCToolbox* toolbox) @@ -104,50 +108,87 @@ TaisyncManager::setToolbox(QGCToolbox* toolbox) QGCTool::setToolbox(toolbox); { //-- Radio Mode - FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, kRADIO_MODE, this); - QQmlEngine::setObjectOwnership(metaData, QQmlEngine::CppOwnership); - metaData->setShortDescription(kRADIO_MODE); - metaData->setLongDescription(kRADIO_MODE); - metaData->setRawDefaultValue(QVariant(0)); - metaData->setHasControl(true); - metaData->setReadOnly(false); - metaData->addEnumInfo(tr("Auto"), QVariant(0)); - metaData->addEnumInfo(tr("Manual"), QVariant(1)); - _radioMode = new Fact("Taisync", metaData, this); + QStringList enums; + enums.append(tr("Auto")); + enums.append(tr("Manual")); + FactMetaData* metaData = _createMetadata(kRADIO_MODE, enums); + _radioMode = new Fact(kTAISYNC_GROUP, metaData, this); QQmlEngine::setObjectOwnership(_radioMode, QQmlEngine::CppOwnership); - connect(_radioMode, &Fact::rawValueChanged, this, &TaisyncManager::_radioSettingsChanged); + _radioModeList.append("auto"); + _radioModeList.append("manual"); + connect(_radioMode, &Fact::_containerRawValueChanged, this, &TaisyncManager::_radioSettingsChanged); } { //-- Radio Channel - FactMetaData* metaData = new FactMetaData(FactMetaData::valueTypeUint32, kRADIO_CHANNEL, this); - QQmlEngine::setObjectOwnership(metaData, QQmlEngine::CppOwnership); - metaData->setShortDescription(kRADIO_CHANNEL); - metaData->setLongDescription(kRADIO_CHANNEL); - metaData->setRawDefaultValue(QVariant(0)); - metaData->setHasControl(true); - metaData->setReadOnly(false); + QStringList enums; for(int i = 0; i < 13; i++) { - metaData->addEnumInfo(QString("ch%1").arg(i), QVariant(i)); + enums.append(QString("ch%1").arg(i)); } - _radioChannel = new Fact("Taisync", metaData, this); + FactMetaData* metaData = _createMetadata(kRADIO_CHANNEL, enums); + _radioChannel = new Fact(kTAISYNC_GROUP, metaData, this); QQmlEngine::setObjectOwnership(_radioChannel, QQmlEngine::CppOwnership); - connect(_radioChannel, &Fact::rawValueChanged, this, &TaisyncManager::_radioSettingsChanged); + connect(_radioChannel, &Fact::_containerRawValueChanged, this, &TaisyncManager::_radioSettingsChanged); + } + { + //-- Video Output + QStringList enums; + enums.append(tr("Stream")); + enums.append(tr("HDMI Port")); + FactMetaData* metaData = _createMetadata(kVIDEO_OUTPUT, enums); + _videoOutput = new Fact(kTAISYNC_GROUP, metaData, this); + QQmlEngine::setObjectOwnership(_videoOutput, QQmlEngine::CppOwnership); + _videoOutputList.append("phone"); + _videoOutputList.append("hdmi"); + connect(_videoOutput, &Fact::_containerRawValueChanged, this, &TaisyncManager::_videoSettingsChanged); + } + { + //-- Video Mode + QStringList enums; + enums.append("H264"); + enums.append("H265"); + FactMetaData* metaData = _createMetadata(kVIDEO_MODE, enums); + _videoMode = new Fact(kTAISYNC_GROUP, metaData, this); + QQmlEngine::setObjectOwnership(_videoMode, QQmlEngine::CppOwnership); + connect(_videoMode, &Fact::_containerRawValueChanged, this, &TaisyncManager::_videoSettingsChanged); + } + { + //-- Video Rate + QStringList enums; + enums.append(tr("Low")); + enums.append(tr("Medium")); + enums.append(tr("High")); + FactMetaData* metaData = _createMetadata(kVIDEO_RATE, enums); + _videoRate = new Fact(kTAISYNC_GROUP, metaData, this); + QQmlEngine::setObjectOwnership(_videoRate, QQmlEngine::CppOwnership); + _videoRateList.append("low"); + _videoRateList.append("middle"); + _videoRateList.append("high"); + connect(_videoRate, &Fact::_containerRawValueChanged, this, &TaisyncManager::_videoSettingsChanged); } _reset(); } //----------------------------------------------------------------------------- void -TaisyncManager::setDecodeIndex(int idx) +TaisyncManager::_radioSettingsChanged(QVariant) { - (void)idx; + if(_taiSettings) { + _taiSettings->setRadioSettings( + _radioModeList[_radioMode->rawValue().toInt()], + _radioChannel->enumStringValue()); + } } //----------------------------------------------------------------------------- void -TaisyncManager::setRateIndex(int idx) +TaisyncManager::_videoSettingsChanged(QVariant) { - (void)idx; + if(_taiSettings) { + _taiSettings->setVideoSettings( + _videoOutputList[_videoOutput->rawValue().toInt()], + _videoMode->enumStringValue(), + _videoRateList[_videoRate->rawValue().toInt()]); + } } //----------------------------------------------------------------------------- @@ -314,6 +355,7 @@ TaisyncManager::_checkTaisync() void TaisyncManager::_updateSettings(QByteArray jSonData) { + qCDebug(TaisyncVerbose) << jSonData; QJsonParseError jsonParseError; QJsonDocument doc = QJsonDocument::fromJson(jSonData, &jsonParseError); if (jsonParseError.error != QJsonParseError::NoError) { @@ -348,14 +390,20 @@ TaisyncManager::_updateSettings(QByteArray jSonData) } //-- Radio Settings? } else if(jSonData.contains("\"freq\":")) { - QString mode = jObj["mode"].toString(_radioMode->enumStringValue()); - QString channel = jObj["freq"].toString(_radioChannel->enumStringValue()); - _radioMode->_containerSetRawValue(mode); - _radioChannel->_containerSetRawValue(channel); + int idx = _radioModeList.indexOf(jObj["mode"].toString(_radioMode->enumStringValue())); + if(idx >= 0) _radioMode->_containerSetRawValue(idx); + idx = _radioChannel->valueIndex(jObj["freq"].toString(_radioChannel->enumStringValue())); + if(idx < 0) idx = 0; + _radioChannel->_containerSetRawValue(idx); //-- Video Settings? } else if(jSonData.contains("\"maxbitrate\":")) { - //{\"decode\":\"phone\",\"mode\":\"h264\",\"maxbitrate\":\"high\"} - - + int idx; + idx = _videoMode->valueIndex(jObj["mode"].toString(_videoMode->enumStringValue())); + if(idx < 0) idx = 0; + _videoMode->_containerSetRawValue(idx); + idx = _videoRateList.indexOf(jObj["maxbitrate"].toString(_videoMode->enumStringValue())); + if(idx >= 0) _videoRate->_containerSetRawValue(idx); + idx = _videoOutputList.indexOf(jObj["decode"].toString(_videoOutput->enumStringValue())); + if(idx >= 0) _videoOutput->_containerSetRawValue(idx); } } diff --git a/src/Taisync/TaisyncManager.h b/src/Taisync/TaisyncManager.h index 36715fffcce1333784b3971e2903f3ee7488125b..00e1bebab848678e8605e543b5a0e9d0c93619d2 100644 --- a/src/Taisync/TaisyncManager.h +++ b/src/Taisync/TaisyncManager.h @@ -36,12 +36,11 @@ public: Q_PROPERTY(int downlinkRSSI READ downlinkRSSI NOTIFY linkChanged) Q_PROPERTY(QString serialNumber READ serialNumber NOTIFY infoChanged) Q_PROPERTY(QString fwVersion READ fwVersion NOTIFY infoChanged) - Q_PROPERTY(QStringList decodeList READ decodeList NOTIFY decodeIndexChanged) - Q_PROPERTY(int decodeIndex READ decodeIndex WRITE setDecodeIndex NOTIFY decodeIndexChanged) - Q_PROPERTY(QStringList rateList READ rateList NOTIFY rateIndexChanged) - Q_PROPERTY(int rateIndex READ rateIndex WRITE setRateIndex NOTIFY rateIndexChanged) Q_PROPERTY(Fact* radioMode READ radioMode CONSTANT) Q_PROPERTY(Fact* radioChannel READ radioChannel CONSTANT) + Q_PROPERTY(Fact* videoOutput READ videoOutput CONSTANT) + Q_PROPERTY(Fact* videoMode READ videoMode CONSTANT) + Q_PROPERTY(Fact* videoRate READ videoRate CONSTANT) explicit TaisyncManager (QGCApplication* app, QGCToolbox* toolbox); ~TaisyncManager () override; @@ -55,14 +54,11 @@ public: int downlinkRSSI () { return _uplinkRSSI; } QString serialNumber () { return _serialNumber; } QString fwVersion () { return _fwVersion; } - QStringList decodeList () { return _decodeList; } - int decodeIndex () { return _decodeIndex; } - void setDecodeIndex (int idx); - QStringList rateList () { return _rateList; } - int rateIndex () { return _rateIndex; } - void setRateIndex (int idx); Fact* radioMode () { return _radioMode; } Fact* radioChannel () { return _radioChannel; } + Fact* videoOutput () { return _videoOutput; } + Fact* videoMode () { return _videoMode; } + Fact* videoRate () { return _videoRate; } signals: void linkChanged (); @@ -80,6 +76,7 @@ private slots: void _setEnabled (); void _setVideoEnabled (); void _radioSettingsChanged (QVariant); + void _videoSettingsChanged (QVariant); #if defined(__ios__) || defined(__android__) void _readUDPBytes (); void _readTelemBytes (QByteArray bytesIn); @@ -88,6 +85,7 @@ private slots: private: void _close (); void _reset (); + FactMetaData *_createMetadata (const char *name, QStringList enums); private: @@ -130,4 +128,10 @@ private: QString _fwVersion; Fact* _radioMode = nullptr; Fact* _radioChannel = nullptr; + Fact* _videoOutput = nullptr; + Fact* _videoMode = nullptr; + Fact* _videoRate = nullptr; + QStringList _radioModeList; + QStringList _videoOutputList; + QStringList _videoRateList; }; diff --git a/src/Taisync/TaisyncSettings.cc b/src/Taisync/TaisyncSettings.cc index 98d00193b0e86af9e987115a4bba6aa5491cb81b..22da201614fea0661d1e7d3a1901370e3e165ebb 100644 --- a/src/Taisync/TaisyncSettings.cc +++ b/src/Taisync/TaisyncSettings.cc @@ -21,6 +21,7 @@ static const char* kPostReq = static const char* kGetReq = "GET %1 HTTP/1.1\r\n\r\n"; static const char* kRadioURI = "/v1/radio.json"; +static const char* kVideoURI = "/v1/video.json"; //----------------------------------------------------------------------------- TaisyncSettings::TaisyncSettings(QObject* parent) @@ -64,7 +65,7 @@ TaisyncSettings::requestFreqScan() bool TaisyncSettings::requestVideoSettings() { - return _request("/v1/video.json"); + return _request(kVideoURI); } //----------------------------------------------------------------------------- @@ -93,7 +94,7 @@ TaisyncSettings::_post(const QString& post, const QString &postPayload) { if(_tcpSocket) { QString req = QString(kPostReq).arg(post).arg(postPayload.size()).arg(postPayload); - qCDebug(TaisyncVerbose) << "Request" << req; + qCDebug(TaisyncVerbose) << "Post" << req; _tcpSocket->write(req.toUtf8()); return true; } @@ -105,10 +106,19 @@ bool TaisyncSettings::setRadioSettings(const QString& mode, const QString& channel) { static const char* kRadioPost = "{\"mode\":\"%1\",\"freq\":\"%2\"}"; - QString post = QString(kRadioPost).arg(mode.size()).arg(channel); + QString post = QString(kRadioPost).arg(mode).arg(channel); return _post(kRadioURI, post); } +//----------------------------------------------------------------------------- +bool +TaisyncSettings::setVideoSettings(const QString& output, const QString& mode, const QString& rate) +{ + static const char* kVideoPost = "{\"decode\":\"%1\",\"mode\":\"%2\",\"maxbitrate\":\"%3\"}"; + QString post = QString(kVideoPost).arg(output).arg(mode).arg(rate); + return _post(kVideoURI, post); +} + //----------------------------------------------------------------------------- void TaisyncSettings::_readBytes() diff --git a/src/Taisync/TaisyncSettings.h b/src/Taisync/TaisyncSettings.h index bb2f40789013739f76ddb432190e53553133138e..5fc710795497bbdba119117b90615794f6d0be47 100644 --- a/src/Taisync/TaisyncSettings.h +++ b/src/Taisync/TaisyncSettings.h @@ -23,6 +23,7 @@ public: bool requestVideoSettings (); bool requestRadioSettings (); bool setRadioSettings (const QString& mode, const QString& channel); + bool setVideoSettings (const QString& output, const QString& mode, const QString& rate); signals: void updateSettings (QByteArray jSonData); diff --git a/src/Taisync/TaisyncSettings.qml b/src/Taisync/TaisyncSettings.qml index 30a34af1f155cbe63bcbe9dde0e91cc470f31e60..7575b618d264372e1f07e453557b268bd1ef3468 100644 --- a/src/Taisync/TaisyncSettings.qml +++ b/src/Taisync/TaisyncSettings.qml @@ -166,7 +166,7 @@ QGCView { height: devInfoLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter - visible: _taisyncEnabled + visible: _taisyncEnabled && QGroundControl.taisyncManager.connected QGCLabel { id: devInfoLabel text: qsTr("Device Info") @@ -177,7 +177,7 @@ QGCView { height: devInfoCol.height + (ScreenTools.defaultFontPixelHeight * 2) width: _panelWidth color: qgcPal.windowShade - visible: _taisyncEnabled + visible: _taisyncEnabled && QGroundControl.taisyncManager.connected anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter Column { @@ -214,7 +214,7 @@ QGCView { height: radioSettingsLabel.height anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter - visible: _taisyncEnabled + visible: _taisyncEnabled && QGroundControl.taisyncManager.linkConnected QGCLabel { id: radioSettingsLabel text: qsTr("Radio Settings") @@ -225,7 +225,7 @@ QGCView { height: radioSettingsCol.height + (ScreenTools.defaultFontPixelHeight * 2) width: _panelWidth color: qgcPal.windowShade - visible: _taisyncEnabled + visible: _taisyncEnabled && QGroundControl.taisyncManager.linkConnected anchors.margins: ScreenTools.defaultFontPixelWidth anchors.horizontalCenter: parent.horizontalCenter Column { @@ -260,6 +260,68 @@ QGCView { } } } + //----------------------------------------------------------------- + //-- Video Settings + Item { + width: _panelWidth + height: videoSettingsLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + visible: _taisyncEnabled && QGroundControl.taisyncManager.linkConnected + QGCLabel { + id: videoSettingsLabel + text: qsTr("Video Settings") + font.family: ScreenTools.demiboldFontFamily + } + } + Rectangle { + height: videoSettingsCol.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + visible: _taisyncEnabled && QGroundControl.taisyncManager.linkConnected + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Column { + id: videoSettingsCol + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + width: parent.width + anchors.centerIn: parent + GridLayout { + anchors.margins: ScreenTools.defaultFontPixelHeight + columnSpacing: ScreenTools.defaultFontPixelWidth * 2 + anchors.horizontalCenter: parent.horizontalCenter + columns: 2 + QGCLabel { + text: qsTr("Video Output:") + Layout.minimumWidth: _labelWidth + } + FactComboBox { + fact: QGroundControl.taisyncManager.videoOutput + indexModel: true + enabled: QGroundControl.taisyncManager.linkConnected + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Encoder:") + } + FactComboBox { + fact: QGroundControl.taisyncManager.videoMode + indexModel: true + enabled: QGroundControl.taisyncManager.linkConnected + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Bit Rate:") + } + FactComboBox { + fact: QGroundControl.taisyncManager.videoRate + indexModel: true + enabled: QGroundControl.taisyncManager.linkConnected + Layout.minimumWidth: _valueWidth + } + } + } + } } } }