1 /***************************************************************************
2 QgsQtLocationConnection.cpp - description
3 ---------------------
4 begin : December 7th, 2011
5 copyright : (C) 2011 by Marco Bernasocchi, Bernawebdesign.ch
6 email : marco at bernawebdesign dot ch
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgsqtlocationconnection.h"
19 #include "qgslogger.h"
20
21 #include <QLocalSocket>
22 #include <QTimer>
23 #include <QMetaType>
24
QgsQtLocationConnection()25 QgsQtLocationConnection::QgsQtLocationConnection()
26 : QgsGpsConnection( new QLocalSocket() )
27 {
28 //needed to fix https://sourceforge.net/p/necessitas/tickets/146/
29 qRegisterMetaType< QList<QGeoSatelliteInfo> >( "QList<QGeoSatelliteInfo>" );
30
31 startSatelliteMonitor();
32 startGPS();
33
34 //HACK to signal the gpsinformationwidget that we have a QtLocationConnection
35 QTimer::singleShot( 500, this, SLOT( broadcastConnectionAvailable() ) );
36 }
37
38 //Needed to make connection detectable (half HACK)
39 //this signals that the device has started the GPS successfully,
40 //not that it has a fix yet.
broadcastConnectionAvailable()41 void QgsQtLocationConnection::broadcastConnectionAvailable()
42 {
43 if ( locationDataSource )
44 {
45 mStatus = GPSDataReceived;
46 emit stateChanged( mLastGPSInformation );
47 }
48 }
49
50 //TODO: Temporarily needed to workaround https://sourceforge.net/p/necessitas/tickets/147/
positionUpdated(const QGeoPositionInfo & info)51 void QgsQtLocationConnection::positionUpdated( const QGeoPositionInfo &info )
52 {
53 mInfo = info;
54 parseData();
55 }
56
parseData()57 void QgsQtLocationConnection::parseData()
58 {
59 if ( locationDataSource )
60 {
61 mStatus = GPSDataReceived;
62 //const QGeoPositionInfo &info = locationDataSource->lastKnownPosition();
63 if ( mInfo.isValid() )
64 {
65 // mInfo.HorizontalAccuracy;
66 mLastGPSInformation.latitude = mInfo.coordinate().latitude();
67 mLastGPSInformation.longitude = mInfo.coordinate().longitude();
68 mLastGPSInformation.elevation = mInfo.coordinate().altitude();
69 mLastGPSInformation.speed = mInfo.attribute( QGeoPositionInfo::GroundSpeed ) * 3.6; // m/s to km/h
70 mLastGPSInformation.direction = mInfo.attribute( QGeoPositionInfo::Direction );
71 mLastGPSInformation.utcDateTime = mInfo.timestamp();
72 mLastGPSInformation.fixType = mInfo.coordinate().type() + 1;
73 //< fixType, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D)
74 //< coordinate().type(), returns 0 = Fix not available; 1 = 2D; 2 = 3D)
75 mLastGPSInformation.hacc = mInfo.attribute( QGeoPositionInfo::HorizontalAccuracy ); //< Horizontal dilution of precision
76 mLastGPSInformation.vacc = mInfo.attribute( QGeoPositionInfo::VerticalAccuracy ); //< Vertical dilution of precision
77
78 //TODO implement dop maybe by getting a
79 //http://developer.android.com/reference/android/location/GpsStatus.NmeaListener.html
80 //http://doc.qt.nokia.com/qtmobility-1.1/qnmeapositioninfosource.html
81 //into QtLocation and subclass QgsNMEAConnection directly?
82 //mLastGPSInformation.pdop; //< Dilution of precision
83 //mLastGPSInformation.hdop; //< Horizontal dilution of precision
84 //mLastGPSInformation.vdop; //< Vertical dilution of precision
85
86 //mLastGPSInformation.fixMode; //< Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D)
87 //mLastGPSInformation.quality; //< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive)
88 //mLastGPSInformation.status; //< Status (A = active or V = void)
89
90 emit stateChanged( mLastGPSInformation );
91 QgsDebugMsg( QStringLiteral( "Valid QGeoPositionInfo, positionUpdated" ) );
92 }
93 }
94 }
95
satellitesInViewUpdated(const QList<QGeoSatelliteInfo> & satellites)96 void QgsQtLocationConnection::satellitesInViewUpdated(
97 const QList<QGeoSatelliteInfo> &satellites )
98 {
99 // The number of satellites in view is updated
100 mLastGPSInformation.satellitesInView.clear();
101 for ( int i = 0; i < satellites.size(); ++i )
102 {
103 QGeoSatelliteInfo currentSatellite = satellites.at( i );
104 QgsSatelliteInfo satelliteInfo;
105 satelliteInfo.azimuth = currentSatellite.attribute( QGeoSatelliteInfo::Azimuth );
106 satelliteInfo.elevation = currentSatellite.attribute( QGeoSatelliteInfo::Elevation );
107 #if defined(HAVE_QT_MOBILITY_LOCATION )
108 satelliteInfo.id = currentSatellite.prnNumber();
109 #else // QtPositioning
110 satelliteInfo.id = currentSatellite.satelliteIdentifier();
111 #endif
112 satelliteInfo.signal = currentSatellite.signalStrength();
113 mLastGPSInformation.satellitesInView.append( satelliteInfo );
114 }
115 mLastGPSInformation.satInfoComplete = true; //to be used to determine when to graph signal and satellite position
116 emit stateChanged( mLastGPSInformation );
117 QgsDebugMsg( QStringLiteral( "satellitesInViewUpdated" ) );
118 }
119
satellitesInUseUpdated(const QList<QGeoSatelliteInfo> & satellites)120 void QgsQtLocationConnection::satellitesInUseUpdated(
121 const QList<QGeoSatelliteInfo> &satellites )
122 {
123 // The number of satellites in use is updated
124 mLastGPSInformation.satellitesUsed = QString::number( satellites.count() ).toInt();
125
126 mLastGPSInformation.satPrn.clear();
127 for ( const QGeoSatelliteInfo ¤tSatellite : satellites )
128 {
129 //add pnr to mLastGPSInformation.satPrn
130 #if defined(HAVE_QT_MOBILITY_LOCATION )
131 mLastGPSInformation.satPrn.append( currentSatellite.prnNumber() );
132 #else // QtPositioning
133 mLastGPSInformation.satPrn.append( currentSatellite.satelliteIdentifier() );
134 #endif
135
136 //set QgsSatelliteInfo.inuse to true for the satellites in use
137 for ( QgsSatelliteInfo &satInView : mLastGPSInformation.satellitesInView )
138 {
139 #if defined(HAVE_QT_MOBILITY_LOCATION )
140 if ( satInView.id == currentSatellite.prnNumber() )
141 #else // QtPositioning
142 if ( satInView.id == currentSatellite.satelliteIdentifier() )
143 #endif
144 {
145 satInView.inUse = true;
146 break;
147 }
148 }
149 }
150 mLastGPSInformation.satInfoComplete = true; //to be used to determine when to graph signal and satellite position
151 emit stateChanged( mLastGPSInformation );
152 QgsDebugMsg( QStringLiteral( "satellitesInUseUpdated" ) );
153 }
154
startGPS()155 void QgsQtLocationConnection::startGPS()
156 {
157 QgsDebugMsg( QStringLiteral( "Starting GPS QtLocation connection" ) );
158 // Obtain the location data source if it is not obtained already
159 if ( !locationDataSource )
160 {
161 locationDataSource = QGeoPositionInfoSource::createDefaultSource( this );
162 if ( locationDataSource )
163 {
164 locationDataSource->setPreferredPositioningMethods( QGeoPositionInfoSource::SatellitePositioningMethods ); //QGeoPositionInfoSource::AllPositioningMethods
165 locationDataSource->setUpdateInterval( 1000 );
166 // Whenever the location data source signals that the current
167 // position is updated, the positionUpdated function is called.
168 QObject::connect( locationDataSource.data(),
169 &QGeoPositionInfoSource::positionUpdated,
170 this,
171 &QgsQtLocationConnection::positionUpdated );
172 // Start listening for position updates
173 locationDataSource->startUpdates();
174 }
175 else
176 {
177 // Not able to obtain the location data source
178 QgsDebugMsg( QStringLiteral( "No QtLocation Position Source" ) );
179 }
180 }
181 else
182 {
183 // Start listening for position updates
184 locationDataSource->startUpdates();
185 }
186 }
187
startSatelliteMonitor()188 void QgsQtLocationConnection::startSatelliteMonitor()
189 {
190 QgsDebugMsg( QStringLiteral( "Starting GPS QtLocation satellite monitor" ) );
191
192 if ( !satelliteInfoSource )
193 {
194 satelliteInfoSource = QGeoSatelliteInfoSource::createDefaultSource( this );
195 if ( satelliteInfoSource )
196 {
197 QgsDebugMsg( QStringLiteral( "satelliteMonitor started" ) );
198 // Whenever the satellite info source signals that the number of
199 // satellites in use is updated, the satellitesInUseUpdated function
200 // is called
201 QObject::connect( satelliteInfoSource.data(),
202 &QGeoSatelliteInfoSource::satellitesInUseUpdated,
203 this,
204 &QgsQtLocationConnection::satellitesInUseUpdated );
205
206 // Whenever the satellite info source signals that the number of
207 // satellites in view is updated, the satellitesInViewUpdated function
208 // is called
209 QObject::connect( satelliteInfoSource.data(),
210 &QGeoSatelliteInfoSource::satellitesInViewUpdated,
211 this,
212 &QgsQtLocationConnection::satellitesInViewUpdated );
213
214 // Start listening for satellite updates
215 satelliteInfoSource->startUpdates();
216 }
217 else
218 {
219 // Not able to obtain the Satellite data source
220 QgsDebugMsg( QStringLiteral( "No QtLocation Satellite Source" ) );
221 }
222 }
223 else
224 {
225 // Start listening for position updates
226 satelliteInfoSource->startUpdates();
227 }
228 }
229