QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  QgsDebugMsg( "numBytes:" + QString::number( numBytes ) );
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( QLatin1String( "$" ) );
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" ) ) )
98  {
99  QgsDebugMsg( substring );
100  processGgaSentence( ba.data(), ba.length() );
102  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
103  }
104  else if ( substring.startsWith( QLatin1String( "$GPRMC" ) ) || substring.startsWith( QLatin1String( "$GNRMC" ) ) )
105  {
106  QgsDebugMsg( substring );
107  processRmcSentence( ba.data(), ba.length() );
109  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
110  }
111  else if ( substring.startsWith( QLatin1String( "$GPGSV" ) ) )
112  {
113  QgsDebugMsg( substring );
114  processGsvSentence( ba.data(), ba.length() );
116  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
117  }
118  else if ( substring.startsWith( QLatin1String( "$GPVTG" ) ) )
119  {
120  QgsDebugMsg( substring );
121  processVtgSentence( ba.data(), ba.length() );
123  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
124  }
125  else if ( substring.startsWith( QLatin1String( "$GPGSA" ) ) )
126  {
127  QgsDebugMsg( substring );
128  processGsaSentence( ba.data(), ba.length() );
130  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
131  }
132  else if ( substring.startsWith( QLatin1String( "$GPGST" ) ) )
133  {
134  QgsDebugMsg( substring );
135  processGstSentence( ba.data(), ba.length() );
137  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
138  }
139  emit nmeaSentenceReceived( substring ); // added to be able to save raw data
140  }
141  }
142  mStringBuffer.remove( 0, endSentenceIndex + 2 );
143  }
144 }
145 
146 void QgsNmeaConnection::processGgaSentence( const char *data, int len )
147 {
148  nmeaGPGGA result;
149  if ( nmea_parse_GPGGA( data, len, &result ) )
150  {
151  //update mLastGPSInformation
152  double longitude = result.lon;
153  if ( result.ew == 'W' )
154  {
155  longitude = -longitude;
156  }
157  double latitude = result.lat;
158  if ( result.ns == 'S' )
159  {
160  latitude = -latitude;
161  }
162 
163  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
164  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
165  mLastGPSInformation.elevation = result.elv;
166  mLastGPSInformation.quality = result.sig;
167  mLastGPSInformation.satellitesUsed = result.satinuse;
168  }
169 }
170 
171 void QgsNmeaConnection::processGstSentence( const char *data, int len )
172 {
173  nmeaGPGST result;
174  if ( nmea_parse_GPGST( data, len, &result ) )
175  {
176  //update mLastGPSInformation
177  double sig_lat = result.sig_lat;
178  double sig_lon = result.sig_lon;
179  double sig_alt = result.sig_alt;
180 
181  // Horizontal RMS
182  mLastGPSInformation.hacc = sqrt( ( pow( sig_lat, 2 ) + pow( sig_lon, 2 ) ) / 2.0 );
183  // Vertical RMS
184  mLastGPSInformation.vacc = sig_alt;
185  }
186 }
187 
188 void QgsNmeaConnection::processRmcSentence( const char *data, int len )
189 {
190  nmeaGPRMC result;
191  if ( nmea_parse_GPRMC( data, len, &result ) )
192  {
193  double longitude = result.lon;
194  if ( result.ew == 'W' )
195  {
196  longitude = -longitude;
197  }
198  double latitude = result.lat;
199  if ( result.ns == 'S' )
200  {
201  latitude = -latitude;
202  }
203  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
204  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
205  mLastGPSInformation.speed = KNOTS_TO_KMH * result.speed;
206  mLastGPSInformation.direction = result.direction;
207  mLastGPSInformation.status = result.status; // A,V
208 
209  //date and time
210  QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
211  QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec ); // added msec part
212  if ( date.isValid() && time.isValid() )
213  {
214  mLastGPSInformation.utcDateTime.setTimeSpec( Qt::UTC );
215  mLastGPSInformation.utcDateTime.setDate( date );
216  mLastGPSInformation.utcDateTime.setTime( time );
217  QgsDebugMsg( QStringLiteral( "utc time:" ) );
219  QgsDebugMsg( QStringLiteral( "local time:" ) );
220  QgsDebugMsg( mLastGPSInformation.utcDateTime.toLocalTime().toString() );
221  }
222  }
223 }
224 
225 void QgsNmeaConnection::processGsvSentence( const char *data, int len )
226 {
227  nmeaGPGSV result;
228  if ( nmea_parse_GPGSV( data, len, &result ) )
229  {
230  //clear satellite information when a new series of packs arrives
231  if ( result.pack_index == 1 )
232  {
234  }
235 
236  // for determining when to graph sat info
237  mLastGPSInformation.satInfoComplete = ( result.pack_index == result.pack_count );
238 
239  for ( int i = 0; i < NMEA_SATINPACK; ++i )
240  {
241  nmeaSATELLITE currentSatellite = result.sat_data[i];
242  QgsSatelliteInfo satelliteInfo;
243  satelliteInfo.azimuth = currentSatellite.azimuth;
244  satelliteInfo.elevation = currentSatellite.elv;
245  satelliteInfo.id = currentSatellite.id;
246  satelliteInfo.inUse = currentSatellite.in_use; // the GSA processing below does NOT set the sats in use
247  satelliteInfo.signal = currentSatellite.sig;
248  mLastGPSInformation.satellitesInView.append( satelliteInfo );
249  }
250 
251  }
252 }
253 
254 void QgsNmeaConnection::processVtgSentence( const char *data, int len )
255 {
256  nmeaGPVTG result;
257  if ( nmea_parse_GPVTG( data, len, &result ) )
258  {
259  mLastGPSInformation.speed = result.spk;
260  }
261 }
262 
263 void QgsNmeaConnection::processGsaSentence( const char *data, int len )
264 {
265  nmeaGPGSA result;
266  if ( nmea_parse_GPGSA( data, len, &result ) )
267  {
268  mLastGPSInformation.satPrn.clear();
269  mLastGPSInformation.hdop = result.HDOP;
270  mLastGPSInformation.pdop = result.PDOP;
271  mLastGPSInformation.vdop = result.VDOP;
272  mLastGPSInformation.fixMode = result.fix_mode;
273  mLastGPSInformation.fixType = result.fix_type;
274  for ( int i = 0; i < NMEA_MAXSAT; i++ )
275  {
276  mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
277  }
278  }
279 }
QgsGpsInformation mLastGPSInformation
Last state of the gps related variables (e.g. position, time, ...)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QString mStringBuffer
Store data from the device before it is processed.
void processGsaSentence(const char *data, int len)
process GSA sentence
void parseData() override
Parse available data source content.
QIODevice * mSource
Data source (e.g. serial device, socket, file,...)
QList< QgsSatelliteInfo > satellitesInView
QList< int > satPrn
void stateChanged(const QgsGpsInformation &info)
void processGsvSentence(const char *data, int len)
process GSV sentence
void processStringBuffer()
Splits mStringBuffer into sentences and calls libnmea.
void processGstSentence(const char *data, int len)
process GST sentence
QgsNmeaConnection(QIODevice *device)
Constructs a QgsNmeaConnection with given device.
void processRmcSentence(const char *data, int len)
process RMC sentence
Status mStatus
Connection status.
void processGgaSentence(const char *data, int len)
process GGA sentence
#define KNOTS_TO_KMH
void nmeaSentenceReceived(const QString &substring)
void processVtgSentence(const char *data, int len)
process VTG sentence
Abstract base class for connection to a GPS device.