This commit is contained in:
ladyada 2020-01-17 16:18:09 -05:00
parent 418d265a74
commit e4eb78f41c
2 changed files with 507 additions and 444 deletions

View File

@ -30,116 +30,118 @@
#include <Adafruit_GPS.h> #include <Adafruit_GPS.h>
static boolean strStartsWith(const char* str, const char* prefix); static boolean strStartsWith(const char *str, const char *prefix);
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Parse a NMEA string @brief Parse a NMEA string
@param nmea Pointer to the 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 @return True if we parsed it, false if it has an invalid checksum or invalid
data
*/ */
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::parse(char *nmea) { boolean Adafruit_GPS::parse(char *nmea) {
// do checksum check // do checksum check
if(!check(nmea)) return false; if (!check(nmea))
// passed the check, so there's a valid source in thisSource and a valid sentence in thisSentence 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 // look for a few common sentences
char *p = nmea; // Pointer to move through the sentence -- good parsers are non-destructive char *p = nmea; // Pointer to move through the sentence -- good parsers are
p = strchr(p, ',')+1; // Skip to the character after the next comma, then check sentence. // non-destructive
p = strchr(p, ',') +
1; // Skip to the character after the next comma, then check sentence.
if (!strcmp(thisSentence,"GGA")) { if (!strcmp(thisSentence, "GGA")) {
// found GGA // found GGA
// get time // get time
parseTime(p); parseTime(p);
// parse out latitude // parse out latitude
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseLat(p); parseLat(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLatDir(p)) return false; if (!parseLatDir(p))
return false;
// parse out longitude // parse out longitude
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseLon(p); parseLon(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLonDir(p)) return false; if (!parseLonDir(p))
return false;
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
fixquality = atoi(p); fixquality = atoi(p);
if(fixquality > 0){ if (fixquality > 0) {
fix = true; fix = true;
lastFix = sentTime; lastFix = sentTime;
} else } else
fix = false; fix = false;
} }
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
satellites = atoi(p); satellites = atoi(p);
} }
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
HDOP = atof(p); HDOP = atof(p);
} }
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
altitude = atof(p); altitude = atof(p);
} }
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
geoidheight = atof(p); geoidheight = atof(p);
} }
} }
else if (!strcmp(thisSentence,"RMC")) { else if (!strcmp(thisSentence, "RMC")) {
// found RMC // found RMC
// get time // get time
parseTime(p); parseTime(p);
// fix or no fix // fix or no fix
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseFix(p)) return false; if (!parseFix(p))
return false;
// parse out latitude // parse out latitude
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseLat(p); parseLat(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLatDir(p)) return false; if (!parseLatDir(p))
return false;
// parse out longitude // parse out longitude
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseLon(p); parseLon(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLonDir(p)) return false; if (!parseLonDir(p))
return false;
// speed // speed
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
speed = atof(p); speed = atof(p);
} }
// angle // angle
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
angle = atof(p); angle = atof(p);
} }
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
uint32_t fulldate = atof(p); uint32_t fulldate = atof(p);
day = fulldate / 10000; day = fulldate / 10000;
month = (fulldate % 10000) / 100; month = (fulldate % 10000) / 100;
@ -148,67 +150,68 @@ boolean Adafruit_GPS::parse(char *nmea) {
} }
} }
else if (!strcmp(thisSentence,"GLL")) { else if (!strcmp(thisSentence, "GLL")) {
// found GLL // found GLL
// parse out latitude // parse out latitude
parseLat(p); parseLat(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLatDir(p)) return false; if (!parseLatDir(p))
return false;
// parse out longitude // parse out longitude
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseLon(p); parseLon(p);
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseLonDir(p)) return false; if (!parseLonDir(p))
return false;
// get time // get time
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
parseTime(p); parseTime(p);
// fix or no fix // fix or no fix
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if(!parseFix(p)) return false; if (!parseFix(p))
return false;
} }
else if (!strcmp(thisSentence,"GSA")) { else if (!strcmp(thisSentence, "GSA")) {
// found GSA // found GSA
// parse out Auto selection, but ignore them // parse out Auto selection, but ignore them
// parse out 3d fixquality // parse out 3d fixquality
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
fixquality_3d = atoi(p); fixquality_3d = atoi(p);
} }
// skip 12 Satellite PDNs without interpreting them // skip 12 Satellite PDNs without interpreting them
for(int i = 0;i < 12;i++) p = strchr(p, ',')+1; for (int i = 0; i < 12; i++)
p = strchr(p, ',') + 1;
//parse out PDOP // parse out PDOP
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
PDOP = atof(p); PDOP = atof(p);
} }
// parse out HDOP, we also parse this from the GGA sentence. Chipset should report the same for both // parse out HDOP, we also parse this from the GGA sentence. Chipset should
p = strchr(p, ',')+1; // report the same for both
if (',' != *p) p = strchr(p, ',') + 1;
{ if (',' != *p) {
HDOP = atof(p); HDOP = atof(p);
} }
// parse out VDOP // parse out VDOP
p = strchr(p, ',')+1; p = strchr(p, ',') + 1;
if (',' != *p) if (',' != *p) {
{
VDOP = atof(p); VDOP = atof(p);
} }
} }
// we dont parse the remaining, yet! // we dont parse the remaining, yet!
else return false; else
return false;
// Record the successful parsing of where the last data came from and when // Record the successful parsing of where the last data came from and when
strcpy(lastSource,thisSource); strcpy(lastSource, thisSource);
strcpy(lastSentence,thisSentence); strcpy(lastSentence, thisSentence);
lastUpdate = millis(); lastUpdate = millis();
return true; return true;
} }
@ -224,38 +227,48 @@ boolean Adafruit_GPS::parse(char *nmea) {
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::check(char *nmea) { boolean Adafruit_GPS::check(char *nmea) {
thisCheck = 0; // new check thisCheck = 0; // new check
if(*nmea != '$') return false; // doesn't start with $ if (*nmea != '$')
else thisCheck += NMEA_HAS_DOLLAR; return false; // doesn't start with $
// do checksum check -- first look if we even have one -- ignore all but last * else
thisCheck += NMEA_HAS_DOLLAR;
// do checksum check -- first look if we even have one -- ignore all but last
// *
char *ast = nmea; // not strchr(nmea,'*'); for first * char *ast = nmea; // not strchr(nmea,'*'); for first *
while(*ast) ast++; // go to the end while (*ast)
while(*ast != '*' && ast > nmea) ast--; // then back to * if it's there ast++; // go to the end
if (*ast != '*') return false; // there is no asterisk while (*ast != '*' && ast > nmea)
ast--; // then back to * if it's there
if (*ast != '*')
return false; // there is no asterisk
else { else {
uint16_t sum = parseHex(*(ast+1)) * 16; // extract checksum uint16_t sum = parseHex(*(ast + 1)) * 16; // extract checksum
sum += parseHex(*(ast+2)); sum += parseHex(*(ast + 2));
char *p = nmea; // check checksum char *p = nmea; // check checksum
for (char *p1 = p+1; p1 < ast; p1++) sum ^= *p1; for (char *p1 = p + 1; p1 < ast; p1++)
if (sum != 0) return false; // bad checksum :( sum ^= *p1;
else thisCheck += NMEA_HAS_CHECKSUM; if (sum != 0)
return false; // bad checksum :(
else
thisCheck += NMEA_HAS_CHECKSUM;
} }
// extract source of variable length // extract source of variable length
char *p = nmea +1; char *p = nmea + 1;
const char *src = tokenOnList(p,sources); const char *src = tokenOnList(p, sources);
if(src){ if (src) {
strcpy(thisSource,src); strcpy(thisSource, src);
thisCheck += NMEA_HAS_SOURCE; thisCheck += NMEA_HAS_SOURCE;
} else return false; } else
return false;
p += strlen(src); p += strlen(src);
// extract sentence id and check if parsed // extract sentence id and check if parsed
const char *snc = tokenOnList(p,sentences_parsed); const char *snc = tokenOnList(p, sentences_parsed);
if(snc){ if (snc) {
strcpy(thisSentence,snc); strcpy(thisSentence, snc);
thisCheck += NMEA_HAS_SENTENCE_P + NMEA_HAS_SENTENCE; thisCheck += NMEA_HAS_SENTENCE_P + NMEA_HAS_SENTENCE;
} else { // check if known } else { // check if known
snc = tokenOnList(p,sentences_known); snc = tokenOnList(p, sentences_known);
if(snc){ if (snc) {
strcpy(thisSentence,snc); strcpy(thisSentence, snc);
thisCheck += NMEA_HAS_SENTENCE; thisCheck += NMEA_HAS_SENTENCE;
return false; return false;
} }
@ -271,11 +284,13 @@ boolean Adafruit_GPS::check(char *nmea) {
@return Pointer to the found token, or NULL if it fails @return Pointer to the found token, or NULL if it fails
*/ */
/**************************************************************************/ /**************************************************************************/
const char * Adafruit_GPS::tokenOnList(char *token, const char **list) { const char *Adafruit_GPS::tokenOnList(char *token, const char **list) {
int i = 0; // index in the list int i = 0; // index in the list
while(strncmp(list[i],"ZZ",2) && i < 1000){ // stop at terminator and don't crash without it while (strncmp(list[i], "ZZ", 2) &&
i < 1000) { // stop at terminator and don't crash without it
// test for a match on the sentence name // test for a match on the sentence name
if(!strncmp((const char *)list[i],(const char *)token,strlen(list[i]))) return list[i]; if (!strncmp((const char *)list[i], (const char *)token, strlen(list[i])))
return list[i];
i++; i++;
} }
return NULL; // couldn't find a match return NULL; // couldn't find a match
@ -292,14 +307,14 @@ const char * Adafruit_GPS::tokenOnList(char *token, const char **list) {
@return none @return none
*/ */
/**************************************************************************/ /**************************************************************************/
void Adafruit_GPS::addChecksum(char *buff){ void Adafruit_GPS::addChecksum(char *buff) {
char cs = 0; char cs = 0;
int i = 1; int i = 1;
while(buff[i]){ while (buff[i]) {
cs ^= buff[i]; cs ^= buff[i];
i++; i++;
} }
sprintf(buff,"%s*%02X",buff,cs); sprintf(buff, "%s*%02X", buff, cs);
} }
/**************************************************************************/ /**************************************************************************/
@ -315,7 +330,7 @@ void Adafruit_GPS::parseTime(char *p) {
minute = (time % 10000) / 100; minute = (time % 10000) / 100;
seconds = (time % 100); seconds = (time % 100);
p = strchr(p, '.')+1; p = strchr(p, '.') + 1;
milliseconds = atoi(p); milliseconds = atoi(p);
lastTime = sentTime; lastTime = sentTime;
} }
@ -330,8 +345,7 @@ void Adafruit_GPS::parseLat(char *p) {
int32_t degree; int32_t degree;
long minutes; long minutes;
char degreebuff[10]; char degreebuff[10];
if (',' != *p) if (',' != *p) {
{
strncpy(degreebuff, p, 2); strncpy(degreebuff, p, 2);
p += 2; p += 2;
degreebuff[2] = '\0'; degreebuff[2] = '\0';
@ -343,8 +357,8 @@ void Adafruit_GPS::parseLat(char *p) {
long minutes = 50 * atol(degreebuff) / 3; long minutes = 50 * atol(degreebuff) / 3;
latitude_fixed = degree + minutes; latitude_fixed = degree + minutes;
latitude = degree / 100000 + minutes * 0.000006F; latitude = degree / 100000 + minutes * 0.000006F;
latitudeDegrees = (latitude-100*int(latitude/100))/60.0; latitudeDegrees = (latitude - 100 * int(latitude / 100)) / 60.0;
latitudeDegrees += int(latitude/100); latitudeDegrees += int(latitude / 100);
} }
} }
@ -380,8 +394,7 @@ void Adafruit_GPS::parseLon(char *p) {
int32_t degree; int32_t degree;
long minutes; long minutes;
char degreebuff[10]; char degreebuff[10];
if (',' != *p) if (',' != *p) {
{
strncpy(degreebuff, p, 3); strncpy(degreebuff, p, 3);
p += 3; p += 3;
degreebuff[3] = '\0'; degreebuff[3] = '\0';
@ -393,8 +406,8 @@ void Adafruit_GPS::parseLon(char *p) {
minutes = 50 * atol(degreebuff) / 3; minutes = 50 * atol(degreebuff) / 3;
longitude_fixed = degree + minutes; longitude_fixed = degree + minutes;
longitude = degree / 100000 + minutes * 0.000006F; longitude = degree / 100000 + minutes * 0.000006F;
longitudeDegrees = (longitude-100*int(longitude/100))/60.0; longitudeDegrees = (longitude - 100 * int(longitude / 100)) / 60.0;
longitudeDegrees += int(longitude/100); longitudeDegrees += int(longitude / 100);
} }
} }
@ -406,8 +419,7 @@ void Adafruit_GPS::parseLon(char *p) {
*/ */
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::parseLonDir(char *p) { boolean Adafruit_GPS::parseLonDir(char *p) {
if (',' != *p) if (',' != *p) {
{
if (p[0] == 'W') { if (p[0] == 'W') {
lon = 'W'; lon = 'W';
longitudeDegrees *= -1.0; longitudeDegrees *= -1.0;
@ -431,11 +443,10 @@ boolean Adafruit_GPS::parseLonDir(char *p) {
*/ */
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::parseFix(char *p) { boolean Adafruit_GPS::parseFix(char *p) {
if (p[0] == 'A'){ if (p[0] == 'A') {
fix = true; fix = true;
lastFix = sentTime; lastFix = sentTime;
} } else if (p[0] == 'V')
else if (p[0] == 'V')
fix = false; fix = false;
else else
return false; return false;
@ -449,9 +460,7 @@ boolean Adafruit_GPS::parseFix(char *p) {
@return float value in seconds since last fix. @return float value in seconds since last fix.
*/ */
/**************************************************************************/ /**************************************************************************/
float Adafruit_GPS::secondsSinceFix() { float Adafruit_GPS::secondsSinceFix() { return (millis() - lastFix) / 1000.; }
return (millis()-lastFix) / 1000.;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -460,9 +469,7 @@ float Adafruit_GPS::secondsSinceFix() {
@return float value in seconds since last GPS time. @return float value in seconds since last GPS time.
*/ */
/**************************************************************************/ /**************************************************************************/
float Adafruit_GPS::secondsSinceTime() { float Adafruit_GPS::secondsSinceTime() { return (millis() - lastTime) / 1000.; }
return (millis()-lastTime) / 1000.;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -471,18 +478,18 @@ float Adafruit_GPS::secondsSinceTime() {
@return float value in seconds since last GPS date. @return float value in seconds since last GPS date.
*/ */
/**************************************************************************/ /**************************************************************************/
float Adafruit_GPS::secondsSinceDate() { float Adafruit_GPS::secondsSinceDate() { return (millis() - lastDate) / 1000.; }
return (millis()-lastDate) / 1000.;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief How many bytes are available to read - part of 'Print'-class functionality @brief How many bytes are available to read - part of 'Print'-class
functionality
@return Bytes available, 0 if none @return Bytes available, 0 if none
*/ */
/**************************************************************************/ /**************************************************************************/
size_t Adafruit_GPS::available(void) { size_t Adafruit_GPS::available(void) {
if (paused) return 0; if (paused)
return 0;
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
if (gpsSwSerial) { if (gpsSwSerial) {
@ -493,14 +500,16 @@ size_t Adafruit_GPS::available(void) {
return gpsHwSerial->available(); return gpsHwSerial->available();
} }
if (gpsI2C || gpsSPI) { if (gpsI2C || gpsSPI) {
return 1; // I2C/SPI doesnt have 'availability' so always has a byte at least to read! return 1; // I2C/SPI doesnt have 'availability' so always has a byte at
// least to read!
} }
return 0; return 0;
} }
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Write a byte to the underlying transport - part of 'Print'-class functionality @brief Write a byte to the underlying transport - part of 'Print'-class
functionality
@param c A single byte to send @param c A single byte to send
@return Bytes written - 1 on success, 0 on failure @return Bytes written - 1 on success, 0 on failure
*/ */
@ -550,10 +559,11 @@ char Adafruit_GPS::read(void) {
uint32_t tStart = millis(); // as close as we can get to time char was sent uint32_t tStart = millis(); // as close as we can get to time char was sent
char c = 0; char c = 0;
if (paused) return c; if (paused)
return c;
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
if(gpsSwSerial) { if (gpsSwSerial) {
if (!gpsSwSerial->available()) if (!gpsSwSerial->available())
return c; return c;
c = gpsSwSerial->read(); c = gpsSwSerial->read();
@ -570,11 +580,12 @@ char Adafruit_GPS::read(void) {
_buff_idx++; _buff_idx++;
} else { } else {
// refill the buffer! // refill the buffer!
if (gpsI2C->requestFrom(0x10, GPS_MAX_I2C_TRANSFER, true) == GPS_MAX_I2C_TRANSFER) { if (gpsI2C->requestFrom(0x10, GPS_MAX_I2C_TRANSFER, true) ==
GPS_MAX_I2C_TRANSFER) {
// got data! // got data!
_buff_max = 0; _buff_max = 0;
char curr_char = 0; char curr_char = 0;
for (int i=0; i<GPS_MAX_I2C_TRANSFER; i++) { for (int i = 0; i < GPS_MAX_I2C_TRANSFER; i++) {
curr_char = gpsI2C->read(); curr_char = gpsI2C->read();
if ((curr_char == 0x0A) && (last_char != 0x0D)) { if ((curr_char == 0x0A) && (last_char != 0x0D)) {
// skip duplicate 0x0A's - but keep as part of a CRLF // skip duplicate 0x0A's - but keep as part of a CRLF
@ -606,14 +617,16 @@ char Adafruit_GPS::read(void) {
} }
gpsSPI->endTransaction(); gpsSPI->endTransaction();
// skip duplicate 0x0A's - but keep as part of a CRLF // skip duplicate 0x0A's - but keep as part of a CRLF
} while (((c == 0x0A) && (last_char != 0x0D)) || (!isprint(c) && !isspace(c)) ); } while (((c == 0x0A) && (last_char != 0x0D)) ||
(!isprint(c) && !isspace(c)));
last_char = c; last_char = c;
} }
//Serial.print(c); // Serial.print(c);
currentline[lineidx++] = c; currentline[lineidx++] = c;
if (lineidx >= MAXLINELENGTH) if (lineidx >= MAXLINELENGTH)
lineidx = MAXLINELENGTH-1; // ensure there is someplace to put the next received character lineidx = MAXLINELENGTH -
1; // ensure there is someplace to put the next received character
if (c == '\n') { if (c == '\n') {
currentline[lineidx] = 0; currentline[lineidx] = 0;
@ -626,9 +639,9 @@ char Adafruit_GPS::read(void) {
lastline = line2; lastline = line2;
} }
//Serial.println("----"); // Serial.println("----");
//Serial.println((char *)lastline); // Serial.println((char *)lastline);
//Serial.println("----"); // Serial.println("----");
lineidx = 0; lineidx = 0;
recvdflag = true; recvdflag = true;
recvdTime = millis(); // time we got the end of the string recvdTime = millis(); // time we got the end of the string
@ -637,7 +650,8 @@ char Adafruit_GPS::read(void) {
return c; // wait until next character to set time return c; // wait until next character to set time
} }
if(firstChar == 0) firstChar = tStart; if (firstChar == 0)
firstChar = tStart;
return c; return c;
} }
@ -648,8 +662,7 @@ char Adafruit_GPS::read(void) {
*/ */
/**************************************************************************/ /**************************************************************************/
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
Adafruit_GPS::Adafruit_GPS(SoftwareSerial *ser) Adafruit_GPS::Adafruit_GPS(SoftwareSerial *ser) {
{
common_init(); // Set everything to common state, then... common_init(); // Set everything to common state, then...
gpsSwSerial = ser; // ...override gpsSwSerial with value passed. gpsSwSerial = ser; // ...override gpsSwSerial with value passed.
} }
@ -690,7 +703,6 @@ Adafruit_GPS::Adafruit_GPS(SPIClass *theSPI, int8_t cspin) {
gpsSPI_cs = cspin; gpsSPI_cs = cspin;
} }
/**************************************************************************/ /**************************************************************************/
/*! /*!
@brief Initialization code used by all constructor types @brief Initialization code used by all constructor types
@ -709,13 +721,13 @@ void Adafruit_GPS::common_init(void) {
currentline = line1; currentline = line1;
lastline = line2; lastline = line2;
hour = minute = seconds = year = month = day = hour = minute = seconds = year = month = day = fixquality = fixquality_3d =
fixquality = fixquality_3d = satellites = 0; // uint8_t satellites = 0; // uint8_t
lat = lon = mag = 0; // char lat = lon = mag = 0; // char
fix = false; // boolean fix = false; // boolean
milliseconds = 0; // uint16_t milliseconds = 0; // uint16_t
latitude = longitude = geoidheight = altitude = latitude = longitude = geoidheight = altitude = speed = angle = magvariation =
speed = angle = magvariation = HDOP = VDOP = PDOP = 0.0; // float HDOP = VDOP = PDOP = 0.0; // float
} }
/**************************************************************************/ /**************************************************************************/
@ -725,10 +737,9 @@ void Adafruit_GPS::common_init(void) {
@returns True on successful hardware init, False on failure @returns True on successful hardware init, False on failure
*/ */
/**************************************************************************/ /**************************************************************************/
bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr) bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr) {
{
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
if(gpsSwSerial) { if (gpsSwSerial) {
gpsSwSerial->begin(baud_or_i2caddr); gpsSwSerial->begin(baud_or_i2caddr);
} }
#endif #endif
@ -744,7 +755,7 @@ bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr)
} }
// A basic scanner, see if it ACK's // A basic scanner, see if it ACK's
gpsI2C->beginTransmission(_i2caddr); gpsI2C->beginTransmission(_i2caddr);
return (gpsI2C->endTransmission () == 0); return (gpsI2C->endTransmission() == 0);
} }
if (gpsSPI) { if (gpsSPI) {
gpsSPI->begin(); gpsSPI->begin();
@ -765,9 +776,7 @@ bool Adafruit_GPS::begin(uint32_t baud_or_i2caddr)
@param str Pointer to a string holding the command to send @param str Pointer to a string holding the command to send
*/ */
/**************************************************************************/ /**************************************************************************/
void Adafruit_GPS::sendCommand(const char *str) { void Adafruit_GPS::sendCommand(const char *str) { println(str); }
println(str);
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -775,9 +784,7 @@ void Adafruit_GPS::sendCommand(const char *str) {
@return True if received, false if not @return True if received, false if not
*/ */
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::newNMEAreceived(void) { boolean Adafruit_GPS::newNMEAreceived(void) { return recvdflag; }
return recvdflag;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -785,9 +792,7 @@ boolean Adafruit_GPS::newNMEAreceived(void) {
@param p True = pause, false = unpause @param p True = pause, false = unpause
*/ */
/**************************************************************************/ /**************************************************************************/
void Adafruit_GPS::pause(boolean p) { void Adafruit_GPS::pause(boolean p) { paused = p; }
paused = p;
}
/**************************************************************************/ /**************************************************************************/
/*! /*!
@ -804,7 +809,8 @@ char *Adafruit_GPS::lastNMEA(void) {
/*! /*!
@brief Parse a hex character and return the appropriate decimal value @brief Parse a hex character and return the appropriate decimal value
@param c Hex character, e.g. '0' or 'B' @param c Hex character, e.g. '0' or 'B'
@return Integer value of the hex character. Returns 0 if c is not a proper character @return Integer value of the hex character. Returns 0 if c is not a proper
character
*/ */
/**************************************************************************/ /**************************************************************************/
// read a Hex value and return the decimal equivalent // read a Hex value and return the decimal equivalent
@ -816,7 +822,7 @@ uint8_t Adafruit_GPS::parseHex(char c) {
if (c < 'A') if (c < 'A')
return 0; return 0;
if (c <= 'F') if (c <= 'F')
return (c - 'A')+10; return (c - 'A') + 10;
// if (c > 'F') // if (c > 'F')
return 0; return 0;
} }
@ -826,12 +832,14 @@ uint8_t Adafruit_GPS::parseHex(char c) {
@brief Wait for a specified sentence from the device @brief Wait for a specified sentence from the device
@param wait4me Pointer to a string holding the desired response @param wait4me Pointer to a string holding the desired response
@param max How long to wait, default is MAXWAITSENTENCE @param max How long to wait, default is MAXWAITSENTENCE
@param usingInterrupts True if using interrupts to read from the GPS (default is false) @param usingInterrupts True if using interrupts to read from the GPS
(default is false)
@return True if we got what we wanted, false otherwise @return True if we got what we wanted, false otherwise
*/ */
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::waitForSentence(const char *wait4me, uint8_t max, boolean usingInterrupts) { boolean Adafruit_GPS::waitForSentence(const char *wait4me, uint8_t max,
uint8_t i=0; boolean usingInterrupts) {
uint8_t i = 0;
while (i < max) { while (i < max) {
if (!usingInterrupts) if (!usingInterrupts)
read(); read();
@ -881,23 +889,23 @@ boolean Adafruit_GPS::LOCUS_StopLogger(void) {
boolean Adafruit_GPS::LOCUS_ReadStatus(void) { boolean Adafruit_GPS::LOCUS_ReadStatus(void) {
sendCommand(PMTK_LOCUS_QUERY_STATUS); sendCommand(PMTK_LOCUS_QUERY_STATUS);
if (! waitForSentence("$PMTKLOG")) if (!waitForSentence("$PMTKLOG"))
return false; return false;
char *response = lastNMEA(); char *response = lastNMEA();
uint16_t parsed[10]; uint16_t parsed[10];
uint8_t i; uint8_t i;
for (i=0; i<10; i++) parsed[i] = -1; for (i = 0; i < 10; i++)
parsed[i] = -1;
response = strchr(response, ','); response = strchr(response, ',');
for (i=0; i<10; i++) { for (i = 0; i < 10; i++) {
if (!response || (response[0] == 0) || (response[0] == '*')) if (!response || (response[0] == 0) || (response[0] == '*'))
break; break;
response++; response++;
parsed[i]=0; parsed[i] = 0;
while ((response[0] != ',') && while ((response[0] != ',') && (response[0] != '*') && (response[0] != 0)) {
(response[0] != '*') && (response[0] != 0)) {
parsed[i] *= 10; parsed[i] *= 10;
char c = response[0]; char c = response[0];
if (isDigit(c)) if (isDigit(c))
@ -932,12 +940,13 @@ boolean Adafruit_GPS::LOCUS_ReadStatus(void) {
/**************************************************************************/ /**************************************************************************/
boolean Adafruit_GPS::standby(void) { boolean Adafruit_GPS::standby(void) {
if (inStandbyMode) { if (inStandbyMode) {
return false; // Returns false if already in standby mode, so that you do not wake it up by sending commands to GPS return false; // Returns false if already in standby mode, so that you do
} // not wake it up by sending commands to GPS
else { } else {
inStandbyMode = true; inStandbyMode = true;
sendCommand(PMTK_STANDBY); sendCommand(PMTK_STANDBY);
//return waitForSentence(PMTK_STANDBY_SUCCESS); // don't seem to be fast enough to catch the message, or something else just is not working // return waitForSentence(PMTK_STANDBY_SUCCESS); // don't seem to be fast
// enough to catch the message, or something else just is not working
return true; return true;
} }
} }
@ -953,8 +962,7 @@ boolean Adafruit_GPS::wakeup(void) {
inStandbyMode = false; inStandbyMode = false;
sendCommand(""); // send byte to wake it up sendCommand(""); // send byte to wake it up
return waitForSentence(PMTK_AWAKE); return waitForSentence(PMTK_AWAKE);
} } else {
else {
return false; // Returns false if not in standby mode, nothing to wakeup return false; // Returns false if not in standby mode, nothing to wakeup
} }
} }
@ -967,8 +975,7 @@ boolean Adafruit_GPS::wakeup(void) {
@return True if str starts with prefix, false otherwise @return True if str starts with prefix, false otherwise
*/ */
/**************************************************************************/ /**************************************************************************/
static boolean strStartsWith(const char* str, const char* prefix) static boolean strStartsWith(const char *str, const char *prefix) {
{
while (*prefix) { while (*prefix) {
if (*prefix++ != *str++) if (*prefix++ != *str++)
return false; return false;

View File

@ -26,36 +26,46 @@
#ifndef _ADAFRUIT_GPS_H #ifndef _ADAFRUIT_GPS_H
#define _ADAFRUIT_GPS_H #define _ADAFRUIT_GPS_H
#define USE_SW_SERIAL ///< comment this out if you don't want to include software serial in the library #define USE_SW_SERIAL ///< comment this out if you don't want to include
#define GPS_DEFAULT_I2C_ADDR 0x10 ///< The default address for I2C transport of GPS data ///< software serial in the library
#define GPS_MAX_I2C_TRANSFER 32 ///< The max number of bytes we'll try to read at once #define GPS_DEFAULT_I2C_ADDR \
#define GPS_MAX_SPI_TRANSFER 100 ///< The max number of bytes we'll try to read at once 0x10 ///< The default address for I2C transport of GPS data
#define GPS_MAX_I2C_TRANSFER \
32 ///< The max number of bytes we'll try to read at once
#define GPS_MAX_SPI_TRANSFER \
100 ///< The max number of bytes we'll try to read at once
#define MAXLINELENGTH 120 ///< how long are max NMEA lines to parse? #define MAXLINELENGTH 120 ///< how long are max NMEA lines to parse?
#define NMEA_MAX_SENTENCE_ID 20 ///< maximum length of a sentence ID name, including terminating 0 #define NMEA_MAX_SENTENCE_ID \
#define NMEA_MAX_SOURCE_ID 3 ///< maximum length of a source ID name, including terminating 0 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
#include "Arduino.h" #include "Arduino.h"
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
#include <SoftwareSerial.h> #include <SoftwareSerial.h>
#endif #endif
#include <Wire.h>
#include <SPI.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) Different commands to set the update rate from once a second (1 Hz) to 10 times
Note that these only control the rate at which the position is echoed, to actually speed up the a second (10Hz) Note that these only control the rate at which the position is
position fix you must also send one of the position fix rate commands below too. */ echoed, to actually speed up the position fix you must also send one of the
#define PMTK_SET_NMEA_UPDATE_100_MILLIHERTZ "$PMTK220,10000*2F" ///< Once every 10 seconds, 100 millihertz. position fix rate commands below too. */
#define PMTK_SET_NMEA_UPDATE_200_MILLIHERTZ "$PMTK220,5000*1B" ///< Once every 5 seconds, 200 millihertz. #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_1HZ "$PMTK220,1000*1F" ///< 1 Hz
#define PMTK_SET_NMEA_UPDATE_2HZ "$PMTK220,500*2B" ///< 2 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_5HZ "$PMTK220,200*2C" ///< 5 Hz
#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F" ///< 10 Hz #define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F" ///< 10 Hz
// Position fix update rate commands. // 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_100_MILLIHERTZ \
#define PMTK_API_SET_FIX_CTL_200_MILLIHERTZ "$PMTK300,5000,0,0,0,0*18" ///< Once every 5 seconds, 200 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_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 #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! // Can't fix position faster than 5 times a second!
@ -64,43 +74,67 @@
#define PMTK_SET_BAUD_57600 "$PMTK251,57600*2C" ///< 57600 bps #define PMTK_SET_BAUD_57600 "$PMTK251,57600*2C" ///< 57600 bps
#define PMTK_SET_BAUD_9600 "$PMTK251,9600*17" ///< 9600 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_GLLONLY \
#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 "$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
#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 ///< GPGLL sentence
#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_RMCONLY \
#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 "$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
#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 ///< GPRMC sentence
#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_VTGONLY \
#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 "$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
#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 ///< GPVTG
#define PMTK_SET_NMEA_OUTPUT_OFF "$PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28" ///< turn off output #define PMTK_SET_NMEA_OUTPUT_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
// to generate your own sentences, check out the MTK command datasheet and use a checksum calculator // checksum calculator such as the awesome
// such as the awesome http://www.hhhh.org/wiml/proj/nmeaxor.html // http://www.hhhh.org/wiml/proj/nmeaxor.html
#define PMTK_LOCUS_STARTLOG "$PMTK185,0*22" ///< Start logging data #define PMTK_LOCUS_STARTLOG "$PMTK185,0*22" ///< Start logging data
#define PMTK_LOCUS_STOPLOG "$PMTK185,1*23" ///< Stop 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_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_QUERY_STATUS "$PMTK183*38" ///< Query the logging status
#define PMTK_LOCUS_ERASE_FLASH "$PMTK184,1*22" ///< Erase the log flash data #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_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 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_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_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 \
"$PMTK161,0*28" ///< standby command & boot successful message
#define PMTK_STANDBY_SUCCESS "$PMTK001,161,3*36" ///< Not needed currently #define PMTK_STANDBY_SUCCESS "$PMTK001,161,3*36" ///< Not needed currently
#define PMTK_AWAKE "$PMTK010,002*2D" ///< Wake up #define PMTK_AWAKE "$PMTK010,002*2D" ///< Wake up
#define PMTK_Q_RELEASE "$PMTK605*31" ///< ask for the release and version #define PMTK_Q_RELEASE "$PMTK605*31" ///< ask for the release and version
#define PGCMD_ANTENNA \
#define PGCMD_ANTENNA "$PGCMD,33,1*6C" ///< request for updates on antenna status "$PGCMD,33,1*6C" ///< request for updates on antenna status
#define PGCMD_NOANTENNA "$PGCMD,33,0*6D" ///< don't show antenna status messages #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 #define MAXWAITSENTENCE \
10 ///< how long to wait when we're looking for a response
/**************************************************************************/ /**************************************************************************/
/// type for resulting code from running check() /// type for resulting code from running check()
@ -118,8 +152,8 @@ typedef enum {
/*! /*!
@brief The GPS class @brief The GPS class
*/ */
class Adafruit_GPS : public Print{ class Adafruit_GPS : public Print {
public: public:
bool begin(uint32_t baud_or_i2caddr); bool begin(uint32_t baud_or_i2caddr);
#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL) #if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
@ -154,10 +188,16 @@ class Adafruit_GPS : public Print{
boolean standby(void); boolean standby(void);
int thisCheck = 0; ///< the results of the check on the current sentence int thisCheck = 0; ///< the results of the check on the current sentence
char thisSource[NMEA_MAX_SOURCE_ID] = {0}; ///< the first two letters of the current sentence, e.g. WI, GP char thisSource[NMEA_MAX_SOURCE_ID] = {
char thisSentence[NMEA_MAX_SENTENCE_ID] = {0}; ///< the next three letters of the current sentence, e.g. GLL, RMC 0}; ///< the first two letters of the current sentence, e.g. WI, GP
char lastSource[NMEA_MAX_SOURCE_ID] = {0}; ///< the results of the check on the most recent successfully parsed sentence char thisSentence[NMEA_MAX_SENTENCE_ID] = {
char lastSentence[NMEA_MAX_SENTENCE_ID] = {0}; ///< the next three letters of the most recent successfully parsed sentence, e.g. GLL, RMC 0}; ///< the next three letters of the current sentence, e.g. GLL, RMC
char lastSource[NMEA_MAX_SOURCE_ID] = {
0}; ///< the results of the check on the most recent successfully parsed
///< sentence
char lastSentence[NMEA_MAX_SENTENCE_ID] = {
0}; ///< the next three letters of the most recent successfully parsed
///< sentence, e.g. GLL, RMC
uint8_t hour; ///< GMT hours uint8_t hour; ///< GMT hours
uint8_t minute; ///< GMT minutes uint8_t minute; ///< GMT minutes
@ -167,11 +207,14 @@ class Adafruit_GPS : public Print{
uint8_t month; ///< GMT month uint8_t month; ///< GMT month
uint8_t day; ///< GMT day uint8_t day; ///< GMT day
float latitude; ///< Floating point latitude value in degrees/minutes as received from the GPS (DDMM.MMMM) float latitude; ///< Floating point latitude value in degrees/minutes as
float longitude; ///< Floating point longitude value in degrees/minutes as received from the GPS (DDDMM.MMMM) ///< received from the GPS (DDMM.MMMM)
float 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, /** Fixed point latitude and longitude value with degrees stored in units of
and minutes stored in units of 1/100000 degrees. See pull #13 for more details: 1/100000 degrees, and minutes stored in units of 1/100000 degrees. See pull
#13 for more details:
https://github.com/adafruit/Adafruit-GPS-Library/pull/13 */ https://github.com/adafruit/Adafruit-GPS-Library/pull/13 */
int32_t latitude_fixed; ///< Fixed point latitude in decimal degrees int32_t latitude_fixed; ///< Fixed point latitude in decimal degrees
int32_t longitude_fixed; ///< Fixed point longitude in decimal degrees int32_t longitude_fixed; ///< Fixed point longitude in decimal degrees
@ -183,9 +226,12 @@ class Adafruit_GPS : public Print{
float speed; ///< Current speed over ground in knots float speed; ///< Current speed over ground in knots
float angle; ///< Course in degrees from true north float angle; ///< Course in degrees from true north
float magvariation; ///< Magnetic variation in degrees (vs. true north) float magvariation; ///< Magnetic variation in degrees (vs. true north)
float HDOP; ///< Horizontal Dilution of Precision - relative accuracy of horizontal position float HDOP; ///< Horizontal Dilution of Precision - relative accuracy of
float VDOP; ///< Vertical Dilution of Precision - relative accuracy of vertical position ///< horizontal position
float PDOP; ///< Position Dilution of Precision - Complex maths derives a simple, single number for each kind of DOP 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; ///< N/S char lat; ///< N/S
char lon; ///< E/W char lon; ///< E/W
char mag; ///< Magnetic variation direction char mag; ///< Magnetic variation direction
@ -194,7 +240,8 @@ class Adafruit_GPS : public Print{
uint8_t fixquality_3d; ///< 3D fix quality (1, 3, 3 = Nofix, 2D fix, 3D fix) uint8_t fixquality_3d; ///< 3D fix quality (1, 3, 3 = Nofix, 2D fix, 3D fix)
uint8_t satellites; ///< Number of satellites in use uint8_t satellites; ///< Number of satellites in use
boolean waitForSentence(const char *wait, uint8_t max = MAXWAITSENTENCE, boolean usingInterrupts = false); boolean waitForSentence(const char *wait, uint8_t max = MAXWAITSENTENCE,
boolean usingInterrupts = false);
boolean LOCUS_StartLogger(void); boolean LOCUS_StartLogger(void);
boolean LOCUS_StopLogger(void); boolean LOCUS_StopLogger(void);
boolean LOCUS_ReadStatus(void); boolean LOCUS_ReadStatus(void);
@ -210,8 +257,8 @@ class Adafruit_GPS : public Print{
uint8_t LOCUS_status; ///< 0: Logging, 1: Stop logging uint8_t LOCUS_status; ///< 0: Logging, 1: Stop logging
uint8_t LOCUS_percent; ///< Log life used percentage uint8_t LOCUS_percent; ///< Log life used percentage
private: private:
const char * tokenOnList(char *token, const char **list); const char *tokenOnList(char *token, const char **list);
void parseTime(char *); void parseTime(char *);
void parseLat(char *); void parseLat(char *);
boolean parseLatDir(char *); boolean parseLatDir(char *);
@ -219,18 +266,24 @@ class Adafruit_GPS : public Print{
boolean parseLonDir(char *); boolean parseLonDir(char *);
boolean parseFix(char *); boolean parseFix(char *);
// used by check() for validity tests, room for future expansion // used by check() for validity tests, room for future expansion
const char *sources[5] = {"II", "WI", "GP", "GN", "ZZZ"}; ///< valid source ids const char *sources[5] = {"II", "WI", "GP", "GN",
const char *sentences_parsed[5] = {"GGA", "GLL", "GSA", "RMC", "ZZZ"}; ///< parseable sentence ids "ZZZ"}; ///< valid source ids
const char *sentences_known[1] = {"ZZZ"}; ///< known, but not parseable sentence ids const char *sentences_parsed[5] = {"GGA", "GLL", "GSA", "RMC",
"ZZZ"}; ///< parseable sentence ids
const char *sentences_known[1] = {
"ZZZ"}; ///< known, but not parseable sentence ids
// Make all of these times far in the past by setting them near the middle of the // Make all of these times far in the past by setting them near the middle of
// millis() range. Timing assumes that sentences are parsed promptly. // the millis() range. Timing assumes that sentences are parsed promptly.
uint32_t lastUpdate = 2000000000L; ///< millis() when last full sentence successfully parsed uint32_t lastUpdate =
2000000000L; ///< millis() when last full sentence successfully parsed
uint32_t lastFix = 2000000000L; ///< millis() when last fix received uint32_t lastFix = 2000000000L; ///< millis() when last fix received
uint32_t lastTime = 2000000000L; ///< millis() when last time received uint32_t lastTime = 2000000000L; ///< millis() when last time received
uint32_t lastDate = 2000000000L; ///< millis() when last date received uint32_t lastDate = 2000000000L; ///< millis() when last date received
uint32_t recvdTime = 2000000000L; ///< millis() when last full sentence received uint32_t recvdTime =
uint32_t sentTime = 2000000000L; ///< millis() when first character of last full sentence received 2000000000L; ///< millis() when last full sentence received
uint32_t sentTime = 2000000000L; ///< millis() when first character of last
///< full sentence received
boolean paused; boolean paused;
uint8_t parseResponse(char *response); uint8_t parseResponse(char *response);
@ -241,16 +294,19 @@ class Adafruit_GPS : public Print{
TwoWire *gpsI2C; TwoWire *gpsI2C;
SPIClass *gpsSPI; SPIClass *gpsSPI;
int8_t gpsSPI_cs = -1; int8_t gpsSPI_cs = -1;
SPISettings gpsSPI_settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); // default SPISettings gpsSPI_settings =
char _spibuffer[GPS_MAX_SPI_TRANSFER]; // for when we write data, we need to read it too! SPISettings(1000000, MSBFIRST, SPI_MODE0); // default
char _spibuffer[GPS_MAX_SPI_TRANSFER]; // for when we write data, we need to
// read it too!
uint8_t _i2caddr; uint8_t _i2caddr;
char _i2cbuffer[GPS_MAX_I2C_TRANSFER]; char _i2cbuffer[GPS_MAX_I2C_TRANSFER];
int8_t _buff_max = -1, _buff_idx = 0; int8_t _buff_max = -1, _buff_idx = 0;
char last_char = 0; char last_char = 0;
volatile char line1[MAXLINELENGTH]; ///< We double buffer: read one line in and leave one for the main program volatile char line1[MAXLINELENGTH]; ///< We double buffer: read one line in
///< and leave one for the main program
volatile char line2[MAXLINELENGTH]; ///< Second buffer volatile char line2[MAXLINELENGTH]; ///< Second buffer
volatile uint8_t lineidx=0; ///< our index into filling the current line volatile uint8_t lineidx = 0; ///< our index into filling the current line
volatile char *currentline; ///< Pointer to current line buffer volatile char *currentline; ///< Pointer to current line buffer
volatile char *lastline; ///< Pointer to previous line buffer volatile char *lastline; ///< Pointer to previous line buffer
volatile boolean recvdflag; ///< Received flag volatile boolean recvdflag; ///< Received flag