diff --git a/Adafruit_GPS.cpp b/src/Adafruit_GPS.cpp similarity index 68% rename from Adafruit_GPS.cpp rename to src/Adafruit_GPS.cpp index 6315222..9823fc4 100644 --- a/Adafruit_GPS.cpp +++ b/src/Adafruit_GPS.cpp @@ -32,206 +32,6 @@ static boolean strStartsWith(const char *str, const char *prefix); -/**************************************************************************/ -/*! - @brief Parse a NMEA string - @param nmea Pointer to the NMEA string - @return True if we parsed it, false if it has an invalid checksum or invalid - data -*/ -/**************************************************************************/ -boolean Adafruit_GPS::parse(char *nmea) { - // do checksum check - if (!check(nmea)) - return false; - // passed the check, so there's a valid source in thisSource and a valid - // sentence in thisSentence - - // look for a few common sentences - char *p = nmea; // Pointer to move through the sentence -- good parsers are - // non-destructive - p = strchr(p, ',') + - 1; // Skip to the character after the next comma, then check sentence. - - if (!strcmp(thisSentence, "GGA")) { - // found GGA - // get time - parseTime(p); - - // 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; - - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - fixquality = atoi(p); - if (fixquality > 0) { - fix = true; - lastFix = sentTime; - } else - fix = false; - } - - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - satellites = atoi(p); - } - - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - HDOP = atof(p); - } - - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - altitude = atof(p); - } - - p = strchr(p, ',') + 1; - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - geoidheight = atof(p); - } - } - - else if (!strcmp(thisSentence, "RMC")) { - // found RMC - // get time - parseTime(p); - - // fix or no fix - p = strchr(p, ',') + 1; - if (!parseFix(p)) - return false; - - // 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; - - // speed - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - speed = atof(p); - } - - // angle - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - angle = atof(p); - } - - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - uint32_t fulldate = atof(p); - day = fulldate / 10000; - month = (fulldate % 10000) / 100; - year = (fulldate % 100); - lastDate = sentTime; - } - } - - else if (!strcmp(thisSentence, "GLL")) { - // found GLL - // parse out latitude - 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; - } - - else if (!strcmp(thisSentence, "GSA")) { - // found GSA - // parse out Auto selection, but ignore them - // parse out 3d fixquality - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - fixquality_3d = atoi(p); - } - // skip 12 Satellite PDNs without interpreting them - for (int i = 0; i < 12; i++) - p = strchr(p, ',') + 1; - - // parse out PDOP - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - PDOP = atof(p); - } - // parse out HDOP, we also parse this from the GGA sentence. Chipset should - // report the same for both - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - HDOP = atof(p); - } - // parse out VDOP - p = strchr(p, ',') + 1; - if (!isEmpty(p)) { - VDOP = atof(p); - } - } - -#ifdef NMEA_EXTENSIONS // Sentences not required for basic GPS functionality - else if (!strcmp(thisSentence, "TXT")) { //*******************************TXT - if (!isEmpty(p)) - txtTot = atoi(p); - p = strchr(p, ',') + 1; - if (!isEmpty(p)) - txtN = atoi(p); - p = strchr(p, ',') + 1; - if (!isEmpty(p)) - txtID = atoi(p); - p = strchr(p, ',') + 1; - if (!isEmpty(p)) - parseStr(txtTXT, p, 61); // copy the text to NMEA TXT max of 61 characters - } -#endif // NMEA_EXTENSIONS - - // we dont parse the remaining, yet! - else - return false; - - // Record the successful parsing of where the last data came from and when - strcpy(lastSource, thisSource); - strcpy(lastSentence, thisSentence); - lastUpdate = millis(); - return true; -} - /**************************************************************************/ /*! @brief Check an NMEA string for basic format, valid source ID and valid @@ -520,28 +320,42 @@ boolean Adafruit_GPS::parseFix(char *p) { /*! @brief Time in seconds since the last position 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. + @return nmea_float_t value in seconds since last fix. */ /**************************************************************************/ -float Adafruit_GPS::secondsSinceFix() { return (millis() - lastFix) / 1000.; } +nmea_float_t Adafruit_GPS::secondsSinceFix() { + return (millis() - lastFix) / 1000.; +} /**************************************************************************/ /*! @brief Time in seconds since the last GPS time 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 GPS time. + @return nmea_float_t value in seconds since last GPS time. */ /**************************************************************************/ -float Adafruit_GPS::secondsSinceTime() { return (millis() - lastTime) / 1000.; } +nmea_float_t Adafruit_GPS::secondsSinceTime() { + return (millis() - lastTime) / 1000.; +} /**************************************************************************/ /*! @brief Time in seconds since the last GPS date 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 GPS date. + @return nmea_float_t value in seconds since last GPS date. */ /**************************************************************************/ -float Adafruit_GPS::secondsSinceDate() { return (millis() - lastDate) / 1000.; } +nmea_float_t Adafruit_GPS::secondsSinceDate() { + return (millis() - lastDate) / 1000.; +} + +/**************************************************************************/ +/*! + @brief Fakes time of receipt of a sentence. Use between build() and parse() + to make the timing look like the sentence arrived from the GPS. +*/ +/**************************************************************************/ +void Adafruit_GPS::resetSentTime() { sentTime = millis(); } /**************************************************************************/ /*! @@ -790,7 +604,7 @@ void Adafruit_GPS::common_init(void) { fix = false; // boolean milliseconds = 0; // uint16_t latitude = longitude = geoidheight = altitude = speed = angle = magvariation = - HDOP = VDOP = PDOP = 0.0; // float + HDOP = VDOP = PDOP = 0.0; // nmea_float_t } /**************************************************************************/ @@ -1045,176 +859,3 @@ static boolean strStartsWith(const char *str, const char *prefix) { } return true; } - -#ifdef NMEA_EXTENSIONS -/**************************************************************************/ -/*! - @brief Fakes time of receipt of a sentence. Use between build() and parse() - to make the timing look like the sentence arrived from the GPS. -*/ -/**************************************************************************/ -void Adafruit_GPS::resetSentTime() { sentTime = millis(); } - -/**************************************************************************/ -/*! - @brief Build an NMEA sentence string based on the relevant variables. - Sentences start with a $, then a two character source identifier, then - a three character sentence name that defines the format, then a comma - and more comma separated fields defined by the sentence name. There are - many sentences listed that are not yet supported. Most of these sentence - definitions were found at http://fort21.ru/download/NMEAdescription.pdf - - build() will work with other lengths for source and sentence to allow - extension to building proprietary sentences like $PMTK220,100*2F. - - build() will not work properly in an environment that does not support - the %f floating point formatter in sprintf(), and will return NULL. - - build() adds Carriage Return and Line Feed to sentences to conform to - NMEA-183, so send your output with a print, not a println. - - Some of the data in these test sentences may be arbitrary, e.g. for the - TXT sentence which has a more complicated protocol for multiple lines - sent as a message set. Also, the data in the class variables are presumed - to be valid, so these sentences may contain values that are stale, or - the result of initialization rather than measurement. - - @param nmea Pointer to the NMEA string buffer. Must be big enough to - hold the sentence. No guarantee what will be in it if the - building of the sentence fails. - @param thisSource Pointer to the source name string (2 upper case) - @param thisSentence Pointer to the sentence name string (3 upper case) - @param ref Reference for the sentence, usually relative (R) or true (T) - @return Pointer to sentence if successful, NULL if fails -*/ -/**************************************************************************/ -char *Adafruit_GPS::build(char *nmea, const char *thisSource, - const char *thisSentence, char ref) { - sprintf(nmea, "%6.2f", 123.45); // fail if sprintf() doesn't handle floats - if (strcmp(nmea, "123.45")) - return NULL; - *nmea = '$'; - char *p = nmea + 1; // Pointer to move through the sentence - strncpy(p, thisSource, strlen(thisSource)); - p += strlen(thisSource); - strncpy(p, thisSentence, strlen(thisSentence)); - p += strlen(thisSentence); - *p = ','; - p += 1; // Now $XXSSS, and need to add argument fields - // This may look inefficient, but an M0 will get down the list in about 1 us / - // strcmp()! Put the GPS sentences from Adafruit_GPS at the top to make - // pruning excess code easier. Otherwise, keep them alphabetical for ease of - // reading. - - if (!strcmp(thisSentence, - "GGA")) { //********************************************GGA - // GGA Global Positioning System Fix Data. Time, Position and fix related - // data for a GPS receiver - // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // | | | | | | | | | | | | | | | - //$--GGA,hhmmss.ss,ddmm.mm,a,dddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh - // 1) Time (UTC) - // 2) Latitude - // 3) N or S (North or South) - // 4) Longitude - // 5) E or W (East or West) - // 6) GPS Quality Indicator, 0 - fix not available, 1 - GPS fix, 2 - - // Differential GPS fix 7) Number of satellites in view, 00 - 12 8) - // Horizontal Dilution of precision 9) Antenna Altitude above/below - // mean-sea-level (geoid) 10) Units of antenna altitude, meters 11) Geoidal - // separation, the difference between the WGS-84 earth - // ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below - // ellipsoid - // 12) Units of geoidal separation, meters - // 13) Age of differential GPS data, time in seconds since last SC104 - // type 1 or 9 update, null field when DGPS is not used - // 14) Differential reference station ID, 0000-1023 - // 15) Checksum - sprintf(p, "%09.2f,%09.4f,%c,%010.4f,%c,%d,%02d,%f,%f,M,%f,M,,", - hour * 10000L + minute * 100L + seconds + milliseconds / 1000., - latitude, lat, longitude, lon, fixquality, satellites, HDOP, - altitude, geoidheight); - - } else if (!strcmp(thisSentence, - "GLL")) { //********************************************GLL - // GLL Geographic Position – Latitude/Longitude - // 1 2 3 4 5 6 7 - // | | | | | | | - //$--GLL,llll.ll,a,yyyyy.yy,a,hhmmss.ss,A*hh - // 1) Latitude ddmm.mm format - // 2) N or S (North or South) - // 3) Longitude dddmm.mm format - // 4) E or W (East or West) - // 5) Time (UTC) - // 6) Status A - Data Valid, V - Data Invalid - // 7) Checksum - sprintf(p, "%09.4f,%c,%010.4f,%c,%09.2f,A", latitude, lat, longitude, lon, - hour * 10000L + minute * 100L + seconds + milliseconds / 1000.); - - } else if (!strcmp(thisSentence, - "GSA")) { //******************************************** - // GSA GPS DOP and active satellites - // 1 2 3 14 15 16 17 18 - // | | | | | | | | - //$--GSA,a,a,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x.x,x.x,x.x*hh - // 1) Selection mode - // 2) Mode - // 3) ID of 1st satellite used for fix - // 4) ID of 2nd satellite used for fix - // ... - // 14) ID of 12th satellite used for fix - // 15) PDOP in meters - // 16) HDOP in meters - // 17) VDOP in meters - // 18) Checksum - return NULL; - - } else if (!strcmp(thisSentence, - "RMC")) { //********************************************RMC - // RMC Recommended Minimum Navigation Information - // 12 - // 1 2 3 4 5 6 7 8 9 10 11 | - // | | | | | | | | | | | | - //$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxxxx,x.x,a*hh - // 1) Time (UTC) - // 2) Status, V = Navigation receiver warning - // 3) Latitude - // 4) N or S - // 5) Longitude - // 6) E or W - // 7) Speed over ground, knots - // 8) Track made good, degrees true - // 9) Date, ddmmyy - // 10) Magnetic Variation, degrees - // 11) E or W - // 12) Checksum - sprintf(p, "%09.2f,A,%09.4f,%c,%010.4f,%c,%f,%f,%06d,%f,%c", - hour * 10000L + minute * 100L + seconds + milliseconds / 1000., - latitude, lat, longitude, lon, speed, angle, - day * 10000 + month * 100 + year, magvariation, mag); - - } else if (!strcmp(thisSentence, - "TXT")) { //********************************************TXT - // as mentioned in https://github.com/adafruit/Adafruit_GPS/issues/95 - // TXT Text Transmission - // 1 2 3 4 5 - // | | | | | - //$--TXT,xx,xx,xx,c--c*hh - // 1) Total Number of Sentences 01-99 - // 2) Sentence Number 01-99 - // 3) Text Identifier 01-99 - // 4) Text String, max 61 characters - // 5) Checksum - sprintf(p, "01,01,23,This is the text of the sample message"); - - } else { - return NULL; // didn't find a match for the build request - } - - addChecksum(nmea); // Successful completion - sprintf(nmea, "%s\r\n", - nmea); // Add Carriage Return and Line Feed to comply with NMEA-183 - return nmea; // return pointer to finished product -} - -#endif // NMEA_EXTENSIONS diff --git a/Adafruit_GPS.h b/src/Adafruit_GPS.h similarity index 57% rename from Adafruit_GPS.h rename to src/Adafruit_GPS.h index e752127..74b04ae 100644 --- a/Adafruit_GPS.h +++ b/src/Adafruit_GPS.h @@ -53,99 +53,11 @@ #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #include #endif +#include +#include #include #include -/**************************************************************************/ -/** - Different commands to set the update rate from once a second (1 Hz) to 10 times - a second (10Hz) Note that these only control the rate at which the position is - echoed, to actually speed up the position fix you must also send one of the - position fix rate commands below too. */ -#define PMTK_SET_NMEA_UPDATE_100_MILLIHERTZ \ - "$PMTK220,10000*2F" ///< Once every 10 seconds, 100 millihertz. -#define PMTK_SET_NMEA_UPDATE_200_MILLIHERTZ \ - "$PMTK220,5000*1B" ///< Once every 5 seconds, 200 millihertz. -#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F" ///< 1 Hz -#define PMTK_SET_NMEA_UPDATE_2HZ "$PMTK220,500*2B" ///< 2 Hz -#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C" ///< 5 Hz -#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F" ///< 10 Hz -// Position fix update rate commands. -#define PMTK_API_SET_FIX_CTL_100_MILLIHERTZ \ - "$PMTK300,10000,0,0,0,0*2C" ///< Once every 10 seconds, 100 millihertz. -#define PMTK_API_SET_FIX_CTL_200_MILLIHERTZ \ - "$PMTK300,5000,0,0,0,0*18" ///< Once every 5 seconds, 200 millihertz. -#define PMTK_API_SET_FIX_CTL_1HZ "$PMTK300,1000,0,0,0,0*1C" ///< 1 Hz -#define PMTK_API_SET_FIX_CTL_5HZ "$PMTK300,200,0,0,0,0*2F" ///< 5 Hz -// Can't fix position faster than 5 times a second! - -#define PMTK_SET_BAUD_115200 "$PMTK251,115200*1F" ///< 115200 bps -#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_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_RMCGGAGSA \ - "$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on GPRMC, GPGGA - ///< and GPGSA -#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 - -// to generate your own sentences, check out the MTK command datasheet and use a -// checksum calculator such as the awesome -// http://www.hhhh.org/wiml/proj/nmeaxor.html - -#define PMTK_LOCUS_STARTLOG "$PMTK185,0*22" ///< Start logging data -#define PMTK_LOCUS_STOPLOG "$PMTK185,1*23" ///< Stop logging data -#define PMTK_LOCUS_STARTSTOPACK \ - "$PMTK001,185,3*3C" ///< Acknowledge the start or stop command -#define PMTK_LOCUS_QUERY_STATUS "$PMTK183*38" ///< Query the logging status -#define PMTK_LOCUS_ERASE_FLASH "$PMTK184,1*22" ///< Erase the log flash data -#define LOCUS_OVERLAP \ - 0 ///< If flash is full, log will overwrite old data with new logs -#define LOCUS_FULLSTOP 1 ///< If flash is full, logging will stop - -#define PMTK_ENABLE_SBAS \ - "$PMTK313,1*2E" ///< Enable search for SBAS satellite (only works with 1Hz - ///< output rate) -#define PMTK_ENABLE_WAAS "$PMTK301,2*2E" ///< Use WAAS for DGPS correction data - -#define PMTK_STANDBY \ - "$PMTK161,0*28" ///< standby command & boot successful message -#define PMTK_STANDBY_SUCCESS "$PMTK001,161,3*36" ///< Not needed currently -#define PMTK_AWAKE "$PMTK010,002*2D" ///< Wake up - -#define PMTK_Q_RELEASE "$PMTK605*31" ///< ask for the release and version - -#define PGCMD_ANTENNA \ - "$PGCMD,33,1*6C" ///< request for updates on antenna status -#define PGCMD_NOANTENNA "$PGCMD,33,0*6D" ///< don't show antenna status messages - -#define MAXWAITSENTENCE \ - 10 ///< how long to wait when we're looking for a response -/**************************************************************************/ - /// type for resulting code from running check() typedef enum { NMEA_BAD = 0, ///< passed none of the checks @@ -189,9 +101,10 @@ public: boolean check(char *nmea); boolean parse(char *); void addChecksum(char *buff); - float secondsSinceFix(); - float secondsSinceTime(); - float secondsSinceDate(); + nmea_float_t secondsSinceFix(); + nmea_float_t secondsSinceTime(); + nmea_float_t secondsSinceDate(); + void resetSentTime(); boolean wakeup(void); boolean standby(void); @@ -216,10 +129,10 @@ public: uint8_t month; ///< GMT month uint8_t day; ///< GMT day - float latitude; ///< Floating point latitude value in degrees/minutes as - ///< received from the GPS (DDMM.MMMM) - float longitude; ///< Floating point longitude value in degrees/minutes as - ///< received from the GPS (DDDMM.MMMM) + nmea_float_t latitude; ///< Floating point latitude value in degrees/minutes + ///< as received from the GPS (DDMM.MMMM) + nmea_float_t longitude; ///< Floating point longitude value in degrees/minutes + ///< as received from the GPS (DDDMM.MMMM) /** Fixed point latitude and longitude value with degrees stored in units of 1/100000 degrees, and minutes stored in units of 1/100000 degrees. See pull @@ -228,23 +141,23 @@ public: int32_t latitude_fixed; ///< Fixed point latitude in decimal degrees int32_t longitude_fixed; ///< Fixed point longitude in decimal degrees - float latitudeDegrees; ///< Latitude in decimal degrees - float longitudeDegrees; ///< Longitude in decimal degrees - float geoidheight; ///< Diff between geoid height and WGS84 height - float altitude; ///< Altitude in meters above MSL - float speed; ///< Current speed over ground in knots - float angle; ///< Course in degrees from true north - float magvariation; ///< Magnetic variation in degrees (vs. true north) - float HDOP; ///< Horizontal Dilution of Precision - relative accuracy of - ///< horizontal position - float VDOP; ///< Vertical Dilution of Precision - relative accuracy of - ///< vertical position - float PDOP; ///< Position Dilution of Precision - Complex maths derives a - ///< simple, single number for each kind of DOP - char lat = 'X'; ///< N/S - char lon = 'X'; ///< E/W - char mag = 'X'; ///< Magnetic variation direction - boolean fix; ///< Have a fix? + nmea_float_t latitudeDegrees; ///< Latitude in decimal degrees + nmea_float_t longitudeDegrees; ///< Longitude in decimal degrees + nmea_float_t geoidheight; ///< Diff between geoid height and WGS84 height + nmea_float_t altitude; ///< Altitude in meters above MSL + nmea_float_t speed; ///< Current speed over ground in knots + nmea_float_t angle; ///< Course in degrees from true north + nmea_float_t magvariation; ///< Magnetic variation in degrees (vs. true north) + nmea_float_t HDOP; ///< Horizontal Dilution of Precision - relative accuracy + ///< of horizontal position + nmea_float_t VDOP; ///< Vertical Dilution of Precision - relative accuracy + ///< of vertical position + nmea_float_t PDOP; ///< Position Dilution of Precision - Complex maths derives + ///< a simple, single number for each kind of DOP + char lat = 'X'; ///< N/S + char lon = 'X'; ///< E/W + char mag = 'X'; ///< Magnetic variation direction + boolean fix; ///< Have a fix? uint8_t fixquality; ///< Fix quality (0, 1, 2 = Invalid, GPS, DGPS) uint8_t fixquality_3d; ///< 3D fix quality (1, 3, 3 = Nofix, 2D fix, 3D fix) uint8_t satellites; ///< Number of satellites in use @@ -270,7 +183,6 @@ public: // NMEA additional public functions char *build(char *nmea, const char *thisSource, const char *thisSentence, char ref = 'R'); - void resetSentTime(); // NMEA additional public variables char txtTXT[63] = {0}; ///< text content from most recent TXT sentence diff --git a/src/Adafruit_PMTK.h b/src/Adafruit_PMTK.h new file mode 100644 index 0000000..879f030 --- /dev/null +++ b/src/Adafruit_PMTK.h @@ -0,0 +1,116 @@ +/**************************************************************************/ +/*! + @file Adafruit_PMTK.h + + This is the Adafruit GPS library - the ultimate GPS library + for the ultimate GPS module! + + Tested and works great with the Adafruit Ultimate GPS module + using MTK33x9 chipset + ------> http://www.adafruit.com/products/746 + Pick one up today at the Adafruit electronics shop + and help support open source hardware & software! -ada + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + BSD license, check license.txt for more information + All text above must be included in any redistribution +*/ +/**************************************************************************/ + +#ifndef _ADAFRUIT_PMTK_H +#define _ADAFRUIT_PMTK_H + +/**************************************************************************/ +/** + Different commands to set the update rate from once a second (1 Hz) to 10 times + a second (10Hz) Note that these only control the rate at which the position is + echoed, to actually speed up the position fix you must also send one of the + position fix rate commands below too. */ +#define PMTK_SET_NMEA_UPDATE_100_MILLIHERTZ \ + "$PMTK220,10000*2F" ///< Once every 10 seconds, 100 millihertz. +#define PMTK_SET_NMEA_UPDATE_200_MILLIHERTZ \ + "$PMTK220,5000*1B" ///< Once every 5 seconds, 200 millihertz. +#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F" ///< 1 Hz +#define PMTK_SET_NMEA_UPDATE_2HZ "$PMTK220,500*2B" ///< 2 Hz +#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C" ///< 5 Hz +#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F" ///< 10 Hz +// Position fix update rate commands. +#define PMTK_API_SET_FIX_CTL_100_MILLIHERTZ \ + "$PMTK300,10000,0,0,0,0*2C" ///< Once every 10 seconds, 100 millihertz. +#define PMTK_API_SET_FIX_CTL_200_MILLIHERTZ \ + "$PMTK300,5000,0,0,0,0*18" ///< Once every 5 seconds, 200 millihertz. +#define PMTK_API_SET_FIX_CTL_1HZ "$PMTK300,1000,0,0,0,0*1C" ///< 1 Hz +#define PMTK_API_SET_FIX_CTL_5HZ "$PMTK300,200,0,0,0,0*2F" ///< 5 Hz +// Can't fix position faster than 5 times a second! + +#define PMTK_SET_BAUD_115200 "$PMTK251,115200*1F" ///< 115200 bps +#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_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_RMCGGAGSA \ + "$PMTK314,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" ///< turn on GPRMC, GPGGA + ///< and GPGSA +#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 + +// to generate your own sentences, check out the MTK command datasheet and use a +// checksum calculator such as the awesome +// http://www.hhhh.org/wiml/proj/nmeaxor.html + +#define PMTK_LOCUS_STARTLOG "$PMTK185,0*22" ///< Start logging data +#define PMTK_LOCUS_STOPLOG "$PMTK185,1*23" ///< Stop logging data +#define PMTK_LOCUS_STARTSTOPACK \ + "$PMTK001,185,3*3C" ///< Acknowledge the start or stop command +#define PMTK_LOCUS_QUERY_STATUS "$PMTK183*38" ///< Query the logging status +#define PMTK_LOCUS_ERASE_FLASH "$PMTK184,1*22" ///< Erase the log flash data +#define LOCUS_OVERLAP \ + 0 ///< If flash is full, log will overwrite old data with new logs +#define LOCUS_FULLSTOP 1 ///< If flash is full, logging will stop + +#define PMTK_ENABLE_SBAS \ + "$PMTK313,1*2E" ///< Enable search for SBAS satellite (only works with 1Hz + ///< output rate) +#define PMTK_ENABLE_WAAS "$PMTK301,2*2E" ///< Use WAAS for DGPS correction data + +#define PMTK_STANDBY \ + "$PMTK161,0*28" ///< standby command & boot successful message +#define PMTK_STANDBY_SUCCESS "$PMTK001,161,3*36" ///< Not needed currently +#define PMTK_AWAKE "$PMTK010,002*2D" ///< Wake up + +#define PMTK_Q_RELEASE "$PMTK605*31" ///< ask for the release and version + +#define PGCMD_ANTENNA \ + "$PGCMD,33,1*6C" ///< request for updates on antenna status +#define PGCMD_NOANTENNA "$PGCMD,33,0*6D" ///< don't show antenna status messages + +#define MAXWAITSENTENCE \ + 10 ///< how long to wait when we're looking for a response +/**************************************************************************/ +#endif diff --git a/src/NMEA_build.cpp b/src/NMEA_build.cpp new file mode 100644 index 0000000..7ca1e25 --- /dev/null +++ b/src/NMEA_build.cpp @@ -0,0 +1,196 @@ +/**************************************************************************/ +/*! + @file NMEA_build.cpp + + @mainpage Adafruit Ultimate GPS Breakout + + @section intro Introduction + + This is the Adafruit GPS library - the ultimate GPS library + for the ultimate GPS module! + + Tested and works great with the Adafruit Ultimate GPS module + using MTK33x9 chipset + ------> http://www.adafruit.com/products/746 + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + @section author Author + + Written by Limor Fried/Ladyada for Adafruit Industries. + + @section license License + + BSD license, check license.txt for more information + All text above must be included in any redistribution +*/ +/**************************************************************************/ + +#include + +#ifdef NMEA_EXTENSIONS +/**************************************************************************/ +/*! + @brief Build an NMEA sentence string based on the relevant variables. + Sentences start with a $, then a two character source identifier, then + a three character sentence name that defines the format, then a comma + and more comma separated fields defined by the sentence name. There are + many sentences listed that are not yet supported. Most of these sentence + definitions were found at http://fort21.ru/download/NMEAdescription.pdf + + build() will work with other lengths for source and sentence to allow + extension to building proprietary sentences like $PMTK220,100*2F. + + build() will not work properly in an environment that does not support + the %f floating point formatter in sprintf(), and will return NULL. + + build() adds Carriage Return and Line Feed to sentences to conform to + NMEA-183, so send your output with a print, not a println. + + Some of the data in these test sentences may be arbitrary, e.g. for the + TXT sentence which has a more complicated protocol for multiple lines + sent as a message set. Also, the data in the class variables are presumed + to be valid, so these sentences may contain values that are stale, or + the result of initialization rather than measurement. + + @param nmea Pointer to the NMEA string buffer. Must be big enough to + hold the sentence. No guarantee what will be in it if the + building of the sentence fails. + @param thisSource Pointer to the source name string (2 upper case) + @param thisSentence Pointer to the sentence name string (3 upper case) + @param ref Reference for the sentence, usually relative (R) or true (T) + @return Pointer to sentence if successful, NULL if fails +*/ +/**************************************************************************/ +char *Adafruit_GPS::build(char *nmea, const char *thisSource, + const char *thisSentence, char ref) { + sprintf(nmea, "%6.2f", 123.45); // fail if sprintf() doesn't handle floats + if (strcmp(nmea, "123.45")) + return NULL; + *nmea = '$'; + char *p = nmea + 1; // Pointer to move through the sentence + strncpy(p, thisSource, strlen(thisSource)); + p += strlen(thisSource); + strncpy(p, thisSentence, strlen(thisSentence)); + p += strlen(thisSentence); + *p = ','; + p += 1; // Now $XXSSS, and need to add argument fields + // This may look inefficient, but an M0 will get down the list in about 1 us / + // strcmp()! Put the GPS sentences from Adafruit_GPS at the top to make + // pruning excess code easier. Otherwise, keep them alphabetical for ease of + // reading. + + if (!strcmp(thisSentence, + "GGA")) { //********************************************GGA + // GGA Global Positioning System Fix Data. Time, Position and fix related + // data for a GPS receiver + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // | | | | | | | | | | | | | | | + //$--GGA,hhmmss.ss,ddmm.mm,a,dddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh + // 1) Time (UTC) + // 2) Latitude + // 3) N or S (North or South) + // 4) Longitude + // 5) E or W (East or West) + // 6) GPS Quality Indicator, 0 - fix not available, 1 - GPS fix, 2 - + // Differential GPS fix 7) Number of satellites in view, 00 - 12 8) + // Horizontal Dilution of precision 9) Antenna Altitude above/below + // mean-sea-level (geoid) 10) Units of antenna altitude, meters 11) Geoidal + // separation, the difference between the WGS-84 earth + // ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below + // ellipsoid + // 12) Units of geoidal separation, meters + // 13) Age of differential GPS data, time in seconds since last SC104 + // type 1 or 9 update, null field when DGPS is not used + // 14) Differential reference station ID, 0000-1023 + // 15) Checksum + sprintf(p, "%09.2f,%09.4f,%c,%010.4f,%c,%d,%02d,%f,%f,M,%f,M,,", + hour * 10000L + minute * 100L + seconds + milliseconds / 1000., + latitude, lat, longitude, lon, fixquality, satellites, HDOP, + altitude, geoidheight); + + } else if (!strcmp(thisSentence, + "GLL")) { //********************************************GLL + // GLL Geographic Position – Latitude/Longitude + // 1 2 3 4 5 6 7 + // | | | | | | | + //$--GLL,llll.ll,a,yyyyy.yy,a,hhmmss.ss,A*hh + // 1) Latitude ddmm.mm format + // 2) N or S (North or South) + // 3) Longitude dddmm.mm format + // 4) E or W (East or West) + // 5) Time (UTC) + // 6) Status A - Data Valid, V - Data Invalid + // 7) Checksum + sprintf(p, "%09.4f,%c,%010.4f,%c,%09.2f,A", latitude, lat, longitude, lon, + hour * 10000L + minute * 100L + seconds + milliseconds / 1000.); + + } else if (!strcmp(thisSentence, + "GSA")) { //******************************************** + // GSA GPS DOP and active satellites + // 1 2 3 14 15 16 17 18 + // | | | | | | | | + //$--GSA,a,a,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x.x,x.x,x.x*hh + // 1) Selection mode + // 2) Mode + // 3) ID of 1st satellite used for fix + // 4) ID of 2nd satellite used for fix + // ... + // 14) ID of 12th satellite used for fix + // 15) PDOP in meters + // 16) HDOP in meters + // 17) VDOP in meters + // 18) Checksum + return NULL; + + } else if (!strcmp(thisSentence, + "RMC")) { //********************************************RMC + // RMC Recommended Minimum Navigation Information + // 12 + // 1 2 3 4 5 6 7 8 9 10 11 | + // | | | | | | | | | | | | + //$--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxxxx,x.x,a*hh + // 1) Time (UTC) + // 2) Status, V = Navigation receiver warning + // 3) Latitude + // 4) N or S + // 5) Longitude + // 6) E or W + // 7) Speed over ground, knots + // 8) Track made good, degrees true + // 9) Date, ddmmyy + // 10) Magnetic Variation, degrees + // 11) E or W + // 12) Checksum + sprintf(p, "%09.2f,A,%09.4f,%c,%010.4f,%c,%f,%f,%06d,%f,%c", + hour * 10000L + minute * 100L + seconds + milliseconds / 1000., + latitude, lat, longitude, lon, speed, angle, + day * 10000 + month * 100 + year, magvariation, mag); + + } else if (!strcmp(thisSentence, + "TXT")) { //********************************************TXT + // as mentioned in https://github.com/adafruit/Adafruit_GPS/issues/95 + // TXT Text Transmission + // 1 2 3 4 5 + // | | | | | + //$--TXT,xx,xx,xx,c--c*hh + // 1) Total Number of Sentences 01-99 + // 2) Sentence Number 01-99 + // 3) Text Identifier 01-99 + // 4) Text String, max 61 characters + // 5) Checksum + sprintf(p, "01,01,23,This is the text of the sample message"); + + } else { + return NULL; // didn't find a match for the build request + } + + addChecksum(nmea); // Successful completion + sprintf(nmea, "%s\r\n", + nmea); // Add Carriage Return and Line Feed to comply with NMEA-183 + return nmea; // return pointer to finished product +} + +#endif // NMEA_EXTENSIONS diff --git a/src/NMEA_data.h b/src/NMEA_data.h new file mode 100644 index 0000000..27e6396 --- /dev/null +++ b/src/NMEA_data.h @@ -0,0 +1,194 @@ +/**************************************************************************/ +/*! + @file NMEA_data.h +*/ +/**************************************************************************/ +#ifndef _NMEA_DATA_H +#define _NMEA__DATA_H +#include "Arduino.h" + +#define NMEA_MAX_WP_ID \ + 20 ///< maximum length of a waypoint ID name, including terminating 0 +#define NMEA_MAX_SENTENCE_ID \ + 20 ///< maximum length of a sentence ID name, including terminating 0 +#define NMEA_MAX_SOURCE_ID \ + 3 ///< maximum length of a source ID name, including terminating 0 + +/************************************************************************* + doubles and floats are identical on AVR processors like the UNO where space + is tight. doubles avoid the roundoff errors that led to the fixed point mods + in https://github.com/adafruit/Adafruit-GPS-Library/pull/13, provided the + processor supports actual doubles like the SAMD series with more storage. The + total penalty for going all double is under a few hundred bytes / instance or + 0 bytes / instance on an UNO. This typedef allows a switch to lower precision + to save some storage if needed. A float carries 23 bits of fractional + resolution, giving a resolution of at least 9 significant digits, thus 6 + significant digits in the decimal place of an angular value like latitude, and + thus a resolution on earth of at least 110 mm. That's closer than GPS will + hit, and closer than needed for navigation, so floats can be used to save a + little storage. + **************************************************************************/ +#ifndef NMEA_FLOAT_T +#define NMEA_FLOAT_T float ///< let float be overidden on command line +#endif +typedef NMEA_FLOAT_T + nmea_float_t; ///< the type of variables to use for floating point + +/**************************************************************************/ +/*! + Struct to contain all the details associated with the history of an NMEA + data value as an optional extension to the data value struct. The history + is stored as scaled integers to save space while caputuring a reasonable + level of resolution. The integer is set equal to scale * (X - offset) and + can be converted back to an approximate float value with + X = I / scale + offset + + Only some tags have history in order to save memory. Most of the memory + cost is directly in the array. + + 192 history values taken every 20 seconds covers just over an hour. + **************************************************************************/ +typedef struct { + int16_t *data = NULL; ///< array of ints, oldest first + unsigned n = 0; ///< number of history array elements + uint32_t lastHistory = 0; ///< millis() when history was last updated + uint16_t historyInterval = 20; ///< seconds between history updates + nmea_float_t scale = 1.0; ///< history = (smoothed - offset) * scale + nmea_float_t offset = 0.0; ///< value = (float) history / scale + offset +} nmea_history_t; + +/**************************************************************************/ +/*! + Type to characterize the type of value stored in a data value struct. + The sine and cosine components of some angles allow + for smoothing of those angles by averaging of sine and cosine values + that are continuous, rather than angles that are discontinuous at + -180/180 or 359/0 transitions. Types 10-19 must have three contiguous + data value entries set up in the matrix to accommodate the extra sin + and cos values. + */ +/**************************************************************************/ +typedef enum { + NMEA_SIMPLE_FLOAT = 0, ///< A simple floating point number + NMEA_COMPASS_ANGLE = 1, ///< A compass style angle from 0 to 360 degrees + NMEA_BOAT_ANGLE = 2, ///< An angle relative to the boat orientation + ///< from -180 (port) to 180 degrees + NMEA_COMPASS_ANGLE_SIN = + 11, ///< A compass style angle from 0 to 360 degrees, with sin and cos + ///< elements stored for averaging, etc. + NMEA_BOAT_ANGLE_SIN = + 12, ///< An angle relative to the boat orientation from -180 (port) to 180 + ///< degrees, with sin and cos elements stored for averaging, etc. + NMEA_DDMM = 20, ///< A latitude or longitude angle stored in DDMM.mmmm format + ///< like it comes in from the GPS + NMEA_HHMMSS = + 30 ///< A time stored in HHMMSS format like it comes in from the GPS +} nmea_value_type_t; + +/**************************************************************************/ +/*! + Struct to contain all the details associated with an NMEA data value that + can be tracked through time to see how it changes, carries a label, units, + and a format string to determine how it is displayed. Memory footprint + of about 32 bytes per data value, so not tenable in small memory spaces. +*/ +/**************************************************************************/ +typedef struct { + nmea_float_t latest = 0.0; ///< the most recently obtained value + nmea_float_t smoothed = + 0.0; ///< smoothed value based on weight of dt/response + uint32_t lastUpdate = 0; ///< millis() when latest was last set + uint16_t response = 1000; ///< time constant in millis for smoothing + nmea_value_type_t type = + NMEA_SIMPLE_FLOAT; ///< type of float data value represented + byte ockam = 0; ///< the corresponding Ockam Instruments tag number, 0-128 + nmea_history_t *hist = NULL; ///< pointer to history, if any + char *label = NULL; ///< pointer to quantity label, if any + char *unit = NULL; ///< pointer to units label, if any + char *fmt = NULL; ///< pointer to format string, if any +} nmea_datavalue_t; + +/**************************************************************************/ +/*! + Type to provide an index into the array of data values for different + NMEA quantities. The sine and cosine components of some angles allow + for smoothing of those angles by averaging of sine and cosine values + that are continuous, rather than angles that are discontinuous at + -180/180 or 359/0 transitions. Note that the enumerations are arranged + so that NMEA_XXX_SIN = NMEA_XXX + 1, and NMEA_XXX_COS = NMEA_XXX + 2. + */ +/**************************************************************************/ +typedef enum { + NMEA_HDOP = 0, ///< Horizontal Dilution of Position + NMEA_LAT, ///< Latitude in signed decimal degrees -90 to 90 + NMEA_LON, ///< Longitude in signed decimal degrees -180 to 180 + NMEA_LATWP, ///< Waypoint Latitude in signed decimal degrees -90 to 90 + NMEA_LONWP, ///< Waypoint Longitude in signed decimal degrees -180 to 180 + NMEA_SOG, ///< Speed over Ground in knots + NMEA_COG, ///< Course over ground, 0 to 360 degrees true + NMEA_COG_SIN, ///< sine of Course over ground + NMEA_COG_COS, ///< cosine of Course over ground + NMEA_COGWP, ///< Course over ground to the waypoint, 0 to 360 degrees true + NMEA_XTE, ///< Cross track error for the current segment to the waypoint, + ///< Nautical Miles -ve to the left + NMEA_DISTWP, ///< Distance to the waypoint in nautical miles + NMEA_AWA, ///< apparent wind angle relative to the boat -180 to 180 degrees + NMEA_AWA_SIN, ///< sine of apparent wind angle relative to the boat + NMEA_AWA_COS, ///< cosine of apparent wind angle relative to the boat + NMEA_AWS, ///< apparent wind speed, will be coerced to knots + NMEA_TWA, ///< true wind angle relative to the boat -180 to 180 degrees + NMEA_TWA_SIN, ///< sine of true wind angle relative to the boat + NMEA_TWA_COS, ///< cosine of true wind angle relative to the boat + NMEA_TWD, ///< true wind compass direction, magnetic 0 to 360 degrees magnetic + NMEA_TWD_SIN, ///< sine of true wind compass direction, magnetic + NMEA_TWD_COS, ///< cosine of true wind compass direction, magnetic + NMEA_TWS, ///< true wind speed in knots TWS + NMEA_VMG, ///< velocity made good relative to the wind -ve means downwind, + ///< knots + NMEA_VMGWP, ///< velocity made good relative to the waypoint, knots + NMEA_HEEL, ///< boat heel angle, -180 to 180 degrees to starboard + NMEA_PITCH, ///< boat pitch angle, -180 to 180 degrees bow up + NMEA_HDG, ///< magnetic heading, 0 to 360 degrees magnetic + NMEA_HDG_SIN, ///< sine of magnetic heading + NMEA_HDG_COS, ///< cosine of magnetic heading + NMEA_HDT, ///< true heading, 0 to 360 degrees true + NMEA_HDT_SIN, ///< sine of true heading + NMEA_HDT_COS, ///< cosine of true heading + NMEA_VTW, ///< Boat speed through the water in knots + NMEA_LOG, ///< Distance logged through the water in nautical miles + NMEA_LOGR, ///< Distance logged through the water in nautical miles since + ///< reset + NMEA_DEPTH, ///< depth of water below the surface in metres + NMEA_RPM_M1, ///< rpm of motor 1 + NMEA_TEMPERATURE_M1, ///< temperature of motor 1 in C + NMEA_PRESSURE_M1, ///< pressure of motor 1 in kPa + NMEA_VOLTAGE_M1, ///< voltage of motor 1 in Volts + NMEA_CURRENT_M1, ///< current of motor 1 in Amps + NMEA_RPM_M2, ///< rpm of motor 2 + NMEA_TEMPERATURE_M2, ///< temperature of motor 2 in C + NMEA_PRESSURE_M2, ///< pressure of motor 2 in kPa + NMEA_VOLTAGE_M2, ///< voltage of motor 2 in Volts + NMEA_CURRENT_M2, ///< current of motor 2 in Amps + NMEA_TEMPERATURE_AIR, ///< outside temperature in C + NMEA_TEMPERATURE_WATER, ///< sea water temperature in C + NMEA_HUMIDITY, ///< outside relative humidity in % + NMEA_BAROMETER, ///< barometric pressure in Pa absolute -- not altitude + ///< corrected + NMEA_USR_00, ///< spaces for a user sketch to inject its own data + NMEA_USR_01, ///< spaces for a user sketch to inject its own data + NMEA_USR_02, ///< spaces for a user sketch to inject its own data + NMEA_USR_03, + NMEA_USR_04, + NMEA_USR_05, + NMEA_USR_06, + NMEA_USR_07, + NMEA_USR_08, + NMEA_USR_09, + NMEA_USR_10, + NMEA_USR_11, + NMEA_USR_12, + NMEA_MAX_INDEX ///< the largest number in the enum type -- not for data, + ///< but does define size of data value array required. +} nmea_index_t; ///< Indices for data values expected to change often with time + +#endif // _NMEA_DATA_H diff --git a/src/NMEA_parse.cpp b/src/NMEA_parse.cpp new file mode 100644 index 0000000..f48cee0 --- /dev/null +++ b/src/NMEA_parse.cpp @@ -0,0 +1,231 @@ +/**************************************************************************/ +/*! + @file NMEA_parse.cpp + + @mainpage Adafruit Ultimate GPS Breakout + + @section intro Introduction + + This is the Adafruit GPS library - the ultimate GPS library + for the ultimate GPS module! + + Tested and works great with the Adafruit Ultimate GPS module + using MTK33x9 chipset + ------> http://www.adafruit.com/products/746 + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + @section author Author + + Written by Limor Fried/Ladyada for Adafruit Industries. + + @section license License + + BSD license, check license.txt for more information + All text above must be included in any redistribution +*/ +/**************************************************************************/ + +#include + +/**************************************************************************/ +/*! + @brief Parse a NMEA string + @param nmea Pointer to the NMEA string + @return True if we parsed it, false if it has an invalid checksum or invalid + data +*/ +/**************************************************************************/ +boolean Adafruit_GPS::parse(char *nmea) { + // do checksum check + if (!check(nmea)) + return false; + // passed the check, so there's a valid source in thisSource and a valid + // sentence in thisSentence + + // look for a few common sentences + char *p = nmea; // Pointer to move through the sentence -- good parsers are + // non-destructive + p = strchr(p, ',') + + 1; // Skip to the character after the next comma, then check sentence. + + if (!strcmp(thisSentence, "GGA")) { + // found GGA + // get time + parseTime(p); + + // 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; + + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + fixquality = atoi(p); + if (fixquality > 0) { + fix = true; + lastFix = sentTime; + } else + fix = false; + } + + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + satellites = atoi(p); + } + + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + HDOP = atof(p); + } + + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + altitude = atof(p); + } + + p = strchr(p, ',') + 1; + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + geoidheight = atof(p); + } + } + + else if (!strcmp(thisSentence, "RMC")) { + // found RMC + // get time + parseTime(p); + + // fix or no fix + p = strchr(p, ',') + 1; + if (!parseFix(p)) + return false; + + // 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; + + // speed + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + speed = atof(p); + } + + // angle + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + angle = atof(p); + } + + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + uint32_t fulldate = atof(p); + day = fulldate / 10000; + month = (fulldate % 10000) / 100; + year = (fulldate % 100); + lastDate = sentTime; + } + } + + else if (!strcmp(thisSentence, "GLL")) { + // found GLL + // parse out latitude + 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; + } + + else if (!strcmp(thisSentence, "GSA")) { + // found GSA + // parse out Auto selection, but ignore them + // parse out 3d fixquality + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + fixquality_3d = atoi(p); + } + // skip 12 Satellite PDNs without interpreting them + for (int i = 0; i < 12; i++) + p = strchr(p, ',') + 1; + + // parse out PDOP + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + PDOP = atof(p); + } + // parse out HDOP, we also parse this from the GGA sentence. Chipset should + // report the same for both + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + HDOP = atof(p); + } + // parse out VDOP + p = strchr(p, ',') + 1; + if (!isEmpty(p)) { + VDOP = atof(p); + } + } + +#ifdef NMEA_EXTENSIONS // Sentences not required for basic GPS functionality + else if (!strcmp(thisSentence, "TXT")) { //*******************************TXT + if (!isEmpty(p)) + txtTot = atoi(p); + p = strchr(p, ',') + 1; + if (!isEmpty(p)) + txtN = atoi(p); + p = strchr(p, ',') + 1; + if (!isEmpty(p)) + txtID = atoi(p); + p = strchr(p, ',') + 1; + if (!isEmpty(p)) + parseStr(txtTXT, p, 61); // copy the text to NMEA TXT max of 61 characters + } +#endif // NMEA_EXTENSIONS + + // we dont parse the remaining, yet! + else + return false; + + // Record the successful parsing of where the last data came from and when + strcpy(lastSource, thisSource); + strcpy(lastSentence, thisSentence); + lastUpdate = millis(); + return true; +} \ No newline at end of file