Last version of TinyGPS library

Dependents:   Nucleo_gps mbed_2018 mbed_2019_rx3 mbed_2019 ... more

Committer:
dROb
Date:
Sat May 21 12:39:15 2016 +0000
Revision:
0:44bee9056857
Updated TinyGPS library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dROb 0:44bee9056857 1 /*
dROb 0:44bee9056857 2 TinyGPS - a small GPS library for Arduino providing basic NMEA parsing
dROb 0:44bee9056857 3 Based on work by and "distance_to" and "course_to" courtesy of Maarten Lamers.
dROb 0:44bee9056857 4 Suggestion to add satellites(), course_to(), and cardinal(), by Matt Monson.
dROb 0:44bee9056857 5 Precision improvements suggested by Wayne Holder.
dROb 0:44bee9056857 6 Copyright (C) 2008-2013 Mikal Hart
dROb 0:44bee9056857 7 All rights reserved.
dROb 0:44bee9056857 8
dROb 0:44bee9056857 9 This library is free software; you can redistribute it and/or
dROb 0:44bee9056857 10 modify it under the terms of the GNU Lesser General Public
dROb 0:44bee9056857 11 License as published by the Free Software Foundation; either
dROb 0:44bee9056857 12 version 2.1 of the License, or (at your option) any later version.
dROb 0:44bee9056857 13
dROb 0:44bee9056857 14 This library is distributed in the hope that it will be useful,
dROb 0:44bee9056857 15 but WITHOUT ANY WARRANTY; without even the implied warranty of
dROb 0:44bee9056857 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dROb 0:44bee9056857 17 Lesser General Public License for more details.
dROb 0:44bee9056857 18
dROb 0:44bee9056857 19 You should have received a copy of the GNU Lesser General Public
dROb 0:44bee9056857 20 License along with this library; if not, write to the Free Software
dROb 0:44bee9056857 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
dROb 0:44bee9056857 22
dROb 0:44bee9056857 23 MBED port by Sergey Drobyshevskiy (dROb)
dROb 0:44bee9056857 24 */
dROb 0:44bee9056857 25
dROb 0:44bee9056857 26 #include "TinyGPS.h"
dROb 0:44bee9056857 27
dROb 0:44bee9056857 28 #define _GPRMC_TERM "GPRMC"
dROb 0:44bee9056857 29 #define _GPGGA_TERM "GPGGA"
dROb 0:44bee9056857 30
dROb 0:44bee9056857 31 TinyGPS::TinyGPS()
dROb 0:44bee9056857 32 : _time(GPS_INVALID_TIME)
dROb 0:44bee9056857 33 , _date(GPS_INVALID_DATE)
dROb 0:44bee9056857 34 , _latitude(GPS_INVALID_ANGLE)
dROb 0:44bee9056857 35 , _longitude(GPS_INVALID_ANGLE)
dROb 0:44bee9056857 36 , _altitude(GPS_INVALID_ALTITUDE)
dROb 0:44bee9056857 37 , _speed(GPS_INVALID_SPEED)
dROb 0:44bee9056857 38 , _course(GPS_INVALID_ANGLE)
dROb 0:44bee9056857 39 , _hdop(GPS_INVALID_HDOP)
dROb 0:44bee9056857 40 , _numsats(GPS_INVALID_SATELLITES)
dROb 0:44bee9056857 41 , _last_time_fix(GPS_INVALID_FIX_TIME)
dROb 0:44bee9056857 42 , _last_position_fix(GPS_INVALID_FIX_TIME)
dROb 0:44bee9056857 43 , _parity(0)
dROb 0:44bee9056857 44 , _is_checksum_term(false)
dROb 0:44bee9056857 45 , _sentence_type(_GPS_SENTENCE_OTHER)
dROb 0:44bee9056857 46 , _term_number(0)
dROb 0:44bee9056857 47 , _term_offset(0)
dROb 0:44bee9056857 48 , _gps_data_good(false)
dROb 0:44bee9056857 49 #ifndef _GPS_NO_STATS
dROb 0:44bee9056857 50 , _encoded_characters(0)
dROb 0:44bee9056857 51 , _good_sentences(0)
dROb 0:44bee9056857 52 , _failed_checksum(0)
dROb 0:44bee9056857 53 #endif
dROb 0:44bee9056857 54 {
dROb 0:44bee9056857 55 _term[0] = '\0';
dROb 0:44bee9056857 56 }
dROb 0:44bee9056857 57
dROb 0:44bee9056857 58 //
dROb 0:44bee9056857 59 // public methods
dROb 0:44bee9056857 60 //
dROb 0:44bee9056857 61
dROb 0:44bee9056857 62 bool TinyGPS::encode(char c)
dROb 0:44bee9056857 63 {
dROb 0:44bee9056857 64 bool valid_sentence = false;
dROb 0:44bee9056857 65
dROb 0:44bee9056857 66 #ifndef _GPS_NO_STATS
dROb 0:44bee9056857 67 ++_encoded_characters;
dROb 0:44bee9056857 68 #endif
dROb 0:44bee9056857 69 switch(c)
dROb 0:44bee9056857 70 {
dROb 0:44bee9056857 71 case ',': // term terminators
dROb 0:44bee9056857 72 _parity ^= c;
dROb 0:44bee9056857 73 case '\r':
dROb 0:44bee9056857 74 case '\n':
dROb 0:44bee9056857 75 case '*':
dROb 0:44bee9056857 76 if (_term_offset < sizeof(_term))
dROb 0:44bee9056857 77 {
dROb 0:44bee9056857 78 _term[_term_offset] = 0;
dROb 0:44bee9056857 79 valid_sentence = term_complete();
dROb 0:44bee9056857 80 }
dROb 0:44bee9056857 81 ++_term_number;
dROb 0:44bee9056857 82 _term_offset = 0;
dROb 0:44bee9056857 83 _is_checksum_term = c == '*';
dROb 0:44bee9056857 84 return valid_sentence;
dROb 0:44bee9056857 85
dROb 0:44bee9056857 86 case '$': // sentence begin
dROb 0:44bee9056857 87 _term_number = _term_offset = 0;
dROb 0:44bee9056857 88 _parity = 0;
dROb 0:44bee9056857 89 _sentence_type = _GPS_SENTENCE_OTHER;
dROb 0:44bee9056857 90 _is_checksum_term = false;
dROb 0:44bee9056857 91 _gps_data_good = false;
dROb 0:44bee9056857 92 return valid_sentence;
dROb 0:44bee9056857 93 }
dROb 0:44bee9056857 94
dROb 0:44bee9056857 95 // ordinary characters
dROb 0:44bee9056857 96 if (_term_offset < sizeof(_term) - 1)
dROb 0:44bee9056857 97 _term[_term_offset++] = c;
dROb 0:44bee9056857 98 if (!_is_checksum_term)
dROb 0:44bee9056857 99 _parity ^= c;
dROb 0:44bee9056857 100
dROb 0:44bee9056857 101 return valid_sentence;
dROb 0:44bee9056857 102 }
dROb 0:44bee9056857 103
dROb 0:44bee9056857 104 #ifndef _GPS_NO_STATS
dROb 0:44bee9056857 105 void TinyGPS::stats(unsigned long *chars, unsigned short *sentences, unsigned short *failed_cs)
dROb 0:44bee9056857 106 {
dROb 0:44bee9056857 107 if (chars) *chars = _encoded_characters;
dROb 0:44bee9056857 108 if (sentences) *sentences = _good_sentences;
dROb 0:44bee9056857 109 if (failed_cs) *failed_cs = _failed_checksum;
dROb 0:44bee9056857 110 }
dROb 0:44bee9056857 111 #endif
dROb 0:44bee9056857 112
dROb 0:44bee9056857 113 //
dROb 0:44bee9056857 114 // internal utilities
dROb 0:44bee9056857 115 //
dROb 0:44bee9056857 116 int TinyGPS::from_hex(char a)
dROb 0:44bee9056857 117 {
dROb 0:44bee9056857 118 if (a >= 'A' && a <= 'F')
dROb 0:44bee9056857 119 return a - 'A' + 10;
dROb 0:44bee9056857 120 else if (a >= 'a' && a <= 'f')
dROb 0:44bee9056857 121 return a - 'a' + 10;
dROb 0:44bee9056857 122 else
dROb 0:44bee9056857 123 return a - '0';
dROb 0:44bee9056857 124 }
dROb 0:44bee9056857 125
dROb 0:44bee9056857 126 unsigned long TinyGPS::parse_decimal()
dROb 0:44bee9056857 127 {
dROb 0:44bee9056857 128 char *p = _term;
dROb 0:44bee9056857 129 bool isneg = *p == '-';
dROb 0:44bee9056857 130 if (isneg) ++p;
dROb 0:44bee9056857 131 unsigned long ret = 100UL * gpsatol(p);
dROb 0:44bee9056857 132 while (gpsisdigit(*p)) ++p;
dROb 0:44bee9056857 133 if (*p == '.')
dROb 0:44bee9056857 134 {
dROb 0:44bee9056857 135 if (gpsisdigit(p[1]))
dROb 0:44bee9056857 136 {
dROb 0:44bee9056857 137 ret += 10 * (p[1] - '0');
dROb 0:44bee9056857 138 if (gpsisdigit(p[2]))
dROb 0:44bee9056857 139 ret += p[2] - '0';
dROb 0:44bee9056857 140 }
dROb 0:44bee9056857 141 }
dROb 0:44bee9056857 142 return isneg ? -ret : ret;
dROb 0:44bee9056857 143 }
dROb 0:44bee9056857 144
dROb 0:44bee9056857 145 // Parse a string in the form ddmm.mmmmmmm...
dROb 0:44bee9056857 146 unsigned long TinyGPS::parse_degrees()
dROb 0:44bee9056857 147 {
dROb 0:44bee9056857 148 char *p;
dROb 0:44bee9056857 149 unsigned long left_of_decimal = gpsatol(_term);
dROb 0:44bee9056857 150 unsigned long hundred1000ths_of_minute = (left_of_decimal % 100UL) * 100000UL;
dROb 0:44bee9056857 151 for (p=_term; gpsisdigit(*p); ++p);
dROb 0:44bee9056857 152 if (*p == '.')
dROb 0:44bee9056857 153 {
dROb 0:44bee9056857 154 unsigned long mult = 10000;
dROb 0:44bee9056857 155 while (gpsisdigit(*++p))
dROb 0:44bee9056857 156 {
dROb 0:44bee9056857 157 hundred1000ths_of_minute += mult * (*p - '0');
dROb 0:44bee9056857 158 mult /= 10;
dROb 0:44bee9056857 159 }
dROb 0:44bee9056857 160 }
dROb 0:44bee9056857 161 return (left_of_decimal / 100) * 1000000 + (hundred1000ths_of_minute + 3) / 6;
dROb 0:44bee9056857 162 }
dROb 0:44bee9056857 163
dROb 0:44bee9056857 164 #define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
dROb 0:44bee9056857 165
dROb 0:44bee9056857 166 // Processes a just-completed term
dROb 0:44bee9056857 167 // Returns true if new sentence has just passed checksum test and is validated
dROb 0:44bee9056857 168 bool TinyGPS::term_complete()
dROb 0:44bee9056857 169 {
dROb 0:44bee9056857 170 if (_is_checksum_term)
dROb 0:44bee9056857 171 {
dROb 0:44bee9056857 172 byte checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]);
dROb 0:44bee9056857 173 if (checksum == _parity)
dROb 0:44bee9056857 174 {
dROb 0:44bee9056857 175 if (_gps_data_good)
dROb 0:44bee9056857 176 {
dROb 0:44bee9056857 177 #ifndef _GPS_NO_STATS
dROb 0:44bee9056857 178 ++_good_sentences;
dROb 0:44bee9056857 179 #endif
dROb 0:44bee9056857 180 _last_time_fix = _new_time_fix;
dROb 0:44bee9056857 181 _last_position_fix = _new_position_fix;
dROb 0:44bee9056857 182
dROb 0:44bee9056857 183 switch(_sentence_type)
dROb 0:44bee9056857 184 {
dROb 0:44bee9056857 185 case _GPS_SENTENCE_GPRMC:
dROb 0:44bee9056857 186 _time = _new_time;
dROb 0:44bee9056857 187 _date = _new_date;
dROb 0:44bee9056857 188 _latitude = _new_latitude;
dROb 0:44bee9056857 189 _longitude = _new_longitude;
dROb 0:44bee9056857 190 _speed = _new_speed;
dROb 0:44bee9056857 191 _course = _new_course;
dROb 0:44bee9056857 192 break;
dROb 0:44bee9056857 193 case _GPS_SENTENCE_GPGGA:
dROb 0:44bee9056857 194 _altitude = _new_altitude;
dROb 0:44bee9056857 195 _time = _new_time;
dROb 0:44bee9056857 196 _latitude = _new_latitude;
dROb 0:44bee9056857 197 _longitude = _new_longitude;
dROb 0:44bee9056857 198 _numsats = _new_numsats;
dROb 0:44bee9056857 199 _hdop = _new_hdop;
dROb 0:44bee9056857 200 break;
dROb 0:44bee9056857 201 }
dROb 0:44bee9056857 202
dROb 0:44bee9056857 203 return true;
dROb 0:44bee9056857 204 }
dROb 0:44bee9056857 205 }
dROb 0:44bee9056857 206
dROb 0:44bee9056857 207 #ifndef _GPS_NO_STATS
dROb 0:44bee9056857 208 else
dROb 0:44bee9056857 209 ++_failed_checksum;
dROb 0:44bee9056857 210 #endif
dROb 0:44bee9056857 211 return false;
dROb 0:44bee9056857 212 }
dROb 0:44bee9056857 213
dROb 0:44bee9056857 214 // the first term determines the sentence type
dROb 0:44bee9056857 215 if (_term_number == 0)
dROb 0:44bee9056857 216 {
dROb 0:44bee9056857 217 if (!gpsstrcmp(_term, _GPRMC_TERM))
dROb 0:44bee9056857 218 _sentence_type = _GPS_SENTENCE_GPRMC;
dROb 0:44bee9056857 219 else if (!gpsstrcmp(_term, _GPGGA_TERM))
dROb 0:44bee9056857 220 _sentence_type = _GPS_SENTENCE_GPGGA;
dROb 0:44bee9056857 221 else
dROb 0:44bee9056857 222 _sentence_type = _GPS_SENTENCE_OTHER;
dROb 0:44bee9056857 223 return false;
dROb 0:44bee9056857 224 }
dROb 0:44bee9056857 225
dROb 0:44bee9056857 226 if (_sentence_type != _GPS_SENTENCE_OTHER && _term[0])
dROb 0:44bee9056857 227 switch(COMBINE(_sentence_type, _term_number))
dROb 0:44bee9056857 228 {
dROb 0:44bee9056857 229 case COMBINE(_GPS_SENTENCE_GPRMC, 1): // Time in both sentences
dROb 0:44bee9056857 230 case COMBINE(_GPS_SENTENCE_GPGGA, 1):
dROb 0:44bee9056857 231 _new_time = parse_decimal();
dROb 0:44bee9056857 232 _new_time_fix = millis();
dROb 0:44bee9056857 233 break;
dROb 0:44bee9056857 234 case COMBINE(_GPS_SENTENCE_GPRMC, 2): // GPRMC validity
dROb 0:44bee9056857 235 _gps_data_good = _term[0] == 'A';
dROb 0:44bee9056857 236 break;
dROb 0:44bee9056857 237 case COMBINE(_GPS_SENTENCE_GPRMC, 3): // Latitude
dROb 0:44bee9056857 238 case COMBINE(_GPS_SENTENCE_GPGGA, 2):
dROb 0:44bee9056857 239 _new_latitude = parse_degrees();
dROb 0:44bee9056857 240 _new_position_fix = millis();
dROb 0:44bee9056857 241 break;
dROb 0:44bee9056857 242 case COMBINE(_GPS_SENTENCE_GPRMC, 4): // N/S
dROb 0:44bee9056857 243 case COMBINE(_GPS_SENTENCE_GPGGA, 3):
dROb 0:44bee9056857 244 if (_term[0] == 'S')
dROb 0:44bee9056857 245 _new_latitude = -_new_latitude;
dROb 0:44bee9056857 246 break;
dROb 0:44bee9056857 247 case COMBINE(_GPS_SENTENCE_GPRMC, 5): // Longitude
dROb 0:44bee9056857 248 case COMBINE(_GPS_SENTENCE_GPGGA, 4):
dROb 0:44bee9056857 249 _new_longitude = parse_degrees();
dROb 0:44bee9056857 250 break;
dROb 0:44bee9056857 251 case COMBINE(_GPS_SENTENCE_GPRMC, 6): // E/W
dROb 0:44bee9056857 252 case COMBINE(_GPS_SENTENCE_GPGGA, 5):
dROb 0:44bee9056857 253 if (_term[0] == 'W')
dROb 0:44bee9056857 254 _new_longitude = -_new_longitude;
dROb 0:44bee9056857 255 break;
dROb 0:44bee9056857 256 case COMBINE(_GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC)
dROb 0:44bee9056857 257 _new_speed = parse_decimal();
dROb 0:44bee9056857 258 break;
dROb 0:44bee9056857 259 case COMBINE(_GPS_SENTENCE_GPRMC, 8): // Course (GPRMC)
dROb 0:44bee9056857 260 _new_course = parse_decimal();
dROb 0:44bee9056857 261 break;
dROb 0:44bee9056857 262 case COMBINE(_GPS_SENTENCE_GPRMC, 9): // Date (GPRMC)
dROb 0:44bee9056857 263 _new_date = gpsatol(_term);
dROb 0:44bee9056857 264 break;
dROb 0:44bee9056857 265 case COMBINE(_GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA)
dROb 0:44bee9056857 266 _gps_data_good = _term[0] > '0';
dROb 0:44bee9056857 267 break;
dROb 0:44bee9056857 268 case COMBINE(_GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA)
dROb 0:44bee9056857 269 _new_numsats = (unsigned char)atoi(_term);
dROb 0:44bee9056857 270 break;
dROb 0:44bee9056857 271 case COMBINE(_GPS_SENTENCE_GPGGA, 8): // HDOP
dROb 0:44bee9056857 272 _new_hdop = parse_decimal();
dROb 0:44bee9056857 273 break;
dROb 0:44bee9056857 274 case COMBINE(_GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA)
dROb 0:44bee9056857 275 _new_altitude = parse_decimal();
dROb 0:44bee9056857 276 break;
dROb 0:44bee9056857 277 }
dROb 0:44bee9056857 278
dROb 0:44bee9056857 279 return false;
dROb 0:44bee9056857 280 }
dROb 0:44bee9056857 281
dROb 0:44bee9056857 282 long TinyGPS::gpsatol(const char *str)
dROb 0:44bee9056857 283 {
dROb 0:44bee9056857 284 long ret = 0;
dROb 0:44bee9056857 285 while (gpsisdigit(*str))
dROb 0:44bee9056857 286 ret = 10 * ret + *str++ - '0';
dROb 0:44bee9056857 287 return ret;
dROb 0:44bee9056857 288 }
dROb 0:44bee9056857 289
dROb 0:44bee9056857 290 int TinyGPS::gpsstrcmp(const char *str1, const char *str2)
dROb 0:44bee9056857 291 {
dROb 0:44bee9056857 292 while (*str1 && *str1 == *str2)
dROb 0:44bee9056857 293 ++str1, ++str2;
dROb 0:44bee9056857 294 return *str1;
dROb 0:44bee9056857 295 }
dROb 0:44bee9056857 296
dROb 0:44bee9056857 297 /* static */
dROb 0:44bee9056857 298 float TinyGPS::distance_between (float lat1, float long1, float lat2, float long2)
dROb 0:44bee9056857 299 {
dROb 0:44bee9056857 300 // returns distance in meters between two positions, both specified
dROb 0:44bee9056857 301 // as signed decimal-degrees latitude and longitude. Uses great-circle
dROb 0:44bee9056857 302 // distance computation for hypothetical sphere of radius 6372795 meters.
dROb 0:44bee9056857 303 // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
dROb 0:44bee9056857 304 // Courtesy of Maarten Lamers
dROb 0:44bee9056857 305 float delta = toRadians(long1-long2);
dROb 0:44bee9056857 306 float sdlong = sin(delta);
dROb 0:44bee9056857 307 float cdlong = cos(delta);
dROb 0:44bee9056857 308 lat1 = toRadians(lat1);
dROb 0:44bee9056857 309 lat2 = toRadians(lat2);
dROb 0:44bee9056857 310 float slat1 = sin(lat1);
dROb 0:44bee9056857 311 float clat1 = cos(lat1);
dROb 0:44bee9056857 312 float slat2 = sin(lat2);
dROb 0:44bee9056857 313 float clat2 = cos(lat2);
dROb 0:44bee9056857 314 delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
dROb 0:44bee9056857 315 delta = delta * delta;//delta = sq(delta);
dROb 0:44bee9056857 316 delta += (clat2 * sdlong) * (clat2 * sdlong);//delta += sq(clat2 * sdlong);
dROb 0:44bee9056857 317 delta = sqrt(delta);
dROb 0:44bee9056857 318 float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
dROb 0:44bee9056857 319 delta = atan2(delta, denom);
dROb 0:44bee9056857 320 return delta * 6372795;
dROb 0:44bee9056857 321 }
dROb 0:44bee9056857 322
dROb 0:44bee9056857 323 float TinyGPS::course_to (float lat1, float long1, float lat2, float long2)
dROb 0:44bee9056857 324 {
dROb 0:44bee9056857 325 // returns course in degrees (North=0, West=270) from position 1 to position 2,
dROb 0:44bee9056857 326 // both specified as signed decimal-degrees latitude and longitude.
dROb 0:44bee9056857 327 // Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
dROb 0:44bee9056857 328 // Courtesy of Maarten Lamers
dROb 0:44bee9056857 329 float dlon = toRadians(long2-long1);
dROb 0:44bee9056857 330 lat1 = toRadians(lat1);
dROb 0:44bee9056857 331 lat2 = toRadians(lat2);
dROb 0:44bee9056857 332 float a1 = sin(dlon) * cos(lat2);
dROb 0:44bee9056857 333 float a2 = sin(lat1) * cos(lat2) * cos(dlon);
dROb 0:44bee9056857 334 a2 = cos(lat1) * sin(lat2) - a2;
dROb 0:44bee9056857 335 a2 = atan2(a1, a2);
dROb 0:44bee9056857 336 if (a2 < 0.0)
dROb 0:44bee9056857 337 {
dROb 0:44bee9056857 338 a2 += TWO_PI;
dROb 0:44bee9056857 339 }
dROb 0:44bee9056857 340 return toDegrees(a2);
dROb 0:44bee9056857 341 }
dROb 0:44bee9056857 342
dROb 0:44bee9056857 343 const char *TinyGPS::cardinal (float course)
dROb 0:44bee9056857 344 {
dROb 0:44bee9056857 345 static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
dROb 0:44bee9056857 346
dROb 0:44bee9056857 347 int direction = (int)((course + 11.25f) / 22.5f);
dROb 0:44bee9056857 348 return directions[direction % 16];
dROb 0:44bee9056857 349 }
dROb 0:44bee9056857 350
dROb 0:44bee9056857 351 // lat/long in MILLIONTHs of a degree and age of fix in milliseconds
dROb 0:44bee9056857 352 // (note: versions 12 and earlier gave this value in 100,000ths of a degree.
dROb 0:44bee9056857 353 void TinyGPS::get_position(long *latitude, long *longitude, unsigned long *fix_age)
dROb 0:44bee9056857 354 {
dROb 0:44bee9056857 355 if (latitude) *latitude = _latitude;
dROb 0:44bee9056857 356 if (longitude) *longitude = _longitude;
dROb 0:44bee9056857 357 if (fix_age) *fix_age = _last_position_fix == GPS_INVALID_FIX_TIME ?
dROb 0:44bee9056857 358 GPS_INVALID_AGE : millis() - _last_position_fix;
dROb 0:44bee9056857 359 }
dROb 0:44bee9056857 360
dROb 0:44bee9056857 361 // date as ddmmyy, time as hhmmsscc, and age in milliseconds
dROb 0:44bee9056857 362 void TinyGPS::get_datetime(unsigned long *date, unsigned long *time, unsigned long *age)
dROb 0:44bee9056857 363 {
dROb 0:44bee9056857 364 if (date) *date = _date;
dROb 0:44bee9056857 365 if (time) *time = _time;
dROb 0:44bee9056857 366 if (age) *age = _last_time_fix == GPS_INVALID_FIX_TIME ?
dROb 0:44bee9056857 367 GPS_INVALID_AGE : millis() - _last_time_fix;
dROb 0:44bee9056857 368 }
dROb 0:44bee9056857 369
dROb 0:44bee9056857 370 void TinyGPS::f_get_position(float *latitude, float *longitude, unsigned long *fix_age)
dROb 0:44bee9056857 371 {
dROb 0:44bee9056857 372 long lat, lon;
dROb 0:44bee9056857 373 get_position(&lat, &lon, fix_age);
dROb 0:44bee9056857 374 *latitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lat / 1000000.0);
dROb 0:44bee9056857 375 *longitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lon / 1000000.0);
dROb 0:44bee9056857 376 }
dROb 0:44bee9056857 377
dROb 0:44bee9056857 378 void TinyGPS::crack_datetime(int *year, byte *month, byte *day,
dROb 0:44bee9056857 379 byte *hour, byte *minute, byte *second, byte *hundredths, unsigned long *age)
dROb 0:44bee9056857 380 {
dROb 0:44bee9056857 381 unsigned long date, time;
dROb 0:44bee9056857 382 get_datetime(&date, &time, age);
dROb 0:44bee9056857 383 if (year)
dROb 0:44bee9056857 384 {
dROb 0:44bee9056857 385 *year = date % 100;
dROb 0:44bee9056857 386 *year += *year > 80 ? 1900 : 2000;
dROb 0:44bee9056857 387 }
dROb 0:44bee9056857 388 if (month) *month = (date / 100) % 100;
dROb 0:44bee9056857 389 if (day) *day = date / 10000;
dROb 0:44bee9056857 390 if (hour) *hour = time / 1000000;
dROb 0:44bee9056857 391 if (minute) *minute = (time / 10000) % 100;
dROb 0:44bee9056857 392 if (second) *second = (time / 100) % 100;
dROb 0:44bee9056857 393 if (hundredths) *hundredths = time % 100;
dROb 0:44bee9056857 394 }
dROb 0:44bee9056857 395
dROb 0:44bee9056857 396 float TinyGPS::f_altitude()
dROb 0:44bee9056857 397 {
dROb 0:44bee9056857 398 return _altitude == GPS_INVALID_ALTITUDE ? GPS_INVALID_F_ALTITUDE : _altitude / 100.0;
dROb 0:44bee9056857 399 }
dROb 0:44bee9056857 400
dROb 0:44bee9056857 401 float TinyGPS::f_course()
dROb 0:44bee9056857 402 {
dROb 0:44bee9056857 403 return _course == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : _course / 100.0;
dROb 0:44bee9056857 404 }
dROb 0:44bee9056857 405
dROb 0:44bee9056857 406 float TinyGPS::f_speed_knots()
dROb 0:44bee9056857 407 {
dROb 0:44bee9056857 408 return _speed == GPS_INVALID_SPEED ? GPS_INVALID_F_SPEED : _speed / 100.0;
dROb 0:44bee9056857 409 }
dROb 0:44bee9056857 410
dROb 0:44bee9056857 411 float TinyGPS::f_speed_mph()
dROb 0:44bee9056857 412 {
dROb 0:44bee9056857 413 float sk = f_speed_knots();
dROb 0:44bee9056857 414 return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : _GPS_MPH_PER_KNOT * sk;
dROb 0:44bee9056857 415 }
dROb 0:44bee9056857 416
dROb 0:44bee9056857 417 float TinyGPS::f_speed_mps()
dROb 0:44bee9056857 418 {
dROb 0:44bee9056857 419 float sk = f_speed_knots();
dROb 0:44bee9056857 420 return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : _GPS_MPS_PER_KNOT * sk;
dROb 0:44bee9056857 421 }
dROb 0:44bee9056857 422
dROb 0:44bee9056857 423 float TinyGPS::f_speed_kmph()
dROb 0:44bee9056857 424 {
dROb 0:44bee9056857 425 float sk = f_speed_knots();
dROb 0:44bee9056857 426 return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : _GPS_KMPH_PER_KNOT * sk;
dROb 0:44bee9056857 427 }
dROb 0:44bee9056857 428
dROb 0:44bee9056857 429 const float TinyGPS::GPS_INVALID_F_ANGLE = 1000.0;
dROb 0:44bee9056857 430 const float TinyGPS::GPS_INVALID_F_ALTITUDE = 1000000.0;
dROb 0:44bee9056857 431 const float TinyGPS::GPS_INVALID_F_SPEED = -1.0;