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