QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #define KNOTS_TO_KMH 1.852
32 
34  : QgsGpsConnection( device )
35 {
36 }
37 
39 {
40  if ( !mSource )
41  {
42  return;
43  }
44 
45  //print out the data as a test
46  qint64 numBytes = 0;
47  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 ?
48  {
49  numBytes = mSource->size();
50  }
51  else
52  {
53  numBytes = mSource->bytesAvailable();
54  }
55 
56  QgsDebugMsg( "numBytes:" + QString::number( numBytes ) );
57 
58  if ( numBytes >= 6 )
59  {
60  if ( mStatus != GPSDataReceived )
61  {
63  }
64 
65  //append new data to the remaining results from last parseData() call
66  mStringBuffer.append( mSource->read( numBytes ) );
69  }
70 }
71 
73 {
74  int endSentenceIndex = 0;
75  int dollarIndex;
76 
77  while ( ( endSentenceIndex = mStringBuffer.indexOf( QLatin1String( "\r\n" ) ) ) && endSentenceIndex != -1 )
78  {
79  endSentenceIndex = mStringBuffer.indexOf( QLatin1String( "\r\n" ) );
80 
81  dollarIndex = mStringBuffer.indexOf( QLatin1String( "$" ) );
82  if ( endSentenceIndex == -1 )
83  {
84  break;
85  }
86 
87 
88  if ( endSentenceIndex >= dollarIndex )
89  {
90  if ( dollarIndex != -1 )
91  {
92  QString substring = mStringBuffer.mid( dollarIndex, endSentenceIndex );
93  QByteArray ba = substring.toLocal8Bit();
94  if ( substring.startsWith( QLatin1String( "$GPGGA" ) ) )
95  {
96  QgsDebugMsg( substring );
97  processGgaSentence( ba.data(), ba.length() );
99  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
100  }
101  else if ( substring.startsWith( QLatin1String( "$GPRMC" ) ) || substring.startsWith( QLatin1String( "$GNRMC" ) ) )
102  {
103  QgsDebugMsg( substring );
104  processRmcSentence( ba.data(), ba.length() );
106  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
107  }
108  else if ( substring.startsWith( QLatin1String( "$GPGSV" ) ) )
109  {
110  QgsDebugMsg( substring );
111  processGsvSentence( ba.data(), ba.length() );
113  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
114  }
115  else if ( substring.startsWith( QLatin1String( "$GPVTG" ) ) )
116  {
117  QgsDebugMsg( substring );
118  processVtgSentence( ba.data(), ba.length() );
120  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
121  }
122  else if ( substring.startsWith( QLatin1String( "$GPGSA" ) ) )
123  {
124  QgsDebugMsg( substring );
125  processGsaSentence( ba.data(), ba.length() );
127  QgsDebugMsg( QStringLiteral( "*******************GPS data received****************" ) );
128  }
129  emit nmeaSentenceReceived( substring ); // added to be able to save raw data
130  }
131  }
132  mStringBuffer.remove( 0, endSentenceIndex + 2 );
133  }
134 }
135 
136 void QgsNmeaConnection::processGgaSentence( const char *data, int len )
137 {
138  nmeaGPGGA result;
139  if ( nmea_parse_GPGGA( data, len, &result ) )
140  {
141  //update mLastGPSInformation
142  double longitude = result.lon;
143  if ( result.ew == 'W' )
144  {
145  longitude = -longitude;
146  }
147  double latitude = result.lat;
148  if ( result.ns == 'S' )
149  {
150  latitude = -latitude;
151  }
152 
153  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
154  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
155  mLastGPSInformation.elevation = result.elv;
156  mLastGPSInformation.quality = result.sig;
157  mLastGPSInformation.satellitesUsed = result.satinuse;
158  }
159 }
160 
161 void QgsNmeaConnection::processRmcSentence( const char *data, int len )
162 {
163  nmeaGPRMC result;
164  if ( nmea_parse_GPRMC( data, len, &result ) )
165  {
166  double longitude = result.lon;
167  if ( result.ew == 'W' )
168  {
169  longitude = -longitude;
170  }
171  double latitude = result.lat;
172  if ( result.ns == 'S' )
173  {
174  latitude = -latitude;
175  }
176  mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
177  mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
178  mLastGPSInformation.speed = KNOTS_TO_KMH * result.speed;
179  mLastGPSInformation.direction = result.direction;
180  mLastGPSInformation.status = result.status; // A,V
181 
182  //date and time
183  QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
184  QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec ); // added msec part
185  if ( date.isValid() && time.isValid() )
186  {
187  mLastGPSInformation.utcDateTime.setTimeSpec( Qt::UTC );
188  mLastGPSInformation.utcDateTime.setDate( date );
189  mLastGPSInformation.utcDateTime.setTime( time );
190  QgsDebugMsg( QStringLiteral( "utc time:" ) );
192  QgsDebugMsg( QStringLiteral( "local time:" ) );
193  QgsDebugMsg( mLastGPSInformation.utcDateTime.toLocalTime().toString() );
194  }
195  }
196 }
197 
198 void QgsNmeaConnection::processGsvSentence( const char *data, int len )
199 {
200  nmeaGPGSV result;
201  if ( nmea_parse_GPGSV( data, len, &result ) )
202  {
203  //clear satellite information when a new series of packs arrives
204  if ( result.pack_index == 1 )
205  {
207  }
208 
209  // for determining when to graph sat info
210  mLastGPSInformation.satInfoComplete = ( result.pack_index == result.pack_count );
211 
212  for ( int i = 0; i < NMEA_SATINPACK; ++i )
213  {
214  nmeaSATELLITE currentSatellite = result.sat_data[i];
215  QgsSatelliteInfo satelliteInfo;
216  satelliteInfo.azimuth = currentSatellite.azimuth;
217  satelliteInfo.elevation = currentSatellite.elv;
218  satelliteInfo.id = currentSatellite.id;
219  satelliteInfo.inUse = currentSatellite.in_use; // the GSA processing below does NOT set the sats in use
220  satelliteInfo.signal = currentSatellite.sig;
221  mLastGPSInformation.satellitesInView.append( satelliteInfo );
222  }
223 
224  }
225 }
226 
227 void QgsNmeaConnection::processVtgSentence( const char *data, int len )
228 {
229  nmeaGPVTG result;
230  if ( nmea_parse_GPVTG( data, len, &result ) )
231  {
232  mLastGPSInformation.speed = result.spk;
233  }
234 }
235 
236 void QgsNmeaConnection::processGsaSentence( const char *data, int len )
237 {
238  nmeaGPGSA result;
239  if ( nmea_parse_GPGSA( data, len, &result ) )
240  {
241  mLastGPSInformation.satPrn.clear();
242  mLastGPSInformation.hdop = result.HDOP;
243  mLastGPSInformation.pdop = result.PDOP;
244  mLastGPSInformation.vdop = result.VDOP;
245  mLastGPSInformation.fixMode = result.fix_mode;
246  mLastGPSInformation.fixType = result.fix_type;
247  for ( int i = 0; i < NMEA_MAXSAT; i++ )
248  {
249  mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
250  }
251  }
252 }
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.
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.