QGIS API Documentation  2.99.0-Master (19b062c)
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 {
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( "*******************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( "*******************GPS data received****************" );
107  }
108  else if ( substring.startsWith( QLatin1String( "$GPGSV" ) ) )
109  {
110  QgsDebugMsg( substring );
111  processGSVSentence( ba.data(), ba.length() );
113  QgsDebugMsg( "*******************GPS data received****************" );
114  }
115  else if ( substring.startsWith( QLatin1String( "$GPVTG" ) ) )
116  {
117  QgsDebugMsg( substring );
118  processVTGSentence( ba.data(), ba.length() );
120  QgsDebugMsg( "*******************GPS data received****************" );
121  }
122  else if ( substring.startsWith( QLatin1String( "$GPGSA" ) ) )
123  {
124  QgsDebugMsg( substring );
125  processGSASentence( ba.data(), ba.length() );
127  QgsDebugMsg( "*******************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 
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  }
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( "utc time:" );
192  QgsDebugMsg( "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
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;
247  for ( int i = 0; i < NMEA_MAXSAT; i++ )
248  {
249  mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
250  }
251  }
252 }
char ns
[N]orth or [S]outh
Definition: sentence.h:92
void nmeaSentenceReceived(const QString &substring)
Information about satellite.
Definition: info.h:70
int azimuth
Azimuth, degrees from true north, 000 to 359.
Definition: info.h:75
char ns
[N]orth or [S]outh
Definition: sentence.h:43
int nmea_parse_GPGSA(const char *buff, int buff_sz, nmeaGPGSA *pack)
Parse GSA packet from buffer.
Definition: parse.c:254
Status mStatus
Connection status.
void processRMCSentence(const char *data, int len)
int hour
Hours since midnight - [0,23].
Definition: nmeatime.h:48
int mon
Months since January - [0,11].
Definition: nmeatime.h:46
int id
Satellite PRN number.
Definition: info.h:72
double lon
Longitude in NDEG - [degree][min].[sec/60].
Definition: sentence.h:44
int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
Parse GGA packet from buffer.
Definition: parse.c:217
GGA packet information structure (Global Positioning System Fix Data)
Definition: sentence.h:39
double lat
Latitude in NDEG - [degree][min].[sec/60].
Definition: sentence.h:91
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
int year
Years since 1900.
Definition: nmeatime.h:45
double spk
Ground speed, kilometers per hour.
Definition: sentence.h:114
VTG packet information structure (Track made good and ground speed)
Definition: sentence.h:106
int satinuse
Number of satellites in use (not those in view)
Definition: sentence.h:47
QList< QgsSatelliteInfo > satellitesInView
Functions of a low level for analysis of packages of NMEA stream.
double lat
Latitude in NDEG - [degree][min].[sec/60].
Definition: sentence.h:42
void processStringBuffer()
Splits mStringBuffer into sentences and calls libnmea.
double direction
Track angle in degrees True.
Definition: sentence.h:96
QString mStringBuffer
Store data from the device before it is processed.
char ew
[E]ast or [W]est
Definition: sentence.h:45
char status
Status (A = active or V = void)
Definition: sentence.h:90
char ew
[E]ast or [W]est
Definition: sentence.h:94
int elv
Elevation in degrees, 90 maximum.
Definition: info.h:74
QList< int > satPrn
void processGSASentence(const char *data, int len)
int day
Day of the month - [1,31].
Definition: nmeatime.h:47
double VDOP
Vertical dilution of precision.
Definition: sentence.h:68
Abstract base class for connection to a GPS device.
QgsNMEAConnection(QIODevice *dev)
double elv
Antenna altitude above/below mean sea level (geoid)
Definition: sentence.h:49
QgsGPSInformation mLastGPSInformation
Last state of the gps related variables (e.g. position, time, ...)
double speed
Speed over the ground in knots.
Definition: sentence.h:95
void processGGASentence(const char *data, int len)
char fix_mode
Mode (M = Manual, forced to operate in 2D or 3D; A = Automatic, 3D/2D)
Definition: sentence.h:63
double nmea_ndeg2degree(double val)
Convert NDEG (NMEA degree) to fractional degree.
Definition: gmath.c:51
QIODevice * mSource
Data source (e.g. serial device, socket, file,...)
GSA packet information structure (Satellite status)
Definition: sentence.h:61
void parseData() override
Parse available data source content.
int pack_index
Message number.
Definition: sentence.h:78
nmeaTIME utc
UTC of position.
Definition: sentence.h:89
int sig
Signal, 00-99 dB.
Definition: info.h:76
void stateChanged(const QgsGPSInformation &info)
void processGSVSentence(const char *data, int len)
int nmea_parse_GPGSV(const char *buff, int buff_sz, nmeaGPGSV *pack)
Parse GSV packet from buffer.
Definition: parse.c:283
void processVTGSentence(const char *data, int len)
double lon
Longitude in NDEG - [degree][min].[sec/60].
Definition: sentence.h:93
#define KNOTS_TO_KMH
int pack_count
Total number of messages of this type in this cycle.
Definition: sentence.h:77
int sig
GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive)
Definition: sentence.h:46
GSV packet information structure (Satellites in view)
Definition: sentence.h:75
int sec
Seconds after the minute - [0,59].
Definition: nmeatime.h:50
nmeaSATELLITE sat_data[NMEA_SATINPACK]
Definition: sentence.h:80
#define NMEA_SATINPACK
Definition: info.h:44
#define NMEA_MAXSAT
Definition: info.h:43
int msec
Thousandths part of second - [0,999].
Definition: nmeatime.h:51
int sat_prn[NMEA_MAXSAT]
PRNs of satellites used in position fix (null for unused fields)
Definition: sentence.h:65
int min
Minutes after the hour - [0,59].
Definition: nmeatime.h:49
int in_use
Used in position fix.
Definition: info.h:73
int fix_type
Type, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D)
Definition: sentence.h:64
double HDOP
Horizontal dilution of precision.
Definition: sentence.h:67
RMC packet information structure (Recommended Minimum sentence C)
Definition: sentence.h:87
int nmea_parse_GPRMC(const char *buff, int buff_sz, nmeaGPRMC *pack)
Parse RMC packet from buffer.
Definition: parse.c:325
int nmea_parse_GPVTG(const char *buff, int buff_sz, nmeaGPVTG *pack)
Parse VTG packet from buffer.
Definition: parse.c:377
double PDOP
Dilution of precision.
Definition: sentence.h:66