diff --git a/Adafruit_GPS.cpp b/Adafruit_GPS.cpp index 4f84a8a..16b3acf 100755 --- a/Adafruit_GPS.cpp +++ b/Adafruit_GPS.cpp @@ -76,85 +76,36 @@ boolean Adafruit_GPS::parse(char *nmea) { } else { return false; } - int32_t degree; - long minutes; - char degreebuff[10]; // look for a few common sentences + char *p = nmea; + if (strStartsWith(nmea, "$GPGGA")) { // found GGA - char *p = nmea; // get time p = strchr(p, ',')+1; - float timef = atof(p); - uint32_t time = timef; - hour = time / 10000; - minute = (time % 10000) / 100; - seconds = (time % 100); - - milliseconds = fmod(timef, 1.0) * 1000; + parseTime(p); // parse out latitude p = strchr(p, ',')+1; - if (',' != *p) - { - strncpy(degreebuff, p, 2); - p += 2; - degreebuff[2] = '\0'; - degree = atol(degreebuff) * 10000000; - strncpy(degreebuff, p, 2); // minutes - p += 3; // skip decimal point - strncpy(degreebuff + 2, p, 4); - degreebuff[6] = '\0'; - minutes = 50 * atol(degreebuff) / 3; - latitude_fixed = degree + minutes; - latitude = degree / 100000 + minutes * 0.000006F; - latitudeDegrees = (latitude-100*int(latitude/100))/60.0; - latitudeDegrees += int(latitude/100); - } - + parseLat(p); p = strchr(p, ',')+1; - if (',' != *p) - { - if (p[0] == 'S') latitudeDegrees *= -1.0; - if (p[0] == 'N') lat = 'N'; - else if (p[0] == 'S') lat = 'S'; - else if (p[0] == ',') lat = 0; - else return false; - } + if(!parseLatDir(p)) return false; // parse out longitude p = strchr(p, ',')+1; - if (',' != *p) - { - strncpy(degreebuff, p, 3); - p += 3; - degreebuff[3] = '\0'; - degree = atol(degreebuff) * 10000000; - strncpy(degreebuff, p, 2); // minutes - p += 3; // skip decimal point - strncpy(degreebuff + 2, p, 4); - degreebuff[6] = '\0'; - minutes = 50 * atol(degreebuff) / 3; - longitude_fixed = degree + minutes; - longitude = degree / 100000 + minutes * 0.000006F; - longitudeDegrees = (longitude-100*int(longitude/100))/60.0; - longitudeDegrees += int(longitude/100); - } - + parseLon(p); p = strchr(p, ',')+1; - if (',' != *p) - { - if (p[0] == 'W') longitudeDegrees *= -1.0; - if (p[0] == 'W') lon = 'W'; - else if (p[0] == 'E') lon = 'E'; - else if (p[0] == ',') lon = 0; - else return false; - } - + if(!parseLonDir(p)) return false; + p = strchr(p, ',')+1; if (',' != *p) { fixquality = atoi(p); + if(fixquality > 0){ + fix = true; + lastFix = millis(); + } else + fix = false; } p = strchr(p, ',')+1; @@ -183,86 +134,29 @@ boolean Adafruit_GPS::parse(char *nmea) { } return true; } + if (strStartsWith(nmea, "$GPRMC")) { - // found RMC - char *p = nmea; - + // found RMC // get time p = strchr(p, ',')+1; - float timef = atof(p); - uint32_t time = timef; - hour = time / 10000; - minute = (time % 10000) / 100; - seconds = (time % 100); - - milliseconds = fmod(timef, 1.0) * 1000; + parseTime(p); + // fix or no fix p = strchr(p, ',')+1; - // Serial.println(p); - if (p[0] == 'A') - fix = true; - else if (p[0] == 'V') - fix = false; - else - return false; + if(!parseFix(p)) return false; // parse out latitude p = strchr(p, ',')+1; - if (',' != *p) - { - strncpy(degreebuff, p, 2); - p += 2; - degreebuff[2] = '\0'; - long degree = atol(degreebuff) * 10000000; - strncpy(degreebuff, p, 2); // minutes - p += 3; // skip decimal point - strncpy(degreebuff + 2, p, 4); - degreebuff[6] = '\0'; - long minutes = 50 * atol(degreebuff) / 3; - latitude_fixed = degree + minutes; - latitude = degree / 100000 + minutes * 0.000006F; - latitudeDegrees = (latitude-100*int(latitude/100))/60.0; - latitudeDegrees += int(latitude/100); - } - + parseLat(p); p = strchr(p, ',')+1; - if (',' != *p) - { - if (p[0] == 'S') latitudeDegrees *= -1.0; - if (p[0] == 'N') lat = 'N'; - else if (p[0] == 'S') lat = 'S'; - else if (p[0] == ',') lat = 0; - else return false; - } + if(!parseLatDir(p)) return false; // parse out longitude p = strchr(p, ',')+1; - if (',' != *p) - { - strncpy(degreebuff, p, 3); - p += 3; - degreebuff[3] = '\0'; - degree = atol(degreebuff) * 10000000; - strncpy(degreebuff, p, 2); // minutes - p += 3; // skip decimal point - strncpy(degreebuff + 2, p, 4); - degreebuff[6] = '\0'; - minutes = 50 * atol(degreebuff) / 3; - longitude_fixed = degree + minutes; - longitude = degree / 100000 + minutes * 0.000006F; - longitudeDegrees = (longitude-100*int(longitude/100))/60.0; - longitudeDegrees += int(longitude/100); - } - + parseLon(p); p = strchr(p, ',')+1; - if (',' != *p) - { - if (p[0] == 'W') longitudeDegrees *= -1.0; - if (p[0] == 'W') lon = 'W'; - else if (p[0] == 'E') lon = 'E'; - else if (p[0] == ',') lon = 0; - else return false; - } + if(!parseLonDir(p)) return false; + // speed p = strchr(p, ',')+1; if (',' != *p) @@ -285,15 +179,65 @@ boolean Adafruit_GPS::parse(char *nmea) { month = (fulldate % 10000) / 100; year = (fulldate % 100); } - // we dont parse the remaining, yet! return true; } + if (strStartsWith(nmea, "$GPGLL")) { - // found GLL - char *p = nmea; - + // found GLL // parse out latitude p = strchr(p, ',')+1; + parseLat(p); + p = strchr(p, ',')+1; + if(!parseLatDir(p)) return false; + + // parse out longitude + p = strchr(p, ',')+1; + parseLon(p); + p = strchr(p, ',')+1; + if(!parseLonDir(p)) return false; + + // get time + p = strchr(p, ',')+1; + parseTime(p); + + // fix or no fix + p = strchr(p, ',')+1; + if(!parseFix(p)) return false; + + return true; + } + + // we dont parse the remaining, yet! + return false; +} + +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for time + @param p Pointer to the location of the token in the NMEA string +*/ +/**************************************************************************/ +void Adafruit_GPS::parseTime(char *p) { + // get time + float timef = atof(p); + uint32_t time = timef; + hour = time / 10000; + minute = (time % 10000) / 100; + seconds = (time % 100); + + milliseconds = fmod(timef, 1.0) * 1000; +} + +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for latitude angle + @param p Pointer to the location of the token in the NMEA string +*/ +/**************************************************************************/ +void Adafruit_GPS::parseLat(char *p) { + int32_t degree; + long minutes; + char degreebuff[10]; if (',' != *p) { strncpy(degreebuff, p, 2); @@ -310,8 +254,16 @@ boolean Adafruit_GPS::parse(char *nmea) { latitudeDegrees = (latitude-100*int(latitude/100))/60.0; latitudeDegrees += int(latitude/100); } +} - p = strchr(p, ',')+1; +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for latitude direction + @param p Pointer to the location of the token in the NMEA string + @return True if we parsed it, false if it has invalid data +*/ +/**************************************************************************/ +boolean Adafruit_GPS::parseLatDir(char *p) { if (',' != *p) { if (p[0] == 'S') latitudeDegrees *= -1.0; @@ -320,9 +272,19 @@ boolean Adafruit_GPS::parse(char *nmea) { else if (p[0] == ',') lat = 0; else return false; } + return true; +} - // parse out longitude - p = strchr(p, ',')+1; +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for longitude angle + @param p Pointer to the location of the token in the NMEA string +*/ +/**************************************************************************/ +void Adafruit_GPS::parseLon(char *p) { + int32_t degree; + long minutes; + char degreebuff[10]; if (',' != *p) { strncpy(degreebuff, p, 3); @@ -339,8 +301,16 @@ boolean Adafruit_GPS::parse(char *nmea) { longitudeDegrees = (longitude-100*int(longitude/100))/60.0; longitudeDegrees += int(longitude/100); } +} - p = strchr(p, ',')+1; +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for longitude direction + @param p Pointer to the location of the token in the NMEA string + @return True if we parsed it, false if it has invalid data +*/ +/**************************************************************************/ +boolean Adafruit_GPS::parseLonDir(char *p) { if (',' != *p) { if (p[0] == 'W') longitudeDegrees *= -1.0; @@ -349,30 +319,37 @@ boolean Adafruit_GPS::parse(char *nmea) { else if (p[0] == ',') lon = 0; else return false; } + return true; +} - // get time - p = strchr(p, ',')+1; - float timef = atof(p); - uint32_t time = timef; - hour = time / 10000; - minute = (time % 10000) / 100; - seconds = (time % 100); - - milliseconds = fmod(timef, 1.0) * 1000; - - p = strchr(p, ',')+1; - // Serial.println(p); - if (p[0] == 'A') +/**************************************************************************/ +/*! + @brief Parse a part of an NMEA string for whether there is a fix + @param p Pointer to the location of the token in the NMEA string + @return True if we parsed it, false if it has invalid data +*/ +/**************************************************************************/ +boolean Adafruit_GPS::parseFix(char *p) { + if (p[0] == 'A'){ fix = true; + lastFix = millis(); + } else if (p[0] == 'V') fix = false; else return false; - return true; - } +} - return false; +/**************************************************************************/ +/*! + @brief Time in seconds since the last fix was obtained. Will fail by + rolling over to zero after one millis() cycle, about 6-1/2 weeks. + @return float value in seconds since last fix. +*/ +/**************************************************************************/ +float Adafruit_GPS::timeSinceFix() { + return (millis()-lastFix) / 1000.; } /**************************************************************************/ diff --git a/Adafruit_GPS.h b/Adafruit_GPS.h index 2e2f056..5aef9d3 100755 --- a/Adafruit_GPS.h +++ b/Adafruit_GPS.h @@ -55,11 +55,15 @@ #define PMTK_SET_BAUD_57600 "$PMTK251,57600*2C" ///< 57600 bps #define PMTK_SET_BAUD_9600 "$PMTK251,9600*17" ///< 9600 bps -#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on only the second sentence (GPRMC) -#define PMTK_SET_NMEA_OUTPUT_RMCGGA "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn on GPRMC and GGA -#define PMTK_SET_NMEA_OUTPUT_GGAONLY "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on just the GGA +#define PMTK_SET_NMEA_OUTPUT_GLLONLY "$PMTK314,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on only the GPGLL sentence +#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on only the GPRMC sentence +#define PMTK_SET_NMEA_OUTPUT_VTGONLY "$PMTK314,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on only the GPVTG +#define PMTK_SET_NMEA_OUTPUT_GGAONLY "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on just the GPGGA +#define PMTK_SET_NMEA_OUTPUT_GSAONLY "$PMTK314,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on just the GPGSA +#define PMTK_SET_NMEA_OUTPUT_GSVONLY "$PMTK314,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on just the GPGSV +#define PMTK_SET_NMEA_OUTPUT_RMCGGA "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn on GPRMC and GPGGA #define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn on ALL THE DATA -#define PMTK_SET_NMEA_OUTPUT_OFF "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn off output +#define PMTK_SET_NMEA_OUTPUT_OFF "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn off output // to generate your own sentences, check out the MTK command datasheet and use a checksum calculator @@ -115,6 +119,7 @@ class Adafruit_GPS { char read(void); boolean parse(char *); + float timeSinceFix(); boolean wakeup(void); boolean standby(void); @@ -168,6 +173,13 @@ class Adafruit_GPS { uint8_t LOCUS_percent; ///< Log life used percentage private: + void parseTime(char *); + void parseLat(char *); + boolean parseLatDir(char *); + void parseLon(char *); + boolean parseLonDir(char *); + boolean parseFix(char *); + time_t lastFix; boolean paused; uint8_t parseResponse(char *response);