QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
FirmwareUpgrade.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Dialogs
4import QtQuick.Layouts
5
6import QGroundControl
7import QGroundControl.Controls
8import QGroundControl.FactControls
9
10SetupPage {
11 id: firmwarePage
12 pageComponent: firmwarePageComponent
13 pageName: qsTr("Firmware")
14 showAdvanced: globals.activeVehicle && globals.activeVehicle.apmFirmware
15
16 Component {
17 id: firmwarePageComponent
18
19 ColumnLayout {
20 width: availableWidth
21 height: availableHeight
22 spacing: ScreenTools.defaultFontPixelHeight
23
24 // Those user visible strings are hard to translate because we can't send the
25 // HTML strings to translation as this can create a security risk. we need to find
26 // a better way to highlight them, or use less highlights.
27
28 // User visible strings
29 readonly property string title: qsTr("Firmware Setup") // Popup dialog title
30 readonly property string highlightPrefix: "<font color=\"" + qgcPal.warningText + "\">"
31 readonly property string highlightSuffix: "</font>"
32 readonly property string welcomeText: qsTr("%1 can upgrade the firmware on Pixhawk devices and SiK Radios.").arg(QGroundControl.appName)
33 readonly property string welcomeTextSingle: qsTr("Update the autopilot firmware to the latest version")
34 readonly property string plugInText: "<big>" + highlightPrefix + qsTr("Plug in your device") + highlightSuffix + qsTr(" via USB to ") + highlightPrefix + qsTr("start") + highlightSuffix + qsTr(" firmware upgrade.") + "</big>"
35 readonly property string flashFailText: qsTr("If upgrade failed, make sure to connect ") + highlightPrefix + qsTr("directly") + highlightSuffix + qsTr(" to a powered USB port on your computer, not through a USB hub. ") +
36 qsTr("Also make sure you are only powered via USB ") + highlightPrefix + qsTr("not battery") + highlightSuffix + "."
37 readonly property string qgcUnplugText1: qsTr("All %1 connections to vehicles must be ").arg(QGroundControl.appName) + highlightPrefix + qsTr(" disconnected ") + highlightSuffix + qsTr("prior to firmware upgrade.")
38 readonly property string qgcUnplugText2: highlightPrefix + "<big>" + qsTr("Please unplug your Pixhawk and/or Radio from USB.") + "</big>" + highlightSuffix
39
40 readonly property int _defaultFimwareTypePX4: 12
41 readonly property int _defaultFimwareTypeAPM: 3
42
43 property var _firmwareUpgradeSettings: QGroundControl.settingsManager.firmwareUpgradeSettings
44 property var _defaultFirmwareFact: _firmwareUpgradeSettings.defaultFirmwareType
45 property bool _defaultFirmwareIsPX4: true
46
47 property string firmwareWarningMessage
48 property bool firmwareWarningMessageVisible: false
49 property bool initialBoardSearch: true
50 property string firmwareName
51
52 property bool _singleFirmwareMode: QGroundControl.corePlugin.options.firmwareUpgradeSingleURL.length != 0 ///< true: running in special single firmware download mode
53
54 function setupPageCompleted() {
55 controller.startBoardSearch()
56 _defaultFirmwareIsPX4 = _defaultFirmwareFact.rawValue === _defaultFimwareTypePX4 // we don't want this to be bound and change as radios are selected
57 }
58
59 QGCFileDialog {
60 id: customFirmwareDialog
61 title: qsTr("Select Firmware File")
62 nameFilters: [qsTr("Firmware Files (*.px4 *.apj *.bin *.ihx)"), qsTr("All Files (*)")]
63 folder: QGroundControl.settingsManager.appSettings.logSavePath
64 onAcceptedForLoad: (file) => {
65 controller.flashFirmwareUrl(file)
66 close()
67 }
68 }
69
70 FirmwareUpgradeController {
71 id: controller
72 progressBar: progressBar
73 statusLog: statusTextArea
74
75 property var activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
76
77 onActiveVehicleChanged: {
78 if (!globals.activeVehicle) {
79 statusTextArea.append(plugInText)
80 }
81 }
82
83 onNoBoardFound: {
84 initialBoardSearch = false
85 if (!QGroundControl.multiVehicleManager.activeVehicleAvailable) {
86 statusTextArea.append(plugInText)
87 }
88 }
89
90 onBoardGone: {
91 initialBoardSearch = false
92 if (!QGroundControl.multiVehicleManager.activeVehicleAvailable) {
93 statusTextArea.append(plugInText)
94 }
95 }
96
97 onBoardFound: {
98 if (initialBoardSearch) {
99 // Board was found right away, so something is already plugged in before we've started upgrade
100 statusTextArea.append(qgcUnplugText1)
101 statusTextArea.append(qgcUnplugText2)
102
103 var availableDevices = controller.availableBoardsName()
104 if (availableDevices.length > 1) {
105 statusTextArea.append(highlightPrefix + qsTr("Multiple devices detected! Remove all detected devices to perform the firmware upgrade."))
106 statusTextArea.append(qsTr("Detected [%1]: ").arg(availableDevices.length) + availableDevices.join(", "))
107 }
108 if (QGroundControl.multiVehicleManager.activeVehicle) {
109 QGroundControl.multiVehicleManager.activeVehicle.vehicleLinkManager.autoDisconnect = true
110 }
111 } else {
112 // We end up here when we detect a board plugged in after we've started upgrade
113 statusTextArea.append(highlightPrefix + qsTr("Found device") + highlightSuffix + ": " + controller.boardType)
114 }
115 }
116
117 onShowFirmwareSelectDlg: firmwareSelectDialogFactory.open()
118 onError: statusTextArea.append(flashFailText)
119 }
120
121 QGCPopupDialogFactory {
122 id: firmwareSelectDialogFactory
123
124 dialogComponent: firmwareSelectDialogComponent
125 }
126
127 Component {
128 id: firmwareSelectDialogComponent
129
130 QGCPopupDialog {
131 id: firmwareSelectDialog
132 title: qsTr("Firmware Setup")
133 buttons: Dialog.Ok | Dialog.Cancel
134
135 property bool showFirmwareTypeSelection: _advanced.checked
136
137 function firmwareVersionChanged(model) {
138 firmwareWarningMessageVisible = false
139 // All of this bizarre, setting model to null and index to 1 and then to 0 is to work around
140 // strangeness in the combo box implementation. This sequence of steps correctly changes the combo model
141 // without generating any warnings and correctly updates the combo text with the new selection.
142 firmwareBuildTypeCombo.model = null
143 firmwareBuildTypeCombo.model = model
144 firmwareBuildTypeCombo.currentIndex = 1
145 firmwareBuildTypeCombo.currentIndex = 0
146 }
147
148 function updatePX4VersionDisplay() {
149 var versionString = ""
150 if (_advanced.checked) {
151 switch (controller.selectedFirmwareBuildType) {
152 case FirmwareUpgradeController.StableFirmware:
153 versionString = controller.px4StableVersion
154 break
155 case FirmwareUpgradeController.BetaFirmware:
156 versionString = controller.px4BetaVersion
157 break
158 }
159 } else {
160 versionString = controller.px4StableVersion
161 }
162 px4FlightStackRadio.text = qsTr("PX4 Pro ") + versionString
163 //px4FlightStackRadio2.text = qsTr("PX4 Pro ") + versionString
164 }
165
166 Component.onCompleted: {
167 firmwarePage.advanced = false
168 firmwarePage.showAdvanced = false
169 updatePX4VersionDisplay()
170 }
171
172 Connections {
173 target: controller
174 onError: reject()
175 }
176
177 onAccepted: {
178 if (_singleFirmwareMode) {
179 controller.flashSingleFirmwareMode(controller.selectedFirmwareBuildType)
180 } else {
181 var firmwareBuildType = firmwareBuildTypeCombo.model.get(firmwareBuildTypeCombo.currentIndex).firmwareType
182 var vehicleType = FirmwareUpgradeController.DefaultVehicleFirmware
183
184 var stack = apmFlightStack.checked ? FirmwareUpgradeController.AutoPilotStackAPM : FirmwareUpgradeController.AutoPilotStackPX4
185 if (apmFlightStack.checked) {
186 if (firmwareBuildType === FirmwareUpgradeController.CustomFirmware) {
187 vehicleType = apmVehicleTypeCombo.currentIndex
188 } else {
189 if (controller.apmFirmwareNames.length === 0) {
190 // Not ready yet, or no firmware available
191 QGroundControl.showMessageDialog(firmwarePage, firmwareSelectDialog.title, qsTr("Either firmware list is still downloading, or no firmware is available for current selection."))
192 firmwareSelectDialog.preventClose = true
193 return
194 }
195 if (ardupilotFirmwareSelectionCombo.currentIndex == -1) {
196 QGroundControl.showMessageDialog(firmwarePage, firmwareSelectDialog.title, qsTr("You must choose a board type."))
197 firmwareSelectDialog.preventClose = true
198 return
199 }
200
201 var firmwareUrl = controller.apmFirmwareUrls[ardupilotFirmwareSelectionCombo.currentIndex]
202 if (firmwareUrl == "") {
203 QGroundControl.showMessageDialog(firmwarePage, firmwareSelectDialog.title, qsTr("No firmware was found for the current selection."))
204 firmwareSelectDialog.preventClose = true
205 return
206 }
207 controller.flashFirmwareUrl(controller.apmFirmwareUrls[ardupilotFirmwareSelectionCombo.currentIndex])
208 return
209 }
210 }
211 //-- If custom, get file path
212 if (firmwareBuildType === FirmwareUpgradeController.CustomFirmware) {
213 customFirmwareDialog.openForLoad()
214 } else {
215 controller.flash(stack, firmwareBuildType, vehicleType)
216 }
217 }
218 }
219
220 function reject() {
221 statusTextArea.append(highlightPrefix + qsTr("Upgrade cancelled") + highlightSuffix)
222 statusTextArea.append("------------------------------------------")
223 controller.cancel()
224 close()
225 }
226
227 ListModel {
228 id: firmwareBuildTypeList
229
230 ListElement {
231 text: qsTr("Standard Version (stable)")
232 firmwareType: FirmwareUpgradeController.StableFirmware
233 }
234 ListElement {
235 text: qsTr("Beta Testing (beta)")
236 firmwareType: FirmwareUpgradeController.BetaFirmware
237 }
238 ListElement {
239 text: qsTr("Developer Build (master)")
240 firmwareType: FirmwareUpgradeController.DeveloperFirmware
241 }
242 ListElement {
243 text: qsTr("Custom firmware file...")
244 firmwareType: FirmwareUpgradeController.CustomFirmware
245 }
246 }
247
248 ListModel {
249 id: singleFirmwareModeTypeList
250
251 ListElement {
252 text: qsTr("Standard Version")
253 firmwareType: FirmwareUpgradeController.StableFirmware
254 }
255 ListElement {
256 text: qsTr("Custom firmware file...")
257 firmwareType: FirmwareUpgradeController.CustomFirmware
258 }
259 }
260
261 ColumnLayout {
262 width: Math.max(ScreenTools.defaultFontPixelWidth * 40, firmwareRadiosColumn.width)
263 spacing: globals.defaultTextHeight / 2
264
265 QGCLabel {
266 Layout.fillWidth: true
267 wrapMode: Text.WordWrap
268 text: (_singleFirmwareMode || !QGroundControl.apmFirmwareSupported) ? _singleFirmwareLabel : _pixhawkLabel
269
270 readonly property string _pixhawkLabel: qsTr("Detected Pixhawk board. You can select from the following flight stacks:")
271 readonly property string _singleFirmwareLabel: qsTr("Press Ok to upgrade your vehicle.")
272 }
273
274 Column {
275 id: firmwareRadiosColumn
276 spacing: 0
277
278 visible: !_singleFirmwareMode && QGroundControl.apmFirmwareSupported
279
280 Component.onCompleted: {
281 if(!QGroundControl.apmFirmwareSupported) {
282 _defaultFirmwareFact.rawValue = _defaultFimwareTypePX4
283 firmwareVersionChanged(firmwareBuildTypeList)
284 }
285 }
286
287 QGCRadioButton {
288 id: px4FlightStackRadio
289 text: qsTr("PX4 Pro ")
290 font.bold: _defaultFirmwareIsPX4
291 checked: _defaultFirmwareIsPX4
292
293 onClicked: {
294 _defaultFirmwareFact.rawValue = _defaultFimwareTypePX4
295 firmwareVersionChanged(firmwareBuildTypeList)
296 }
297 }
298
299 QGCRadioButton {
300 id: apmFlightStack
301 text: qsTr("ArduPilot")
302 font.bold: !_defaultFirmwareIsPX4
303 checked: !_defaultFirmwareIsPX4
304
305 onClicked: {
306 _defaultFirmwareFact.rawValue = _defaultFimwareTypeAPM
307 firmwareVersionChanged(firmwareBuildTypeList)
308 }
309 }
310 }
311
312 FactComboBox {
313 Layout.fillWidth: true
314 visible: apmFlightStack.checked
315 fact: _firmwareUpgradeSettings.apmChibiOS
316 indexModel: false
317 }
318
319 FactComboBox {
320 id: apmVehicleTypeCombo
321 Layout.fillWidth: true
322 visible: apmFlightStack.checked
323 fact: _firmwareUpgradeSettings.apmVehicleType
324 indexModel: false
325 }
326
327 QGCComboBox {
328 id: ardupilotFirmwareSelectionCombo
329 Layout.fillWidth: true
330 visible: apmFlightStack.checked && !controller.downloadingFirmwareList && controller.apmFirmwareNames.length !== 0
331 model: controller.apmFirmwareNames
332 onModelChanged: currentIndex = controller.apmFirmwareNamesBestIndex
333 }
334
335 QGCLabel {
336 Layout.fillWidth: true
337 wrapMode: Text.WordWrap
338 text: qsTr("Downloading list of available firmwares...")
339 visible: controller.downloadingFirmwareList
340 }
341
342 QGCLabel {
343 Layout.fillWidth: true
344 wrapMode: Text.WordWrap
345 text: qsTr("No Firmware Available")
346 visible: !controller.downloadingFirmwareList && (QGroundControl.apmFirmwareSupported && controller.apmFirmwareNames.length === 0)
347 }
348
349 QGCCheckBox {
350 id: _advanced
351 text: qsTr("Advanced settings")
352 checked: false
353
354 onClicked: {
355 firmwareBuildTypeCombo.currentIndex = 0
356 firmwareWarningMessageVisible = false
357 updatePX4VersionDisplay()
358 }
359 }
360
361 QGCLabel {
362 Layout.fillWidth: true
363 wrapMode: Text.WordWrap
364 visible: showFirmwareTypeSelection
365 text: _singleFirmwareMode ? qsTr("Select the standard version or one from the file system (previously downloaded):") :
366 qsTr("Select which version of the above flight stack you would like to install:")
367 }
368
369 QGCComboBox {
370 id: firmwareBuildTypeCombo
371 Layout.fillWidth: true
372 visible: showFirmwareTypeSelection
373 textRole: "text"
374 model: _singleFirmwareMode ? singleFirmwareModeTypeList : firmwareBuildTypeList
375
376 onActivated: (index) => {
377 controller.selectedFirmwareBuildType = model.get(index).firmwareType
378 if (model.get(index).firmwareType === FirmwareUpgradeController.BetaFirmware) {
379 firmwareWarningMessageVisible = true
380 firmwareVersionWarningLabel.text = qsTr("WARNING: BETA FIRMWARE. ") +
381 qsTr("This firmware version is ONLY intended for beta testers. ") +
382 qsTr("Although it has received FLIGHT TESTING, it represents actively changed code. ") +
383 qsTr("Do NOT use for normal operation.")
384 } else if (model.get(index).firmwareType === FirmwareUpgradeController.DeveloperFirmware) {
385 firmwareWarningMessageVisible = true
386 firmwareVersionWarningLabel.text = qsTr("WARNING: CONTINUOUS BUILD FIRMWARE. ") +
387 qsTr("This firmware has NOT BEEN FLIGHT TESTED. ") +
388 qsTr("It is only intended for DEVELOPERS. ") +
389 qsTr("Run bench tests without props first. ") +
390 qsTr("Do NOT fly this without additional safety precautions. ") +
391 qsTr("Follow the forums actively when using it.")
392 } else {
393 firmwareWarningMessageVisible = false
394 }
395 updatePX4VersionDisplay()
396 }
397 }
398
399 QGCLabel {
400 id: firmwareVersionWarningLabel
401 Layout.fillWidth: true
402 wrapMode: Text.WordWrap
403 visible: firmwareWarningMessageVisible
404 }
405 } // ColumnLayout
406 } // QGCPopupDialog
407 } // Component - firmwareSelectDialogComponent
408
409 ProgressBar {
410 id: progressBar
411 Layout.preferredWidth: parent.width
412 visible: !flashBootloaderButton.visible
413 }
414
415 QGCButton {
416 id: flashBootloaderButton
417 text: qsTr("Flash ChibiOS Bootloader")
418 visible: firmwarePage.advanced
419 onClicked: globals.activeVehicle.flashBootloader()
420 }
421
422 TextArea {
423 id: statusTextArea
424 Layout.preferredWidth: parent.width
425 Layout.fillHeight: true
426 readOnly: true
427 font.pointSize: ScreenTools.defaultFontPointSize
428 textFormat: TextEdit.RichText
429 text: _singleFirmwareMode ? welcomeTextSingle : welcomeText
430 color: qgcPal.text
431
432 background: Rectangle {
433 color: qgcPal.windowShade
434 }
435 }
436
437 } // ColumnLayout
438 } // Component
439} // SetupPage