Skip to content

Commit f10be97

Browse files
committed
(1) New High Precision parseDegrees() supports high-end Leica receivers with sub-centimeter accuracy, (2) Integral lat and long changed to degrees + billionths, (3) Allow time and date to be extracted from GPGGA and GPRMC even without fix. (4) Clean up spurious comments, (5) Library version now a string (0.92), (6) Improved KitchenSink sample, (7) Rewrote examples to support slightly changed API.
1 parent 803d68e commit f10be97

7 files changed

Lines changed: 1716 additions & 93 deletions

File tree

TinyGPS++.cpp

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ TinyGPSPlus::TinyGPSPlus()
3636
, curSentenceType(GPS_SENTENCE_OTHER)
3737
, curTermNumber(0)
3838
, curTermOffset(0)
39-
, gpsDataGood(false)
39+
, sentenceHasFix(false)
4040
, customElts(0)
4141
, customCandidates(0)
4242
, encodedCharCount(0)
43-
, goodSentenceCount(0)
43+
, sentencesWithFixCount(0)
4444
, failedChecksumCount(0)
4545
, passedChecksumCount(0)
4646
{
@@ -81,7 +81,7 @@ bool TinyGPSPlus::encode(char c)
8181
parity = 0;
8282
curSentenceType = GPS_SENTENCE_OTHER;
8383
isChecksumTerm = false;
84-
gpsDataGood = false;
84+
sentenceHasFix = false;
8585
return false;
8686

8787
default: // ordinary characters
@@ -127,21 +127,26 @@ int32_t TinyGPSPlus::parseDecimal(const char *term)
127127

128128
// static
129129
// Parse degrees in that funny NMEA format DDMM.MMMM
130-
uint32_t TinyGPSPlus::parseDegrees(const char *term)
130+
void TinyGPSPlus::parseDegrees(const char *term, int16_t &degrees, uint32_t &billionths)
131131
{
132-
unsigned long leftOfDecimal = atol(term);
133-
unsigned long _100000thsOfMinute = (leftOfDecimal % 100UL) * 100000UL;
134-
while (isdigit(*term)) ++term;
132+
uint32_t leftOfDecimal = (uint32_t)atol(term);
133+
uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
134+
uint32_t multiplier = 10000000UL;
135+
uint32_t tenMillionthsOfMinutes = minutes * multiplier;
136+
137+
degrees = (int16_t)(leftOfDecimal / 100);
138+
139+
while (isdigit(*term))
140+
++term;
141+
135142
if (*term == '.')
136-
{
137-
unsigned long mult = 10000;
138143
while (isdigit(*++term))
139144
{
140-
_100000thsOfMinute += mult * (*term - '0');
141-
mult /= 10;
145+
multiplier /= 10;
146+
tenMillionthsOfMinutes += (*term - '0') * multiplier;
142147
}
143-
}
144-
return (leftOfDecimal / 100) * 1000000 + (_100000thsOfMinute + 3) / 6;
148+
149+
billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
145150
}
146151

147152
#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
@@ -150,34 +155,38 @@ uint32_t TinyGPSPlus::parseDegrees(const char *term)
150155
// Returns true if new sentence has just passed checksum test and is validated
151156
bool TinyGPSPlus::endOfTermHandler()
152157
{
153-
// If it's the checksum term, and the checksum checks out and it's got "good" data, then commit it
158+
// If it's the checksum term, and the checksum checks out, commit
154159
if (isChecksumTerm)
155160
{
156161
byte checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
157162
if (checksum == parity)
158163
{
159164
passedChecksumCount++;
160-
if (gpsDataGood)
161-
{
162-
++goodSentenceCount;
165+
if (sentenceHasFix)
166+
++sentencesWithFixCount;
163167

164-
switch(curSentenceType)
168+
switch(curSentenceType)
169+
{
170+
case GPS_SENTENCE_GPRMC:
171+
date.commit();
172+
time.commit();
173+
if (sentenceHasFix)
165174
{
166-
case GPS_SENTENCE_GPRMC:
167-
date.commit();
168-
time.commit();
169175
location.commit();
170176
speed.commit();
171177
course.commit();
172-
break;
173-
case GPS_SENTENCE_GPGGA:
174-
time.commit();
175-
location.commit();
176-
altitude.commit();
177-
satellites.commit();
178-
hdop.commit();
179-
break;
180178
}
179+
break;
180+
case GPS_SENTENCE_GPGGA:
181+
time.commit();
182+
if (sentenceHasFix)
183+
{
184+
location.commit();
185+
altitude.commit();
186+
}
187+
satellites.commit();
188+
hdop.commit();
189+
break;
181190
}
182191

183192
// Commit all custom listeners of this sentence type
@@ -220,7 +229,7 @@ bool TinyGPSPlus::endOfTermHandler()
220229
time.setTime(term);
221230
break;
222231
case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity
223-
gpsDataGood = term[0] == 'A';
232+
sentenceHasFix = term[0] == 'A';
224233
break;
225234
case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude
226235
case COMBINE(GPS_SENTENCE_GPGGA, 2):
@@ -229,7 +238,7 @@ bool TinyGPSPlus::endOfTermHandler()
229238
case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S
230239
case COMBINE(GPS_SENTENCE_GPGGA, 3):
231240
if (term[0] == 'S')
232-
location.newlat = -location.newlat;
241+
location.iNewLatDegrees = -location.iNewLatDegrees;
233242
break;
234243
case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude
235244
case COMBINE(GPS_SENTENCE_GPGGA, 4):
@@ -238,7 +247,7 @@ bool TinyGPSPlus::endOfTermHandler()
238247
case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W
239248
case COMBINE(GPS_SENTENCE_GPGGA, 5):
240249
if (term[0] == 'W')
241-
location.newlng = -location.newlng;
250+
location.iNewLngDegrees = -location.iNewLngDegrees;
242251
break;
243252
case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
244253
speed.set(term);
@@ -250,7 +259,7 @@ bool TinyGPSPlus::endOfTermHandler()
250259
date.setDate(term);
251260
break;
252261
case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
253-
gpsDataGood = term[0] > '0';
262+
sentenceHasFix = term[0] > '0';
254263
break;
255264
case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
256265
satellites.set(term);
@@ -320,39 +329,44 @@ double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long
320329
const char *TinyGPSPlus::cardinal(double course)
321330
{
322331
static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
323-
324332
int direction = (int)((course + 11.25f) / 22.5f);
325333
return directions[direction % 16];
326334
}
327335

328336
void TinyGPSLocation::commit()
329337
{
330-
ilat = newlat;
331-
ilng = newlng;
338+
iLatDegrees = iNewLatDegrees;
339+
uLatBillionths = uNewLatBillionths;
340+
iLngDegrees = iNewLngDegrees;
341+
uLngBillionths = uNewLngBillionths;
332342
lastCommitTime = millis();
333343
valid = updated = true;
334344
}
335345

336346
void TinyGPSLocation::setLatitude(const char *term)
337347
{
338-
newlat = TinyGPSPlus::parseDegrees(term);
348+
TinyGPSPlus::parseDegrees(term, iNewLatDegrees, uNewLatBillionths);
339349
}
340350

341351
void TinyGPSLocation::setLongitude(const char *term)
342352
{
343-
newlng = TinyGPSPlus::parseDegrees(term);
353+
TinyGPSPlus::parseDegrees(term, iNewLngDegrees, uNewLngBillionths);
344354
}
345355

346356
double TinyGPSLocation::lat()
347357
{
348358
updated = false;
349-
return ilat / 1000000.0;
359+
return iLatDegrees > 0 ?
360+
(iLatDegrees + uLatBillionths / 1000000000.0) :
361+
(iLatDegrees - uLatBillionths / 1000000000.0);
350362
}
351363

352364
double TinyGPSLocation::lng()
353365
{
354366
updated = false;
355-
return ilng / 1000000.0;
367+
return iLngDegrees > 0 ?
368+
(iLngDegrees + uLngBillionths / 1000000000.0) :
369+
(iLngDegrees - uLngBillionths / 1000000000.0);
356370
}
357371

358372
void TinyGPSDate::commit()

TinyGPS++.h

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3131
#endif
3232
#include <limits.h>
3333

34-
#define _GPS_VERSION 1 // software version of this library
34+
#define _GPS_VERSION "0.92" // software version of this library
3535
#define _GPS_MPH_PER_KNOT 1.15077945
3636
#define _GPS_MPS_PER_KNOT 0.51444444
3737
#define _GPS_KMPH_PER_KNOT 1.852
3838
#define _GPS_MILES_PER_METER 0.00062137112
3939
#define _GPS_KM_PER_METER 0.001
4040
#define _GPS_FEET_PER_METER 3.2808399
4141
#define _GPS_MAX_FIELD_SIZE 15
42-
/*
43-
Field Type Format Source Notes
44-
----- ---- ------ ------ -----
45-
Time u32 hhmmsscc GPRMC.1 OR GPGGA.1 Decimal
46-
RmcValid bool isvalid GPRMC.2 =='A'
47-
Latitude: i32 dmill GPRMC.3/4 OR GPGGA 2/3 Degrees (N/S)
48-
Longitude i32 dmill GPRMC.5/6 or GPGGA.4/5 Degrees (E/W)
49-
Speed u32 kn100 GPRMC.7 Decimal
50-
Course u32 deg100 GPRMC.8 Decimal
51-
Date u32 ddmmyy GPRMC.9
52-
FixValid bool isgood GPGGA.6 > '0'
53-
Satellites u8 sats GPGGA.7 Decimal
54-
HDOP u32 hdop100 GPGGA.8 Decimal
55-
Altitude i32 cm GPGGA.9 Decimal
56-
*/
5742

5843
struct TinyGPSLocation
5944
{
@@ -63,17 +48,21 @@ struct TinyGPSLocation
6348
bool isUpdated() const { return updated; }
6449
uint32_t age() const { return valid ? millis() - lastCommitTime : (uint32_t)ULONG_MAX; }
6550

66-
int32_t rawLat() { updated = false; return ilat; }
67-
int32_t rawLng() { updated = false; return ilng; }
68-
double lat();
69-
double lng();
51+
int16_t rawLatDegrees() { updated = false; return iLatDegrees; }
52+
int16_t rawLngDegrees() { updated = false; return iLngDegrees; }
53+
uint32_t rawLatBillionths() { updated = false; return uLatBillionths; }
54+
uint32_t rawLngBillionths() { updated = false; return uLngBillionths; }
55+
double lat();
56+
double lng();
7057

71-
TinyGPSLocation() : valid(false), updated(false), ilat(0), ilng(0)
58+
TinyGPSLocation() : valid(false), updated(false),
59+
iLatDegrees(0), iLngDegrees(0), uLatBillionths(0), uLngBillionths(0)
7260
{}
7361

7462
private:
7563
bool valid, updated;
76-
int32_t ilat, newlat, ilng, newlng;
64+
int16_t iLatDegrees, iNewLatDegrees, iLngDegrees, iNewLngDegrees;
65+
uint32_t uLatBillionths, uNewLatBillionths, uLngBillionths, uNewLngBillionths;
7766
uint32_t lastCommitTime;
7867
void commit();
7968
void setLatitude(const char *term);
@@ -233,19 +222,19 @@ class TinyGPSPlus
233222
TinyGPSInteger satellites;
234223
TinyGPSDecimal hdop;
235224

236-
static int libraryVersion() { return _GPS_VERSION; }
225+
static const char *libraryVersion() { return _GPS_VERSION; }
237226

238227
static double distanceBetween(double lat1, double long1, double lat2, double long2);
239228
static double courseTo(double lat1, double long1, double lat2, double long2);
240229
static const char *cardinal(double course);
241230

242231
static int32_t parseDecimal(const char *term);
243-
static uint32_t parseDegrees(const char *term);
232+
static void parseDegrees(const char *term, int16_t &degrees, uint32_t &billionths);
244233

245-
uint32_t charsProcessed() const { return encodedCharCount; }
246-
uint32_t goodSentences() const { return goodSentenceCount; }
247-
uint32_t failedChecksum() const { return failedChecksumCount; }
248-
uint32_t passedChecksum() const { return passedChecksumCount; }
234+
uint32_t charsProcessed() const { return encodedCharCount; }
235+
uint32_t sentencesWithFix() const { return sentencesWithFixCount; }
236+
uint32_t failedChecksum() const { return failedChecksumCount; }
237+
uint32_t passedChecksum() const { return passedChecksumCount; }
249238

250239
private:
251240
enum {GPS_SENTENCE_GPGGA, GPS_SENTENCE_GPRMC, GPS_SENTENCE_OTHER};
@@ -257,7 +246,7 @@ class TinyGPSPlus
257246
uint8_t curSentenceType;
258247
uint8_t curTermNumber;
259248
uint8_t curTermOffset;
260-
bool gpsDataGood;
249+
bool sentenceHasFix;
261250

262251
// custom element support
263252
friend class TinyGPSCustom;
@@ -267,7 +256,7 @@ class TinyGPSPlus
267256

268257
// statistics
269258
uint32_t encodedCharCount;
270-
uint32_t goodSentenceCount;
259+
uint32_t sentencesWithFixCount;
271260
uint32_t failedChecksumCount;
272261
uint32_t passedChecksumCount;
273262

examples/FullExample/FullExample.ino

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void loop()
6666
printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);
6767

6868
printInt(gps.charsProcessed(), true, 6);
69-
printInt(gps.goodSentences(), true, 10);
69+
printInt(gps.sentencesWithFix(), true, 10);
7070
printInt(gps.failedChecksum(), true, 9);
7171
Serial.println();
7272

@@ -156,4 +156,4 @@ static void printStr(const char *str, int len)
156156
for (int i=0; i<len; ++i)
157157
Serial.print(i<slen ? str[i] : ' ');
158158
smartDelay(0);
159-
}
159+
}

examples/KitchenSink/KitchenSink.ino

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ void loop()
4040
Serial.print(F("LOCATION Fix Age="));
4141
Serial.print(gps.location.age());
4242
Serial.print(F("ms Raw Lat="));
43-
Serial.print(gps.location.rawLat());
44-
Serial.print(F(" Raw Long="));
45-
Serial.print(gps.location.rawLng());
46-
Serial.print(F(" Lat="));
43+
Serial.print(gps.location.rawLatDegrees());
44+
Serial.print(" and ");
45+
Serial.print(gps.location.rawLatBillionths());
46+
Serial.print(F(" billionths, Raw Long="));
47+
Serial.print(gps.location.rawLngDegrees());
48+
Serial.print(".");
49+
Serial.print(gps.location.rawLngBillionths());
50+
Serial.print(F(" billionths, Lat="));
4751
Serial.print(gps.location.lat(), 6);
4852
Serial.print(F(" Long="));
4953
Serial.println(gps.location.lng(), 6);
@@ -167,8 +171,8 @@ void loop()
167171

168172
Serial.print(F("DIAGS Chars="));
169173
Serial.print(gps.charsProcessed());
170-
Serial.print(F(" Good-sentences="));
171-
Serial.print(gps.goodSentences());
174+
Serial.print(F(" Sentences-with-Fix="));
175+
Serial.print(gps.sentencesWithFix());
172176
Serial.print(F(" Failed-checksum="));
173177
Serial.print(gps.failedChecksum());
174178
Serial.print(F(" Passed-checksum="));

0 commit comments

Comments
 (0)