summaryrefslogtreecommitdiff
path: root/libraries/TinyGPS
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/TinyGPS')
-rw-r--r--libraries/TinyGPS/Examples/static_test/static_test.pde124
-rw-r--r--libraries/TinyGPS/Examples/test_with_gps_device/test_with_gps_device.pde138
-rw-r--r--libraries/TinyGPS/TinyGPS.cpp303
-rw-r--r--libraries/TinyGPS/TinyGPS.h165
-rw-r--r--libraries/TinyGPS/keywords.txt41
5 files changed, 771 insertions, 0 deletions
diff --git a/libraries/TinyGPS/Examples/static_test/static_test.pde b/libraries/TinyGPS/Examples/static_test/static_test.pde
new file mode 100644
index 0000000..0482123
--- /dev/null
+++ b/libraries/TinyGPS/Examples/static_test/static_test.pde
@@ -0,0 +1,124 @@
+#include <TinyGPS.h>
+#include <avr\pgmspace.h>
+
+/* This sample code demonstrates the basic use of a TinyGPS object.
+ Typically, you would feed it characters from a serial GPS device, but
+ this example uses static strings for simplicity.
+*/
+prog_char str1[] PROGMEM = "$GPRMC,201547.000,A,3014.5527,N,09749.5808,W,0.24,163.05,040109,,*1A";
+prog_char str2[] PROGMEM = "$GPGGA,201548.000,3014.5529,N,09749.5808,W,1,07,1.5,225.6,M,-22.5,M,18.8,0000*78";
+prog_char str3[] PROGMEM = "$GPRMC,201548.000,A,3014.5529,N,09749.5808,W,0.17,53.25,040109,,*2B";
+prog_char str4[] PROGMEM = "$GPGGA,201549.000,3014.5533,N,09749.5812,W,1,07,1.5,223.5,M,-22.5,M,18.8,0000*7C";
+prog_char *teststrs[4] = {str1, str2, str3, str4};
+
+void sendstring(TinyGPS &gps, const PROGMEM char *str);
+void gpsdump(TinyGPS &gps);
+
+void setup()
+{
+ Serial.begin(115200);
+
+ Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
+ Serial.println("by Mikal Hart");
+ Serial.println();
+ Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
+ Serial.println();
+
+ for (int i=0; i<4; ++i)
+ {
+ TinyGPS test_gps;
+ Serial.print("Test string #"); Serial.println(i+1);
+ Serial.println("--------------");
+ sendstring(test_gps, teststrs[i]);
+ gpsdump(test_gps);
+ Serial.println();
+ }
+}
+
+void loop()
+{
+}
+
+void printFloat(double number, int digits=5)
+{
+ // Handle negative numbers
+ if (number < 0.0)
+ {
+ Serial.print('-');
+ number = -number;
+ }
+
+ // Round correctly so that print(1.999, 2) prints as "2.00"
+ double rounding = 0.5;
+ for (uint8_t i=0; i<digits; ++i)
+ rounding /= 10.0;
+
+ number += rounding;
+
+ // Extract the integer part of the number and print it
+ unsigned long int_part = (unsigned long)number;
+ double remainder = number - (double)int_part;
+ Serial.print(int_part);
+
+ // Print the decimal point, but only if there are digits beyond
+ if (digits > 0)
+ Serial.print(".");
+
+ // Extract digits from the remainder one at a time
+ while (digits-- > 0)
+ {
+ remainder *= 10.0;
+ int toPrint = int(remainder);
+ Serial.print(toPrint);
+ remainder -= toPrint;
+ }
+}
+
+void sendstring(TinyGPS &gps, const PROGMEM char *str)
+{
+ while (true)
+ {
+ char c = pgm_read_byte_near(str++);
+ if (!c) break;
+ Serial.print(c);
+ gps.encode(c);
+ }
+ Serial.println();
+ gps.encode('\r');
+ gps.encode('\n');
+}
+
+void gpsdump(TinyGPS &gps)
+{
+ long lat, lon;
+ float flat, flon;
+ unsigned long age, date, time, chars;
+ int year;
+ byte month, day, hour, minute, second, hundredths;
+ unsigned short sentences, failed;
+
+ gps.get_position(&lat, &lon, &age);
+ Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ gps.f_get_position(&flat, &flon, &age);
+ Serial.print("Lat/Long(float): "); printFloat(flat); Serial.print(", "); printFloat(flon);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ gps.get_datetime(&date, &time, &age);
+ Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): "); Serial.print(time);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
+ Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
+ Serial.print(" Time: "); Serial.print(static_cast<int>(hour)); Serial.print(":"); Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second)); Serial.print("."); Serial.print(static_cast<int>(hundredths));
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): "); Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
+ Serial.print("Alt(float): "); printFloat(gps.f_altitude(), 2); Serial.print(" Course(float): "); printFloat(gps.f_course(), 2); Serial.println();
+ Serial.print("Speed (knots): "); printFloat(gps.f_speed_knots(), 2); Serial.print(" (mph): "); printFloat(gps.f_speed_mph(), 2);
+ Serial.print(" (mps): "); printFloat(gps.f_speed_mps(), 2); Serial.print(" (kmph): "); printFloat(gps.f_speed_kmph(), 2); Serial.println();
+ gps.stats(&chars, &sentences, &failed);
+ Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: "); Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
+}
+
diff --git a/libraries/TinyGPS/Examples/test_with_gps_device/test_with_gps_device.pde b/libraries/TinyGPS/Examples/test_with_gps_device/test_with_gps_device.pde
new file mode 100644
index 0000000..7292b68
--- /dev/null
+++ b/libraries/TinyGPS/Examples/test_with_gps_device/test_with_gps_device.pde
@@ -0,0 +1,138 @@
+#include <NewSoftSerial.h>
+#include <TinyGPS.h>
+
+/* This sample code demonstrates the normal use of a TinyGPS object.
+ It requires the use of NewSoftSerial, and assumes that you have a
+ 4800-baud serial GPS device hooked up on pins 2(rx) and 3(tx).
+*/
+
+TinyGPS gps;
+NewSoftSerial nss(2, 3);
+
+void gpsdump(TinyGPS &gps);
+bool feedgps();
+void printFloat(double f, int digits = 2);
+
+void setup()
+{
+ Serial.begin(115200);
+ nss.begin(4800);
+
+ Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
+ Serial.println("by Mikal Hart");
+ Serial.println();
+ Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
+ Serial.println();
+}
+
+void loop()
+{
+ bool newdata = false;
+ unsigned long start = millis();
+
+ // Every 5 seconds we print an update
+ while (millis() - start < 5000)
+ {
+ if (feedgps())
+ newdata = true;
+ }
+
+ if (newdata)
+ {
+ Serial.println("Acquired Data");
+ Serial.println("-------------");
+ gpsdump(gps);
+ Serial.println("-------------");
+ Serial.println();
+ }
+}
+
+void printFloat(double number, int digits)
+{
+ // Handle negative numbers
+ if (number < 0.0)
+ {
+ Serial.print('-');
+ number = -number;
+ }
+
+ // Round correctly so that print(1.999, 2) prints as "2.00"
+ double rounding = 0.5;
+ for (uint8_t i=0; i<digits; ++i)
+ rounding /= 10.0;
+
+ number += rounding;
+
+ // Extract the integer part of the number and print it
+ unsigned long int_part = (unsigned long)number;
+ double remainder = number - (double)int_part;
+ Serial.print(int_part);
+
+ // Print the decimal point, but only if there are digits beyond
+ if (digits > 0)
+ Serial.print(".");
+
+ // Extract digits from the remainder one at a time
+ while (digits-- > 0)
+ {
+ remainder *= 10.0;
+ int toPrint = int(remainder);
+ Serial.print(toPrint);
+ remainder -= toPrint;
+ }
+}
+
+void gpsdump(TinyGPS &gps)
+{
+ long lat, lon;
+ float flat, flon;
+ unsigned long age, date, time, chars;
+ int year;
+ byte month, day, hour, minute, second, hundredths;
+ unsigned short sentences, failed;
+
+ gps.get_position(&lat, &lon, &age);
+ Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ feedgps(); // If we don't feed the gps during this long routine, we may drop characters and get checksum errors
+
+ gps.f_get_position(&flat, &flon, &age);
+ Serial.print("Lat/Long(float): "); printFloat(flat, 5); Serial.print(", "); printFloat(flon, 5);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ feedgps();
+
+ gps.get_datetime(&date, &time, &age);
+ Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): "); Serial.print(time);
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ feedgps();
+
+ gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
+ Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
+ Serial.print(" Time: "); Serial.print(static_cast<int>(hour)); Serial.print(":"); Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second)); Serial.print("."); Serial.print(static_cast<int>(hundredths));
+ Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
+
+ feedgps();
+
+ Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): "); Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
+ Serial.print("Alt(float): "); printFloat(gps.f_altitude()); Serial.print(" Course(float): "); printFloat(gps.f_course()); Serial.println();
+ Serial.print("Speed(knots): "); printFloat(gps.f_speed_knots()); Serial.print(" (mph): "); printFloat(gps.f_speed_mph());
+ Serial.print(" (mps): "); printFloat(gps.f_speed_mps()); Serial.print(" (kmph): "); printFloat(gps.f_speed_kmph()); Serial.println();
+
+ feedgps();
+
+ gps.stats(&chars, &sentences, &failed);
+ Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: "); Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
+}
+
+bool feedgps()
+{
+ while (nss.available())
+ {
+ if (gps.encode(nss.read()))
+ return true;
+ }
+ return false;
+}
diff --git a/libraries/TinyGPS/TinyGPS.cpp b/libraries/TinyGPS/TinyGPS.cpp
new file mode 100644
index 0000000..15f1614
--- /dev/null
+++ b/libraries/TinyGPS/TinyGPS.cpp
@@ -0,0 +1,303 @@
+/*
+ TinyGPS - a small GPS library for Arduino providing basic NMEA parsing
+ Based on work by and "distance_to" courtesy of Maarten Lamers.
+ Copyright (C) 2008-2011 Mikal Hart
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "WProgram.h"
+#include "TinyGPS.h"
+
+#define _GPRMC_TERM "GPRMC"
+#define _GPGGA_TERM "GPGGA"
+
+TinyGPS::TinyGPS()
+: _time(GPS_INVALID_TIME)
+, _date(GPS_INVALID_DATE)
+, _latitude(GPS_INVALID_ANGLE)
+, _longitude(GPS_INVALID_ANGLE)
+, _altitude(GPS_INVALID_ALTITUDE)
+, _speed(GPS_INVALID_SPEED)
+, _course(GPS_INVALID_ANGLE)
+, _last_time_fix(GPS_INVALID_FIX_TIME)
+, _last_position_fix(GPS_INVALID_FIX_TIME)
+, _parity(0)
+, _is_checksum_term(false)
+, _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)
+, _failed_checksum(0)
+#endif
+{
+ _term[0] = '\0';
+}
+
+//
+// public methods
+//
+
+bool TinyGPS::encode(char c)
+{
+ bool valid_sentence = false;
+
+ ++_encoded_characters;
+ switch(c)
+ {
+ case ',': // term terminators
+ _parity ^= c;
+ case '\r':
+ case '\n':
+ case '*':
+ if (_term_offset < sizeof(_term))
+ {
+ _term[_term_offset] = 0;
+ valid_sentence = term_complete();
+ }
+ ++_term_number;
+ _term_offset = 0;
+ _is_checksum_term = c == '*';
+ return valid_sentence;
+
+ case '$': // sentence begin
+ _term_number = _term_offset = 0;
+ _parity = 0;
+ _sentence_type = _GPS_SENTENCE_OTHER;
+ _is_checksum_term = false;
+ _gps_data_good = false;
+ return valid_sentence;
+ }
+
+ // ordinary characters
+ if (_term_offset < sizeof(_term) - 1)
+ _term[_term_offset++] = c;
+ if (!_is_checksum_term)
+ _parity ^= c;
+
+ return valid_sentence;
+}
+
+#ifndef _GPS_NO_STATS
+void TinyGPS::stats(unsigned long *chars, unsigned short *sentences, unsigned short *failed_cs)
+{
+ if (chars) *chars = _encoded_characters;
+ if (sentences) *sentences = _good_sentences;
+ if (failed_cs) *failed_cs = _failed_checksum;
+}
+#endif
+
+//
+// internal utilities
+//
+int TinyGPS::from_hex(char a)
+{
+ if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ return a - '0';
+}
+
+unsigned long TinyGPS::parse_decimal()
+{
+ char *p = _term;
+ bool isneg = *p == '-';
+ if (isneg) ++p;
+ unsigned long ret = 100UL * gpsatol(p);
+ while (gpsisdigit(*p)) ++p;
+ if (*p == '.')
+ {
+ if (gpsisdigit(p[1]))
+ {
+ ret += 10 * (p[1] - '0');
+ if (gpsisdigit(p[2]))
+ ret += p[2] - '0';
+ }
+ }
+ return isneg ? -ret : ret;
+}
+
+unsigned long TinyGPS::parse_degrees()
+{
+ char *p;
+ unsigned long left = gpsatol(_term);
+ unsigned long tenk_minutes = (left % 100UL) * 10000UL;
+ for (p=_term; gpsisdigit(*p); ++p);
+ if (*p == '.')
+ {
+ unsigned long mult = 1000;
+ while (gpsisdigit(*++p))
+ {
+ tenk_minutes += mult * (*p - '0');
+ mult /= 10;
+ }
+ }
+ return (left / 100) * 100000 + tenk_minutes / 6;
+}
+
+// Processes a just-completed term
+// Returns true if new sentence has just passed checksum test and is validated
+bool TinyGPS::term_complete()
+{
+ if (_is_checksum_term)
+ {
+ byte checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]);
+ if (checksum == _parity)
+ {
+ if (_gps_data_good)
+ {
+#ifndef _GPS_NO_STATS
+ ++_good_sentences;
+#endif
+ _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;
+ }
+
+ return true;
+ }
+ }
+
+#ifndef _GPS_NO_STATS
+ else
+ ++_failed_checksum;
+#endif
+ return false;
+ }
+
+ // the first term determines the sentence type
+ if (_term_number == 0)
+ {
+ if (!gpsstrcmp(_term, _GPRMC_TERM))
+ _sentence_type = _GPS_SENTENCE_GPRMC;
+ else if (!gpsstrcmp(_term, _GPGGA_TERM))
+ _sentence_type = _GPS_SENTENCE_GPGGA;
+ else
+ _sentence_type = _GPS_SENTENCE_OTHER;
+ return false;
+ }
+
+ if (_sentence_type != _GPS_SENTENCE_OTHER && _term[0])
+ switch((_sentence_type == _GPS_SENTENCE_GPGGA ? 200 : 100) + _term_number)
+ {
+ case 101: // Time in both sentences
+ case 201:
+ _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();
+ _new_position_fix = millis();
+ break;
+ case 104: // N/S
+ case 203:
+ if (_term[0] == 'S')
+ _new_latitude = -_new_latitude;
+ break;
+ case 105: // Longitude
+ case 204:
+ _new_longitude = parse_degrees();
+ break;
+ case 106: // E/W
+ case 205:
+ if (_term[0] == 'W')
+ _new_longitude = -_new_longitude;
+ break;
+ case 107: // Speed (GPRMC)
+ _new_speed = parse_decimal();
+ break;
+ case 108: // Course (GPRMC)
+ _new_course = parse_decimal();
+ 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();
+ break;
+ }
+
+ return false;
+}
+
+long TinyGPS::gpsatol(const char *str)
+{
+ long ret = 0;
+ while (gpsisdigit(*str))
+ ret = 10 * ret + *str++ - '0';
+ return ret;
+}
+
+int TinyGPS::gpsstrcmp(const char *str1, const char *str2)
+{
+ while (*str1 && *str1 == *str2)
+ ++str1, ++str2;
+ return *str1;
+}
+
+/* static */
+float TinyGPS::distance_between (float lat1, float long1, float lat2, float long2)
+{
+ // returns distance in meters between two positions, both specified
+ // as signed decimal-degrees latitude and longitude. Uses great-circle
+ // distance computation for hypothetical sphere of radius 6372795 meters.
+ // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
+ // Courtesy of Maarten Lamers
+ float delta = radians(long1-long2);
+ float sdlong = sin(delta);
+ float cdlong = cos(delta);
+ lat1 = radians(lat1);
+ lat2 = radians(lat2);
+ float slat1 = sin(lat1);
+ float clat1 = cos(lat1);
+ float slat2 = sin(lat2);
+ float clat2 = cos(lat2);
+ delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
+ delta = sq(delta);
+ delta += sq(clat2 * sdlong);
+ delta = sqrt(delta);
+ float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
+ delta = atan2(delta, denom);
+ return delta * 6372795;
+}
diff --git a/libraries/TinyGPS/TinyGPS.h b/libraries/TinyGPS/TinyGPS.h
new file mode 100644
index 0000000..7bcb0a7
--- /dev/null
+++ b/libraries/TinyGPS/TinyGPS.h
@@ -0,0 +1,165 @@
+/*
+ TinyGPS - a small GPS library for Arduino providing basic NMEA parsing
+ Based on work by and "distance_to" courtesy of Maarten Lamers.
+ Copyright (C) 2008-2011 Mikal Hart
+ All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef TinyGPS_h
+#define TinyGPS_h
+
+#include "WProgram.h"
+
+#define _GPS_VERSION 10 // software version of this library
+#define _GPS_MPH_PER_KNOT 1.15077945
+#define _GPS_MPS_PER_KNOT 0.51444444
+#define _GPS_KMPH_PER_KNOT 1.852
+#define _GPS_MILES_PER_METER 0.00062137112
+#define _GPS_KM_PER_METER 0.001
+//#define _GPS_NO_STATS
+
+class TinyGPS
+{
+ public:
+ TinyGPS();
+ bool encode(char c); // process one character received from GPS
+ TinyGPS &operator << (char c) {encode(c); return *this;}
+
+ // lat/long in hundred thousandths of a degree and age of fix in milliseconds
+ inline void get_position(long *latitude, long *longitude, unsigned long *fix_age = 0)
+ {
+ if (latitude) *latitude = _latitude;
+ if (longitude) *longitude = _longitude;
+ if (fix_age) *fix_age = _last_position_fix == GPS_INVALID_FIX_TIME ?
+ GPS_INVALID_AGE : millis() - _last_position_fix;
+ }
+
+ // date as ddmmyy, time as hhmmsscc, and age in milliseconds
+ inline void get_datetime(unsigned long *date, unsigned long *time, unsigned long *fix_age = 0)
+ {
+ if (date) *date = _date;
+ if (time) *time = _time;
+ if (fix_age) *fix_age = _last_time_fix == GPS_INVALID_FIX_TIME ?
+ GPS_INVALID_AGE : millis() - _last_time_fix;
+ }
+
+ // signed altitude in centimeters (from GPGGA sentence)
+ inline long altitude() { return _altitude; }
+
+ // course in last full GPRMC sentence in 100th of a degree
+ inline unsigned long course() { return _course; }
+
+ // speed in last full GPRMC sentence in 100ths of a knot
+ unsigned long speed() { return _speed; }
+
+#ifndef _GPS_NO_STATS
+ void stats(unsigned long *chars, unsigned short *good_sentences, unsigned short *failed_cs);
+#endif
+
+ inline void f_get_position(float *latitude, float *longitude, unsigned long *fix_age = 0)
+ {
+ long lat, lon;
+ get_position(&lat, &lon, fix_age);
+ *latitude = lat / 100000.0;
+ *longitude = lon / 100000.0;
+ }
+
+ inline void crack_datetime(int *year, byte *month, byte *day,
+ byte *hour, byte *minute, byte *second, byte *hundredths = 0, unsigned long *fix_age = 0)
+ {
+ unsigned long date, time;
+ get_datetime(&date, &time, fix_age);
+ if (year)
+ {
+ *year = date % 100;
+ *year += *year > 80 ? 1900 : 2000;
+ }
+ if (month) *month = (date / 100) % 100;
+ if (day) *day = date / 10000;
+ if (hour) *hour = time / 1000000;
+ if (minute) *minute = (time / 10000) % 100;
+ if (second) *second = (time / 100) % 100;
+ if (hundredths) *hundredths = time % 100;
+ }
+
+ inline float f_altitude() { return altitude() / 100.0; }
+ inline float f_course() { return course() / 100.0; }
+ inline float f_speed_knots() { return speed() / 100.0; }
+ inline float f_speed_mph() { return _GPS_MPH_PER_KNOT * f_speed_knots(); }
+ inline float f_speed_mps() { return _GPS_MPS_PER_KNOT * f_speed_knots(); }
+ inline float f_speed_kmph() { return _GPS_KMPH_PER_KNOT * f_speed_knots(); }
+
+ static int library_version() { return _GPS_VERSION; }
+
+ 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};
+
+
+ static float distance_between (float lat1, float long1, float lat2, float long2);
+
+private:
+ enum {_GPS_SENTENCE_GPGGA, _GPS_SENTENCE_GPRMC, _GPS_SENTENCE_OTHER};
+
+ // properties
+ unsigned long _time, _new_time;
+ unsigned long _date, _new_date;
+ long _latitude, _new_latitude;
+ long _longitude, _new_longitude;
+ long _altitude, _new_altitude;
+ unsigned long _speed, _new_speed;
+ unsigned long _course, _new_course;
+
+ unsigned long _last_time_fix, _new_time_fix;
+ unsigned long _last_position_fix, _new_position_fix;
+
+ // parsing state variables
+ byte _parity;
+ bool _is_checksum_term;
+ char _term[15];
+ byte _sentence_type;
+ byte _term_number;
+ byte _term_offset;
+ bool _gps_data_good;
+
+#ifndef _GPS_NO_STATS
+ // statistics
+ unsigned long _encoded_characters;
+ unsigned short _good_sentences;
+ unsigned short _failed_checksum;
+ unsigned short _passed_checksum;
+#endif
+
+ // internal utilities
+ int from_hex(char a);
+ unsigned long parse_decimal();
+ unsigned long parse_degrees();
+ bool term_complete();
+ bool gpsisdigit(char c) { return c >= '0' && c <= '9'; }
+ long gpsatol(const char *str);
+ int gpsstrcmp(const char *str1, const char *str2);
+};
+
+// Arduino 0012 workaround
+#undef int
+#undef char
+#undef long
+#undef byte
+#undef float
+#undef abs
+#undef round
+
+#endif
diff --git a/libraries/TinyGPS/keywords.txt b/libraries/TinyGPS/keywords.txt
new file mode 100644
index 0000000..fc4989d
--- /dev/null
+++ b/libraries/TinyGPS/keywords.txt
@@ -0,0 +1,41 @@
+#######################################
+# Syntax Coloring Map for TinyGPS
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+TinyGPS KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+encode KEYWORD2
+get_position KEYWORD2
+get_datetime KEYWORD2
+altitude KEYWORD2
+speed KEYWORD2
+course KEYWORD2
+stats KEYWORD2
+f_get_position KEYWORD2
+crack_datetime KEYWORD2
+f_altitude KEYWORD2
+f_course KEYWORD2
+f_speed_knots KEYWORD2
+f_speed_mph KEYWORD2
+f_speed_mps KEYWORD2
+f_speed_kmph KEYWORD2
+library_version KEYWORD2
+distance_between KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+GPS_INVALID_AGE LITERAL1
+GPS_INVALID_ANGLE LITERAL1
+GPS_INVALID_ALTITUDE LITERAL1
+GPS_INVALID_DATE LITERAL1
+GPS_INVALID_TIME LITERAL1