diff --git a/libs/mavlink/include/mavlink/v2.0 b/libs/mavlink/include/mavlink/v2.0 index 171c83700c6318af9ffb4a7ee733567b55a14543..600bbff722a13cfa61fe053de1da07069bab1d10 160000 --- a/libs/mavlink/include/mavlink/v2.0 +++ b/libs/mavlink/include/mavlink/v2.0 @@ -1 +1 @@ -Subproject commit 171c83700c6318af9ffb4a7ee733567b55a14543 +Subproject commit 600bbff722a13cfa61fe053de1da07069bab1d10 diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 3147c4a2e85eed9ab7854e6deda920835f4461b7..be714830c48ad1067dd1dd1ea48767d29bcee1fa 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -482,6 +482,7 @@ HEADERS += \ src/Settings/AppSettings.h \ src/Settings/AutoConnectSettings.h \ src/Settings/BrandImageSettings.h \ + src/Settings/FirmwareUpgradeSettings.h \ src/Settings/FlightMapSettings.h \ src/Settings/FlyViewSettings.h \ src/Settings/OfflineMapsSettings.h \ @@ -659,6 +660,7 @@ SOURCES += \ src/Settings/AppSettings.cc \ src/Settings/AutoConnectSettings.cc \ src/Settings/BrandImageSettings.cc \ + src/Settings/FirmwareUpgradeSettings.cc \ src/Settings/FlightMapSettings.cc \ src/Settings/FlyViewSettings.cc \ src/Settings/OfflineMapsSettings.cc \ diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 469ed45fc79cf53a5ba323648cda06cf1e8251a7..d5517633cc55309b478d40fddc9302aedd7c3bb3 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -213,8 +213,6 @@ src/Settings/APMMavlinkStreamRate.SettingsGroup.json src/MissionManager/BreachReturn.FactMetaData.json - src/Settings/OfflineMaps.SettingsGroup.json - src/Settings/PlanView.SettingsGroup.json src/Settings/App.SettingsGroup.json src/Settings/AutoConnect.SettingsGroup.json src/Settings/BrandImage.SettingsGroup.json @@ -223,6 +221,7 @@ src/MissionManager/CameraSpec.FactMetaData.json src/MissionManager/CorridorScan.SettingsGroup.json src/QmlControls/EditPositionDialog.FactMetaData.json + src/Settings/FirmwareUpgrade.SettingsGroup.json src/Settings/FlightMap.SettingsGroup.json src/Settings/FlyView.SettingsGroup.json src/MissionManager/FWLandingPattern.FactMetaData.json @@ -233,6 +232,8 @@ src/MissionManager/MavCmdInfoSub.json src/MissionManager/MavCmdInfoVTOL.json src/MissionManager/MissionSettings.FactMetaData.json + src/Settings/OfflineMaps.SettingsGroup.json + src/Settings/PlanView.SettingsGroup.json src/MissionManager/QGCMapCircle.Facts.json src/MissionManager/RallyPoint.FactMetaData.json src/Settings/RTK.SettingsGroup.json diff --git a/src/AutoPilotPlugins/CMakeLists.txt b/src/AutoPilotPlugins/CMakeLists.txt index d8a1718652b8aaa3f47141dde140ac693d02bc06..9d27b5e061f7cb8a17ec41d644d4a57a546bfc12 100644 --- a/src/AutoPilotPlugins/CMakeLists.txt +++ b/src/AutoPilotPlugins/CMakeLists.txt @@ -1,9 +1,7 @@ add_library(AutoPilotPlugins APM/APMAirframeComponent.cc - APM/APMAirframeComponentAirframes.cc APM/APMAirframeComponentController.cc - APM/APMAirframeLoader.cc APM/APMAutoPilotPlugin.cc APM/APMCameraComponent.cc APM/APMCompassCal.cc diff --git a/src/Camera/QGCCameraManager.cc b/src/Camera/QGCCameraManager.cc index 5c7c5bb85aabe3c823f40c31119c2406caf5cf86..d44c37660ee8c55155e58400d30eabf095c8af99 100644 --- a/src/Camera/QGCCameraManager.cc +++ b/src/Camera/QGCCameraManager.cc @@ -107,8 +107,8 @@ QGCCameraManager::_handleHeartbeat(const mavlink_message_t &message) { mavlink_heartbeat_t heartbeat; mavlink_msg_heartbeat_decode(&message, &heartbeat); - //-- If this heartbeat is from a different component within the vehicle - if(_vehicleReadyState && _vehicle->id() == message.sysid && _vehicle->defaultComponentId() != message.compid) { + //-- Only pay attention to "camera" component IDs + if(_vehicleReadyState && _vehicle->id() == message.sysid && message.compid >= MAV_COMP_ID_CAMERA && message.compid <= MAV_COMP_ID_CAMERA6) { //-- First time hearing from this one? QString sCompID = QString::number(message.compid); if(!_cameraInfoRequest.contains(sCompID)) { @@ -135,8 +135,7 @@ QGCCameraManager::_handleHeartbeat(const mavlink_message_t &message) } } else { pInfo->tryCount++; - //-- Request camera info. Again. It could be something other than a camera, in which - // case, we won't ever receive it. + //-- Request camera info again. _requestCameraInfo(message.compid); } } diff --git a/src/Microhard/MicrohardManager.cc b/src/Microhard/MicrohardManager.cc index 4735de1f466be38bfb4ab95f51babd794823b4e7..7381d24fc9668048390ceb8e07d3462b75943a79 100644 --- a/src/Microhard/MicrohardManager.cc +++ b/src/Microhard/MicrohardManager.cc @@ -15,13 +15,12 @@ #include -#define LONG_TIMEOUT 5000 +#define SHORT_TIMEOUT 2500 +#define LONG_TIMEOUT 5000 static const char *kMICROHARD_GROUP = "Microhard"; static const char *kLOCAL_IP = "LocalIP"; static const char *kREMOTE_IP = "RemoteIP"; -static const char *kGROUND_IP = "GroundIP"; -static const char *kAIR_IP = "AirIP"; static const char *kNET_MASK = "NetMask"; static const char *kCFG_PASSWORD = "ConfigPassword"; static const char *kENC_KEY = "EncryptionKey"; @@ -38,8 +37,6 @@ MicrohardManager::MicrohardManager(QGCApplication* app, QGCToolbox* toolbox) settings.beginGroup(kMICROHARD_GROUP); _localIPAddr = settings.value(kLOCAL_IP, QString("192.168.168.1")).toString(); _remoteIPAddr = settings.value(kREMOTE_IP, QString("192.168.168.2")).toString(); - _groundIPAddr = settings.value(kGROUND_IP, QString("192.168.168.101")).toString(); - _airIPAddr = settings.value(kAIR_IP, QString("192.168.168.213")).toString(); _netMask = settings.value(kNET_MASK, QString("255.255.255.0")).toString(); _configPassword = settings.value(kCFG_PASSWORD, QString("admin")).toString(); _encryptionKey = settings.value(kENC_KEY, QString("1234567890")).toString(); @@ -117,10 +114,10 @@ MicrohardManager::setToolbox(QGCToolbox* toolbox) //----------------------------------------------------------------------------- bool -MicrohardManager::setIPSettings(QString localIP_, QString remoteIP_, QString groundIP_, QString airIP_, QString netMask_, QString cfgPassword_, QString encryptionKey_) +MicrohardManager::setIPSettings(QString localIP_, QString remoteIP_, QString netMask_, QString cfgPassword_, QString encryptionKey_) { if (_localIPAddr != localIP_ || _remoteIPAddr != remoteIP_ || _netMask != netMask_ || - _configPassword != cfgPassword_ || _encryptionKey != encryptionKey_ || _groundIPAddr != groundIP_ || _airIPAddr != airIP_) + _configPassword != cfgPassword_ || _encryptionKey != encryptionKey_) { if (_mhSettingsLoc && _encryptionKey != encryptionKey_) { _mhSettingsLoc->setEncryptionKey(encryptionKey_); @@ -128,8 +125,6 @@ MicrohardManager::setIPSettings(QString localIP_, QString remoteIP_, QString gro _localIPAddr = localIP_; _remoteIPAddr = remoteIP_; - _groundIPAddr = groundIP_; - _airIPAddr = airIP_; _netMask = netMask_; _configPassword = cfgPassword_; _encryptionKey = encryptionKey_; @@ -138,8 +133,6 @@ MicrohardManager::setIPSettings(QString localIP_, QString remoteIP_, QString gro settings.beginGroup(kMICROHARD_GROUP); settings.setValue(kLOCAL_IP, localIP_); settings.setValue(kREMOTE_IP, remoteIP_); - settings.setValue(kGROUND_IP, groundIP_); - settings.setValue(kAIR_IP, airIP_); settings.setValue(kNET_MASK, netMask_); settings.setValue(kCFG_PASSWORD, cfgPassword_); settings.setValue(kENC_KEY, encryptionKey_); @@ -169,7 +162,7 @@ MicrohardManager::_setEnabled() connect(_mhSettingsRem, &MicrohardSettings::connected, this, &MicrohardManager::_connectedRem); connect(_mhSettingsRem, &MicrohardSettings::rssiUpdated, this, &MicrohardManager::_rssiUpdatedRem); } - _workTimer.start(1000); + _workTimer.start(SHORT_TIMEOUT); } else { //-- Stop everything _close(); @@ -268,5 +261,5 @@ MicrohardManager::_checkMicrohard() _mhSettingsRem->getStatus(); } } - _workTimer.start(_isConnected ? 1000 : LONG_TIMEOUT); + _workTimer.start(_isConnected ? SHORT_TIMEOUT : LONG_TIMEOUT); } diff --git a/src/Microhard/MicrohardManager.h b/src/Microhard/MicrohardManager.h index 2dc49047241fdb45758048a70d418e847e963200..55955c067f4eecc59341d8ab2191334892a6b78c 100644 --- a/src/Microhard/MicrohardManager.h +++ b/src/Microhard/MicrohardManager.h @@ -32,13 +32,11 @@ public: Q_PROPERTY(int downlinkRSSI READ downlinkRSSI NOTIFY linkChanged) Q_PROPERTY(QString localIPAddr READ localIPAddr NOTIFY localIPAddrChanged) Q_PROPERTY(QString remoteIPAddr READ remoteIPAddr NOTIFY remoteIPAddrChanged) - Q_PROPERTY(QString groundIPAddr READ groundIPAddr NOTIFY groundIPAddrChanged) - Q_PROPERTY(QString airIPAddr READ airIPAddr NOTIFY airIPAddrChanged) Q_PROPERTY(QString netMask READ netMask NOTIFY netMaskChanged) Q_PROPERTY(QString configPassword READ configPassword NOTIFY configPasswordChanged) Q_PROPERTY(QString encryptionKey READ encryptionKey NOTIFY encryptionKeyChanged) - Q_INVOKABLE bool setIPSettings (QString localIP, QString remoteIP, QString groundIP, QString airIP, QString netMask, QString cfgPassword, QString encyrptionKey); + Q_INVOKABLE bool setIPSettings (QString localIP, QString remoteIP, QString netMask, QString cfgPassword, QString encyrptionKey); explicit MicrohardManager (QGCApplication* app, QGCToolbox* toolbox); ~MicrohardManager () override; @@ -51,8 +49,6 @@ public: int downlinkRSSI () { return _uplinkRSSI; } QString localIPAddr () { return _localIPAddr; } QString remoteIPAddr () { return _remoteIPAddr; } - QString airIPAddr () { return _airIPAddr; } - QString groundIPAddr () { return _groundIPAddr; } QString netMask () { return _netMask; } QString configPassword () { return _configPassword; } QString encryptionKey () { return _encryptionKey; } @@ -63,8 +59,6 @@ signals: void connectedChanged (); void localIPAddrChanged (); void remoteIPAddrChanged (); - void airIPAddrChanged (); - void groundIPAddrChanged (); void netMaskChanged (); void configPasswordChanged (); void encryptionKeyChanged (); @@ -98,8 +92,6 @@ private: int _uplinkRSSI = 0; QString _localIPAddr; QString _remoteIPAddr; - QString _groundIPAddr; - QString _airIPAddr; QString _netMask; QString _configPassword; QString _encryptionKey; diff --git a/src/Microhard/MicrohardSettings.qml b/src/Microhard/MicrohardSettings.qml index af5cbf70e0a6f536626154a4a258884c5992cd02..6874a0e8378d00afacdc75ad013e96de4e5fb54d 100644 --- a/src/Microhard/MicrohardSettings.qml +++ b/src/Microhard/MicrohardSettings.qml @@ -41,252 +41,227 @@ Rectangle { readonly property real _internalWidthRatio: 0.8 - QGCFlickable { - clip: true - anchors.fill: parent - contentHeight: settingsColumn.height - contentWidth: settingsColumn.width - Column { - id: settingsColumn + QGCFlickable { + clip: true + anchors.fill: parent + contentHeight: settingsColumn.height + contentWidth: settingsColumn.width + Column { + id: settingsColumn width: _root.width - spacing: ScreenTools.defaultFontPixelHeight * 0.5 - anchors.margins: ScreenTools.defaultFontPixelWidth - //----------------------------------------------------------------- - //-- General - Item { - width: _panelWidth - height: generalLabel.height - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - QGCLabel { - id: generalLabel - text: qsTr("General") - font.family: ScreenTools.demiboldFontFamily + spacing: ScreenTools.defaultFontPixelHeight * 0.5 + anchors.margins: ScreenTools.defaultFontPixelWidth + //----------------------------------------------------------------- + //-- General + Item { + width: _panelWidth + height: generalLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + QGCLabel { + id: generalLabel + text: qsTr("General") + font.family: ScreenTools.demiboldFontFamily + } } - } - Rectangle { - height: generalRow.height + (ScreenTools.defaultFontPixelHeight * 2) - width: _panelWidth - color: qgcPal.windowShade - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - Row { - id: generalRow - spacing: ScreenTools.defaultFontPixelWidth * 4 - anchors.centerIn: parent - Column { - spacing: ScreenTools.defaultFontPixelWidth - FactCheckBox { - text: qsTr("Enable Microhard") - fact: _microhardEnabledFact - enabled: true - visible: _microhardEnabledFact.visible + Rectangle { + height: generalRow.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Row { + id: generalRow + spacing: ScreenTools.defaultFontPixelWidth * 4 + anchors.centerIn: parent + Column { + spacing: ScreenTools.defaultFontPixelWidth + FactCheckBox { + text: qsTr("Enable Microhard") + fact: _microhardEnabledFact + enabled: true + visible: _microhardEnabledFact.visible + } } } } - } - //----------------------------------------------------------------- - //-- Connection Status - Item { - width: _panelWidth - height: statusLabel.height - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - visible: _microhardEnabled - QGCLabel { - id: statusLabel - text: qsTr("Connection Status") - font.family: ScreenTools.demiboldFontFamily + //----------------------------------------------------------------- + //-- Connection Status + Item { + width: _panelWidth + height: statusLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + visible: _microhardEnabled + QGCLabel { + id: statusLabel + text: qsTr("Connection Status") + font.family: ScreenTools.demiboldFontFamily + } } - } - Rectangle { - height: statusCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: _panelWidth - color: qgcPal.windowShade - visible: _microhardEnabled - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - Column { - id: statusCol - 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("Ground Unit:") - Layout.minimumWidth: _labelWidth - } - QGCLabel { - text: QGroundControl.microhardManager.connected ? qsTr("Connected") : qsTr("Not Connected") - color: QGroundControl.microhardManager.connected ? qgcPal.colorGreen : qgcPal.colorRed - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Air Unit:") - } - QGCLabel { - text: QGroundControl.microhardManager.linkConnected ? qsTr("Connected") : qsTr("Not Connected") - color: QGroundControl.microhardManager.linkConnected ? qgcPal.colorGreen : qgcPal.colorRed - } - QGCLabel { - text: qsTr("Uplink RSSI:") - } - QGCLabel { - text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.uplinkRSSI < 0 ? QGroundControl.microhardManager.uplinkRSSI : "" - } - QGCLabel { - text: qsTr("Downlink RSSI:") - } - QGCLabel { - text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.downlinkRSSI < 0 ? QGroundControl.microhardManager.downlinkRSSI : "" + Rectangle { + height: statusCol.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + visible: _microhardEnabled + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Column { + id: statusCol + 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("Ground Unit:") + Layout.minimumWidth: _labelWidth + } + QGCLabel { + text: QGroundControl.microhardManager.connected ? qsTr("Connected") : qsTr("Not Connected") + color: QGroundControl.microhardManager.connected ? qgcPal.colorGreen : qgcPal.colorRed + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Air Unit:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected ? qsTr("Connected") : qsTr("Not Connected") + color: QGroundControl.microhardManager.linkConnected ? qgcPal.colorGreen : qgcPal.colorRed + } + QGCLabel { + text: qsTr("Uplink RSSI:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.uplinkRSSI < 0 ? QGroundControl.microhardManager.uplinkRSSI : "" + } + QGCLabel { + text: qsTr("Downlink RSSI:") + } + QGCLabel { + text: QGroundControl.microhardManager.linkConnected && QGroundControl.microhardManager.downlinkRSSI < 0 ? QGroundControl.microhardManager.downlinkRSSI : "" + } } } } - } - //----------------------------------------------------------------- - //-- IP Settings - Item { - width: _panelWidth - height: ipSettingsLabel.height - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - visible: _microhardEnabled - QGCLabel { - id: ipSettingsLabel - text: qsTr("Network Settings") - font.family: ScreenTools.demiboldFontFamily + //----------------------------------------------------------------- + //-- IP Settings + Item { + width: _panelWidth + height: ipSettingsLabel.height + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + visible: _microhardEnabled + QGCLabel { + id: ipSettingsLabel + text: qsTr("Network Settings") + font.family: ScreenTools.demiboldFontFamily + } } - } - Rectangle { - height: ipSettingsCol.height + (ScreenTools.defaultFontPixelHeight * 2) - width: _panelWidth - color: qgcPal.windowShade - visible: _microhardEnabled - anchors.margins: ScreenTools.defaultFontPixelWidth - anchors.horizontalCenter: parent.horizontalCenter - Column { - id: ipSettingsCol - 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("Local IP Address:") - Layout.minimumWidth: _labelWidth - } - QGCTextField { - id: localIP - text: QGroundControl.microhardManager.localIPAddr - enabled: true - inputMethodHints: Qt.ImhFormattedNumbersOnly - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Remote IP Address:") - } - QGCTextField { - id: remoteIP - text: QGroundControl.microhardManager.remoteIPAddr - enabled: true - inputMethodHints: Qt.ImhFormattedNumbersOnly - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Ground Unit IP Address:") - Layout.minimumWidth: _labelWidth - } - QGCTextField { - id: groundIP - text: QGroundControl.microhardManager.groundIPAddr - enabled: true - inputMethodHints: Qt.ImhFormattedNumbersOnly - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Air Unit IP Address:") - } - QGCTextField { - id: airIP - text: QGroundControl.microhardManager.airIPAddr - enabled: true - inputMethodHints: Qt.ImhFormattedNumbersOnly - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Network Mask:") - } - QGCTextField { - id: netMask - text: QGroundControl.microhardManager.netMask - enabled: true - inputMethodHints: Qt.ImhFormattedNumbersOnly - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Configuration password:") - } - QGCTextField { - id: configPassword - text: QGroundControl.microhardManager.configPassword - enabled: true - inputMethodHints: Qt.ImhHiddenText - Layout.minimumWidth: _valueWidth - } - QGCLabel { - text: qsTr("Encryption key:") - } - QGCTextField { - id: encryptionKey - text: QGroundControl.microhardManager.encryptionKey - enabled: true - inputMethodHints: Qt.ImhHiddenText - Layout.minimumWidth: _valueWidth + Rectangle { + height: ipSettingsCol.height + (ScreenTools.defaultFontPixelHeight * 2) + width: _panelWidth + color: qgcPal.windowShade + visible: _microhardEnabled + anchors.margins: ScreenTools.defaultFontPixelWidth + anchors.horizontalCenter: parent.horizontalCenter + Column { + id: ipSettingsCol + 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("Local IP Address:") + Layout.minimumWidth: _labelWidth + } + QGCTextField { + id: localIP + text: QGroundControl.microhardManager.localIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Remote IP Address:") + } + QGCTextField { + id: remoteIP + text: QGroundControl.microhardManager.remoteIPAddr + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Network Mask:") + } + QGCTextField { + id: netMask + text: QGroundControl.microhardManager.netMask + enabled: true + inputMethodHints: Qt.ImhFormattedNumbersOnly + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Configuration password:") + } + QGCTextField { + id: configPassword + text: QGroundControl.microhardManager.configPassword + enabled: true + inputMethodHints: Qt.ImhHiddenText + Layout.minimumWidth: _valueWidth + } + QGCLabel { + text: qsTr("Encryption key:") + } + QGCTextField { + id: encryptionKey + text: QGroundControl.microhardManager.encryptionKey + enabled: true + inputMethodHints: Qt.ImhHiddenText + Layout.minimumWidth: _valueWidth + } } - } - Item { - width: 1 - height: ScreenTools.defaultFontPixelHeight - } - QGCButton { - function validateIPaddress(ipaddress) { - if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) - return true - return false + Item { + width: 1 + height: ScreenTools.defaultFontPixelHeight } - function testEnabled() { - if(localIP.text === QGroundControl.microhardManager.localIPAddr && - remoteIP.text === QGroundControl.microhardManager.remoteIPAddr && - groundIP.text === QGroundControl.microhardManager.groundIPAddr && - airIP.text === QGroundControl.microhardManager.airIPAddr && - netMask.text === QGroundControl.microhardManager.netMask && - configPassword.text === QGroundControl.microhardManager.configPassword && - encryptionKey.text === QGroundControl.microhardManager.encryptionKey) + QGCButton { + function validateIPaddress(ipaddress) { + if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) + return true return false - if(!validateIPaddress(localIP.text)) return false - if(!validateIPaddress(remoteIP.text)) return false - if(!validateIPaddress(groundIP.text)) return false - if(!validateIPaddress(airIP.text)) return false - if(!validateIPaddress(netMask.text)) return false - return true - } - enabled: testEnabled() - text: qsTr("Apply") - anchors.horizontalCenter: parent.horizontalCenter - onClicked: { - QGroundControl.microhardManager.setIPSettings(localIP.text, remoteIP.text, groundIP.text, airIP.text, netMask.text, configPassword.text, encryptionKey.text) - } + } + function testEnabled() { + if(localIP.text === QGroundControl.microhardManager.localIPAddr && + remoteIP.text === QGroundControl.microhardManager.remoteIPAddr && + netMask.text === QGroundControl.microhardManager.netMask && + configPassword.text === QGroundControl.microhardManager.configPassword && + encryptionKey.text === QGroundControl.microhardManager.encryptionKey) + return false + if(!validateIPaddress(localIP.text)) return false + if(!validateIPaddress(remoteIP.text)) return false + if(!validateIPaddress(netMask.text)) return false + return true + } + enabled: testEnabled() + text: qsTr("Apply") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + QGroundControl.microhardManager.setIPSettings(localIP.text, remoteIP.text, netMask.text, configPassword.text, encryptionKey.text) + } + } } } } } } -} diff --git a/src/Settings/FirmwareUpgrade.SettingsGroup.json b/src/Settings/FirmwareUpgrade.SettingsGroup.json new file mode 100644 index 0000000000000000000000000000000000000000..97711ac1210c27ee1d712dcbab1d5d804283ae1b --- /dev/null +++ b/src/Settings/FirmwareUpgrade.SettingsGroup.json @@ -0,0 +1,22 @@ +[ +{ + "name": "defaultFirmwareType", + "shortDescription": "Default firmware type for flashing", + "type": "uint32", + "defaultValue": 12 +}, +{ + "name": "apmChibiOS", + "type": "uint32", + "enumStrings": "ChibiOS,NuttX", + "enumValues": "0,1", + "defaultValue": 0 +}, +{ + "name": "apmVehicleType", + "type": "uint32", + "enumStrings": "Multi-Rotor,Helicopter,Plane,Rover,Sub", + "enumValues": "0,1,2,3,4", + "defaultValue": 0 +} +] diff --git a/src/Settings/FirmwareUpgradeSettings.cc b/src/Settings/FirmwareUpgradeSettings.cc new file mode 100644 index 0000000000000000000000000000000000000000..0adab2b4fe2f0c8c0e9f144cbcc370fb1c497086 --- /dev/null +++ b/src/Settings/FirmwareUpgradeSettings.cc @@ -0,0 +1,22 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +#include "FirmwareUpgradeSettings.h" + +#include +#include + +DECLARE_SETTINGGROUP(FirmwareUpgrade, "FirmwareUpgrade") +{ + qmlRegisterUncreatableType("QGroundControl.SettingsManager", 1, 0, "FirmwareUpgradeSettings", "Reference only"); +} + +DECLARE_SETTINGSFACT(FirmwareUpgradeSettings, defaultFirmwareType) +DECLARE_SETTINGSFACT(FirmwareUpgradeSettings, apmChibiOS) +DECLARE_SETTINGSFACT(FirmwareUpgradeSettings, apmVehicleType) diff --git a/src/Settings/FirmwareUpgradeSettings.h b/src/Settings/FirmwareUpgradeSettings.h new file mode 100644 index 0000000000000000000000000000000000000000..5e7fe17306e3f8599f47a2d0a20fafc92450d184 --- /dev/null +++ b/src/Settings/FirmwareUpgradeSettings.h @@ -0,0 +1,26 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ +#pragma once + +#include "SettingsGroup.h" +#include "QGCMAVLink.h" + +class FirmwareUpgradeSettings : public SettingsGroup +{ + Q_OBJECT + +public: + FirmwareUpgradeSettings(QObject* parent = nullptr); + + DEFINE_SETTING_NAME_GROUP() + + DEFINE_SETTINGFACT(defaultFirmwareType) + DEFINE_SETTINGFACT(apmChibiOS) + DEFINE_SETTINGFACT(apmVehicleType) +}; diff --git a/src/Settings/SettingsManager.cc b/src/Settings/SettingsManager.cc index 963e1bf5895012ae16196bb940774fc0263d7f53..4b6968fd1a55bf84d951335190e581d1214aa7a9 100644 --- a/src/Settings/SettingsManager.cc +++ b/src/Settings/SettingsManager.cc @@ -27,6 +27,7 @@ SettingsManager::SettingsManager(QGCApplication* app, QGCToolbox* toolbox) , _planViewSettings (nullptr) , _brandImageSettings (nullptr) , _offlineMapsSettings (nullptr) + , _firmwareUpgradeSettings (nullptr) #if !defined(NO_ARDUPILOT_DIALECT) , _apmMavlinkStreamRateSettings (nullptr) #endif @@ -40,20 +41,21 @@ void SettingsManager::setToolbox(QGCToolbox *toolbox) QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); qmlRegisterUncreatableType("QGroundControl.SettingsManager", 1, 0, "SettingsManager", "Reference only"); - _unitsSettings = new UnitsSettings (this); // Must be first since AppSettings references it - _appSettings = new AppSettings (this); - _autoConnectSettings = new AutoConnectSettings (this); - _videoSettings = new VideoSettings (this); - _flightMapSettings = new FlightMapSettings (this); - _rtkSettings = new RTKSettings (this); - _flyViewSettings = new FlyViewSettings (this); - _planViewSettings = new PlanViewSettings (this); - _brandImageSettings = new BrandImageSettings (this); - _offlineMapsSettings = new OfflineMapsSettings (this); + _unitsSettings = new UnitsSettings (this); // Must be first since AppSettings references it + _appSettings = new AppSettings (this); + _autoConnectSettings = new AutoConnectSettings (this); + _videoSettings = new VideoSettings (this); + _flightMapSettings = new FlightMapSettings (this); + _rtkSettings = new RTKSettings (this); + _flyViewSettings = new FlyViewSettings (this); + _planViewSettings = new PlanViewSettings (this); + _brandImageSettings = new BrandImageSettings (this); + _offlineMapsSettings = new OfflineMapsSettings (this); + _firmwareUpgradeSettings = new FirmwareUpgradeSettings (this); #if !defined(NO_ARDUPILOT_DIALECT) - _apmMavlinkStreamRateSettings = new APMMavlinkStreamRateSettings (this); + _apmMavlinkStreamRateSettings = new APMMavlinkStreamRateSettings(this); #endif #if defined(QGC_AIRMAP_ENABLED) - _airMapSettings = new AirMapSettings (this); + _airMapSettings = new AirMapSettings (this); #endif } diff --git a/src/Settings/SettingsManager.h b/src/Settings/SettingsManager.h index 141730f0097f4cd7c70cae6f2cbbb22fc056cd0b..6c3f867ed1041b237fde3a805dbbe037e3662c6a 100644 --- a/src/Settings/SettingsManager.h +++ b/src/Settings/SettingsManager.h @@ -25,6 +25,7 @@ #include "BrandImageSettings.h" #include "OfflineMapsSettings.h" #include "APMMavlinkStreamRateSettings.h" +#include "FirmwareUpgradeSettings.h" #if defined(QGC_AIRMAP_ENABLED) #include "AirMapSettings.h" #endif @@ -50,7 +51,8 @@ public: Q_PROPERTY(QObject* flyViewSettings READ flyViewSettings CONSTANT) Q_PROPERTY(QObject* planViewSettings READ planViewSettings CONSTANT) Q_PROPERTY(QObject* brandImageSettings READ brandImageSettings CONSTANT) - Q_PROPERTY(QObject* offlineMapsSettings READ offlineMapsSettings CONSTANT) + Q_PROPERTY(QObject* offlineMapsSettings READ offlineMapsSettings CONSTANT) + Q_PROPERTY(QObject* firmwareUpgradeSettings READ firmwareUpgradeSettings CONSTANT) #if !defined(NO_ARDUPILOT_DIALECT) Q_PROPERTY(QObject* apmMavlinkStreamRateSettings READ apmMavlinkStreamRateSettings CONSTANT) #endif @@ -70,6 +72,7 @@ public: PlanViewSettings* planViewSettings (void) { return _planViewSettings; } BrandImageSettings* brandImageSettings (void) { return _brandImageSettings; } OfflineMapsSettings* offlineMapsSettings (void) { return _offlineMapsSettings; } + FirmwareUpgradeSettings* firmwareUpgradeSettings (void) { return _firmwareUpgradeSettings; } #if !defined(NO_ARDUPILOT_DIALECT) APMMavlinkStreamRateSettings* apmMavlinkStreamRateSettings(void) { return _apmMavlinkStreamRateSettings; } #endif @@ -87,6 +90,7 @@ private: PlanViewSettings* _planViewSettings; BrandImageSettings* _brandImageSettings; OfflineMapsSettings* _offlineMapsSettings; + FirmwareUpgradeSettings* _firmwareUpgradeSettings; #if !defined(NO_ARDUPILOT_DIALECT) APMMavlinkStreamRateSettings* _apmMavlinkStreamRateSettings; #endif diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc index df21fd0e354582a6306a7e354856c02c6966fc8c..40c87af24f9f6346322bf70c7558295f4aaa7369 100644 --- a/src/Vehicle/Vehicle.cc +++ b/src/Vehicle/Vehicle.cc @@ -3333,6 +3333,10 @@ void Vehicle::_handleCommandAck(mavlink_message_t& message) //_startPlanRequest(); } + if (ack.command == MAV_CMD_FLASH_BOOTLOADER && ack.result == MAV_RESULT_ACCEPTED) { + qgcApp()->showMessage(tr("Bootloader flash succeeded")); + } + if (_mavCommandQueue.count() && ack.command == _mavCommandQueue[0].command) { _mavCommandAckTimer.stop(); showError = _mavCommandQueue[0].showError; diff --git a/src/VehicleSetup/FirmwareUpgrade.qml b/src/VehicleSetup/FirmwareUpgrade.qml index f145c5b5d6baf82f2f79cae8ccecf831f06c3f5e..37898104ec173c454a28f5f18c895d4703ced3fe 100644 --- a/src/VehicleSetup/FirmwareUpgrade.qml +++ b/src/VehicleSetup/FirmwareUpgrade.qml @@ -58,8 +58,9 @@ SetupPage { readonly property int _defaultFimwareTypePX4: 12 readonly property int _defaultFimwareTypeAPM: 3 - property var _defaultFirmwareFact: QGroundControl.settingsManager.appSettings.defaultFirmwareType - property bool _defaultFirmwareIsPX4: true + property var _firmwareUpgradeSettings: QGroundControl.settingsManager.firmwareUpgradeSettings + property var _defaultFirmwareFact: _firmwareUpgradeSettings.defaultFirmwareType + property bool _defaultFirmwareIsPX4: true property string firmwareWarningMessage property bool initialBoardSearch: true @@ -77,6 +78,18 @@ SetupPage { controller.startBoardSearch() _defaultFirmwareIsPX4 = _defaultFirmwareFact.rawValue === _defaultFimwareTypePX4 // we don't want this to be bound and change as radios are selected } + function firmwareVersionChanged(model) { + firmwareVersionWarningLabel.visible = false + // All of this bizarre, setting model to null and index to 1 and then to 0 is to work around + // strangeness in the combo box implementation. This sequence of steps correctly changes the combo model + // without generating any warnings and correctly updates the combo text with the new selection. + firmwareBuildTypeCombo.model = null + firmwareBuildTypeCombo.model = model + firmwareBuildTypeCombo.currentIndex = 1 + firmwareBuildTypeCombo.currentIndex = 0 + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } FirmwareUpgradeController { id: controller @@ -139,7 +152,7 @@ SetupPage { function updatePX4VersionDisplay() { var versionString = "" if (_advanced.checked) { - switch (controller.selectedFirmwareType) { + switch (controller.selectedFirmwareBuildType) { case FirmwareUpgradeController.StableFirmware: versionString = controller.px4StableVersion break @@ -150,8 +163,8 @@ SetupPage { } else { versionString = controller.px4StableVersion } - px4FlightStackRadio1.text = qsTr("PX4 Flight Stack ") + versionString - px4FlightStackRadio2.text = qsTr("PX4 Flight Stack ") + versionString + px4FlightStackRadio.text = qsTr("PX4 Pro ") + versionString + //px4FlightStackRadio2.text = qsTr("PX4 Pro ") + versionString } Component.onCompleted: { @@ -161,12 +174,11 @@ SetupPage { } function accept() { - hideDialog() if (_singleFirmwareMode) { - controller.flashSingleFirmwareMode(controller.selectedFirmwareType) + controller.flashSingleFirmwareMode(controller.selectedFirmwareBuildType) } else { var stack - var firmwareType = firmwareVersionCombo.model.get(firmwareVersionCombo.currentIndex).firmwareType + var firmwareBuildType = firmwareBuildTypeCombo.model.get(firmwareBuildTypeCombo.currentIndex).firmwareType var vehicleType = FirmwareUpgradeController.DefaultVehicleFirmware if (px4Flow) { @@ -175,11 +187,25 @@ SetupPage { } else { stack = apmFlightStack.checked ? FirmwareUpgradeController.AutoPilotStackAPM : FirmwareUpgradeController.AutoPilotStackPX4 if (apmFlightStack.checked) { - vehicleType = controller.vehicleTypeFromVersionIndex(vehicleTypeSelectionCombo.currentIndex) + if (firmwareBuildType === FirmwareUpgradeController.CustomFirmware) { + vehicleType = apmVehicleTypeCombo.currentIndex + } else { + if (controller.apmFirmwareNames.length === 0) { + // Not ready yet, or no firmware available + return + } + var firmwareUrl = controller.apmFirmwareUrls[ardupilotFirmwareSelectionCombo.currentIndex] + if (firmwareUrl == "") { + return + } + controller.flashFirmwareUrl(controller.apmFirmwareUrls[ardupilotFirmwareSelectionCombo.currentIndex]) + hideDialog() + return + } } } - - controller.flash(stack, firmwareType, vehicleType) + controller.flash(stack, firmwareBuildType, vehicleType) + hideDialog() } } @@ -195,7 +221,7 @@ SetupPage { } ListModel { - id: firmwareTypeList + id: firmwareBuildTypeList ListElement { text: qsTr("Standard Version (stable)") @@ -275,65 +301,86 @@ SetupPage { readonly property string _singleFirmwareLabel: qsTr("Press Ok to upgrade your vehicle.") } - function firmwareVersionChanged(model) { - firmwareVersionWarningLabel.visible = false - // All of this bizarre, setting model to null and index to 1 and then to 0 is to work around - // strangeness in the combo box implementation. This sequence of steps correctly changes the combo model - // without generating any warnings and correctly updates the combo text with the new selection. - firmwareVersionCombo.model = null - firmwareVersionCombo.model = model - firmwareVersionCombo.currentIndex = 1 - firmwareVersionCombo.currentIndex = 0 - } + QGCLabel { text: qsTr("Flight Stack") } - // The following craziness of three radio buttons to represent two radio buttons is so that the - // order can be changed such that the default firmware button is always on the top + RowLayout { + spacing: _margins + layoutDirection: px4FlightStackRadio.checked ? Qt.LeftToRight : Qt.RightToLeft + + // The following craziness of three radio buttons to represent two radio buttons is so that the + // order can be changed such that the default firmware button is always on the top //-- Visible only if you have an option. If it's the only option, it's already setup. - QGCRadioButton { - id: px4FlightStackRadio1 - text: qsTr("PX4 Flight Stack ") - textBold: _defaultFirmwareIsPX4 - checked: _defaultFirmwareIsPX4 - visible: _defaultFirmwareIsPX4 && !_singleFirmwareMode && !px4Flow && QGroundControl.hasAPMSupport - - onClicked: { - _defaultFirmwareFact.rawValue = _defaultFimwareTypePX4 - parent.firmwareVersionChanged(firmwareTypeList) + QGCRadioButton { + id: px4FlightStackRadio + exclusiveGroup: firmwareGroup + text: qsTr("PX4 Pro ") + textBold: _defaultFirmwareIsPX4 + checked: _defaultFirmwareIsPX4 + visible: !_singleFirmwareMode && !px4Flow + + onClicked: { + _defaultFirmwareFact.rawValue = _defaultFimwareTypePX4 + firmwareVersionChanged(firmwareBuildTypeList) + } } - } - QGCRadioButton { - id: apmFlightStack - text: qsTr("ArduPilot Flight Stack") - textBold: !_defaultFirmwareIsPX4 - checked: !_defaultFirmwareIsPX4 + QGCRadioButton { + id: apmFlightStack + exclusiveGroup: firmwareGroup + text: qsTr("ArduPilot") + textBold: !_defaultFirmwareIsPX4 + checked: !_defaultFirmwareIsPX4 visible: !_singleFirmwareMode && !px4Flow && QGroundControl.hasAPMSupport - onClicked: { - _defaultFirmwareFact.rawValue = _defaultFimwareTypeAPM - parent.firmwareVersionChanged(firmwareTypeList) + onClicked: { + _defaultFirmwareFact.rawValue = _defaultFimwareTypeAPM + firmwareVersionChanged(firmwareBuildTypeList) + } } } - //-- Visible only if you have an option. If it's the only option, it's already setup. - QGCRadioButton { - id: px4FlightStackRadio2 - text: qsTr("PX4 Flight Stack ") - visible: !_defaultFirmwareIsPX4 && !_singleFirmwareMode && !px4Flow && QGroundControl.hasAPMSupport + FactComboBox { + anchors.left: parent.left + anchors.right: parent.right + visible: !px4Flow && apmFlightStack.checked + fact: _firmwareUpgradeSettings.apmChibiOS + indexModel: false + } - onClicked: { - _defaultFirmwareFact.rawValue = _defaultFimwareTypePX4 - parent.firmwareVersionChanged(firmwareTypeList) - } + FactComboBox { + id: apmVehicleTypeCombo + anchors.left: parent.left + anchors.right: parent.right + visible: !px4Flow && apmFlightStack.checked + fact: _firmwareUpgradeSettings.apmVehicleType + indexModel: false } QGCComboBox { - id: vehicleTypeSelectionCombo + id: ardupilotFirmwareSelectionCombo anchors.left: parent.left anchors.right: parent.right - visible: !px4Flow && apmFlightStack.checked - model: controller.apmAvailableVersions + visible: !px4Flow && apmFlightStack.checked && !controller.downloadingFirmwareList && controller.apmFirmwareNames.length !== 0 + model: controller.apmFirmwareNames + + onModelChanged: console.log("model", model) + } + + QGCLabel { + anchors.left: parent.left + anchors.right: parent.right + wrapMode: Text.WordWrap + text: qsTr("Downloading list of available firmwares...") + visible: controller.downloadingFirmwareList + } + + QGCLabel { + anchors.left: parent.left + anchors.right: parent.right + wrapMode: Text.WordWrap + text: qsTr("No Firmware Available") + visible: !controller.downloadingFirmwareList && controller.apmFirmwareNames.length === 0 } QGCComboBox { @@ -363,7 +410,7 @@ SetupPage { checked: px4Flow ? true : false onClicked: { - firmwareVersionCombo.currentIndex = 0 + firmwareBuildTypeCombo.currentIndex = 0 firmwareVersionWarningLabel.visible = false updatePX4VersionDisplay() } @@ -385,15 +432,15 @@ SetupPage { } QGCComboBox { - id: firmwareVersionCombo + id: firmwareBuildTypeCombo anchors.left: parent.left anchors.right: parent.right visible: showFirmwareTypeSelection - model: _singleFirmwareMode ? singleFirmwareModeTypeList : (px4Flow ? px4FlowTypeList : firmwareTypeList) - currentIndex: controller.selectedFirmwareType + model: _singleFirmwareMode ? singleFirmwareModeTypeList : (px4Flow ? px4FlowTypeList : firmwareBuildTypeList) + currentIndex: controller.selectedFirmwareBuildType onActivated: { - controller.selectedFirmwareType = model.get(index).firmwareType + controller.selectedFirmwareBuildType = model.get(index).firmwareType if (model.get(index).firmwareType === FirmwareUpgradeController.BetaFirmware) { firmwareVersionWarningLabel.visible = true firmwareVersionWarningLabel.text = qsTr("WARNING: BETA FIRMWARE. ") + diff --git a/src/VehicleSetup/FirmwareUpgradeController.cc b/src/VehicleSetup/FirmwareUpgradeController.cc index f35f87f965f400c6dcccb0db95f20853cabd4bdc..07cc7347702d39bd1c5055255fe687d327905386 100644 --- a/src/VehicleSetup/FirmwareUpgradeController.cc +++ b/src/VehicleSetup/FirmwareUpgradeController.cc @@ -7,11 +7,6 @@ * ****************************************************************************/ - -/// @file -/// @brief PX4 Firmware Upgrade UI -/// @author Don Gagne - #include "FirmwareUpgradeController.h" #include "Bootloader.h" //-- TODO: #include "QGCQFileDialog.h" @@ -19,6 +14,8 @@ #include "QGCFileDownload.h" #include "QGCOptions.h" #include "QGCCorePlugin.h" +#include "FirmwareUpgradeSettings.h" +#include "SettingsManager.h" #include #include @@ -27,31 +24,57 @@ #include #include +const char* FirmwareUpgradeController::_manifestFirmwareJsonKey = "firmware"; +const char* FirmwareUpgradeController::_manifestBoardIdJsonKey = "board_id"; +const char* FirmwareUpgradeController::_manifestMavTypeJsonKey = "mav-type"; +const char* FirmwareUpgradeController::_manifestFormatJsonKey = "format"; +const char* FirmwareUpgradeController::_manifestUrlJsonKey = "url"; +const char* FirmwareUpgradeController::_manifestMavFirmwareVersionTypeJsonKey = "mav-firmware-version-type"; +const char* FirmwareUpgradeController::_manifestUSBIDJsonKey = "USBID"; +const char* FirmwareUpgradeController::_manifestMavFirmwareVersionJsonKey = "mav-firmware-version"; +const char* FirmwareUpgradeController::_manifestBootloaderStrJsonKey = "bootloader_str"; +const char* FirmwareUpgradeController::_manifestLatestKey = "latest"; +const char* FirmwareUpgradeController::_manifestPlatformKey = "platform"; +const char* FirmwareUpgradeController::_manifestBrandNameKey = "brand_name"; + struct FirmwareToUrlElement_t { - FirmwareUpgradeController::AutoPilotStackType_t stackType; - FirmwareUpgradeController::FirmwareType_t firmwareType; - FirmwareUpgradeController::FirmwareVehicleType_t vehicleType; - QString url; + FirmwareUpgradeController::AutoPilotStackType_t stackType; + FirmwareUpgradeController::FirmwareBuildType_t firmwareType; + FirmwareUpgradeController::FirmwareVehicleType_t vehicleType; + QString url; }; uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareId) { return static_cast(( firmwareId.autopilotStackType | - (firmwareId.firmwareType << 8) | - (firmwareId.firmwareVehicleType << 16) )); + (firmwareId.firmwareType << 8) | + (firmwareId.firmwareVehicleType << 16) )); } /// @Brief Constructs a new FirmwareUpgradeController Widget. This widget is used within the PX4VehicleConfig set of screens. FirmwareUpgradeController::FirmwareUpgradeController(void) : _singleFirmwareURL (qgcApp()->toolbox()->corePlugin()->options()->firmwareUpgradeSingleURL()) , _singleFirmwareMode (!_singleFirmwareURL.isEmpty()) + , _downloadingFirmwareList (false) , _downloadManager (nullptr) , _downloadNetworkReply (nullptr) , _statusLog (nullptr) - , _selectedFirmwareType (StableFirmware) + , _selectedFirmwareBuildType (StableFirmware) , _image (nullptr) , _apmBoardDescriptionReplaceText ("") + , _apmChibiOSSetting (qgcApp()->toolbox()->settingsManager()->firmwareUpgradeSettings()->apmChibiOS()) + , _apmVehicleTypeSetting (qgcApp()->toolbox()->settingsManager()->firmwareUpgradeSettings()->apmVehicleType()) { + _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["OFFICIAL"] = StableFirmware; + _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["BETA"] = BetaFirmware; + _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap["DEV"] = DeveloperFirmware; + + _manifestMavTypeToFirmwareVehicleTypeMap["Copter"] = CopterFirmware; + _manifestMavTypeToFirmwareVehicleTypeMap["HELICOPTER"] = HeliFirmware; + _manifestMavTypeToFirmwareVehicleTypeMap["FIXED_WING"] = PlaneFirmware; + _manifestMavTypeToFirmwareVehicleTypeMap["GROUND_ROVER"] = RoverFirmware; + _manifestMavTypeToFirmwareVehicleTypeMap["SUBMARINE"] = SubFirmware; + _threadController = new PX4FirmwareUpgradeThreadController(this); Q_CHECK_PTR(_threadController); @@ -70,8 +93,12 @@ FirmwareUpgradeController::FirmwareUpgradeController(void) connect(&_eraseTimer, &QTimer::timeout, this, &FirmwareUpgradeController::_eraseProgressTick); + connect(_apmChibiOSSetting, &Fact::rawValueChanged, this, &FirmwareUpgradeController::_buildAPMFirmwareNames); + connect(_apmVehicleTypeSetting, &Fact::rawValueChanged, this, &FirmwareUpgradeController::_buildAPMFirmwareNames); + _initFirmwareHash(); _determinePX4StableVersion(); + _downloadArduPilotManifest(); } FirmwareUpgradeController::~FirmwareUpgradeController() @@ -97,7 +124,7 @@ void FirmwareUpgradeController::startBoardSearch(void) } void FirmwareUpgradeController::flash(AutoPilotStackType_t stackType, - FirmwareType_t firmwareType, + FirmwareBuildType_t firmwareType, FirmwareVehicleType_t vehicleType) { qCDebug(FirmwareUpgradeLog) << "_flash stackType:firmwareType:vehicleType" << stackType << firmwareType << vehicleType; @@ -108,6 +135,18 @@ void FirmwareUpgradeController::flash(AutoPilotStackType_t stackType, // We haven't found the bootloader yet. Need to wait until then to flash _startFlashWhenBootloaderFound = true; _startFlashWhenBootloaderFoundFirmwareIdentity = firmwareId; + _firmwareFilename.clear(); + } +} + +void FirmwareUpgradeController::flashFirmwareUrl(QString firmwareFlashUrl) +{ + _firmwareFilename = firmwareFlashUrl; + if (_bootloaderFound) { + _downloadFirmware(); + } else { + // We haven't found the bootloader yet. Need to wait until then to flash + _startFlashWhenBootloaderFound = true; } } @@ -116,7 +155,7 @@ void FirmwareUpgradeController::flash(const FirmwareIdentifier& firmwareId) flash(firmwareId.autopilotStackType, firmwareId.firmwareType, firmwareId.firmwareVehicleType); } -void FirmwareUpgradeController::flashSingleFirmwareMode(FirmwareType_t firmwareType) +void FirmwareUpgradeController::flashSingleFirmwareMode(FirmwareBuildType_t firmwareType) { flash(SingleFirmwareMode, firmwareType, DefaultVehicleFirmware); } @@ -129,9 +168,12 @@ void FirmwareUpgradeController::cancel(void) void FirmwareUpgradeController::_foundBoard(bool firstAttempt, const QSerialPortInfo& info, int boardType, QString boardName) { - _foundBoardInfo = info; - _foundBoardType = static_cast(boardType); - _foundBoardTypeName = boardName; + _foundBoardInfo = info; + _foundBoardType = static_cast(boardType); + _foundBoardTypeName = boardName; + + qDebug() << info.manufacturer() << info.description(); + _startFlashWhenBootloaderFound = false; if (_foundBoardType == QGCSerialPortInfo::BoardTypeSiKRadio) { @@ -178,7 +220,9 @@ void FirmwareUpgradeController::_foundBootloader(int bootloaderVersion, int boar flash(_startFlashWhenBootloaderFoundFirmwareIdentity); } - _loadAPMVersions(_bootloaderBoardID); + if (_rgManifestFirmwareInfo.count()) { + _buildAPMFirmwareNames(); + } } @@ -197,19 +241,6 @@ void FirmwareUpgradeController::_initFirmwareHash() { AutoPilotStackPX4, StableFirmware, DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/stable/aerocore_default.px4"}, { AutoPilotStackPX4, BetaFirmware, DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/beta/aerocore_default.px4"}, { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://gumstix-aerocore.s3.amazonaws.com/PX4/master/aerocore_default.px4"}, - #if !defined(NO_ARDUPILOT_DIALECT) - { AutoPilotStackAPM, BetaFirmware, CopterFirmware, "http://firmware.ardupilot.org/Copter/beta/PX4/ArduCopter-v2.px4"}, - { AutoPilotStackAPM, StableFirmware, HeliFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Copter/stable/PX4-heli/ArduCopter-v2.px4"}, - { AutoPilotStackAPM, StableFirmware, PlaneFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Plane/stable/PX4/ArduPlane-v2.px4"}, - { AutoPilotStackAPM, StableFirmware, RoverFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Rover/stable/PX4/APMrover2-v2.px4"}, - { AutoPilotStackAPM, BetaFirmware, HeliFirmware, "http://firmware.ardupilot.org/Copter/beta/PX4-heli/ArduCopter-v2.px4"}, - { AutoPilotStackAPM, BetaFirmware, PlaneFirmware, "http://firmware.ardupilot.org/Plane/beta/PX4/ArduPlane-v2.px4"}, - { AutoPilotStackAPM, BetaFirmware, RoverFirmware, "http://firmware.ardupilot.org/Rover/beta/PX4/APMrover2-v2.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, CopterFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4/ArduCopter-v2.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, HeliFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Copter/latest/PX4-heli/ArduCopter-v2.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, PlaneFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Plane/latest/PX4/ArduPlane-v2.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, RoverFirmware, "http://gumstix-aerocore.s3.amazonaws.com/Rover/latest/PX4/APMrover2-v2.px4"} - #endif }; //////////////////////////////////// AUAVX2_1 firmwares ////////////////////////////////////////////////// @@ -217,23 +248,6 @@ void FirmwareUpgradeController::_initFirmwareHash() { AutoPilotStackPX4, StableFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/stable/auav-x21_default.px4"}, { AutoPilotStackPX4, BetaFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/beta/auav-x21_default.px4"}, { AutoPilotStackPX4, DeveloperFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/Firmware/master/auav-x21_default.px4"}, - #if !defined(NO_ARDUPILOT_DIALECT) - { AutoPilotStackAPM, StableFirmware, CopterFirmware, "http://firmware.ardupilot.org/Copter/stable/PX4/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, StableFirmware, HeliFirmware, "http://firmware.ardupilot.org/Copter/stable/PX4-heli/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, StableFirmware, PlaneFirmware, "http://firmware.ardupilot.org/Plane/stable/PX4/ArduPlane-v2.px4"}, - { AutoPilotStackAPM, StableFirmware, RoverFirmware, "http://firmware.ardupilot.org/Rover/stable/PX4/APMrover2-v2.px4"}, - { AutoPilotStackAPM, StableFirmware, SubFirmware, "http://firmware.ardupilot.org/Sub/stable/PX4/ArduSub-v2.px4"}, - { AutoPilotStackAPM, BetaFirmware, CopterFirmware, "http://firmware.ardupilot.org/Copter/beta/PX4/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, BetaFirmware, HeliFirmware, "http://firmware.ardupilot.org/Copter/beta/PX4-heli/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, BetaFirmware, PlaneFirmware, "http://firmware.ardupilot.org/Plane/beta/PX4/ArduPlane-v3.px4"}, - { AutoPilotStackAPM, BetaFirmware, RoverFirmware, "http://firmware.ardupilot.org/Rover/beta/PX4/APMrover2-v3.px4"}, - { AutoPilotStackAPM, BetaFirmware, SubFirmware, "http://firmware.ardupilot.org/Sub/beta/PX4/ArduSub-v3.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, CopterFirmware, "http://firmware.ardupilot.org/Copter/latest/PX4/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, HeliFirmware, "http://firmware.ardupilot.org/Copter/latest/PX4-heli/ArduCopter-v3.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, PlaneFirmware, "http://firmware.ardupilot.org/Plane/latest/PX4/ArduPlane-v3.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, RoverFirmware, "http://firmware.ardupilot.org/Rover/latest/PX4/APMrover2-v3.px4"}, - { AutoPilotStackAPM, DeveloperFirmware, SubFirmware, "http://firmware.ardupilot.org/Sub/latest/PX4/ArduSub-v3.px4"} - #endif }; //////////////////////////////////// MindPXFMUV2 firmwares ////////////////////////////////////////////////// FirmwareToUrlElement_t rgMindPXFMUV2FirmwareArray[] = { @@ -288,7 +302,7 @@ void FirmwareUpgradeController::_initFirmwareHash() { ThreeDRRadio, StableFirmware, DefaultVehicleFirmware, "http://px4-travis.s3.amazonaws.com/SiK/stable/radio~hm_trp.ihx"} }; - // We build the maps for PX4 and ArduPilot firmwares dynamically using the data below + // We build the maps for PX4 firmwares dynamically using the data below #if 0 Example URLs for PX4 and ArduPilot @@ -298,77 +312,14 @@ void FirmwareUpgradeController::_initFirmwareHash() #endif QString px4Url ("http://px4-travis.s3.amazonaws.com/Firmware/%1/px4fmu-%2_default.px4"); - QString apmUrl ("http://firmware.ardupilot.org/%1/%2/%3/%4-v%5.px4"); - QString apmChibiOSUrl ("http://firmware.ardupilot.org/%1/%2/fmuv%3%4/%5.apj"); - QMap px4MapFirmwareTypeToDir; + QMap px4MapFirmwareTypeToDir; px4MapFirmwareTypeToDir[StableFirmware] = QStringLiteral("stable"); px4MapFirmwareTypeToDir[BetaFirmware] = QStringLiteral("beta"); px4MapFirmwareTypeToDir[DeveloperFirmware] = QStringLiteral("master"); -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmMapVehicleTypeToDir; - apmMapVehicleTypeToDir[CopterFirmware] = QStringLiteral("Copter"); - apmMapVehicleTypeToDir[HeliFirmware] = QStringLiteral("Copter"); - apmMapVehicleTypeToDir[PlaneFirmware] = QStringLiteral("Plane"); - apmMapVehicleTypeToDir[RoverFirmware] = QStringLiteral("Rover"); - apmMapVehicleTypeToDir[SubFirmware] = QStringLiteral("Sub"); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmChibiOSMapVehicleTypeToDir; - apmChibiOSMapVehicleTypeToDir[CopterChibiOSFirmware] = QStringLiteral("Copter"); - apmChibiOSMapVehicleTypeToDir[HeliChibiOSFirmware] = QStringLiteral("Copter"); - apmChibiOSMapVehicleTypeToDir[PlaneChibiOSFirmware] = QStringLiteral("Plane"); - apmChibiOSMapVehicleTypeToDir[RoverChibiOSFirmware] = QStringLiteral("Rover"); - apmChibiOSMapVehicleTypeToDir[SubChibiOSFirmware] = QStringLiteral("Sub"); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmMapFirmwareTypeToDir; - apmMapFirmwareTypeToDir[StableFirmware] = QStringLiteral("stable"); - apmMapFirmwareTypeToDir[BetaFirmware] = QStringLiteral("beta"); - apmMapFirmwareTypeToDir[DeveloperFirmware] = QStringLiteral("latest"); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmMapVehicleTypeToPX4Dir; - apmMapVehicleTypeToPX4Dir[CopterFirmware] = QStringLiteral("PX4"); - apmMapVehicleTypeToPX4Dir[HeliFirmware] = QStringLiteral("PX4-heli"); - apmMapVehicleTypeToPX4Dir[PlaneFirmware] = QStringLiteral("PX4"); - apmMapVehicleTypeToPX4Dir[RoverFirmware] = QStringLiteral("PX4"); - apmMapVehicleTypeToPX4Dir[SubFirmware] = QStringLiteral("PX4"); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmMapVehicleTypeToFilename; - apmMapVehicleTypeToFilename[CopterFirmware] = QStringLiteral("ArduCopter"); - apmMapVehicleTypeToFilename[HeliFirmware] = QStringLiteral("ArduCopter"); - apmMapVehicleTypeToFilename[PlaneFirmware] = QStringLiteral("ArduPlane"); - apmMapVehicleTypeToFilename[RoverFirmware] = QStringLiteral("APMrover2"); - apmMapVehicleTypeToFilename[SubFirmware] = QStringLiteral("ArduSub"); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmChibiOSMapVehicleTypeToFmuDir; - apmChibiOSMapVehicleTypeToFmuDir[CopterChibiOSFirmware] = QString(); - apmChibiOSMapVehicleTypeToFmuDir[HeliChibiOSFirmware] = QStringLiteral("-heli"); - apmChibiOSMapVehicleTypeToFmuDir[PlaneChibiOSFirmware] = QString(); - apmChibiOSMapVehicleTypeToFmuDir[RoverChibiOSFirmware] = QString(); - apmChibiOSMapVehicleTypeToFmuDir[SubChibiOSFirmware] = QString(); -#endif - -#if !defined(NO_ARDUPILOT_DIALECT) - QMap apmChibiOSMapVehicleTypeToFilename; - apmChibiOSMapVehicleTypeToFilename[CopterChibiOSFirmware] = QStringLiteral("arducopter"); - apmChibiOSMapVehicleTypeToFilename[HeliChibiOSFirmware] = QStringLiteral("arducopter-heli"); - apmChibiOSMapVehicleTypeToFilename[PlaneChibiOSFirmware] = QStringLiteral("arduplane"); - apmChibiOSMapVehicleTypeToFilename[RoverChibiOSFirmware] = QStringLiteral("ardurover"); - apmChibiOSMapVehicleTypeToFilename[SubChibiOSFirmware] = QStringLiteral("ardusub"); -#endif - // PX4 Firmwares - for (const FirmwareType_t& firmwareType: px4MapFirmwareTypeToDir.keys()) { + for (const FirmwareBuildType_t& firmwareType: px4MapFirmwareTypeToDir.keys()) { QString dir = px4MapFirmwareTypeToDir[firmwareType]; _rgFMUV5Firmware.insert (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v5")); _rgFMUV4PROFirmware.insert (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v4pro")); @@ -377,49 +328,6 @@ void FirmwareUpgradeController::_initFirmwareHash() _rgPX4FMUV2Firmware.insert (FirmwareIdentifier(AutoPilotStackPX4, firmwareType, DefaultVehicleFirmware), px4Url.arg(dir).arg("v2")); } -#if !defined(NO_ARDUPILOT_DIALECT) - // ArduPilot non-ChibiOS Firmwares for direct board id to fmu mappings - for (const FirmwareType_t& firmwareType: apmMapFirmwareTypeToDir.keys()) { - QString firmwareTypeDir = apmMapFirmwareTypeToDir[firmwareType]; - for (const FirmwareVehicleType_t& vehicleType: apmMapVehicleTypeToDir.keys()) { - QString vehicleTypeDir = apmMapVehicleTypeToDir[vehicleType]; - QString px4Dir = apmMapVehicleTypeToPX4Dir[vehicleType]; - QString filename = apmMapVehicleTypeToFilename[vehicleType]; - _rgFMUV5Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg(px4Dir).arg(filename).arg("5")); - _rgFMUV4Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg(px4Dir).arg(filename).arg("4")); - _rgFMUV3Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg(px4Dir).arg(filename).arg("3")); - _rgPX4FMUV2Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg(px4Dir).arg(filename).arg("2")); - } - } - - // ArduPilot ChibiOS Firmwares for direct board id to fmu mappings. Used when bootloader is not new ArduPilot bootloader. - for (const FirmwareType_t& firmwareType: apmMapFirmwareTypeToDir.keys()) { - QString firmwareTypeDir = apmMapFirmwareTypeToDir[firmwareType]; - for (const FirmwareVehicleType_t& vehicleType: apmChibiOSMapVehicleTypeToDir.keys()) { - QString vehicleTypeDir = apmChibiOSMapVehicleTypeToDir[vehicleType]; - QString fmuDir = apmChibiOSMapVehicleTypeToFmuDir[vehicleType]; - QString filename = apmChibiOSMapVehicleTypeToFilename[vehicleType]; - _rgFMUV5Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmChibiOSUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg("5").arg(fmuDir).arg(filename)); - _rgFMUV4Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmChibiOSUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg("4").arg(fmuDir).arg(filename)); - _rgFMUV3Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmChibiOSUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg("3").arg(fmuDir).arg(filename)); - _rgPX4FMUV2Firmware.insert (FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), apmChibiOSUrl.arg(vehicleTypeDir).arg(firmwareTypeDir).arg("2").arg(fmuDir).arg(filename)); - } - } - - // ArduPilot ChibiOS Firmwares when board id is an unknown type but follows ArduPilot port info naming conventions. - // This is only used if the board is using the new ArduPilot bootloader port naming scheme. - for (const FirmwareType_t& firmwareType: apmMapFirmwareTypeToDir.keys()) { - QString firmwareTypeDir = apmMapFirmwareTypeToDir[firmwareType]; - for (const FirmwareVehicleType_t& vehicleType: apmChibiOSMapVehicleTypeToDir.keys()) { - QString namedURL("http://firmware.ardupilot.org/%1/%2/%3%4/%5.apj"); - QString vehicleTypeDir = apmChibiOSMapVehicleTypeToDir[vehicleType]; - QString fmuDir = apmChibiOSMapVehicleTypeToFmuDir[vehicleType]; - QString filename = apmChibiOSMapVehicleTypeToFilename[vehicleType]; - _rgAPMChibiosReplaceNamedBoardFirmware.insert(FirmwareIdentifier(AutoPilotStackAPM, firmwareType, vehicleType), namedURL.arg(vehicleTypeDir).arg(firmwareTypeDir).arg(_apmBoardDescriptionReplaceText).arg(fmuDir).arg(filename)); - } - } -#endif - int size = sizeof(rgAeroCoreFirmwareArray)/sizeof(rgAeroCoreFirmwareArray[0]); for (int i = 0; i < size; i++) { const FirmwareToUrlElement_t& element = rgAeroCoreFirmwareArray[i]; @@ -550,24 +458,6 @@ QHash* FirmwareUpgradeCo break; } - // Check for ArduPilot ChibiOS bootloader - QStringList rgManufacturers = { QStringLiteral("ArduPilot"), QStringLiteral("Hex/ProfiCNC"), QStringLiteral("Holybro") }; - QString apmDescriptionSuffix("-BL"); - if (rgManufacturers.contains(_foundBoardInfo.manufacturer()) && _foundBoardInfo.description().endsWith(apmDescriptionSuffix)) { - // Board ios using a ChibiOS bootloader. Prefer naming scheme from that over board ids for ArduPilot entries. - - // First remove the ChibiOS by board id entries from the list - for (const FirmwareIdentifier& firmwareId: _rgAPMChibiosReplaceNamedBoardFirmware.keys()) { - _rgFirmwareDynamic.remove(firmwareId); - } - - // Now add the ChibiOS by board description entries to the list - for (const FirmwareIdentifier& firmwareId: _rgAPMChibiosReplaceNamedBoardFirmware.keys()) { - QString namedUrl = _rgAPMChibiosReplaceNamedBoardFirmware[firmwareId]; - _rgFirmwareDynamic.insert(firmwareId, namedUrl.replace(_apmBoardDescriptionReplaceText, _foundBoardInfo.description().left(_foundBoardInfo.description().length() - apmDescriptionSuffix.length()))); - } - } - return &_rgFirmwareDynamic; } @@ -659,7 +549,7 @@ void FirmwareUpgradeController::_firmwareDownloadError(QString errorMsg) } /// @brief returns firmware type as a string -QString FirmwareUpgradeController::firmwareTypeAsString(FirmwareType_t type) const +QString FirmwareUpgradeController::firmwareTypeAsString(FirmwareBuildType_t type) const { switch (type) { case StableFirmware: @@ -757,119 +647,62 @@ void FirmwareUpgradeController::_eraseComplete(void) _eraseTimer.stop(); } -void FirmwareUpgradeController::_loadAPMVersions(uint32_t bootloaderBoardID) +void FirmwareUpgradeController::setSelectedFirmwareBuildType(FirmwareBuildType_t firmwareType) { - _apmVersionMap.clear(); - - QHash* prgFirmware = _firmwareHashForBoardId(static_cast(bootloaderBoardID)); - - for (FirmwareIdentifier firmwareId: prgFirmware->keys()) { - if (firmwareId.autopilotStackType == AutoPilotStackAPM) { - QString versionFile = QFileInfo(prgFirmware->value(firmwareId)).path() + "/git-version.txt"; - - qCDebug(FirmwareUpgradeLog) << "Downloading" << versionFile; - QGCFileDownload* downloader = new QGCFileDownload(this); - connect(downloader, &QGCFileDownload::downloadFinished, this, &FirmwareUpgradeController::_apmVersionDownloadFinished); - downloader->download(versionFile); - } - } + _selectedFirmwareBuildType = firmwareType; + emit selectedFirmwareBuildTypeChanged(_selectedFirmwareBuildType); + _buildAPMFirmwareNames(); } -void FirmwareUpgradeController::_apmVersionDownloadFinished(QString remoteFile, QString localFile) +void FirmwareUpgradeController::_buildAPMFirmwareNames(void) { - qCDebug(FirmwareUpgradeLog) << "Download complete" << remoteFile << localFile; - - // Now read the version file and pull out the version string + qCDebug(FirmwareUpgradeLog) << "_buildAPMFirmwareNames"; - QFile versionFile(localFile); - versionFile.open(QIODevice::ReadOnly | QIODevice::Text); - QTextStream stream(&versionFile); - QString versionContents = stream.readAll(); + bool chibios = _apmChibiOSSetting->rawValue().toInt() == 0; + FirmwareVehicleType_t vehicleType = static_cast(_apmVehicleTypeSetting->rawValue().toInt()); - QString version; - QRegularExpression re("APMVERSION: (.*)$"); - QRegularExpressionMatch match = re.match(versionContents); - if (match.hasMatch()) { - version = match.captured(1); - } - - if (version.isEmpty()) { - qWarning() << "Unable to parse version info from file" << remoteFile; - sender()->deleteLater(); - return; - } + _apmFirmwareNames.clear(); + _apmFirmwareUrls.clear(); - // In order to determine the firmware and vehicle type for this file we find the matching entry in the firmware list + QString apmDescriptionSuffix("-BL"); + bool bootloaderMatch = _foundBoardInfo.description().endsWith(apmDescriptionSuffix); + + for (const ManifestFirmwareInfo_t& firmwareInfo: _rgManifestFirmwareInfo) { + bool match = false; + if (firmwareInfo.firmwareBuildType == _selectedFirmwareBuildType && firmwareInfo.chibios == chibios && firmwareInfo.vehicleType == vehicleType) { + if (bootloaderMatch) { + if (firmwareInfo.rgBootloaderPortString.contains(_foundBoardInfo.description())) { + qCDebug(FirmwareUpgradeLog) << "Bootloader match:" << firmwareInfo.friendlyName << _foundBoardInfo.description() << firmwareInfo.rgBootloaderPortString << firmwareInfo.url << firmwareInfo.vehicleType; + match = true; + } + } else { + if (firmwareInfo.rgVID.contains(_foundBoardInfo.vendorIdentifier()) && firmwareInfo.rgPID.contains(_foundBoardInfo.productIdentifier())) { + qCDebug(FirmwareUpgradeLog) << "Fallback match:" << firmwareInfo.friendlyName << _foundBoardInfo.vendorIdentifier() << _foundBoardInfo.productIdentifier() << _bootloaderBoardID << firmwareInfo.url << firmwareInfo.vehicleType; + match = true; + } + } + } - QHash* prgFirmware = _firmwareHashForBoardId(static_cast(_bootloaderBoardID)); + // Do a final filter on fmuv2/fmuv3 + if (match && _bootloaderBoardID == Bootloader::boardIDPX4FMUV3) { + match = !firmwareInfo.fmuv2; + } - QString remotePath = QFileInfo(remoteFile).path(); - for (FirmwareIdentifier firmwareId: prgFirmware->keys()) { - if (remotePath == QFileInfo((*prgFirmware)[firmwareId]).path()) { - qCDebug(FirmwareUpgradeLog) << "Adding version to map, version:firwmareType:vehicleType" << version << firmwareId.firmwareType << firmwareId.firmwareVehicleType; - _apmVersionMap[firmwareId.firmwareType][firmwareId.firmwareVehicleType] = version; + if (match) { + _apmFirmwareNames.append(firmwareInfo.friendlyName); + _apmFirmwareUrls.append(firmwareInfo.url); } } - emit apmAvailableVersionsChanged(); - sender()->deleteLater(); -} - -void FirmwareUpgradeController::setSelectedFirmwareType(FirmwareType_t firmwareType) -{ - _selectedFirmwareType = firmwareType; - emit selectedFirmwareTypeChanged(_selectedFirmwareType); - emit apmAvailableVersionsChanged(); -} - -QStringList FirmwareUpgradeController::apmAvailableVersions(void) -{ - QStringList list; - QList vehicleTypes; - - // This allows us to force the order of the combo box display - vehicleTypes << CopterChibiOSFirmware << HeliChibiOSFirmware << PlaneChibiOSFirmware << RoverChibiOSFirmware << SubChibiOSFirmware << CopterFirmware << HeliFirmware << PlaneFirmware << RoverFirmware << SubFirmware; - - _apmVehicleTypeFromCurrentVersionList.clear(); - - for (FirmwareVehicleType_t vehicleType: vehicleTypes) { - if (_apmVersionMap[_selectedFirmwareType].contains(vehicleType)) { - QString version; - - switch (vehicleType) { - case CopterFirmware: - version = tr("NuttX - MultiRotor:"); - break; - case HeliFirmware: - version = tr("NuttX - Heli:"); - break; - case CopterChibiOSFirmware: - version = tr("ChibiOS- MultiRotor:"); - break; - case HeliChibiOSFirmware: - version = tr("ChibiOS - Heli:"); - break; - case PlaneChibiOSFirmware: - case RoverChibiOSFirmware: - case SubChibiOSFirmware: - version = tr("ChibiOS - "); - break; - default: - version = tr("NuttX - "); - break; - } - - version += _apmVersionMap[_selectedFirmwareType][vehicleType]; - _apmVehicleTypeFromCurrentVersionList.append(vehicleType); - - list << version; - } + if (_apmFirmwareNames.count() > 1) { + _apmFirmwareNames.prepend(tr("Choose board type")); + _apmFirmwareUrls.prepend(QString()); } - return list; + emit apmFirmwareNamesChanged(); } -FirmwareUpgradeController::FirmwareVehicleType_t FirmwareUpgradeController::vehicleTypeFromVersionIndex(int index) +FirmwareUpgradeController::FirmwareVehicleType_t FirmwareUpgradeController::vehicleTypeFromFirmwareSelectionIndex(int index) { if (index < 0 || index >= _apmVehicleTypeFromCurrentVersionList.count()) { qWarning() << "Invalid index, index:count" << index << _apmVehicleTypeFromCurrentVersionList.count(); @@ -944,3 +777,147 @@ void FirmwareUpgradeController::_px4ReleasesGithubDownloadError(QString errorMsg { qCWarning(FirmwareUpgradeLog) << "PX4 releases github download failed" << errorMsg; } + +void FirmwareUpgradeController::_downloadArduPilotManifest(void) +{ + _downloadingFirmwareList = true; + emit downloadingFirmwareListChanged(true); + + QGCFileDownload* downloader = new QGCFileDownload(this); + connect(downloader, &QGCFileDownload::downloadFinished, this, &FirmwareUpgradeController::_ardupilotManifestDownloadFinished); + connect(downloader, &QGCFileDownload::error, this, &FirmwareUpgradeController::_ardupilotManifestDownloadError); +#if 0 + downloader->download(QStringLiteral("http://firmware.ardupilot.org/manifest.json.gz")); +#else + downloader->download(QStringLiteral("http://firmware.ardupilot.org/manifest.json")); +#endif +} + +void FirmwareUpgradeController::_ardupilotManifestDownloadFinished(QString remoteFile, QString localFile) +{ + Q_UNUSED(remoteFile); + + // Delete the QGCFileDownload object + sender()->deleteLater(); + + qDebug() << "_ardupilotManifestDownloadFinished" << remoteFile << localFile; + +#if 0 + QFile gzipFile(localFile); + if (!gzipFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCWarning(FirmwareUpgradeLog) << "Unable to open ArduPilot firmware manifest file" << localFile << gzipFile.errorString(); + QFile::remove(localFile); + return; + } + + // Store decompressed size as first four bytes. This is required by qUncompress routine. + QByteArray raw; + int decompressedSize = 3073444; + raw.append((unsigned char)((decompressedSize >> 24) & 0xFF)); + raw.append((unsigned char)((decompressedSize >> 16) & 0xFF)); + raw.append((unsigned char)((decompressedSize >> 8) & 0xFF)); + raw.append((unsigned char)((decompressedSize >> 0) & 0xFF)); + + raw.append(gzipFile.readAll()); + QByteArray bytes = qUncompress(raw); +#else + + + QFile jsonFile(localFile); + if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCWarning(FirmwareUpgradeLog) << "Unable to open ArduPilot firmware manifest file" << localFile << jsonFile.errorString(); + QFile::remove(localFile); + return; + } + QByteArray bytes = jsonFile.readAll(); + jsonFile.close(); +#endif + QFile::remove(localFile); + + QJsonParseError jsonParseError; + QJsonDocument doc = QJsonDocument::fromJson(bytes, &jsonParseError); + if (jsonParseError.error != QJsonParseError::NoError) { + qCWarning(FirmwareUpgradeLog) << "Unable to open ArduPilot manifest json document" << localFile << jsonParseError.errorString(); + } + + + + + QJsonObject json = doc.object(); + QJsonArray rgFirmware = json[_manifestFirmwareJsonKey].toArray(); + + for (int i=0; i(firmwareJson[_manifestBoardIdJsonKey].toInt()); + firmwareInfo.firmwareBuildType = firmwareBuildType; + firmwareInfo.vehicleType = firmwareVehicleType; + firmwareInfo.url = firmwareJson[_manifestUrlJsonKey].toString(); + firmwareInfo.version = firmwareJson[_manifestMavFirmwareVersionJsonKey].toString(); + firmwareInfo.chibios = format == QStringLiteral("apj"); + firmwareInfo.fmuv2 = platform.contains(QStringLiteral("fmuv2")); + + QJsonArray bootloaderArray = firmwareJson[_manifestBootloaderStrJsonKey].toArray(); + for (int j=0; j - -#ifndef FirmwareUpgradeController_H -#define FirmwareUpgradeController_H +#pragma once #include "PX4FirmwareUpgradeThread.h" #include "LinkManager.h" #include "FirmwareImage.h" +#include "Fact.h" #include #include @@ -38,7 +34,7 @@ class FirmwareUpgradeController : public QObject public: typedef enum { - AutoPilotStackPX4, + AutoPilotStackPX4 = 0, AutoPilotStackAPM, PX4FlowPX4, PX4FlowAPM, @@ -47,35 +43,30 @@ public: } AutoPilotStackType_t; typedef enum { - StableFirmware, + StableFirmware = 0, BetaFirmware, DeveloperFirmware, CustomFirmware - } FirmwareType_t; + } FirmwareBuildType_t; typedef enum { - CopterFirmware, + CopterFirmware = 0, HeliFirmware, PlaneFirmware, RoverFirmware, SubFirmware, - CopterChibiOSFirmware, - HeliChibiOSFirmware, - PlaneChibiOSFirmware, - RoverChibiOSFirmware, - SubChibiOSFirmware, DefaultVehicleFirmware } FirmwareVehicleType_t; Q_ENUM(AutoPilotStackType_t) - Q_ENUM(FirmwareType_t) + Q_ENUM(FirmwareBuildType_t) Q_ENUM(FirmwareVehicleType_t) class FirmwareIdentifier { public: FirmwareIdentifier(AutoPilotStackType_t stack = AutoPilotStackPX4, - FirmwareType_t firmware = StableFirmware, + FirmwareBuildType_t firmware = StableFirmware, FirmwareVehicleType_t vehicle = DefaultVehicleFirmware) : autopilotStackType(stack), firmwareType(firmware), firmwareVehicleType(vehicle) {} @@ -88,22 +79,24 @@ public: // members AutoPilotStackType_t autopilotStackType; - FirmwareType_t firmwareType; + FirmwareBuildType_t firmwareType; FirmwareVehicleType_t firmwareVehicleType; }; FirmwareUpgradeController(void); ~FirmwareUpgradeController(); - Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound) - Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound) - Q_PROPERTY(QString boardType MEMBER _foundBoardTypeName NOTIFY boardFound) - Q_PROPERTY(bool pixhawkBoard READ pixhawkBoard NOTIFY boardFound) - Q_PROPERTY(bool px4FlowBoard READ px4FlowBoard NOTIFY boardFound) - Q_PROPERTY(FirmwareType_t selectedFirmwareType READ selectedFirmwareType WRITE setSelectedFirmwareType NOTIFY selectedFirmwareTypeChanged) - Q_PROPERTY(QStringList apmAvailableVersions READ apmAvailableVersions NOTIFY apmAvailableVersionsChanged) - Q_PROPERTY(QString px4StableVersion READ px4StableVersion NOTIFY px4StableVersionChanged) - Q_PROPERTY(QString px4BetaVersion READ px4BetaVersion NOTIFY px4BetaVersionChanged) + Q_PROPERTY(bool downloadingFirmwareList MEMBER _downloadingFirmwareList NOTIFY downloadingFirmwareListChanged) + Q_PROPERTY(QString boardPort READ boardPort NOTIFY boardFound) + Q_PROPERTY(QString boardDescription READ boardDescription NOTIFY boardFound) + Q_PROPERTY(QString boardType MEMBER _foundBoardTypeName NOTIFY boardFound) + Q_PROPERTY(bool pixhawkBoard READ pixhawkBoard NOTIFY boardFound) + Q_PROPERTY(bool px4FlowBoard READ px4FlowBoard NOTIFY boardFound) + Q_PROPERTY(FirmwareBuildType_t selectedFirmwareBuildType READ selectedFirmwareBuildType WRITE setSelectedFirmwareBuildType NOTIFY selectedFirmwareBuildTypeChanged) + Q_PROPERTY(QStringList apmFirmwareNames MEMBER _apmFirmwareNames NOTIFY apmFirmwareNamesChanged) + Q_PROPERTY(QStringList apmFirmwareUrls MEMBER _apmFirmwareUrls NOTIFY apmFirmwareNamesChanged) + Q_PROPERTY(QString px4StableVersion READ px4StableVersion NOTIFY px4StableVersionChanged) + Q_PROPERTY(QString px4BetaVersion READ px4BetaVersion NOTIFY px4BetaVersionChanged) /// TextArea for log output Q_PROPERTY(QQuickItem* statusLog READ statusLog WRITE setStatusLog) @@ -119,13 +112,15 @@ public: /// Called when the firmware type has been selected by the user to continue the flash process. Q_INVOKABLE void flash(AutoPilotStackType_t stackType, - FirmwareType_t firmwareType = StableFirmware, + FirmwareBuildType_t firmwareType = StableFirmware, FirmwareVehicleType_t vehicleType = DefaultVehicleFirmware ); + Q_INVOKABLE void flashFirmwareUrl(QString firmwareUrl); + /// Called to flash when upgrade is running in singleFirmwareMode - Q_INVOKABLE void flashSingleFirmwareMode(FirmwareType_t firmwareType); + Q_INVOKABLE void flashSingleFirmwareMode(FirmwareBuildType_t firmwareType); - Q_INVOKABLE FirmwareVehicleType_t vehicleTypeFromVersionIndex(int index); + Q_INVOKABLE FirmwareVehicleType_t vehicleTypeFromFirmwareSelectionIndex(int index); // overload, not exposed to qml side void flash(const FirmwareIdentifier& firmwareId); @@ -141,28 +136,28 @@ public: QString boardPort(void) { return _foundBoardInfo.portName(); } QString boardDescription(void) { return _foundBoardInfo.description(); } - FirmwareType_t selectedFirmwareType(void) { return _selectedFirmwareType; } - void setSelectedFirmwareType(FirmwareType_t firmwareType); - QString firmwareTypeAsString(FirmwareType_t type) const; + FirmwareBuildType_t selectedFirmwareBuildType(void) { return _selectedFirmwareBuildType; } + void setSelectedFirmwareBuildType(FirmwareBuildType_t firmwareType); + QString firmwareTypeAsString(FirmwareBuildType_t type) const; - QStringList apmAvailableVersions(void); - QString px4StableVersion(void) { return _px4StableVersion; } - QString px4BetaVersion(void) { return _px4BetaVersion; } + QString px4StableVersion (void) { return _px4StableVersion; } + QString px4BetaVersion (void) { return _px4BetaVersion; } bool pixhawkBoard(void) const { return _foundBoardType == QGCSerialPortInfo::BoardTypePixhawk; } bool px4FlowBoard(void) const { return _foundBoardType == QGCSerialPortInfo::BoardTypePX4Flow; } signals: - void boardFound(void); - void noBoardFound(void); - void boardGone(void); - void flashComplete(void); - void flashCancelled(void); - void error(void); - void selectedFirmwareTypeChanged(FirmwareType_t firmwareType); - void apmAvailableVersionsChanged(void); - void px4StableVersionChanged(const QString& px4StableVersion); - void px4BetaVersionChanged(const QString& px4BetaVersion); + void boardFound (void); + void noBoardFound (void); + void boardGone (void); + void flashComplete (void); + void flashCancelled (void); + void error (void); + void selectedFirmwareBuildTypeChanged(FirmwareBuildType_t firmwareType); + void apmFirmwareNamesChanged (void); + void px4StableVersionChanged (const QString& px4StableVersion); + void px4BetaVersionChanged (const QString& px4BetaVersion); + void downloadingFirmwareListChanged (bool downloadingFirmwareList); private slots: void _firmwareDownloadProgress(qint64 curr, qint64 total); @@ -180,22 +175,25 @@ private slots: void _eraseStarted(void); void _eraseComplete(void); void _eraseProgressTick(void); - void _apmVersionDownloadFinished(QString remoteFile, QString localFile); void _px4ReleasesGithubDownloadFinished(QString remoteFile, QString localFile); void _px4ReleasesGithubDownloadError(QString errorMsg); + void _ardupilotManifestDownloadFinished(QString remoteFile, QString localFile); + void _ardupilotManifestDownloadError(QString errorMsg); + void _buildAPMFirmwareNames(void); private: - void _getFirmwareFile(FirmwareIdentifier firmwareId); - void _initFirmwareHash(); - void _downloadFirmware(void); - void _appendStatusLog(const QString& text, bool critical = false); - void _errorCancel(const QString& msg); - void _loadAPMVersions(uint32_t bootloaderBoardID); QHash* _firmwareHashForBoardId(int boardId); - void _determinePX4StableVersion(void); + void _getFirmwareFile(FirmwareIdentifier firmwareId); + void _initFirmwareHash (void); + void _downloadFirmware (void); + void _appendStatusLog (const QString& text, bool critical = false); + void _errorCancel (const QString& msg); + void _determinePX4StableVersion (void); + void _downloadArduPilotManifest (void); QString _singleFirmwareURL; bool _singleFirmwareMode; + bool _downloadingFirmwareList; QString _portName; QString _portDescription; @@ -220,7 +218,7 @@ private: QHash _rgAPMChibiosReplaceNamedBoardFirmware; QHash _rgFirmwareDynamic; - QMap > _apmVersionMap; + QMap > _apmVersionMap; QList _apmVehicleTypeFromCurrentVersionList; /// Information which comes back from the bootloader @@ -259,7 +257,7 @@ private: QGCSerialPortInfo::BoardType_t _foundBoardType; QString _foundBoardTypeName; - FirmwareType_t _selectedFirmwareType; + FirmwareBuildType_t _selectedFirmwareBuildType; FirmwareImage* _image; @@ -267,9 +265,46 @@ private: QString _px4BetaVersion; // Version strange for latest PX4 beta const QString _apmBoardDescriptionReplaceText; + + static const char* _manifestFirmwareJsonKey; + static const char* _manifestBoardIdJsonKey; + static const char* _manifestMavTypeJsonKey; + static const char* _manifestFormatJsonKey; + static const char* _manifestUrlJsonKey; + static const char* _manifestMavFirmwareVersionTypeJsonKey; + static const char* _manifestUSBIDJsonKey; + static const char* _manifestMavFirmwareVersionJsonKey; + static const char* _manifestBootloaderStrJsonKey; + static const char* _manifestLatestKey; + static const char* _manifestPlatformKey; + static const char* _manifestBrandNameKey; + + typedef struct { + uint32_t boardId; + FirmwareBuildType_t firmwareBuildType; + FirmwareVehicleType_t vehicleType; + QString url; + QString version; + QStringList rgBootloaderPortString; + QList rgVID; + QList rgPID; + QString friendlyName; + bool chibios; + bool fmuv2; + } ManifestFirmwareInfo_t; + + + QList _rgManifestFirmwareInfo; + QMap _manifestMavFirmwareVersionTypeToFirmwareBuildTypeMap; + QMap _manifestMavTypeToFirmwareVehicleTypeMap; + QStringList _apmFirmwareNames; + QStringList _apmFirmwareUrls; + Fact* _apmChibiOSSetting; + Fact* _apmVehicleTypeSetting; + + FirmwareBuildType_t _manifestMavFirmwareVersionTypeToFirmwareBuildType (const QString& manifestMavFirmwareVersionType); + FirmwareVehicleType_t _manifestMavTypeToFirmwareVehicleType (const QString& manifestMavType); }; // global hashing function uint qHash(const FirmwareUpgradeController::FirmwareIdentifier& firmwareId); - -#endif diff --git a/src/VideoStreaming/VideoReceiver.cc b/src/VideoStreaming/VideoReceiver.cc index 369fb492c51c52e67d863ee406c6634cd45768f3..5e693fc07d415fdc43ec556cef4146a40fc57165 100644 --- a/src/VideoStreaming/VideoReceiver.cc +++ b/src/VideoStreaming/VideoReceiver.cc @@ -712,17 +712,18 @@ VideoReceiver::startRecording(const QString &videoFile) gst_object_ref(_sink->mux); gst_object_ref(_sink->filesink); - gst_bin_add_many(GST_BIN(_pipeline), _sink->queue, _sink->parse, _sink->mux, _sink->filesink, nullptr); - gst_element_link_many(_sink->queue, _sink->parse, _sink->mux, _sink->filesink, nullptr); + gst_bin_add_many(GST_BIN(_pipeline), _sink->queue, _sink->parse, _sink->mux, nullptr); + gst_element_link_many(_sink->queue, _sink->parse, _sink->mux, nullptr); gst_element_sync_state_with_parent(_sink->queue); gst_element_sync_state_with_parent(_sink->parse); gst_element_sync_state_with_parent(_sink->mux); - gst_element_sync_state_with_parent(_sink->filesink); // Install a probe on the recording branch to drop buffers until we hit our first keyframe // When we hit our first keyframe, we can offset the timestamps appropriately according to the first keyframe time // This will ensure the first frame is a keyframe at t=0, and decoding can begin immediately on playback + // Once we have this valid frame, we attach the filesink. + // Attaching it here would cause the filesink to fail to preroll and to stall the pipeline for a few seconds. GstPad* probepad = gst_element_get_static_pad(_sink->queue, "src"); gst_pad_add_probe(probepad, (GstPadProbeType)(GST_PAD_PROBE_TYPE_BUFFER /* | GST_PAD_PROBE_TYPE_BLOCK */), _keyframeWatch, this, nullptr); // to drop the buffer or to block the buffer? gst_object_unref(probepad); @@ -875,6 +876,12 @@ VideoReceiver::_keyframeWatch(GstPad* pad, GstPadProbeInfo* info, gpointer user_ gst_element_set_base_time(pThis->_pipeline, time); // offset pipeline timestamps to start at zero again buf->dts = 0; // The offset will not apply to this current buffer, our first frame, timestamp is zero buf->pts = 0; + + // Add the filesink once we have a valid I-frame + gst_bin_add_many(GST_BIN(pThis->_pipeline), pThis->_sink->filesink, nullptr); + gst_element_link_many(pThis->_sink->mux, pThis->_sink->filesink, nullptr); + gst_element_sync_state_with_parent(pThis->_sink->filesink); + qCDebug(VideoReceiverLog) << "Got keyframe, stop dropping buffers"; } }