Merge pull request #111 from sellensr/master

Moved to src, reorganized files, added typedefs
This commit is contained in:
Matt Goodrich 2020-01-27 12:09:07 -05:00 committed by GitHub
commit 5d28fd9672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 785 additions and 495 deletions

View File

@ -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

View File

@ -53,99 +53,11 @@
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
#include <SoftwareSerial.h>
#endif
#include <Adafruit_PMTK.h>
#include <NMEA_data.h>
#include <SPI.h>
#include <Wire.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
/**************************************************************************/
/// 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

116
src/Adafruit_PMTK.h Normal file
View File

@ -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

196
src/NMEA_build.cpp Normal file
View File

@ -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 <Adafruit_GPS.h>
#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

194
src/NMEA_data.h Normal file
View File

@ -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

231
src/NMEA_parse.cpp Normal file
View File

@ -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 <Adafruit_GPS.h>
/**************************************************************************/
/*!
@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;
}