Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GSV & GSA sentences to get satellite ID and SNR information #54

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 187 additions & 60 deletions src/TinyGPS++.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <ctype.h>
#include <stdlib.h>

#define _GPRMCterm "GPRMC"
#define _GPGGAterm "GPGGA"
#define _GNRMCterm "GNRMC"
#define _GNGGAterm "GNGGA"

TinyGPSPlus::TinyGPSPlus()
: parity(0)
, isChecksumTerm(false)
, curSentenceType(GPS_SENTENCE_OTHER)
, curSentenceSystem(GPS_SYSTEM_GPS)
, curTermNumber(0)
, curTermOffset(0)
, sentenceHasFix(false)
Expand Down Expand Up @@ -82,6 +78,7 @@ bool TinyGPSPlus::encode(char c)
curTermNumber = curTermOffset = 0;
parity = 0;
curSentenceType = GPS_SENTENCE_OTHER;
curSentenceSystem = GPS_SYSTEM_GPS;
isChecksumTerm = false;
sentenceHasFix = false;
return false;
Expand Down Expand Up @@ -190,6 +187,15 @@ bool TinyGPSPlus::endOfTermHandler()
satellites.commit();
hdop.commit();
break;
case GPS_SENTENCE_GPGSV:
satellitesStats.commit();
break;
case GPS_SENTENCE_GPGSA:
if (!satellitesStats.snrDataPresent) {
satellitesStats.commit();
}
hdop.commit();
break;
}

// Commit all custom listeners of this sentence type
Expand All @@ -209,12 +215,7 @@ bool TinyGPSPlus::endOfTermHandler()
// the first term determines the sentence type
if (curTermNumber == 0)
{
if (!strcmp(term, _GPRMCterm) || !strcmp(term, _GNRMCterm))
curSentenceType = GPS_SENTENCE_GPRMC;
else if (!strcmp(term, _GPGGAterm) || !strcmp(term, _GNGGAterm))
curSentenceType = GPS_SENTENCE_GPGGA;
else
curSentenceType = GPS_SENTENCE_OTHER;
parseSentenceType(term);

// Any custom candidates of this sentence type?
for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
Expand All @@ -224,59 +225,98 @@ bool TinyGPSPlus::endOfTermHandler()
return false;
}

if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
if (curSentenceType != GPS_SENTENCE_OTHER && term[0]) {
switch(COMBINE(curSentenceType, curTermNumber))
{
case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences
case COMBINE(GPS_SENTENCE_GPGGA, 1):
time.setTime(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
sentenceHasFix = term[0] == 'A';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
case COMBINE(GPS_SENTENCE_GPGGA, 2):
location.setLatitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
case COMBINE(GPS_SENTENCE_GPGGA, 3):
location.rawNewLatData.negative = term[0] == 'S';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
case COMBINE(GPS_SENTENCE_GPGGA, 4):
location.setLongitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W
case COMBINE(GPS_SENTENCE_GPGGA, 5):
location.rawNewLngData.negative = term[0] == 'W';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
speed.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC)
course.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC)
date.setDate(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
sentenceHasFix = term[0] > '0';
break;
case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
satellites.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP
hdop.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA)
altitude.set(term);
break;
{
case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences
case COMBINE(GPS_SENTENCE_GPGGA, 1):
time.setTime(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
sentenceHasFix = term[0] == 'A';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
case COMBINE(GPS_SENTENCE_GPGGA, 2):
location.setLatitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
case COMBINE(GPS_SENTENCE_GPGGA, 3):
location.rawNewLatData.negative = term[0] == 'S';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
case COMBINE(GPS_SENTENCE_GPGGA, 4):
location.setLongitude(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W
case COMBINE(GPS_SENTENCE_GPGGA, 5):
location.rawNewLngData.negative = term[0] == 'W';
break;
case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
speed.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC)
course.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC)
date.setDate(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
sentenceHasFix = term[0] > '0';
location.newFixQuality = sentenceHasFix ? (FixQuality)(term[0] - '0') : Invalid;
break;
case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
satellites.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP
case COMBINE(GPS_SENTENCE_GPGSA, 16): // HDOP
hdop.set(term);
break;
case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA)
altitude.set(term);
break;
case COMBINE(GPS_SENTENCE_GPRMC, 12):
location.newFixMode = (FixMode)term[0];
break;
case COMBINE(GPS_SENTENCE_GPGSV, 2): // GSV message index
satellitesStats.setMessageSeqNr(term, curSentenceSystem);
break;
case COMBINE(GPS_SENTENCE_GPGSV, 4): // GSV satellite PRN number
case COMBINE(GPS_SENTENCE_GPGSV, 8):
case COMBINE(GPS_SENTENCE_GPGSV, 12):
case COMBINE(GPS_SENTENCE_GPGSV, 16):
satellitesStats.setSatId(term);
break;
case COMBINE(GPS_SENTENCE_GPGSV, 7): // GSV satellite SNR
case COMBINE(GPS_SENTENCE_GPGSV, 11):
case COMBINE(GPS_SENTENCE_GPGSV, 15):
case COMBINE(GPS_SENTENCE_GPGSV, 19):
satellitesStats.setSatSNR(term);
break;
}
// GSA messages have the items sequential, so handle them separately
if (curSentenceType == GPS_SENTENCE_GPGSA)
{
if (!satellitesStats.snrDataPresent)
{
// GSA messages may only be used when no GSV messages are being processed.
// Satellite IDs in GSA messages may be in different order compared to GSV messages.
if (curTermNumber >= 3 && curTermNumber <= 14)
{
satellitesStats.setSatId(term);
}
}
}
}

// Set custom values as needed
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
if (p->termNumber == curTermNumber)
p->set(term);
for (TinyGPSCustom *p = customCandidates;
p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber;
p = p->next)
{
if (p->termNumber == curTermNumber) {
p->set(term);
}
}

return false;
}
Expand Down Expand Up @@ -366,6 +406,27 @@ double TinyGPSLocation::lng()
return rawLngData.negative ? -ret : ret;
}

void TinyGPSSatellites::commit()
{
satsTracked = 0;
satsVisible = 0;
bestSNR = 0;
for (byte i = 0; i < _GPS_MAX_ARRAY_LENGTH; ++i) {
if (id[i] != 0) {
if (snr[i] != 0) {
++satsTracked;
if (snr[i] > bestSNR) {
bestSNR = snr[i];
}
}
++satsVisible;
}
}
pos = -1;
lastCommitTime = millis();
valid = updated = true;
}

void TinyGPSDate::commit()
{
date = newDate;
Expand All @@ -380,6 +441,40 @@ void TinyGPSTime::commit()
valid = updated = true;
}

void TinyGPSSatellites::setSatId(const char *term)
{
if (pos < _GPS_MAX_ARRAY_LENGTH) {
++pos;
uint32_t value = atol(term);
if (id[pos] != value) {
id[pos] = static_cast<byte>(value);
snr[pos] = 0;
}
}
}

void TinyGPSSatellites::setSatSNR(const char *term)
{
if (pos < _GPS_MAX_ARRAY_LENGTH) {
// Do not increase pos, GSV line has ID first and other parameters later
snr[pos] = atol(term);
snrDataPresent = true;
}
}

void TinyGPSSatellites::setMessageSeqNr(const char *term, uint8_t sentenceSystem)
{
int32_t seqNr = atol(term);
int32_t newPos = (seqNr - 1) * 4 + (sentenceSystem * _GPS_MAX_NR_ACTIVE_SATELLITES);
if (newPos >= 0 && newPos < _GPS_MAX_ARRAY_LENGTH) {
for (byte i = newPos; i < (newPos + 4) && i < _GPS_MAX_ARRAY_LENGTH; ++i) {
id[i] = 0;
snr[i] = 0;
}
pos = static_cast<int8_t>(newPos - 1); // setSatId will increment pos first.
}
}

void TinyGPSTime::setTime(const char *term)
{
newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
Expand Down Expand Up @@ -487,6 +582,38 @@ void TinyGPSCustom::set(const char *term)
strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer));
}

void TinyGPSPlus::parseSentenceType(const char *term)
{
curSentenceType = GPS_SENTENCE_OTHER;
curSentenceSystem = GPS_SYSTEM_GPS;
size_t length = strlen(term);
if (length < 5 || term[0] != 'G') {
return;
}
switch (term[1]) {
case 'L': curSentenceSystem = GPS_SYSTEM_GLONASS; break;
case 'A': curSentenceSystem = GPS_SYSTEM_GALILEO; break;
case 'B': curSentenceSystem = GPS_SYSTEM_BEIDOU; break;
}
if (strcmp(&term[2], "RMC") == 0)
{
curSentenceType = GPS_SENTENCE_GPRMC;
}
else if (strcmp(&term[2], "GGA") == 0)
{
curSentenceType = GPS_SENTENCE_GPGGA;
}
else if (strcmp(&term[2], "GSA") == 0)
{
curSentenceType = GPS_SENTENCE_GPGSA;
}
else if (strcmp(&term[2], "GSV") == 0)
{
curSentenceType = GPS_SENTENCE_GPGSV;
}
}


void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
{
TinyGPSCustom **ppelt;
Expand Down
Loading