Skip to content

Commit 01aa2ba

Browse files
authored
Add GPS resilience monitoring with GNSS_INTEGRITY message (#13812)
1 parent 0110962 commit 01aa2ba

17 files changed

+588
-10
lines changed

qgcimages.qrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
<file alias="GeoFenceLight.svg">src/AutoPilotPlugins/PX4/Images/GeoFenceLight.svg</file>
104104
<file alias="GeoTagIcon.svg">src/AnalyzeView/GeoTagIcon.svg</file>
105105
<file alias="Gps.svg">src/UI/toolbar/Images/Gps.svg</file>
106+
<file alias="GpsAuthentication.svg">src/UI/toolbar/Images/GpsAuthentication.svg</file>
107+
<file alias="GpsInterference.svg">src/UI/toolbar/Images/GpsInterference.svg</file>
106108
<file alias="Hamburger.svg">src/UI/toolbar/Images/Hamburger.svg</file>
107109
<file alias="HamburgerThin.svg">src/UI/toolbar/Images/HamburgerThin.svg</file>
108110
<file alias="Help.svg">src/FlightMap/Images/Help.svg</file>

src/FirmwarePlugin/FirmwarePlugin.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ const QVariantList &FirmwarePlugin::toolIndicators(const Vehicle*)
195195
if (_toolIndicatorList.isEmpty()) {
196196
_toolIndicatorList = QVariantList({
197197
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/VehicleGPSIndicator.qml")),
198+
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/GPSResilienceIndicator.qml")),
198199
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/TelemetryRSSIIndicator.qml")),
199200
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Toolbar/RCRSSIIndicator.qml")),
200201
QVariant::fromValue(QUrl::fromUserInput("qrc:/qml/QGroundControl/Controls/BatteryIndicator.qml")),

src/QmlControls/GPSIndicatorPage.qml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ ToolIndicatorPage {
5454
updateSettingsDisplayId()
5555
}
5656

57+
function errorText() {
58+
if (!_activeVehicle) {
59+
return qsTr("Disconnected");
60+
}
61+
62+
switch (_activeVehicle.gps.systemErrors.value) {
63+
case 1:
64+
return qsTr("Incoming correction");
65+
case 2:
66+
return qsTr("Configuration");
67+
case 4:
68+
return qsTr("Software");
69+
case 8:
70+
return qsTr("Antenna");
71+
case 16:
72+
return qsTr("Event congestion");
73+
case 32:
74+
return qsTr("CPU overload");
75+
case 64:
76+
return qsTr("Output congestion");
77+
default:
78+
return qsTr("Multiple errors");
79+
}
80+
}
5781

5882
contentComponent: Component {
5983
ColumnLayout {
@@ -87,6 +111,12 @@ ToolIndicatorPage {
87111
label: qsTr("Course Over Ground")
88112
labelText: activeVehicle ? activeVehicle.gps.courseOverGround.valueString : valueNA
89113
}
114+
115+
LabelledLabel {
116+
label: qsTr("GPS Error")
117+
labelText: errorText()
118+
visible: activeVehicle && activeVehicle.gps.systemErrors.value > 0
119+
}
90120
}
91121

92122
SettingsGroupLayout {

src/UI/toolbar/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ qt_add_qml_module(ToolbarModule
1010
EscIndicatorPage.qml
1111
GCSControlIndicator.qml
1212
GimbalIndicator.qml
13+
GPSResilienceIndicator.qml
1314
JoystickIndicator.qml
1415
ModeIndicator.qml
1516
MultiVehicleSelector.qml
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/****************************************************************************
2+
*
3+
* (c) 2009-2024 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4+
*
5+
* QGroundControl is licensed according to the terms in the file
6+
* COPYING.md in the root of the source code directory.
7+
*
8+
****************************************************************************/
9+
10+
import QtQuick
11+
import QtQuick.Layouts
12+
13+
import QGroundControl
14+
import QGroundControl.Controls
15+
16+
//-------------------------------------------------------------------------
17+
//-- GPS Resilience Indicator
18+
Item {
19+
id: control
20+
width: height
21+
anchors.top: parent.top
22+
anchors.bottom: parent.bottom
23+
visible: showIndicator
24+
25+
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
26+
property var _gpsAggregate: _activeVehicle ? _activeVehicle.gpsAggregate : null
27+
28+
property var qgcPal: QGroundControl.globalPalette
29+
30+
property bool showIndicator: _activeVehicle && _gpsAggregate && (
31+
(_gpsAggregate.authenticationState.value > 0 && _gpsAggregate.authenticationState.value < 255) ||
32+
(_gpsAggregate.spoofingState.value > 0 && _gpsAggregate.spoofingState.value < 255) ||
33+
(_gpsAggregate.jammingState.value > 0 && _gpsAggregate.jammingState.value < 255)
34+
)
35+
36+
// Authentication Icon (Outer/Bottom Layer)
37+
QGCColoredImage {
38+
id: authIcon
39+
width: parent.height * 0.95
40+
height: parent.height * 0.95
41+
anchors.centerIn: parent
42+
source: "/qmlimages/GpsAuthentication.svg"
43+
fillMode: Image.PreserveAspectFit
44+
sourceSize.height: height
45+
color: _authColor()
46+
visible: _gpsAggregate && _gpsAggregate.authenticationState.value > 0 && _gpsAggregate.authenticationState.value < 255
47+
}
48+
49+
// Interference Icon (Inner/Top Layer)
50+
QGCColoredImage {
51+
id: interfIcon
52+
width: parent.height * 0.55
53+
height: parent.height * 0.55
54+
anchors.centerIn: parent
55+
source: "/qmlimages/GpsInterference.svg"
56+
fillMode: Image.PreserveAspectFit
57+
sourceSize.height: height
58+
color: _interfColor()
59+
visible: _gpsAggregate && (Math.max(_gpsAggregate.spoofingState.value, _gpsAggregate.jammingState.value) > 0) && (Math.max(_gpsAggregate.spoofingState.value, _gpsAggregate.jammingState.value) < 255)
60+
}
61+
62+
function _authColor() {
63+
if (!_gpsAggregate) return qgcPal.colorGrey;
64+
switch (_gpsAggregate.authenticationState.value) {
65+
case 1: return qgcPal.colorYellow; // Initializing
66+
case 2: return qgcPal.colorRed; // Error
67+
case 3: return qgcPal.colorGreen; // OK
68+
default: return qgcPal.colorGrey; // Unknown or Disabled
69+
}
70+
}
71+
72+
function _interfColor() {
73+
if (!_gpsAggregate) return qgcPal.colorGrey;
74+
let maxState = Math.max(_gpsAggregate.spoofingState.value, _gpsAggregate.jammingState.value);
75+
switch (maxState) {
76+
case 1: return qgcPal.colorGreen; // Not spoofed/jammed
77+
case 2: return qgcPal.colorOrange; // Mitigated
78+
case 3: return qgcPal.colorRed; // Detected
79+
default: return qgcPal.colorGrey; // Unknown
80+
}
81+
}
82+
83+
MouseArea {
84+
anchors.fill: parent
85+
onClicked: mainWindow.showIndicatorDrawer(resiliencePopup, control)
86+
}
87+
88+
Component {
89+
id: resiliencePopup
90+
ToolIndicatorPage {
91+
showExpand: expandedComponent ? true : false
92+
contentComponent: resilienceContent
93+
}
94+
}
95+
96+
Component {
97+
id: resilienceContent
98+
ColumnLayout {
99+
spacing: ScreenTools.defaultFontPixelHeight / 2
100+
101+
// Unified GPS Resilience Status
102+
SettingsGroupLayout {
103+
heading: qsTr("GPS Resilience Status")
104+
showDividers: true
105+
106+
LabelledLabel {
107+
label: qsTr("GPS Jamming")
108+
labelText: _gpsAggregate ? (_gpsAggregate.jammingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
109+
visible: _gpsAggregate && _gpsAggregate.jammingState.value > 0 && _gpsAggregate.jammingState.value < 255
110+
}
111+
112+
LabelledLabel {
113+
label: qsTr("GPS Spoofing")
114+
labelText: _gpsAggregate ? (_gpsAggregate.spoofingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
115+
visible: _gpsAggregate && _gpsAggregate.spoofingState.value > 0 && _gpsAggregate.spoofingState.value < 255
116+
}
117+
118+
LabelledLabel {
119+
label: qsTr("GPS Authentication")
120+
labelText: _gpsAggregate ? (_gpsAggregate.authenticationState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
121+
visible: _gpsAggregate && _gpsAggregate.authenticationState.value > 0 && _gpsAggregate.authenticationState.value < 255
122+
}
123+
}
124+
125+
// GPS 1 Details
126+
SettingsGroupLayout {
127+
heading: qsTr("GPS 1 Details")
128+
showDividers: true
129+
visible: _activeVehicle && _activeVehicle.gps && (
130+
(_activeVehicle.gps.jammingState.value > 0 && _activeVehicle.gps.jammingState.value < 255) ||
131+
(_activeVehicle.gps.spoofingState.value > 0 && _activeVehicle.gps.spoofingState.value < 255) ||
132+
(_activeVehicle.gps.authenticationState.value > 0 && _activeVehicle.gps.authenticationState.value < 255)
133+
)
134+
135+
LabelledLabel {
136+
label: qsTr("Jamming")
137+
labelText: (_activeVehicle && _activeVehicle.gps) ? (_activeVehicle.gps.jammingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
138+
visible: _activeVehicle.gps.jammingState.value > 0 && _activeVehicle.gps.jammingState.value < 255
139+
}
140+
LabelledLabel {
141+
label: qsTr("Spoofing")
142+
labelText: (_activeVehicle && _activeVehicle.gps) ? (_activeVehicle.gps.spoofingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
143+
visible: _activeVehicle.gps.spoofingState.value > 0 && _activeVehicle.gps.spoofingState.value < 255
144+
}
145+
LabelledLabel {
146+
label: qsTr("Authentication")
147+
labelText: (_activeVehicle && _activeVehicle.gps) ? (_activeVehicle.gps.authenticationState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
148+
visible: _activeVehicle.gps.authenticationState.value > 0 && _activeVehicle.gps.authenticationState.value < 255
149+
}
150+
}
151+
152+
// GPS 2 Details
153+
SettingsGroupLayout {
154+
heading: qsTr("GPS 2 Details")
155+
showDividers: true
156+
visible: _activeVehicle && _activeVehicle.gps2 && (
157+
(_activeVehicle.gps2.jammingState.value > 0 && _activeVehicle.gps2.jammingState.value < 255) ||
158+
(_activeVehicle.gps2.spoofingState.value > 0 && _activeVehicle.gps2.spoofingState.value < 255) ||
159+
(_activeVehicle.gps2.authenticationState.value > 0 && _activeVehicle.gps2.authenticationState.value < 255)
160+
)
161+
162+
LabelledLabel {
163+
label: qsTr("Jamming")
164+
labelText: (_activeVehicle && _activeVehicle.gps2) ? (_activeVehicle.gps2.jammingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
165+
visible: _activeVehicle.gps2.jammingState.value > 0 && _activeVehicle.gps2.jammingState.value < 255
166+
}
167+
LabelledLabel {
168+
label: qsTr("Spoofing")
169+
labelText: (_activeVehicle && _activeVehicle.gps2) ? (_activeVehicle.gps2.spoofingState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
170+
visible: _activeVehicle.gps2.spoofingState.value > 0 && _activeVehicle.gps2.spoofingState.value < 255
171+
}
172+
LabelledLabel {
173+
label: qsTr("Authentication")
174+
labelText: (_activeVehicle && _activeVehicle.gps2) ? (_activeVehicle.gps2.authenticationState.enumStringValue || qsTr("n/a")) : qsTr("n/a")
175+
visible: _activeVehicle.gps2.authenticationState.value > 0 && _activeVehicle.gps2.authenticationState.value < 255
176+
}
177+
}
178+
}
179+
}
180+
}
Lines changed: 7 additions & 0 deletions
Loading
Lines changed: 18 additions & 0 deletions
Loading

src/Vehicle/FactGroups/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ target_sources(${CMAKE_PROJECT_NAME}
2727
VehicleGPS2FactGroup.h
2828
VehicleGPSFactGroup.cc
2929
VehicleGPSFactGroup.h
30+
VehicleGPSAggregateFactGroup.cc
31+
VehicleGPSAggregateFactGroup.h
3032
VehicleLocalPositionFactGroup.cc
3133
VehicleLocalPositionFactGroup.h
3234
VehicleLocalPositionSetpointFactGroup.cc

src/Vehicle/FactGroups/GPSFact.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,55 @@
5858
"name": "count",
5959
"shortDesc": "Sat Count",
6060
"type": "uint32"
61+
},
62+
{
63+
"name": "systemErrors",
64+
"shortDesc": "General System Errors",
65+
"type": "uint32"
66+
},
67+
{
68+
"name": "spoofingState",
69+
"shortDesc": "Signal Spoofing State",
70+
"type": "uint8",
71+
"enumStrings": "Unknown,Not spoofed,Mitigated,Ongoing",
72+
"enumValues": "0,1,2,3",
73+
"decimalPlaces": 0
74+
},
75+
{
76+
"name": "jammingState",
77+
"shortDesc": "Signal Jamming State",
78+
"type": "uint8",
79+
"enumStrings": "Unknown,Not jammed,Mitigated,Ongoing",
80+
"enumValues": "0,1,2,3",
81+
"decimalPlaces": 0
82+
},
83+
{
84+
"name": "authenticationState",
85+
"shortDesc": "Signal Authentication State",
86+
"type": "uint8",
87+
"enumStrings": "Unknown,Initializing,Error,Ok,Disabled",
88+
"enumValues": "0,1,2,3,4",
89+
"decimalPlaces": 0
90+
},
91+
{
92+
"name": "correctionsQuality",
93+
"shortDesc": "Corrections Quality",
94+
"type": "uint8"
95+
},
96+
{
97+
"name": "systemQuality",
98+
"shortDesc": "System Status Quality",
99+
"type": "uint8"
100+
},
101+
{
102+
"name": "gnssSignalQuality",
103+
"shortDesc": "Gnss Signal Quality",
104+
"type": "uint8"
105+
},
106+
{
107+
"name": "postProcessingQuality",
108+
"shortDesc": "Post Processing Quality",
109+
"type": "uint8"
61110
}
62111
]
63112
}

src/Vehicle/FactGroups/VehicleGPS2FactGroup.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "VehicleGPS2FactGroup.h"
22
#include "Vehicle.h"
33
#include "QGCGeo.h"
4+
#include "development/mavlink_msg_gnss_integrity.h"
45

56
#include <QtPositioning/QGeoCoordinate>
67

@@ -12,6 +13,9 @@ void VehicleGPS2FactGroup::handleMessage(Vehicle *vehicle, const mavlink_message
1213
case MAVLINK_MSG_ID_GPS2_RAW:
1314
_handleGps2Raw(message);
1415
break;
16+
case MAVLINK_MSG_ID_GNSS_INTEGRITY:
17+
_handleGnssIntegrity(message);
18+
break;
1519
default:
1620
break;
1721
}

0 commit comments

Comments
 (0)