1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/****************************************************************************
*
* (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "PositionManager.h"
#include "QGCApplication.h"
#include "QGCCorePlugin.h"
QGCPositionManager::QGCPositionManager(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool (app, toolbox)
{
}
QGCPositionManager::~QGCPositionManager()
{
delete(_simulatedSource);
delete(_nmeaSource);
}
void QGCPositionManager::setToolbox(QGCToolbox *toolbox)
{
QGCTool::setToolbox(toolbox);
//-- First see if plugin provides a position source
_defaultSource = toolbox->corePlugin()->createPositionSource(this);
if (_defaultSource) {
_usingPluginSource = true;
}
if (qgcApp()->runningUnitTests()) {
// Units test on travis fail due to lack of position source
return;
}
if (!_defaultSource) {
//-- Otherwise, create a default one
_defaultSource = QGeoPositionInfoSource::createDefaultSource(this);
}
_simulatedSource = new SimulatedPosition();
#if 1
setPositionSource(QGCPositionSource::InternalGPS);
#else
setPositionSource(QGCPositionManager::Simulated);
#endif
}
void QGCPositionManager::setNmeaSourceDevice(QIODevice* device)
{
// stop and release _nmeaSource
if (_nmeaSource) {
_nmeaSource->stopUpdates();
disconnect(_nmeaSource);
// if _currentSource is pointing there, point to null
if (_currentSource == _nmeaSource){
_currentSource = nullptr;
}
delete _nmeaSource;
_nmeaSource = nullptr;
}
_nmeaSource = new QNmeaPositionInfoSource(QNmeaPositionInfoSource::RealTimeMode, this);
_nmeaSource->setDevice(device);
setPositionSource(QGCPositionManager::NmeaGPS);
}
void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update)
{
_geoPositionInfo = update;
QGeoCoordinate newGCSPosition = QGeoCoordinate();
qreal newGCSHeading = update.attribute(QGeoPositionInfo::Direction);
if (update.isValid()) {
// Note that gcsPosition filters out possible crap values
if (qAbs(update.coordinate().latitude()) > 0.001 && qAbs(update.coordinate().longitude()) > 0.001) {
newGCSPosition = update.coordinate();
}
}
if (newGCSPosition != _gcsPosition) {
_gcsPosition = newGCSPosition;
emit gcsPositionChanged(_gcsPosition);
}
// At this point only plugins support gcs heading. The reason is that the quality of heading information from a local
// position device (not a compass) is unknown. In many cases it can only be trusted if the GCS location is moving above
// a certain rate of speed. When it is not, or the gcs is standing still the heading is just random. We don't want these
// random heading to be shown on the fly view. So until we can get a true compass based heading or some smarted heading quality
// information which takes into account the speed of movement we normally don't set a heading. We do use the heading though
// if the plugin overrides the position source. In that case we assume that it hopefully know what it is doing.
if (_usingPluginSource && newGCSHeading != _gcsHeading) {
_gcsHeading = newGCSHeading;
emit gcsHeadingChanged(_gcsHeading);
}
emit positionInfoUpdated(update);
}
int QGCPositionManager::updateInterval() const
{
return _updateInterval;
}
void QGCPositionManager::setPositionSource(QGCPositionManager::QGCPositionSource source)
{
if (_currentSource != nullptr) {
_currentSource->stopUpdates();
disconnect(_currentSource);
}
if (qgcApp()->runningUnitTests()) {
// Units test on travis fail due to lack of position source
return;
}
switch(source) {
case QGCPositionManager::Log:
break;
case QGCPositionManager::Simulated:
_currentSource = _simulatedSource;
break;
case QGCPositionManager::NmeaGPS:
_currentSource = _nmeaSource;
break;
case QGCPositionManager::InternalGPS:
default:
_currentSource = _defaultSource;
break;
}
if (_currentSource != nullptr) {
_updateInterval = _currentSource->minimumUpdateInterval();
_currentSource->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
_currentSource->setUpdateInterval(_updateInterval);
connect(_currentSource, &QGeoPositionInfoSource::positionUpdated, this, &QGCPositionManager::_positionUpdated);
connect(_currentSource, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(_error(QGeoPositionInfoSource::Error)));
_currentSource->startUpdates();
}
}
void QGCPositionManager::_error(QGeoPositionInfoSource::Error positioningError)
{
qWarning() << "QGCPositionManager error" << positioningError;
}