Hats off to mikalhart for all of the contributions. TinyGPS is definitely a good one.
I wanted to add some other fixes to TinyGPS. Currently, TinyGPS makes the assumption that only GPGGA and GPRMC are the only “good” sentences, and data will only be available if those sentences have been parsed within the object as providing active data. I’ve changed it so that data can be retrieved before a fix has been made.
GPGSA, and GPGSV sentences provide a lot of information before a fix has been made. I’ve added a couple of quick pieces of data (satsinview, and satsused) to let you know if you are getting data from satellites before a fix can be made.
Here are the patches:
TinyGPS.h
--- TinyGPS9-orig\TinyGPS.h Thu Apr 02 23:09:36 2009
+++ TinyGPS\TinyGPS.h Wed Jun 17 15:01:36 2009
@@ -65,6 +65,15 @@
// speed in last full GPRMC sentence in 100ths of a knot
unsigned long speed() { return _speed; }
+ // number of satellites in view (GPGSV sentence)
+ unsigned char satsinview() { return _satsinview; }
+
+ // number of satellites used for fix (GPGSA sentence)
+ unsigned char satsused() { return _satsused; }
+
+ // get the fix type
+ unsigned char fixtype() { return _fixtype; }
+
#ifndef _GPS_NO_STATS
void stats(unsigned long *chars, unsigned short *good_sentences, unsigned short *failed_cs);
#endif
@@ -106,9 +115,11 @@
enum {GPS_INVALID_AGE = 0xFFFFFFFF, GPS_INVALID_ANGLE = 999999999, GPS_INVALID_ALTITUDE = 999999999, GPS_INVALID_DATE = 0,
GPS_INVALID_TIME = 0xFFFFFFFF, GPS_INVALID_SPEED = 999999999, GPS_INVALID_FIX_TIME = 0xFFFFFFFF};
+
+ enum {GPS_FIX_NO_FIX = 1, GPS_FIX_2D = 2, GPS_FIX_3D = 3};
private:
- enum {_GPS_SENTENCE_GPGGA, _GPS_SENTENCE_GPRMC, _GPS_SENTENCE_OTHER};
+ enum {_GPS_SENTENCE_GPGGA, _GPS_SENTENCE_GPRMC, _GPS_SENTENCE_GPGSV, _GPS_SENTENCE_GPGSA, _GPS_SENTENCE_OTHER};
// properties
unsigned long _time, _new_time;
@@ -118,6 +129,9 @@
long _altitude, _new_altitude;
unsigned long _speed, _new_speed;
unsigned long _course, _new_course;
+ unsigned char _satsinview, _new_satsinview;
+ unsigned char _satsused, _new_satsused;
+ unsigned char _fixtype, _new_fixtype;
unsigned long _last_time_fix, _new_time_fix;
unsigned long _last_position_fix, _new_position_fix;
@@ -129,7 +143,6 @@
byte _sentence_type;
byte _term_number;
byte _term_offset;
- bool _gps_data_good;
#ifndef _GPS_NO_STATS
// statistics
TinyGPS.cpp
--- TinyGPS9-orig\TinyGPS.cpp Tue Mar 03 22:39:58 2009
+++ TinyGPS\TinyGPS.cpp Wed Jun 17 15:06:40 2009
@@ -23,6 +23,8 @@
#define _GPRMC_TERM "GPRMC"
#define _GPGGA_TERM "GPGGA"
+#define _GPGSV_TERM "GPGSV"
+#define _GPGSA_TERM "GPGSA"
TinyGPS::TinyGPS()
: _time(GPS_INVALID_TIME)
@@ -32,6 +34,9 @@
, _altitude(GPS_INVALID_ALTITUDE)
, _speed(GPS_INVALID_SPEED)
, _course(GPS_INVALID_ANGLE)
+, _satsinview(0)
+, _satsused(0)
+, _fixtype(GPS_FIX_NO_FIX)
, _last_time_fix(GPS_INVALID_FIX_TIME)
, _last_position_fix(GPS_INVALID_FIX_TIME)
, _parity(0)
@@ -39,7 +44,6 @@
, _sentence_type(_GPS_SENTENCE_OTHER)
, _term_number(0)
, _term_offset(0)
-, _gps_data_good(false)
#ifndef _GPS_NO_STATS
, _encoded_characters(0)
, _good_sentences(0)
@@ -80,7 +84,6 @@
_parity = 0;
_sentence_type = _GPS_SENTENCE_OTHER;
_is_checksum_term = false;
- _gps_data_good = false;
return valid_sentence;
}
@@ -161,31 +164,35 @@
byte checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]);
if (checksum == _parity)
{
- if (_gps_data_good)
- {
#ifndef _GPS_NO_STATS
- ++_good_sentences;
+ ++_good_sentences;
#endif
- _last_time_fix = _new_time_fix;
- _last_position_fix = _new_position_fix;
+ _last_time_fix = _new_time_fix;
+ _last_position_fix = _new_position_fix;
- switch(_sentence_type)
- {
- case _GPS_SENTENCE_GPRMC:
- _time = _new_time;
- _date = _new_date;
- _latitude = _new_latitude;
- _longitude = _new_longitude;
- _speed = _new_speed;
- _course = _new_course;
- break;
- case _GPS_SENTENCE_GPGGA:
- _altitude = _new_altitude;
- _time = _new_time;
- _latitude = _new_latitude;
- _longitude = _new_longitude;
- break;
- }
+ switch(_sentence_type)
+ {
+ case _GPS_SENTENCE_GPRMC:
+ _time = _new_time;
+ _date = _new_date;
+ _latitude = _new_latitude;
+ _longitude = _new_longitude;
+ _speed = _new_speed;
+ _course = _new_course;
+ break;
+ case _GPS_SENTENCE_GPGGA:
+ _altitude = _new_altitude;
+ _time = _new_time;
+ _latitude = _new_latitude;
+ _longitude = _new_longitude;
+ break;
+ case _GPS_SENTENCE_GPGSV:
+ _satsinview = _new_satsinview;
+ break;
+ case _GPS_SENTENCE_GPGSA:
+ _satsused = _new_satsused;
+ _fixtype = _new_fixtype;
+ break;
return true;
}
@@ -205,12 +212,42 @@
_sentence_type = _GPS_SENTENCE_GPRMC;
else if (!gpsstrcmp(_term, _GPGGA_TERM))
_sentence_type = _GPS_SENTENCE_GPGGA;
+ else if (!gpsstrcmp(_term, _GPGSV_TERM))
+ {
+ _sentence_type = _GPS_SENTENCE_GPGSV;
+ }
+ else if (!gpsstrcmp(_term, _GPGSA_TERM))
+ {
+ _sentence_type = _GPS_SENTENCE_GPGSA;
+ _new_satsused = 0;
+ }
else
_sentence_type = _GPS_SENTENCE_OTHER;
return false;
}
- if (_sentence_type != _GPS_SENTENCE_OTHER && _term[0])
+ if (_sentence_type == _GPS_SENTENCE_GPGSV && _term_number == 3 && _term[0])
+ {
+ // we've got our number of sats
+ // NOTE: we will more than likely hit this a few times in a row, because
+ // there are usually multiple GPGSV sentences to describe all of the sats
+ _new_satsinview = (unsigned char) gpsatol(_term);
+ }
+ else if (_sentence_type == _GPS_SENTENCE_GPGSA)
+ {
+ if (_term_number == 2 && _term[0]) // Fix type
+ {
+ _new_fixtype = (unsigned char) gpsatol(_term);
+ }
+ else if (_term_number >= 3 && _term_number <= 14 && _term[0]) // Count our sats used
+ {
+ _new_satsused++;
+ }
+// if (_term_number == 15) // PDOP
+// if (_term_number == 16) // HDOP
+// if (_term_number == 17) // VDOP
+ }
+ else if (_sentence_type != _GPS_SENTENCE_OTHER && _term[0])
switch((_sentence_type == _GPS_SENTENCE_GPGGA ? 200 : 100) + _term_number)
{
case 101: // Time in both sentences
@@ -218,9 +255,6 @@
_new_time = parse_decimal();
_new_time_fix = millis();
break;
- case 102: // GPRMC validity
- _gps_data_good = _term[0] == 'A';
- break;
case 103: // Latitude
case 202:
_new_latitude = parse_degrees();
@@ -248,9 +282,6 @@
break;
case 109: // Date (GPRMC)
_new_date = gpsatol(_term);
- break;
- case 206: // Fix data (GPGGA)
- _gps_data_good = _term[0] > '0';
break;
case 209: // Altitude (GPGGA)
_new_altitude = parse_decimal();
Here is how you would now check if a fix has been made and data is valid:
...
// data feeding before here, of course
if(gps.fixtype() > 1)
{
gpsdump();
}
else
{
Serial.print("No Fix. Satellites in view: "); Serial.println(gps.satsinview());
}
...
Let me know what you think.
b
P.S. mikalhart, if you use the SerialComm abstract base class for NewSoftSerial, then you could turn the “gps.encode(c)” into “gps.process()” or such.