QGIS API Documentation  master-3f58142
src/core/gps/qgsnmeaconnection.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsnmeaconnection.cpp  -  description
00003                           ---------------------
00004     begin                : November 30th, 2009
00005     copyright            : (C) 2009 by Marco Hugentobler
00006     email                : marco at hugis dot net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgsnmeaconnection.h"
00019 #include "qextserialport.h"
00020 #include "qgslogger.h"
00021 
00022 #include <QIODevice>
00023 #include <QApplication>
00024 #include <QStringList>
00025 
00026 
00027 //from libnmea
00028 #include "parse.h"
00029 #include "gmath.h"
00030 #include "info.h"
00031 
00032 #define KNOTS_TO_KMH 1.852
00033 
00034 QgsNMEAConnection::QgsNMEAConnection( QIODevice* dev ): QgsGPSConnection( dev )
00035 {
00036 }
00037 
00038 QgsNMEAConnection::~QgsNMEAConnection()
00039 {
00040   //connection will be closed by base class
00041 }
00042 
00043 void QgsNMEAConnection::parseData()
00044 {
00045   if ( !mSource )
00046   {
00047     return;
00048   }
00049 
00050   //print out the data as a test
00051   qint64 numBytes = 0;
00052   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 ?
00053   {
00054     numBytes = mSource->size();
00055   }
00056   else
00057   {
00058     numBytes = mSource->bytesAvailable();
00059   }
00060 
00061   QgsDebugMsg( "numBytes:" + QString::number( numBytes ) );
00062 
00063   if ( numBytes >= 6 )
00064   {
00065     if ( mStatus != GPSDataReceived )
00066     {
00067       mStatus = DataReceived;
00068     }
00069 
00070     //append new data to the remaining results from last parseData() call
00071     mStringBuffer.append( mSource->read( numBytes ) );
00072     processStringBuffer();
00073     emit stateChanged( mLastGPSInformation );
00074   }
00075 }
00076 
00077 void QgsNMEAConnection::processStringBuffer()
00078 {
00079   int endSentenceIndex = 0;
00080   int dollarIndex;
00081 
00082   while (( endSentenceIndex = mStringBuffer.indexOf( "\r\n" ) ) && endSentenceIndex != -1 )
00083   {
00084     endSentenceIndex = mStringBuffer.indexOf( "\r\n" );
00085 
00086     dollarIndex = mStringBuffer.indexOf( "$" );
00087     if ( endSentenceIndex == -1 )
00088     {
00089       break;
00090     }
00091 
00092 
00093     if ( endSentenceIndex >= dollarIndex )
00094     {
00095       if ( dollarIndex != -1 )
00096       {
00097         QString substring = mStringBuffer.mid( dollarIndex, endSentenceIndex );
00098         QByteArray ba = substring.toLocal8Bit();
00099         if ( substring.startsWith( "$GPGGA" ) )
00100         {
00101           QgsDebugMsg( substring );
00102           processGGASentence( ba.data(), ba.length() );
00103           mStatus = GPSDataReceived;
00104           QgsDebugMsg( "*******************GPS data received****************" );
00105         }
00106         else if ( substring.startsWith( "$GPRMC" ) )
00107         {
00108           QgsDebugMsg( substring );
00109           processRMCSentence( ba.data(), ba.length() );
00110           mStatus = GPSDataReceived;
00111           QgsDebugMsg( "*******************GPS data received****************" );
00112         }
00113         else if ( substring.startsWith( "$GPGSV" ) )
00114         {
00115           QgsDebugMsg( substring );
00116           processGSVSentence( ba.data(), ba.length() );
00117           mStatus = GPSDataReceived;
00118           QgsDebugMsg( "*******************GPS data received****************" );
00119         }
00120         else if ( substring.startsWith( "$GPVTG" ) )
00121         {
00122           QgsDebugMsg( substring );
00123           processVTGSentence( ba.data(), ba.length() );
00124           mStatus = GPSDataReceived;
00125           QgsDebugMsg( "*******************GPS data received****************" );
00126         }
00127         else if ( substring.startsWith( "$GPGSA" ) )
00128         {
00129           QgsDebugMsg( substring );
00130           processGSASentence( ba.data(), ba.length() );
00131           mStatus = GPSDataReceived;
00132           QgsDebugMsg( "*******************GPS data received****************" );
00133         }
00134         emit nmeaSentenceReceived( substring );  // added to be able to save raw data
00135       }
00136     }
00137     mStringBuffer.remove( 0, endSentenceIndex + 2 );
00138   }
00139 }
00140 
00141 void QgsNMEAConnection::processGGASentence( const char* data, int len )
00142 {
00143   nmeaGPGGA result;
00144   if ( nmea_parse_GPGGA( data, len, &result ) )
00145   {
00146     //update mLastGPSInformation
00147     double longitude = result.lon;
00148     if ( result.ew == 'W' )
00149     {
00150       longitude = -longitude;
00151     }
00152     double latitude = result.lat;
00153     if ( result.ns == 'S' )
00154     {
00155       latitude = -latitude;
00156     }
00157 
00158     mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
00159     mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
00160     mLastGPSInformation.elevation = result.elv;
00161     mLastGPSInformation.quality = result.sig;
00162     mLastGPSInformation.satellitesUsed = result.satinuse;
00163   }
00164 }
00165 
00166 void QgsNMEAConnection::processRMCSentence( const char* data, int len )
00167 {
00168   nmeaGPRMC result;
00169   if ( nmea_parse_GPRMC( data, len, &result ) )
00170   {
00171     double longitude = result.lon;
00172     if ( result.ew == 'W' )
00173     {
00174       longitude = -longitude;
00175     }
00176     double latitude = result.lat;
00177     if ( result.ns == 'S' )
00178     {
00179       latitude = -latitude;
00180     }
00181     mLastGPSInformation.longitude = nmea_ndeg2degree( longitude );
00182     mLastGPSInformation.latitude = nmea_ndeg2degree( latitude );
00183     mLastGPSInformation.speed = KNOTS_TO_KMH * result.speed;
00184     mLastGPSInformation.direction = result.direction;
00185     mLastGPSInformation.status = result.status;  // A,V
00186 
00187     //date and time
00188     QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
00189     QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec ); // added msec part
00190     if ( date.isValid() && time.isValid() )
00191     {
00192       mLastGPSInformation.utcDateTime.setTimeSpec( Qt::UTC );
00193       mLastGPSInformation.utcDateTime.setDate( date );
00194       mLastGPSInformation.utcDateTime.setTime( time );
00195       QgsDebugMsg( "utc time:" );
00196       QgsDebugMsg( mLastGPSInformation.utcDateTime.toString() );
00197       QgsDebugMsg( "local time:" );
00198       QgsDebugMsg( mLastGPSInformation.utcDateTime.toLocalTime().toString() );
00199     }
00200   }
00201 }
00202 
00203 void QgsNMEAConnection::processGSVSentence( const char* data, int len )
00204 {
00205   nmeaGPGSV result;
00206   if ( nmea_parse_GPGSV( data, len, &result ) )
00207   {
00208     //clear satellite informations when a new series of packs arrives
00209     if ( result.pack_index == 1 )
00210     {
00211       mLastGPSInformation.satellitesInView.clear();
00212     }
00213 
00214     // for determining when to graph sat info
00215     mLastGPSInformation.satInfoComplete = ( result.pack_index == result.pack_count );
00216 
00217     for ( int i = 0; i < NMEA_SATINPACK; ++i )
00218     {
00219       nmeaSATELLITE currentSatellite = result.sat_data[i];
00220       QgsSatelliteInfo satelliteInfo;
00221       satelliteInfo.azimuth = currentSatellite.azimuth;
00222       satelliteInfo.elevation = currentSatellite.elv;
00223       satelliteInfo.id = currentSatellite.id;
00224       satelliteInfo.inUse = currentSatellite.in_use; // the GSA processing below does NOT set the sats in use
00225       satelliteInfo.signal = currentSatellite.sig;
00226       mLastGPSInformation.satellitesInView.append( satelliteInfo );
00227     }
00228 
00229   }
00230 }
00231 
00232 void QgsNMEAConnection::processVTGSentence( const char* data, int len )
00233 {
00234   nmeaGPVTG result;
00235   if ( nmea_parse_GPVTG( data, len, &result ) )
00236   {
00237     mLastGPSInformation.speed = result.spk;
00238   }
00239 }
00240 
00241 void QgsNMEAConnection::processGSASentence( const char* data, int len )
00242 {
00243   nmeaGPGSA result;
00244   if ( nmea_parse_GPGSA( data, len, &result ) )
00245   {
00246     mLastGPSInformation.satPrn.clear();
00247     mLastGPSInformation.hdop = result.HDOP;
00248     mLastGPSInformation.pdop = result.PDOP;
00249     mLastGPSInformation.vdop = result.VDOP;
00250     mLastGPSInformation.fixMode = result.fix_mode;
00251     mLastGPSInformation.fixType = result.fix_type;
00252     for ( int i = 0; i < NMEA_MAXSAT; i++ )
00253     {
00254       mLastGPSInformation.satPrn.append( result.sat_prn[ i ] );
00255     }
00256   }
00257 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines