QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
PositionManager.cpp
Go to the documentation of this file.
1#include "PositionManager.h"
2#include "QGCApplication.h"
3#include "QGCCorePlugin.h"
4#include "SimulatedPosition.h"
5// #include "DeviceInfo.h"
7
8#include <QtCore/QApplicationStatic>
9#include <QtCore/QPermissions>
10#include <QtPositioning/QGeoPositionInfoSource>
11#include <QtPositioning/private/qgeopositioninfosource_p.h>
12#include <QtPositioning/QNmeaPositionInfoSource>
13
14QGC_LOGGING_CATEGORY(QGCPositionManagerLog, "PositionManager.QGCPositionManager")
15
17
19 : QObject(parent)
20{
21 qCDebug(QGCPositionManagerLog) << this;
22}
23
24QGCPositionManager::~QGCPositionManager()
25{
26 qCDebug(QGCPositionManagerLog) << this;
27}
28
29QGCPositionManager *QGCPositionManager::instance()
30{
31 return _positionManager();
32}
33
34void QGCPositionManager::init()
35{
36 if (qgcApp()->runningUnitTests()) {
37 _simulatedSource = new SimulatedPosition(this);
38 _setPositionSource(QGCPositionSource::Simulated);
39 } else {
40 _checkPermission();
41 }
42}
43
44void QGCPositionManager::_setupPositionSources()
45{
46 _defaultSource = QGCCorePlugin::instance()->createPositionSource(this);
47 if (_defaultSource) {
48 _usingPluginSource = true;
49 } else {
50 qCDebug(QGCPositionManagerLog) << Q_FUNC_INFO << QGeoPositionInfoSource::availableSources();
51
52 _defaultSource = QGeoPositionInfoSource::createDefaultSource(this);
53 if (!_defaultSource) {
54 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << "No default source available";
55 return;
56 }
57 }
58
59 _setPositionSource(QGCPositionSource::InternalGPS);
60}
61
62void QGCPositionManager::_handlePermissionStatus(Qt::PermissionStatus permissionStatus)
63{
64 if (permissionStatus == Qt::PermissionStatus::Granted) {
65 _setupPositionSources();
66 } else {
67 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << "Location Permission Denied";
68 }
69}
70
71void QGCPositionManager::_checkPermission()
72{
73 QLocationPermission locationPermission;
74 locationPermission.setAccuracy(QLocationPermission::Precise);
75
76 const Qt::PermissionStatus permissionStatus = QCoreApplication::instance()->checkPermission(locationPermission);
77 if (permissionStatus == Qt::PermissionStatus::Undetermined) {
78 QCoreApplication::instance()->requestPermission(locationPermission, this, [this](const QPermission &permission) {
79 _handlePermissionStatus(permission.status());
80 });
81 } else {
82 _handlePermissionStatus(permissionStatus);
83 }
84}
85
86void QGCPositionManager::setNmeaSourceDevice(QIODevice *device)
87{
88 if (_nmeaSource) {
89 _nmeaSource->stopUpdates();
90 (void) disconnect(_nmeaSource);
91
92 if (_currentSource == _nmeaSource) {
93 _currentSource = nullptr;
94 }
95
96 delete _nmeaSource;
97 _nmeaSource = nullptr;
98 }
99
100 _nmeaSource = new QNmeaPositionInfoSource(QNmeaPositionInfoSource::RealTimeMode, this);
101 _nmeaSource->setDevice(device);
102 _nmeaSource->setUserEquivalentRangeError(5.1);
103 _setPositionSource(QGCPositionManager::NmeaGPS);
104}
105
106void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update)
107{
108 _geoPositionInfo = update;
109
110 QGeoCoordinate newGCSPosition(_gcsPosition);
111
112 if (update.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) {
113 if ((qAbs(update.coordinate().latitude()) > 0.001) && (qAbs(update.coordinate().longitude()) > 0.001)) {
114 _gcsPositionHorizontalAccuracy = update.attribute(QGeoPositionInfo::HorizontalAccuracy);
115 if (_gcsPositionHorizontalAccuracy <= kMinHorizonalAccuracyMeters) {
116 newGCSPosition.setLatitude(update.coordinate().latitude());
117 newGCSPosition.setLongitude(update.coordinate().longitude());
118 }
119 emit gcsPositionHorizontalAccuracyChanged(_gcsPositionHorizontalAccuracy);
120 }
121 }
122
123 if (update.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) {
124 _gcsPositionVerticalAccuracy = update.attribute(QGeoPositionInfo::VerticalAccuracy);
125 if (_gcsPositionVerticalAccuracy <= kMinVerticalAccuracyMeters) {
126 newGCSPosition.setAltitude(update.coordinate().altitude());
127 }
128 }
129
130 _gcsPositionAccuracy = sqrt(pow(_gcsPositionHorizontalAccuracy, 2) + pow(_gcsPositionVerticalAccuracy, 2));
131
132 _setGCSPosition(newGCSPosition);
133
134 if (update.hasAttribute(QGeoPositionInfo::DirectionAccuracy)) {
135 _gcsDirectionAccuracy = update.attribute(QGeoPositionInfo::DirectionAccuracy);
136 if (_gcsDirectionAccuracy <= kMinDirectionAccuracyDegrees) {
137 _setGCSHeading(update.attribute(QGeoPositionInfo::Direction));
138 }
139 } else if (_usingPluginSource) {
140 _setGCSHeading(update.attribute(QGeoPositionInfo::Direction));
141 }
142
143 emit positionInfoUpdated(update);
144}
145
146void QGCPositionManager::_setGCSHeading(qreal newGCSHeading)
147{
148 if (newGCSHeading != _gcsHeading) {
149 _gcsHeading = newGCSHeading;
150 emit gcsHeadingChanged(_gcsHeading);
151 }
152}
153
154void QGCPositionManager::_setGCSPosition(const QGeoCoordinate& newGCSPosition)
155{
156 if (newGCSPosition != _gcsPosition) {
157 _gcsPosition = newGCSPosition;
158 emit gcsPositionChanged(_gcsPosition);
159 }
160}
161
162void QGCPositionManager::_setPositionSource(QGCPositionSource source)
163{
164 if (_currentSource != nullptr) {
165 _currentSource->stopUpdates();
166 (void) disconnect(_currentSource);
167
168 _geoPositionInfo = QGeoPositionInfo();
169 emit positionInfoUpdated(_geoPositionInfo);
170
171 _setGCSPosition(QGeoCoordinate());
172
173 _setGCSHeading(qQNaN());
174
175 _gcsPositionHorizontalAccuracy = std::numeric_limits<qreal>::infinity();
176 emit gcsPositionHorizontalAccuracyChanged(_gcsPositionHorizontalAccuracy);
177 }
178
179 switch (source) {
180 case QGCPositionManager::Log:
181 break;
182 case QGCPositionManager::Simulated:
183 _currentSource = _simulatedSource;
184 break;
185 case QGCPositionManager::NmeaGPS:
186 _currentSource = _nmeaSource;
187 break;
188 case QGCPositionManager::InternalGPS:
189 _currentSource = _defaultSource;
190 break;
191 case QGCPositionManager::ExternalGPS:
192 break;
193 default:
194 _currentSource = _defaultSource;
195 break;
196 }
197
198 if (_currentSource != nullptr) {
199 _currentSource->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
200 _updateInterval = _currentSource->minimumUpdateInterval();
201 #if !defined(Q_OS_DARWIN) && !defined(Q_OS_IOS)
202 _currentSource->setUpdateInterval(_updateInterval);
203 #endif
204 (void) connect(_currentSource, &QGeoPositionInfoSource::positionUpdated, this, &QGCPositionManager::_positionUpdated);
205 (void) connect(_currentSource, &QGeoPositionInfoSource::errorOccurred, this, [](QGeoPositionInfoSource::Error positioningError) {
206 qCWarning(QGCPositionManagerLog) << Q_FUNC_INFO << positioningError;
207 });
208
209 // (void) connect(QGCCompass::instance(), &QGCCompass::positionUpdated, this, &QGCPositionManager::_positionUpdated);
210
211 _currentSource->startUpdates();
212 }
213}
Q_APPLICATION_STATIC(QGCPositionManager, _positionManager)
#define qgcApp()
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void gcsPositionChanged(QGeoCoordinate gcsPosition)
void gcsPositionHorizontalAccuracyChanged(qreal gcsPositionHorizontalAccuracy)
void positionInfoUpdated(QGeoPositionInfo update)
void gcsHeadingChanged(qreal gcsHeading)