QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
MAVLinkInspectorPage.qml
Go to the documentation of this file.
1import QtQuick
2import QtQuick.Controls
3import QtQuick.Layouts
4import QtQuick.Dialogs
5import QtQuick.Window
6import QtCharts
7
8import QGroundControl
9import QGroundControl.Controls
10
11AnalyzePage {
12 id: root
13 headerComponent: headerComponent
14 pageComponent: pageComponent
15 allowPopout: true
16
17 property var curSystem: controller ? controller.activeSystem : null
18 property var curMessage: curSystem && curSystem.messages.count ? curSystem.messages.get(curSystem.selected) : null
19 property int curCompID: 0
20 property real maxButtonWidth: 0
21
22 MAVLinkInspectorController {
23 id: controller
24 }
25
26 function updateEnabledStatus(repeater, message, chart) {
27 if(!message) {
28 return;
29 }
30
31 for (let i = 0; i < repeater.count; i++) {
32 let checkBox = repeater.itemAt(i)
33 if(!checkBox) {
34 continue
35 }
36 const messageField = message.fields.get(i)
37 checkBox.enabled = isCheckboxEnabled(checkBox, messageField, chart)
38 }
39 }
40
41 function isCheckboxEnabled(checkBox, messageField, chart) {
42 if(checkBox.checkState === Qt.Checked) {
43 return true
44 }
45 if(!messageField.selectable) {
46 return false
47 }
48 if(messageField.series !== null) {
49 return false
50 }
51 return chart.roomForNewDimension()
52 }
53
54 Component {
55 id: headerComponent
56 //-- Header
57 RowLayout {
58 id: header
59 anchors.left: parent.left
60 anchors.right: parent.right
61 QGCLabel {
62 text: qsTr("Inspect real time MAVLink messages.")
63 }
64 RowLayout {
65 Layout.alignment: Qt.AlignRight
66 visible: curSystem ? controller.systemNames.length > 1 || curSystem.compIDsStr.length > 2 : false
67 QGCComboBox {
68 id: systemCombo
69 model: controller.systemNames
70 sizeToContents: true
71 visible: controller.systemNames.length > 1
72 onActivated: (index) => { controller.setActiveSystem(controller.systems.get(index).id) }
73
74 Connections {
75 target: controller
76 function onActiveSystemChanged() {
77 for (var systemIndex=0; systemIndex<controller.systems.count; systemIndex++) {
78 if (controller.systems.get(systemIndex) == curSystem) {
79 systemCombo.currentIndex = systemIndex
80 curCompID = 0
81 cidCombo.currentIndex = 0
82 break
83 }
84 }
85 }
86 }
87 }
88 QGCComboBox {
89 id: cidCombo
90 model: curSystem ? curSystem.compIDsStr : []
91 sizeToContents: true
92 visible: curSystem ? curSystem.compIDsStr.length > 2 : false
93 onActivated: (index) => {
94 if(curSystem && curSystem.compIDsStr.length > 1) {
95 if(index < 1)
96 curCompID = 0
97 else
98 curCompID = curSystem.compIDs[index - 1]
99 }
100 }
101 }
102 }
103 }
104 }
105
106 Component {
107 id: pageComponent
108 Row {
109 width: availableWidth
110 height: availableHeight
111 spacing: ScreenTools.defaultFontPixelWidth
112 //-- Messages (Buttons)
113 QGCFlickable {
114 id: buttonGrid
115 flickableDirection: Flickable.VerticalFlick
116 width: maxButtonWidth
117 height: parent.height
118 contentWidth: width
119 contentHeight: buttonCol.height
120 ColumnLayout {
121 id: buttonCol
122 anchors.left: parent.left
123 anchors.right: parent.right
124 spacing: ScreenTools.defaultFontPixelHeight * 0.25
125 Repeater {
126 model: curSystem ? curSystem.messages : []
127 delegate: MAVLinkMessageButton {
128 text: object.name + (object.fieldSelected ? " *" : "")
129 compID: object.compId
130 checked: curSystem ? (curSystem.selected === index) : false
131 messageHz: object.actualRateHz
132 visible: curCompID === 0 || curCompID === compID
133 onClicked: {
134 curSystem.selected = index
135 }
136 Layout.fillWidth: true
137 }
138 }
139 }
140 }
141 //-- Message Data
142 QGCFlickable {
143 id: messageGrid
144 visible: curMessage !== null && (curCompID === 0 || curCompID === curMessage.compId)
145 flickableDirection: Flickable.VerticalFlick
146 width: parent.width - buttonGrid.width - ScreenTools.defaultFontPixelWidth
147 height: parent.height
148 contentWidth: width
149 contentHeight: messageCol.height
150 Column {
151 id: messageCol
152 width: parent.width
153 spacing: ScreenTools.defaultFontPixelHeight * 0.25
154 GridLayout {
155 columns: 2
156 columnSpacing: ScreenTools.defaultFontPixelWidth
157 rowSpacing: ScreenTools.defaultFontPixelHeight * 0.25
158 QGCLabel {
159 text: qsTr("Message:")
160 Layout.minimumWidth: ScreenTools.defaultFontPixelWidth * 20
161 }
162 QGCLabel {
163 color: qgcPal.buttonHighlight
164 text: curMessage ? curMessage.name + ' (' + curMessage.id + ')' : ""
165 }
166
167 QGCLabel { text: qsTr("Component:") }
168 QGCLabel { text: curMessage ? curMessage.compId : "" }
169
170 QGCLabel { text: qsTr("Count:") }
171 QGCLabel { text: curMessage ? curMessage.count : "" }
172
173 QGCLabel { text: qsTr("Actual Rate:") }
174 QGCLabel { text: curMessage ? curMessage.actualRateHz.toFixed(1) + qsTr("Hz") : "" }
175
176 QGCLabel { text: qsTr("Set Rate:") }
177 QGCComboBox {
178 id: msgRateCombo
179 textRole: "text"
180 valueRole: "value"
181 model: [
182 { value: -1, text: qsTr("Disabled") },
183 { value: 0, text: qsTr("Default") },
184 { value: 1, text: qsTr("1Hz") },
185 { value: 2, text: qsTr("2Hz") },
186 { value: 3, text: qsTr("3Hz") },
187 { value: 4, text: qsTr("4Hz") },
188 { value: 5, text: qsTr("5Hz") },
189 { value: 6, text: qsTr("6Hz") },
190 { value: 7, text: qsTr("7Hz") },
191 { value: 8, text: qsTr("8Hz") },
192 { value: 9, text: qsTr("9Hz") },
193 { value: 10, text: qsTr("10Hz") },
194 { value: 25, text: qsTr("25Hz") },
195 { value: 50, text: qsTr("50Hz") },
196 { value: 100, text: qsTr("100Hz") }
197 ]
198 Layout.alignment: Qt.AlignLeft
199 sizeToContents: true
200 Component.onCompleted: reset()
201 onActivated: (index) => controller.setMessageInterval(currentValue)
202 function reset() { currentIndex = indexOfValue(0) }
203 Connections {
204 target: root
205 function onCurMessageChanged() { msgRateCombo.reset() }
206 }
207 Connections {
208 target: curMessage
209 function onTargetRateHzChanged() {
210 const target_index = indexOfValue(curMessage.targetRateHz)
211 if(target_index != -1) {
212 currentIndex = target_index
213 }
214 }
215 }
216 }
217 }
218 Item { height: ScreenTools.defaultFontPixelHeight; width: 1 }
219 //---------------------------------------------------------
220 GridLayout {
221 id: msgInfoGrid
222 columns: 5
223 columnSpacing: ScreenTools.defaultFontPixelWidth * 0.25
224 rowSpacing: ScreenTools.defaultFontPixelHeight * 0.25
225 width: parent.width
226 QGCLabel {
227 text: qsTr("Name")
228 }
229 QGCLabel {
230 text: qsTr("Value")
231 }
232 QGCLabel {
233 text: qsTr("Type")
234 }
235 QGCLabel {
236 text: qsTr("Plot 1")
237 }
238 QGCLabel {
239 text: qsTr("Plot 2")
240 }
241
242 //---------------------------------------------------------
243 Rectangle {
244 Layout.columnSpan: 5
245 Layout.fillWidth: true
246 height: 1
247 color: qgcPal.text
248 }
249 //---------------------------------------------------------
250
251 Repeater {
252 model: curMessage ? curMessage.fields : []
253 delegate: QGCLabel {
254 Layout.row: index + 2
255 Layout.column: 0
256 Layout.minimumWidth: ScreenTools.defaultFontPixelWidth * 20
257 text: object.name
258 }
259 }
260 Repeater {
261 model: curMessage ? curMessage.fields : []
262 delegate: QGCLabel {
263 Layout.row: index + 2
264 Layout.column: 1
265 Layout.minimumWidth: msgInfoGrid.width * 0.25
266 Layout.maximumWidth: msgInfoGrid.width * 0.25
267 text: object.value
268 elide: Text.ElideRight
269 }
270 }
271 Repeater {
272 model: curMessage ? curMessage.fields : []
273 delegate: QGCLabel {
274 Layout.row: index + 2
275 Layout.column: 2
276 Layout.minimumWidth: ScreenTools.defaultFontPixelWidth * 10
277 text: object.type
278 elide: Text.ElideRight
279 }
280 }
281 Repeater {
282 id: chart1Repeater
283 model: curMessage ? curMessage.fields : []
284 delegate: QGCCheckBox {
285 Layout.row: index + 2
286 Layout.column: 3
287 Layout.alignment: Qt.AlignHCenter
288 checked: object.series !== null && object.chartIndex === 0
289 onClicked: {
290 if(checked) {
291 chart1.addDimension(object)
292 } else {
293 chart1.delDimension(object)
294 }
295 updateEnabledStatus(chart1Repeater, curMessage, chart1)
296 updateEnabledStatus(chart2Repeater, curMessage, chart2)
297 }
298 Component.onCompleted: updateEnabledStatus(chart1Repeater, curMessage, chart1)
299 }
300 }
301 Repeater {
302 id: chart2Repeater
303 model: curMessage ? curMessage.fields : []
304 delegate: QGCCheckBox {
305 Layout.row: index + 2
306 Layout.column: 4
307 Layout.alignment: Qt.AlignHCenter
308 checked: object.series !== null && object.chartIndex === 1
309 onClicked: {
310 if(checked) {
311 chart2.addDimension(object)
312 } else {
313 chart2.delDimension(object)
314 }
315 updateEnabledStatus(chart2Repeater, curMessage, chart2)
316 updateEnabledStatus(chart1Repeater, curMessage, chart1)
317 }
318 Component.onCompleted: updateEnabledStatus(chart2Repeater, curMessage, chart2)
319 }
320 }
321 }
322 Item { height: ScreenTools.defaultFontPixelHeight * 0.25; width: 1 }
323 MAVLinkChart {
324 id: chart1
325 height: ScreenTools.defaultFontPixelHeight * 20
326 width: parent.width
327 inspectorController: controller
328 chartIndex: 0
329 }
330 MAVLinkChart {
331 id: chart2
332 height: ScreenTools.defaultFontPixelHeight * 20
333 width: parent.width
334 inspectorController: controller
335 chartIndex: 1
336 }
337 }
338 }
339 }
340 }
341}