QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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  //connection will be closed by base class
41 }
42 
44 {
45  if ( !mSource )
46  {
47  return;
48  }
49 
50  //print out the data as a test
51  qint64 numBytes = 0;
52  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 ?
53  {
54  numBytes = mSource->size();
55  }
56  else
57  {
58  numBytes = mSource->bytesAvailable();
59  }
60 
61  QgsDebugMsg( "numBytes:" + QString::number( numBytes ) );
62 
63  if ( numBytes >= 6 )
64  {
65  if ( mStatus != GPSDataReceived )
66  {
68  }
69 
70  //append new data to the remaining results from last parseData() call
71  mStringBuffer.append( mSource->read( numBytes ) );
74  }
75 }
76 
78 {
79  int endSentenceIndex = 0;
80  int dollarIndex;
81 
82  while (( endSentenceIndex = mStringBuffer.indexOf( "\r\n" ) ) && endSentenceIndex != -1 )
83  {
84  endSentenceIndex = mStringBuffer.indexOf( "\r\n" );
85 
86  dollarIndex = mStringBuffer.indexOf( "$" );
87  if ( endSentenceIndex == -1 )
88  {
89  break;
90  }
91 
92 
93  if ( endSentenceIndex >= dollarIndex )
94  {
95  if ( dollarIndex != -1 )
96  {
97  QString substring = mStringBuffer.mid( dollarIndex, endSentenceIndex );
98  QByteArray ba = substring.toLocal8Bit();
99  if ( substring.startsWith( "$GPGGA" ) )
100  {
101  QgsDebugMsg( substring );
102  processGGASentence( ba.data(), ba.length() );
104  QgsDebugMsg( "*******************GPS data received****************" );
105  }
106  else if ( substring.startsWith( "$GPRMC" ) )
107  {
108  QgsDebugMsg( substring );
109  processRMCSentence( ba.data(), ba.length() );
111  QgsDebugMsg( "*******************GPS data received****************" );
112  }
113  else if ( substring.startsWith( "$GPGSV" ) )
114  {
115  QgsDebugMsg( substring );
116  processGSVSentence( ba.data(), ba.length() );
118  QgsDebugMsg( "*******************GPS data received****************" );
119  }
120  else if ( substring.startsWith( "$GPVTG" ) )
121  {
122  QgsDebugMsg( substring );
123  processVTGSentence( ba.data(), ba.length() );
125  QgsDebugMsg( "*******************GPS data received****************" );
126  }
127  else if ( substring.startsWith( "$GPGSA" ) )
128  {
129  QgsDebugMsg( substring );
130  processGSASentence( ba.data(), ba.length() );
132  QgsDebugMsg( "*******************GPS data received****************" );
133  }
134  emit nmeaSentenceReceived( substring ); // added to be able to save raw data
135  }
136  }
137  mStringBuffer.remove( 0, endSentenceIndex + 2 );
138  }
139 }
140 
141 void QgsNMEAConnection::processGGASentence( const char* data, int len )
142 {
143  nmeaGPGGA result;
144  if ( nmea_parse_GPGGA( data, len, &result ) )
145  {
146  //update mLastGPSInformation
147  double longitude = result.lon;
148  if ( result.ew == 'W' )
149  {
150  longitude = -longitude;
151  }
152  double latitude = result.lat;
153  if ( result.ns == 'S' )
154  {
155  latitude = -latitude;
156  }
157 
163  }
164 }
165 
166 void QgsNMEAConnection::processRMCSentence( const char* data, int len )
167 {
168  nmeaGPRMC result;
169  if ( nmea_parse_GPRMC( data, len, &result ) )
170  {
171  double longitude = result.lon;
172  if ( result.ew == 'W' )
173  {
174  longitude = -longitude;
175  }
176  double latitude = result.lat;
177  if ( result.ns == 'S' )
178  {
179  latitude = -latitude;
180  }
185  mLastGPSInformation.status = result.status; // A,V
186 
187  //date and time
188  QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
189  QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec ); // added msec part
190  if ( date.isValid() && time.isValid() )
191  {
192  mLastGPSInformation.utcDateTime.setTimeSpec( Qt::UTC );
193  mLastGPSInformation.utcDateTime.setDate( date );
194  mLastGPSInformation.utcDateTime.setTime( time );
195  QgsDebugMsg( "utc time:" );
197  QgsDebugMsg( "local time:" );
198  QgsDebugMsg( mLastGPSInformation.utcDateTime.toLocalTime().toString() );
199  }
200  }
201 }
202 
203 void QgsNMEAConnection::processGSVSentence( const char* data, int len )
204 {
205  nmeaGPGSV result;
206  if ( nmea_parse_GPGSV( data, len, &result ) )
207  {
208  //clear satellite information when a new series of packs arrives
209  if ( result.pack_index == 1 )
210  {
212  }
213 
214  // for determining when to graph sat info
216 
217  for ( int i = 0; i < NMEA_SATINPACK; ++i )
218  {
219  nmeaSATELLITE currentSatellite = result.sat_data[i];
220  QgsSatelliteInfo satelliteInfo;
221  satelliteInfo.azimuth = currentSatellite.azimuth;
222  satelliteInfo.elevation = currentSatellite.elv;
223  satelliteInfo.id = currentSatellite.id;
224  satelliteInfo.inUse = currentSatellite.in_use; // the GSA processing below does NOT set the sats in use
225  satelliteInfo.signal = currentSatellite.sig;
226  mLastGPSInformation.satellitesInView.append( satelliteInfo );
227  }
228 
229  }
230 }
231 
232 void QgsNMEAConnection::processVTGSentence( const char* data, int len )
233 {
234  nmeaGPVTG result;
235  if ( nmea_parse_GPVTG( data, len, &result ) )
236  {
237  mLastGPSInformation.speed = result.spk;
238  }
239 }
240 
241 void QgsNMEAConnection::processGSASentence( const char* data, int len )
242 {
243  nmeaGPGSA result;
244  if ( nmea_parse_GPGSA( data, len, &result ) )
245  {
246  mLastGPSInformation.satPrn.clear();
247  mLastGPSInformation.hdop = result.HDOP;
248  mLastGPSInformation.pdop = result.PDOP;
249  mLastGPSInformation.vdop = result.VDOP;
252  for ( int i = 0; i < NMEA_MAXSAT; i++ )
253  {
254  mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
255  }
256  }
257 }