23#include <QApplication>
25#include <QRegularExpression>
29#include "moc_qgsnmeaconnection.cpp"
31using namespace Qt::StringLiterals;
41#define KNOTS_TO_KMH 1.852
62 numBytes =
mSource->bytesAvailable();
92 int endSentenceIndex = 0;
95 while ( ( endSentenceIndex =
mStringBuffer.indexOf(
"\r\n"_L1 ) ) && endSentenceIndex != -1 )
100 if ( endSentenceIndex == -1 )
105 if ( endSentenceIndex >= dollarIndex )
107 if ( dollarIndex != -1 )
109 const QString substring =
mStringBuffer.mid( dollarIndex, endSentenceIndex );
110 QByteArray ba = substring.toLocal8Bit();
111 const thread_local QRegularExpression rxSentence( u
"^\\$([A-Z]{2})([A-Z]{3})"_s );
112 const QRegularExpressionMatch sentenceMatch = rxSentence.match( substring );
113 const QString sentenceId = sentenceMatch.captured( 2 );
114 if ( sentenceId ==
"GGA"_L1 )
120 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
122 else if ( sentenceId ==
"RMC"_L1 )
128 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
130 else if ( sentenceId ==
"GSV"_L1 )
136 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
138 else if ( sentenceId ==
"VTG"_L1 )
144 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
146 else if ( sentenceId ==
"GSA"_L1 )
151 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
153 else if ( sentenceId ==
"GST"_L1 )
159 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
161 else if ( sentenceId ==
"HDT"_L1 )
167 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
169 else if ( sentenceId ==
"HDG"_L1 )
175 QgsDebugMsgLevel( u
"*******************GPS data received****************"_s, 2 );
197 if ( nmea_parse_GPGGA( data, len, &result ) )
200 double longitude = result.lon;
201 if ( result.ew ==
'W' )
203 longitude = -longitude;
205 double latitude = result.lat;
206 if ( result.ns ==
'S' )
208 latitude = -latitude;
216 const QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec );
217 if ( time.isValid() )
230 if ( result.sig >= 0 && result.sig <= 8 )
246 if ( nmea_parse_GPGST( data, len, &result ) )
249 const double sig_lat = result.sig_lat;
250 const double sig_lon = result.sig_lon;
251 const double sig_alt = result.sig_alt;
258 mLastGPSInformation.hvacc = sqrt( ( pow( sig_lat, 2 ) + pow( sig_lon, 2 ) + pow( sig_alt, 2 ) ) / 3.0 );
265 if ( nmea_parse_GPHDT( data, len, &result ) )
274 if ( nmea_parse_HCHDG( data, len, &result ) )
277 if ( result.ew_variation ==
'E' )
287 if ( nmea_parse_GPRMC( data, len, &result ) )
289 double longitude = result.lon;
290 if ( result.ew ==
'W' )
292 longitude = -longitude;
294 double latitude = result.lat;
295 if ( result.ns ==
'S' )
297 latitude = -latitude;
302 if ( !std::isnan( result.direction ) )
306 const QDate date( result.utc.year + 1900, result.utc.mon + 1, result.utc.day );
307 const QTime time( result.utc.hour, result.utc.min, result.utc.sec, result.utc.msec );
308 if ( date.isValid() && time.isValid() )
323 if ( result.status ==
'A' || result.status ==
'D' )
325 if ( result.mode ==
'A' )
330 else if ( result.mode ==
'D' )
335 else if ( result.mode ==
'P' )
340 else if ( result.mode ==
'R' )
345 else if ( result.mode ==
'F' )
350 else if ( result.mode ==
'E' )
355 else if ( result.mode ==
'M' )
360 else if ( result.mode ==
'S' )
371 else if ( result.status ==
'V' )
379 if ( result.navstatus ==
'S' )
383 else if ( result.navstatus ==
'C' )
387 else if ( result.navstatus ==
'U' )
400 if ( nmea_parse_GPGSV( data, len, &result ) )
403 for (
int i = 0; i < NMEA_SATINPACK; ++i )
405 const nmeaSATELLITE currentSatellite = result.sat_data[i];
407 satelliteInfo.
azimuth = currentSatellite.azimuth;
408 satelliteInfo.
elevation = currentSatellite.elv;
409 satelliteInfo.
id = currentSatellite.id;
410 satelliteInfo.
inUse =
false;
415 satelliteInfo.
inUse =
true;
418 satelliteInfo.
signal = currentSatellite.sig;
419 satelliteInfo.
satType = result.talkerId[1];
421 if ( result.talkerId[0] ==
'G' )
423 if ( result.talkerId[1] ==
'P' )
427 else if ( result.talkerId[1] ==
'L' )
431 else if ( result.talkerId[1] ==
'A' )
435 else if ( result.talkerId[1] ==
'B' )
439 else if ( result.talkerId[1] ==
'Q' )
445 if ( satelliteInfo.
satType ==
'P' && satelliteInfo.
id > 32 )
449 satelliteInfo.
id = currentSatellite.id + 87;
452 bool idAlreadyPresent =
false;
458 if ( existingSatInView.
id == currentSatellite.id )
460 idAlreadyPresent =
true;
462 if ( existingSatInView.
signal == 0 )
464 existingSatInView.
signal = currentSatellite.sig;
466 else if ( currentSatellite.sig != 0 )
468 existingSatInView.
signal = ( existingSatInView.
signal + currentSatellite.sig ) / 2;
475 if ( !idAlreadyPresent && currentSatellite.azimuth > 0 && currentSatellite.elv > 0 )
486 if ( nmea_parse_GPVTG( data, len, &result ) )
489 if ( !std::isnan( result.dir ) )
505 if ( nmea_parse_GPGSA( data, len, &result ) )
515 bool mixedConstellation =
false;
516 for (
int i = 0; i < NMEA_MAXSAT; i++ )
518 if ( result.sat_prn[i] > 0 )
524 if ( ( result.talkerId[0] ==
'G' && result.talkerId[1] ==
'L' ) || result.sat_prn[i] > 64 )
526 else if ( result.sat_prn[i] >= 1 && result.sat_prn[i] <= 32 )
528 else if ( result.sat_prn[i] > 32 && result.sat_prn[i] <= 64 )
532 if ( result.sat_prn[i] > 0 )
536 mixedConstellation =
true;
540 commonConstellation = constellation;
545 if ( mixedConstellation )
548 switch ( result.fix_type )
GnssConstellation
GNSS constellation.
@ Gps
Global Positioning System (GPS).
@ Glonass
Global Navigation Satellite System (GLONASS).
@ Unknown
Unknown/other system.
@ Qzss
Quasi Zenith Satellite System (QZSS).
GpsQualityIndicator
GPS signal quality indicator.
@ RTK
Real-time-kynematic.
@ Simulation
Simulation mode.
@ FloatRTK
Float real-time-kynematic.
@ Manual
Manual input mode.
@ NotValid
Navigation status not valid.
QgsGpsInformation mLastGPSInformation
Last state of the gps related variables (e.g. position, time, ...).
void nmeaSentenceReceived(const QString &substring)
Emitted whenever the GPS device receives a raw NMEA sentence.
std::unique_ptr< QIODevice > mSource
Data source (e.g. serial device, socket, file,...).
QgsGpsConnection(QIODevice *dev)
Constructor.
Status mStatus
Connection status.
void stateChanged(const QgsGpsInformation &info)
Emitted whenever the GPS state is changed.
void processVtgSentence(const char *data, int len)
process VTG sentence
void processRmcSentence(const char *data, int len)
process RMC sentence
void parseData() override
Parse available data source content.
void processHchdgSentence(const char *data, int len)
process HCHDG sentence
void processGgaSentence(const char *data, int len)
process GGA sentence
void processGsvSentence(const char *data, int len)
process GSV sentence
void processGstSentence(const char *data, int len)
process GST sentence
void processHdtSentence(const char *data, int len)
process HDT sentence
void processGsaSentence(const char *data, int len)
process GSA sentence
QString mStringBuffer
Store data from the device before it is processed.
QgsNmeaConnection(QIODevice *device)
Constructs a QgsNmeaConnection with given device.
void processStringBuffer()
Splits mStringBuffer into sentences and calls libnmea.
Encapsulates information relating to a GPS satellite.
double elevation
Elevation of the satellite, in degrees.
bool inUse
true if satellite was used in obtaining the position fix.
int signal
Signal strength (0-99dB), or -1 if not available.
int id
Contains the satellite identifier number.
double azimuth
The azimuth of the satellite to true north, in degrees.
QChar satType
satType value from NMEA message $GxGSV, where x: P = GPS; S = SBAS (GPSid> 32 then SBasid = GPSid + 8...
#define QgsDebugMsgLevel(str, level)