QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsnmeaconnection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsnmeaconnection.cpp - description
3  ---------------------
4  begin : November 30th, 2009
5  copyright : (C) 2009 by Marco Hugentobler
6  email : marco at hugis dot net
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 "qgsnmeaconnection.h"
19 #include "qgslogger.h"
20 
21 #include <QIODevice>
22 #include <QApplication>
23 #include <QStringList>
24 
25 
26 //from libnmea
27 #include "parse.h"
28 #include "gmath.h"
29 #include "info.h"
30 
31 // for sqrt
32 #include <math.h>
33 
34 #define KNOTS_TO_KMH 1.852
35 
37  : QgsGpsConnection( device )
38 {
39 }
40 
42 {
43  if ( !mSource )
44  {
45  return;
46  }
47 
48  //print out the data as a test
49  qint64 numBytes = 0;
50  if ( ! mSource->isSequential() ) //necessary because of a bug in QExtSerialPort //SLM - bytesAvailable() works on Windows, so I reversed the logic (added ! ); this is what QIODevice docs say to do; the orig impl of win_qextserialport had an (unsigned int)-1 return on error - it should be (qint64)-1, which was fixed by ?
51  {
52  numBytes = mSource->size();
53  }
54  else
55  {
56  numBytes = mSource->bytesAvailable();
57  }
58 
59  QgsDebugMsgLevel( "numBytes:" + QString::number( numBytes ), 2 );
60 
61  if ( numBytes >= 6 )
62  {
63  if ( mStatus != GPSDataReceived )
64  {
66  }
67 
68  //append new data to the remaining results from last parseData() call
69  mStringBuffer.append( mSource->read( numBytes ) );
72  }
73 }
74 
76 {
77  int endSentenceIndex = 0;
78  int dollarIndex;
79 
80  while ( ( endSentenceIndex = mStringBuffer.indexOf( QLatin1String( "\r\n" ) ) ) && endSentenceIndex != -1 )
81  {
82  endSentenceIndex = mStringBuffer.indexOf( QLatin1String( "\r\n" ) );
83 
84  dollarIndex = mStringBuffer.indexOf( QLatin1Char( '$' ) );
85  if ( endSentenceIndex == -1 )
86  {
87  break;
88  }
89 
90 
91  if ( endSentenceIndex >= dollarIndex )
92  {
93  if ( dollarIndex != -1 )
94  {
95  QString substring = mStringBuffer.mid( dollarIndex, endSentenceIndex );
96  QByteArray ba = substring.toLocal8Bit();
97  if ( substring.startsWith( QLatin1String( "$GPGGA" ) ) || substring.startsWith( QLatin1String( "$GNGGA" ) ) )
98  {
99  QgsDebugMsgLevel( substring, 2 );
100  processGgaSentence( ba.data(), ba.length() );
102  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
103  }
104  else if ( substring.startsWith( QLatin1String( "$GPRMC" ) ) || substring.startsWith( QLatin1String( "$GNRMC" ) ) )
105  {
106  QgsDebugMsgLevel( substring, 2 );
107  processRmcSentence( ba.data(), ba.length() );
109  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
110  }
111  else if ( substring.startsWith( QLatin1String( "$GPGSV" ) ) || substring.startsWith( QLatin1String( "$GNGSV" ) ) )
112  {
113  QgsDebugMsgLevel( substring, 2 );
114  processGsvSentence( ba.data(), ba.length() );
116  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
117  }
118  else if ( substring.startsWith( QLatin1String( "$GPVTG" ) ) || substring.startsWith( QLatin1String( "$GNVTG" ) ) )
119  {
120  QgsDebugMsgLevel( substring, 2 );
121  processVtgSentence( ba.data(), ba.length() );
123  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
124  }
125  else if ( substring.startsWith( QLatin1String( "$GPGSA" ) ) || substring.startsWith( QLatin1String( "$GNGSA" ) ) )
126  {
127  QgsDebugMsgLevel( substring, 2 );
128  processGsaSentence( ba.data(), ba.length() );
130  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
131  }
132  else if ( substring.startsWith( QLatin1String( "$GPGST" ) ) || substring.startsWith( QLatin1String( "$GNGST" ) ) )
133  {
134  QgsDebugMsgLevel( substring, 2 );
135  processGstSentence( ba.data(), ba.length() );
137  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
138  }
139  else if ( substring.startsWith( QLatin1String( "$GPHDT" ) ) || substring.startsWith( QLatin1String( "$GNHDT" ) ) )
140  {
141  QgsDebugMsgLevel( substring, 2 );
142  processHdtSentence( ba.data(), ba.length() );
144  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
145  }
146  else if ( substring.startsWith( QLatin1String( "$HCHDG" ) ) )
147  {
148  QgsDebugMsgLevel( substring, 2 );
149  processHchdgSentence( ba.data(), ba.length() );
151  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
152  }
153  else if ( substring.startsWith( QLatin1String( "$HCHDT" ) ) )
154  {
155  QgsDebugMsgLevel( substring, 2 );
156  processHchdtSentence( ba.data(), ba.length() );
158  QgsDebugMsgLevel( QStringLiteral( "*******************GPS data received****************" ), 2 );
159  }
160  else
161  {
162  QgsDebugMsgLevel( QStringLiteral( "unknown nmea sentence: %1" ).arg( substring ), 2 );
163  }
164  emit nmeaSentenceReceived( substring ); // added to be able to save raw data
165  }
166  }
167  mStringBuffer.remove( 0, endSentenceIndex + 2 );
168  }
169 }
170 
171 void QgsNmeaConnection::processGgaSentence( const char *data, int len )
172 {
173  nmeaGPGGA result;
174  if ( nmea_parse_GPGGA( data, len, &result ) )
175  {
176  //update mLastGPSInformation
177  double longitude = result.lon;
178  if ( result.ew == 'W' )
179  {
180  longitude = -longitude;
181  }
182  double latitude = result.lat;
183  if ( result.ns == 'S' )
184  {
185  latitude = -latitude;
186  }
187 
188  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
189  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
190  mLastGPSInformation.elevation = result.elv;
191  mLastGPSInformation.quality = result.sig;
192  mLastGPSInformation.satellitesUsed = result.satinuse;
193  }
194 }
195 
196 void QgsNmeaConnection::processGstSentence( const char *data, int len )
197 {
198  nmeaGPGST result;
199  if ( nmea_parse_GPGST( data, len, &result ) )
200  {
201  //update mLastGPSInformation
202  double sig_lat = result.sig_lat;
203  double sig_lon = result.sig_lon;
204  double sig_alt = result.sig_alt;
205 
206  // Horizontal RMS
207  mLastGPSInformation.hacc = sqrt( ( pow( sig_lat, 2 ) + pow( sig_lon, 2 ) ) / 2.0 );
208  // Vertical RMS
209  mLastGPSInformation.vacc = sig_alt;
210  }
211 }
212 
213 void QgsNmeaConnection::processHdtSentence( const char *data, int len )
214 {
215  nmeaGPHDT result;
216  if ( nmea_parse_GPHDT( data, len, &result ) )
217  {
218  mLastGPSInformation.direction = result.heading;
219  }
220 }
221 
222 void QgsNmeaConnection::processHchdgSentence( const char *data, int len )
223 {
224  nmeaHCHDG result;
225  if ( nmea_parse_HCHDG( data, len, &result ) )
226  {
227  mLastGPSInformation.direction = result.mag_heading;
228  if ( result.ew_variation == 'E' )
229  mLastGPSInformation.direction += result.mag_variation;
230  else
231  mLastGPSInformation.direction -= result.mag_variation;
232  }
233 }
234 
235 void QgsNmeaConnection::processHchdtSentence( const char *data, int len )
236 {
237  nmeaHCHDT result;
238  if ( nmea_parse_HCHDT( data, len, &result ) )
239  {
240  mLastGPSInformation.direction = result.direction;
241  }
242 }
243 
244 void QgsNmeaConnection::processRmcSentence( const char *data, int len )
245 {
246  nmeaGPRMC result;
247  if ( nmea_parse_GPRMC( data, len, &result ) )
248  {
249  double longitude = result.lon;
250  if ( result.ew == 'W' )
251  {
252  longitude = -longitude;
253  }
254  double latitude = result.lat;
255  if ( result.ns == 'S' )
256  {
257  latitude = -latitude;
258  }
259  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
260  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
261  mLastGPSInformation.speed = KNOTS_TO_KMH * result.speed;
262  if ( !std::isnan( result.direction ) )
263  mLastGPSInformation.direction = result.direction;
264  mLastGPSInformation.status = result.status; // A,V
265 
266  //date and time
267  QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
268  QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec ); // added msec part
269  if ( date.isValid() && time.isValid() )
270  {
271  mLastGPSInformation.utcDateTime.setTimeSpec( Qt::UTC );
272  mLastGPSInformation.utcDateTime.setDate( date );
273  mLastGPSInformation.utcDateTime.setTime( time );
274  QgsDebugMsgLevel( QStringLiteral( "utc time:" ), 2 );
276  QgsDebugMsgLevel( QStringLiteral( "local time:" ), 2 );
277  QgsDebugMsgLevel( mLastGPSInformation.utcDateTime.toLocalTime().toString(), 2 );
278  }
279  }
280 }
281 
282 void QgsNmeaConnection::processGsvSentence( const char *data, int len )
283 {
284  nmeaGPGSV result;
285  if ( nmea_parse_GPGSV( data, len, &result ) )
286  {
287  //clear satellite information when a new series of packs arrives
288  if ( result.pack_index == 1 )
289  {
291  }
292 
293  // for determining when to graph sat info
294  mLastGPSInformation.satInfoComplete = ( result.pack_index == result.pack_count );
295 
296  for ( int i = 0; i < NMEA_SATINPACK; ++i )
297  {
298  nmeaSATELLITE currentSatellite = result.sat_data[i];
299  QgsSatelliteInfo satelliteInfo;
300  satelliteInfo.azimuth = currentSatellite.azimuth;
301  satelliteInfo.elevation = currentSatellite.elv;
302  satelliteInfo.id = currentSatellite.id;
303  satelliteInfo.inUse = currentSatellite.in_use; // the GSA processing below does NOT set the sats in use
304  satelliteInfo.signal = currentSatellite.sig;
305  mLastGPSInformation.satellitesInView.append( satelliteInfo );
306  }
307 
308  }
309 }
310 
311 void QgsNmeaConnection::processVtgSentence( const char *data, int len )
312 {
313  nmeaGPVTG result;
314  if ( nmea_parse_GPVTG( data, len, &result ) )
315  {
316  mLastGPSInformation.speed = result.spk;
317  }
318 }
319 
320 void QgsNmeaConnection::processGsaSentence( const char *data, int len )
321 {
322  nmeaGPGSA result;
323  if ( nmea_parse_GPGSA( data, len, &result ) )
324  {
325  mLastGPSInformation.satPrn.clear();
326  mLastGPSInformation.hdop = result.HDOP;
327  mLastGPSInformation.pdop = result.PDOP;
328  mLastGPSInformation.vdop = result.VDOP;
329  mLastGPSInformation.fixMode = result.fix_mode;
330  mLastGPSInformation.fixType = result.fix_type;
331  for ( int i = 0; i < NMEA_MAXSAT; i++ )
332  {
333  mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
334  }
335  }
336 }
QgsGpsConnection::stateChanged
void stateChanged(const QgsGpsInformation &info)
QgsNmeaConnection::processHdtSentence
void processHdtSentence(const char *data, int len)
process HDT sentence
Definition: qgsnmeaconnection.cpp:213
QgsGpsInformation::vdop
double vdop
Vertical dilution of precision.
Definition: qgsgpsconnection.h:168
QgsGpsInformation::hdop
double hdop
Horizontal dilution of precision.
Definition: qgsgpsconnection.h:163
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsNmeaConnection::processGsaSentence
void processGsaSentence(const char *data, int len)
process GSA sentence
Definition: qgsnmeaconnection.cpp:320
QgsGpsConnection::mStatus
Status mStatus
Connection status.
Definition: qgsgpsconnection.h:306
QgsGpsConnection::nmeaSentenceReceived
void nmeaSentenceReceived(const QString &substring)
QgsGpsInformation::vacc
double vacc
Vertical accuracy in meters.
Definition: qgsgpsconnection.h:174
QgsSatelliteInfo
Encapsulates information relating to a GPS satellite.
Definition: qgsgpsconnection.h:42
QgsNmeaConnection::processHchdtSentence
void processHchdtSentence(const char *data, int len)
process HCHDT sentence
Definition: qgsnmeaconnection.cpp:235
QgsGpsInformation::satellitesUsed
int satellitesUsed
Count of satellites used in obtaining the fix.
Definition: qgsgpsconnection.h:205
QgsSatelliteInfo::signal
int signal
Signal strength (0-99dB), or -1 if not available.
Definition: qgsgpsconnection.h:90
QgsGpsInformation::pdop
double pdop
Dilution of precision.
Definition: qgsgpsconnection.h:158
QgsNmeaConnection::parseData
void parseData() override
Parse available data source content.
Definition: qgsnmeaconnection.cpp:41
QgsGpsConnection::mSource
std::unique_ptr< QIODevice > mSource
Data source (e.g. serial device, socket, file,...)
Definition: qgsgpsconnection.h:302
QgsNmeaConnection::processGsvSentence
void processGsvSentence(const char *data, int len)
process GSV sentence
Definition: qgsnmeaconnection.cpp:282
QgsNmeaConnection::mStringBuffer
QString mStringBuffer
Store data from the device before it is processed.
Definition: qgsnmeaconnection.h:47
QgsGpsInformation::utcDateTime
QDateTime utcDateTime
The date and time at which this position was reported, in UTC time.
Definition: qgsgpsconnection.h:185
QgsSatelliteInfo::elevation
double elevation
Elevation of the satellite, in degrees.
Definition: qgsgpsconnection.h:64
QgsGpsInformation::fixMode
QChar fixMode
Fix mode (where M = Manual, forced to operate in 2D or 3D or A = Automatic, 3D/2D)
Definition: qgsgpsconnection.h:190
QgsGpsInformation::fixType
int fixType
Contains the fix type, where 1 = no fix, 2 = 2d fix, 3 = 3d fix.
Definition: qgsgpsconnection.h:195
QgsNmeaConnection::processHchdgSentence
void processHchdgSentence(const char *data, int len)
process HCHDG sentence
Definition: qgsnmeaconnection.cpp:222
QgsSatelliteInfo::inUse
bool inUse
true if satellite was used in obtaining the position fix.
Definition: qgsgpsconnection.h:57
QgsNmeaConnection::QgsNmeaConnection
QgsNmeaConnection(QIODevice *device)
Constructs a QgsNmeaConnection with given device.
Definition: qgsnmeaconnection.cpp:36
QgsGpsConnection::mLastGPSInformation
QgsGpsInformation mLastGPSInformation
Last state of the gps related variables (e.g. position, time, ...)
Definition: qgsgpsconnection.h:304
QgsSatelliteInfo::id
int id
Contains the satellite identifier number.
Definition: qgsgpsconnection.h:52
QgsGpsInformation::satInfoComplete
bool satInfoComplete
true if satellite information is complete.
Definition: qgsgpsconnection.h:220
QgsNmeaConnection::processStringBuffer
void processStringBuffer()
Splits mStringBuffer into sentences and calls libnmea.
Definition: qgsnmeaconnection.cpp:75
QgsSatelliteInfo::azimuth
double azimuth
The azimuth of the satellite to true north, in degrees.
Definition: qgsgpsconnection.h:78
QgsGpsConnection::DataReceived
@ DataReceived
Definition: qgsgpsconnection.h:272
QgsNmeaConnection::processGstSentence
void processGstSentence(const char *data, int len)
process GST sentence
Definition: qgsnmeaconnection.cpp:196
QgsGpsInformation::speed
double speed
Ground speed, in km/h.
Definition: qgsgpsconnection.h:134
QgsNmeaConnection::processVtgSentence
void processVtgSentence(const char *data, int len)
process VTG sentence
Definition: qgsnmeaconnection.cpp:311
QgsGpsInformation::latitude
double latitude
Latitude in decimal degrees, using the WGS84 datum.
Definition: qgsgpsconnection.h:118
QgsGpsInformation::quality
int quality
GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive)
Definition: qgsgpsconnection.h:200
QgsNmeaConnection::processRmcSentence
void processRmcSentence(const char *data, int len)
process RMC sentence
Definition: qgsnmeaconnection.cpp:244
QgsGpsConnection
Abstract base class for connection to a GPS device.
Definition: qgsgpsconnection.h:247
QgsGpsInformation::satPrn
QList< int > satPrn
IDs of satellites used in the position fix.
Definition: qgsgpsconnection.h:215
QgsGpsInformation::satellitesInView
QList< QgsSatelliteInfo > satellitesInView
Contains a list of information relating to the current satellites in view.
Definition: qgsgpsconnection.h:153
qgslogger.h
QgsGpsInformation::elevation
double elevation
Altitude (in meters) above or below the mean sea level.
Definition: qgsgpsconnection.h:129
QgsGpsConnection::GPSDataReceived
@ GPSDataReceived
Definition: qgsgpsconnection.h:273
qgsnmeaconnection.h
QgsGpsInformation::longitude
double longitude
Longitude in decimal degrees, using the WGS84 datum.
Definition: qgsgpsconnection.h:124
QgsNmeaConnection::processGgaSentence
void processGgaSentence(const char *data, int len)
process GGA sentence
Definition: qgsnmeaconnection.cpp:171
QgsGpsInformation::hacc
double hacc
Horizontal accuracy in meters.
Definition: qgsgpsconnection.h:172
QgsGpsInformation::direction
double direction
The bearing measured in degrees clockwise from true north to the direction of travel.
Definition: qgsgpsconnection.h:141
QgsGpsInformation::status
QChar status
Status (A = active or V = void)
Definition: qgsgpsconnection.h:210
KNOTS_TO_KMH
#define KNOTS_TO_KMH
Definition: qgsnmeaconnection.cpp:34