Port of Arduino TinyGPS library to mbed. Added extra methods to flag receipt/parsing of particular sentences.

Dependents:   Atlas gps_com QuadCopter Quadcopter_mk2 ... more

Port of TinyGPS (from Arduino) to mbed.

Errata: it's been pointed out to me that this version calls an undeclared millis() function. To get this code working in your project, you'll want to set up a Timer object and then call timer.read_ms() ala:

example to replace millis() calls

Timer timer;
...
timer.start();
timer.reset();
...
//x = millis();
x = timer.read_ms();
...
Committer:
shimniok
Date:
Thu Apr 28 15:24:13 2011 +0000
Revision:
1:f522b8bdf987
Parent:
0:8a347288f82c
Removed prototyping code that broke gps data validation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shimniok 0:8a347288f82c 1 /*
shimniok 0:8a347288f82c 2 TinyGPS - a small GPS library for Arduino providing basic NMEA parsing
shimniok 0:8a347288f82c 3 Copyright (C) 2008-9 Mikal Hart
shimniok 0:8a347288f82c 4 All rights reserved.
shimniok 0:8a347288f82c 5
shimniok 0:8a347288f82c 6 This library is free software; you can redistribute it and/or
shimniok 0:8a347288f82c 7 modify it under the terms of the GNU Lesser General Public
shimniok 0:8a347288f82c 8 License as published by the Free Software Foundation; either
shimniok 0:8a347288f82c 9 version 2.1 of the License, or (at your option) any later version.
shimniok 0:8a347288f82c 10
shimniok 0:8a347288f82c 11 This library is distributed in the hope that it will be useful,
shimniok 0:8a347288f82c 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
shimniok 0:8a347288f82c 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
shimniok 0:8a347288f82c 14 Lesser General Public License for more details.
shimniok 0:8a347288f82c 15
shimniok 0:8a347288f82c 16 You should have received a copy of the GNU Lesser General Public
shimniok 0:8a347288f82c 17 License along with this library; if not, write to the Free Software
shimniok 0:8a347288f82c 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
shimniok 0:8a347288f82c 19
shimniok 0:8a347288f82c 20 Ported to mbed by Michael Shimniok http://www.bot-thoughts.com/
shimniok 0:8a347288f82c 21 */
shimniok 0:8a347288f82c 22
shimniok 0:8a347288f82c 23 #include "TinyGPS.h"
shimniok 0:8a347288f82c 24
shimniok 0:8a347288f82c 25 #define _GPRMC_TERM "GPRMC"
shimniok 0:8a347288f82c 26 #define _GPGGA_TERM "GPGGA"
shimniok 0:8a347288f82c 27 #define _GPGSV_TERM "GPGSV"
shimniok 0:8a347288f82c 28
shimniok 0:8a347288f82c 29 TinyGPS::TinyGPS()
shimniok 0:8a347288f82c 30 : _time(GPS_INVALID_TIME)
shimniok 0:8a347288f82c 31 , _date(GPS_INVALID_DATE)
shimniok 0:8a347288f82c 32 , _latitude(GPS_INVALID_ANGLE)
shimniok 0:8a347288f82c 33 , _longitude(GPS_INVALID_ANGLE)
shimniok 0:8a347288f82c 34 , _altitude(GPS_INVALID_ALTITUDE)
shimniok 0:8a347288f82c 35 , _speed(GPS_INVALID_SPEED)
shimniok 0:8a347288f82c 36 , _course(GPS_INVALID_ANGLE)
shimniok 0:8a347288f82c 37 , _hdop(0)
shimniok 0:8a347288f82c 38 , _sat_count(0)
shimniok 0:8a347288f82c 39 , _last_time_fix(GPS_INVALID_FIX_TIME)
shimniok 0:8a347288f82c 40 , _last_position_fix(GPS_INVALID_FIX_TIME)
shimniok 0:8a347288f82c 41 , _parity(0)
shimniok 0:8a347288f82c 42 , _is_checksum_term(false)
shimniok 0:8a347288f82c 43 , _sentence_type(_GPS_SENTENCE_OTHER)
shimniok 0:8a347288f82c 44 , _term_number(0)
shimniok 0:8a347288f82c 45 , _term_offset(0)
shimniok 0:8a347288f82c 46 , _gps_data_good(false)
shimniok 0:8a347288f82c 47 , _rmc_ready(false)
shimniok 0:8a347288f82c 48 , _gga_ready(false)
shimniok 0:8a347288f82c 49 , _gsv_ready(false)
shimniok 0:8a347288f82c 50 #ifndef _GPS_NO_STATS
shimniok 0:8a347288f82c 51 , _encoded_characters(0)
shimniok 0:8a347288f82c 52 , _good_sentences(0)
shimniok 0:8a347288f82c 53 , _failed_checksum(0)
shimniok 0:8a347288f82c 54 #endif
shimniok 0:8a347288f82c 55 {
shimniok 0:8a347288f82c 56 _term[0] = '\0';
shimniok 0:8a347288f82c 57 }
shimniok 0:8a347288f82c 58
shimniok 0:8a347288f82c 59 //
shimniok 0:8a347288f82c 60 // public methods
shimniok 0:8a347288f82c 61 //
shimniok 0:8a347288f82c 62
shimniok 0:8a347288f82c 63 bool TinyGPS::encode(char c)
shimniok 0:8a347288f82c 64 {
shimniok 0:8a347288f82c 65 bool valid_sentence = false;
shimniok 0:8a347288f82c 66
shimniok 0:8a347288f82c 67 ++_encoded_characters;
shimniok 0:8a347288f82c 68 switch(c)
shimniok 0:8a347288f82c 69 {
shimniok 0:8a347288f82c 70 case ',': // term terminators
shimniok 0:8a347288f82c 71 _parity ^= c;
shimniok 0:8a347288f82c 72 case '\r':
shimniok 0:8a347288f82c 73 case '\n':
shimniok 0:8a347288f82c 74 case '*':
shimniok 0:8a347288f82c 75 if (_term_offset < sizeof(_term))
shimniok 0:8a347288f82c 76 {
shimniok 0:8a347288f82c 77 _term[_term_offset] = 0;
shimniok 0:8a347288f82c 78 valid_sentence = term_complete();
shimniok 0:8a347288f82c 79 }
shimniok 0:8a347288f82c 80 ++_term_number;
shimniok 0:8a347288f82c 81 _term_offset = 0;
shimniok 0:8a347288f82c 82 _is_checksum_term = c == '*';
shimniok 0:8a347288f82c 83 return valid_sentence;
shimniok 0:8a347288f82c 84
shimniok 0:8a347288f82c 85 case '$': // sentence begin
shimniok 0:8a347288f82c 86 _term_number = _term_offset = 0;
shimniok 0:8a347288f82c 87 _parity = 0;
shimniok 0:8a347288f82c 88 _sentence_type = _GPS_SENTENCE_OTHER;
shimniok 0:8a347288f82c 89 _is_checksum_term = false;
shimniok 0:8a347288f82c 90 _gps_data_good = false;
shimniok 0:8a347288f82c 91 return valid_sentence;
shimniok 0:8a347288f82c 92 }
shimniok 0:8a347288f82c 93
shimniok 0:8a347288f82c 94 // ordinary characters
shimniok 0:8a347288f82c 95 if (_term_offset < sizeof(_term) - 1)
shimniok 0:8a347288f82c 96 _term[_term_offset++] = c;
shimniok 0:8a347288f82c 97 if (!_is_checksum_term)
shimniok 0:8a347288f82c 98 _parity ^= c;
shimniok 0:8a347288f82c 99
shimniok 0:8a347288f82c 100 return valid_sentence;
shimniok 0:8a347288f82c 101 }
shimniok 0:8a347288f82c 102
shimniok 0:8a347288f82c 103 #ifndef _GPS_NO_STATS
shimniok 0:8a347288f82c 104 void TinyGPS::stats(unsigned long *chars, unsigned short *sentences, unsigned short *failed_cs)
shimniok 0:8a347288f82c 105 {
shimniok 0:8a347288f82c 106 if (chars) *chars = _encoded_characters;
shimniok 0:8a347288f82c 107 if (sentences) *sentences = _good_sentences;
shimniok 0:8a347288f82c 108 if (failed_cs) *failed_cs = _failed_checksum;
shimniok 0:8a347288f82c 109 }
shimniok 0:8a347288f82c 110 #endif
shimniok 0:8a347288f82c 111
shimniok 0:8a347288f82c 112 //
shimniok 0:8a347288f82c 113 // internal utilities
shimniok 0:8a347288f82c 114 //
shimniok 0:8a347288f82c 115 int TinyGPS::from_hex(char a)
shimniok 0:8a347288f82c 116 {
shimniok 0:8a347288f82c 117 if (a >= 'A' && a <= 'F')
shimniok 0:8a347288f82c 118 return a - 'A' + 10;
shimniok 0:8a347288f82c 119 else if (a >= 'a' && a <= 'f')
shimniok 0:8a347288f82c 120 return a - 'a' + 10;
shimniok 0:8a347288f82c 121 else
shimniok 0:8a347288f82c 122 return a - '0';
shimniok 0:8a347288f82c 123 }
shimniok 0:8a347288f82c 124
shimniok 0:8a347288f82c 125 unsigned long TinyGPS::parse_decimal()
shimniok 0:8a347288f82c 126 {
shimniok 0:8a347288f82c 127 char *p = _term;
shimniok 0:8a347288f82c 128 bool isneg = *p == '-';
shimniok 0:8a347288f82c 129 if (isneg) ++p;
shimniok 0:8a347288f82c 130 unsigned long ret = 100UL * gpsatol(p);
shimniok 0:8a347288f82c 131 while (gpsisdigit(*p)) ++p;
shimniok 0:8a347288f82c 132 if (*p == '.')
shimniok 0:8a347288f82c 133 {
shimniok 0:8a347288f82c 134 if (gpsisdigit(p[1]))
shimniok 0:8a347288f82c 135 {
shimniok 0:8a347288f82c 136 ret += 10 * (p[1] - '0');
shimniok 0:8a347288f82c 137 if (gpsisdigit(p[2]))
shimniok 0:8a347288f82c 138 ret += p[2] - '0';
shimniok 0:8a347288f82c 139 }
shimniok 0:8a347288f82c 140 }
shimniok 0:8a347288f82c 141 return isneg ? -ret : ret;
shimniok 0:8a347288f82c 142 }
shimniok 0:8a347288f82c 143
shimniok 0:8a347288f82c 144 unsigned long TinyGPS::parse_degrees()
shimniok 0:8a347288f82c 145 {
shimniok 0:8a347288f82c 146 char *p;
shimniok 0:8a347288f82c 147 unsigned long left = gpsatol(_term);
shimniok 0:8a347288f82c 148 unsigned long tenk_minutes = (left % 100UL) * 10000UL;
shimniok 0:8a347288f82c 149 for (p=_term; gpsisdigit(*p); ++p);
shimniok 0:8a347288f82c 150 if (*p == '.')
shimniok 0:8a347288f82c 151 {
shimniok 0:8a347288f82c 152 unsigned long mult = 1000;
shimniok 0:8a347288f82c 153 while (gpsisdigit(*++p))
shimniok 0:8a347288f82c 154 {
shimniok 0:8a347288f82c 155 tenk_minutes += mult * (*p - '0');
shimniok 0:8a347288f82c 156 mult /= 10;
shimniok 0:8a347288f82c 157 }
shimniok 0:8a347288f82c 158 }
shimniok 0:8a347288f82c 159 return (left / 100) * 100000 + tenk_minutes / 6;
shimniok 0:8a347288f82c 160 }
shimniok 0:8a347288f82c 161
shimniok 0:8a347288f82c 162 // Processes a just-completed term
shimniok 0:8a347288f82c 163 // Returns true if new sentence has just passed checksum test and is validated
shimniok 0:8a347288f82c 164 bool TinyGPS::term_complete()
shimniok 0:8a347288f82c 165 {
shimniok 0:8a347288f82c 166 if (_is_checksum_term)
shimniok 0:8a347288f82c 167 {
shimniok 0:8a347288f82c 168 byte checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]);
shimniok 0:8a347288f82c 169 if (checksum == _parity)
shimniok 0:8a347288f82c 170 {
shimniok 1:f522b8bdf987 171 if (_gps_data_good)
shimniok 0:8a347288f82c 172 {
shimniok 0:8a347288f82c 173 #ifndef _GPS_NO_STATS
shimniok 0:8a347288f82c 174 ++_good_sentences;
shimniok 0:8a347288f82c 175 #endif
shimniok 0:8a347288f82c 176 _last_time_fix = _new_time_fix;
shimniok 0:8a347288f82c 177 _last_position_fix = _new_position_fix;
shimniok 0:8a347288f82c 178
shimniok 0:8a347288f82c 179 switch(_sentence_type)
shimniok 0:8a347288f82c 180 {
shimniok 0:8a347288f82c 181 case _GPS_SENTENCE_GPRMC:
shimniok 0:8a347288f82c 182 _time = _new_time;
shimniok 0:8a347288f82c 183 _date = _new_date;
shimniok 0:8a347288f82c 184 _latitude = _new_latitude;
shimniok 0:8a347288f82c 185 _longitude = _new_longitude;
shimniok 0:8a347288f82c 186 _speed = _new_speed;
shimniok 0:8a347288f82c 187 _course = _new_course;
shimniok 0:8a347288f82c 188 _rmc_ready = true;
shimniok 0:8a347288f82c 189 break;
shimniok 0:8a347288f82c 190 case _GPS_SENTENCE_GPGGA:
shimniok 0:8a347288f82c 191 _altitude = _new_altitude;
shimniok 0:8a347288f82c 192 _time = _new_time;
shimniok 0:8a347288f82c 193 _latitude = _new_latitude;
shimniok 0:8a347288f82c 194 _longitude = _new_longitude;
shimniok 0:8a347288f82c 195 _gga_ready = true;
shimniok 0:8a347288f82c 196 _hdop = _new_hdop;
shimniok 0:8a347288f82c 197 _sat_count = _new_sat_count;
shimniok 0:8a347288f82c 198 case _GPS_SENTENCE_GPGSV:
shimniok 0:8a347288f82c 199 _gsv_ready = true;
shimniok 0:8a347288f82c 200 break;
shimniok 0:8a347288f82c 201 }
shimniok 0:8a347288f82c 202
shimniok 0:8a347288f82c 203 return true;
shimniok 0:8a347288f82c 204 }
shimniok 0:8a347288f82c 205 }
shimniok 0:8a347288f82c 206
shimniok 0:8a347288f82c 207 #ifndef _GPS_NO_STATS
shimniok 0:8a347288f82c 208 else
shimniok 0:8a347288f82c 209 ++_failed_checksum;
shimniok 0:8a347288f82c 210 #endif
shimniok 0:8a347288f82c 211 return false;
shimniok 0:8a347288f82c 212 }
shimniok 0:8a347288f82c 213
shimniok 0:8a347288f82c 214 // the first term determines the sentence type
shimniok 0:8a347288f82c 215 if (_term_number == 0)
shimniok 0:8a347288f82c 216 {
shimniok 0:8a347288f82c 217 if (!gpsstrcmp(_term, _GPRMC_TERM))
shimniok 0:8a347288f82c 218 _sentence_type = _GPS_SENTENCE_GPRMC;
shimniok 0:8a347288f82c 219 else if (!gpsstrcmp(_term, _GPGGA_TERM))
shimniok 0:8a347288f82c 220 _sentence_type = _GPS_SENTENCE_GPGGA;
shimniok 0:8a347288f82c 221 else if (!gpsstrcmp(_term, _GPGSV_TERM))
shimniok 0:8a347288f82c 222 _sentence_type = _GPS_SENTENCE_GPGSV;
shimniok 0:8a347288f82c 223 else
shimniok 0:8a347288f82c 224 _sentence_type = _GPS_SENTENCE_OTHER;
shimniok 0:8a347288f82c 225 return false;
shimniok 0:8a347288f82c 226 }
shimniok 0:8a347288f82c 227
shimniok 0:8a347288f82c 228 if (_sentence_type != _GPS_SENTENCE_OTHER && _term[0])
shimniok 0:8a347288f82c 229 switch((_sentence_type == _GPS_SENTENCE_GPGGA ? 200 : 100) + _term_number)
shimniok 0:8a347288f82c 230 {
shimniok 0:8a347288f82c 231 case 101: // Time in both sentences
shimniok 0:8a347288f82c 232 case 201:
shimniok 0:8a347288f82c 233 _new_time = parse_decimal();
shimniok 0:8a347288f82c 234 _new_time_fix = millis();
shimniok 0:8a347288f82c 235 break;
shimniok 0:8a347288f82c 236 case 102: // GPRMC validity
shimniok 0:8a347288f82c 237 _gps_data_good = _term[0] == 'A';
shimniok 0:8a347288f82c 238 break;
shimniok 0:8a347288f82c 239 case 103: // Latitude
shimniok 0:8a347288f82c 240 case 202:
shimniok 0:8a347288f82c 241 _new_latitude = parse_degrees();
shimniok 0:8a347288f82c 242 _new_position_fix = millis();
shimniok 0:8a347288f82c 243 break;
shimniok 0:8a347288f82c 244 case 104: // N/S
shimniok 0:8a347288f82c 245 case 203:
shimniok 0:8a347288f82c 246 if (_term[0] == 'S')
shimniok 0:8a347288f82c 247 _new_latitude = -_new_latitude;
shimniok 0:8a347288f82c 248 break;
shimniok 0:8a347288f82c 249 case 105: // Longitude
shimniok 0:8a347288f82c 250 case 204:
shimniok 0:8a347288f82c 251 _new_longitude = parse_degrees();
shimniok 0:8a347288f82c 252 break;
shimniok 0:8a347288f82c 253 case 106: // E/W
shimniok 0:8a347288f82c 254 case 205:
shimniok 0:8a347288f82c 255 if (_term[0] == 'W')
shimniok 0:8a347288f82c 256 _new_longitude = -_new_longitude;
shimniok 0:8a347288f82c 257 break;
shimniok 0:8a347288f82c 258 case 107: // Speed (GPRMC)
shimniok 0:8a347288f82c 259 _new_speed = parse_decimal();
shimniok 0:8a347288f82c 260 break;
shimniok 0:8a347288f82c 261 case 108: // Course (GPRMC)
shimniok 0:8a347288f82c 262 _new_course = parse_decimal();
shimniok 0:8a347288f82c 263 break;
shimniok 0:8a347288f82c 264 case 109: // Date (GPRMC)
shimniok 0:8a347288f82c 265 _new_date = gpsatol(_term);
shimniok 0:8a347288f82c 266 break;
shimniok 0:8a347288f82c 267 case 206: // Fix data (GPGGA)
shimniok 0:8a347288f82c 268 _gps_data_good = _term[0] > '0';
shimniok 0:8a347288f82c 269 break;
shimniok 0:8a347288f82c 270 case 207: // Number of satelites tracked (GPGGA)
shimniok 0:8a347288f82c 271 _new_sat_count = parse_decimal();
shimniok 0:8a347288f82c 272 break;
shimniok 0:8a347288f82c 273 case 208: // Horizontal Dilution of Position (GPGGA)
shimniok 0:8a347288f82c 274 _new_hdop = parse_decimal();
shimniok 0:8a347288f82c 275 break;
shimniok 0:8a347288f82c 276 case 209: // Altitude (GPGGA)
shimniok 0:8a347288f82c 277 _new_altitude = parse_decimal();
shimniok 0:8a347288f82c 278 break;
shimniok 0:8a347288f82c 279 } /* switch */
shimniok 0:8a347288f82c 280
shimniok 0:8a347288f82c 281 return false;
shimniok 0:8a347288f82c 282 }
shimniok 0:8a347288f82c 283
shimniok 0:8a347288f82c 284 long TinyGPS::gpsatol(const char *str)
shimniok 0:8a347288f82c 285 {
shimniok 0:8a347288f82c 286 long ret = 0;
shimniok 0:8a347288f82c 287 while (gpsisdigit(*str))
shimniok 0:8a347288f82c 288 ret = 10 * ret + *str++ - '0';
shimniok 0:8a347288f82c 289 return ret;
shimniok 0:8a347288f82c 290 }
shimniok 0:8a347288f82c 291
shimniok 0:8a347288f82c 292 int TinyGPS::gpsstrcmp(const char *str1, const char *str2)
shimniok 0:8a347288f82c 293 {
shimniok 0:8a347288f82c 294 while (*str1 && *str1 == *str2)
shimniok 0:8a347288f82c 295 ++str1, ++str2;
shimniok 0:8a347288f82c 296 return *str1;
shimniok 0:8a347288f82c 297 }