New parse() with more sentences
move other parsing functions in NMEA_parse.cpp fix parseTime to be insensitive to number of decimal places and return bool. add isEmpty() checks where needed. reorder some declarations.
This commit is contained in:
parent
4b6e181770
commit
3876f29fc1
|
|
@ -32,117 +32,6 @@
|
|||
|
||||
static bool strStartsWith(const char *str, const char *prefix);
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check an NMEA string for basic format, valid source ID and valid
|
||||
and valid sentence ID. Update the values of thisCheck, thisSource and
|
||||
thisSentence.
|
||||
@param nmea Pointer to the NMEA string
|
||||
@return True if well formed, false if it has problems
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::check(char *nmea) {
|
||||
thisCheck = 0; // new check
|
||||
if (*nmea != '$')
|
||||
return false; // doesn't start with $
|
||||
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 *
|
||||
while (*ast)
|
||||
ast++; // go to the end
|
||||
while (*ast != '*' && ast > nmea)
|
||||
ast--; // then back to * if it's there
|
||||
if (*ast != '*')
|
||||
return false; // there is no asterisk
|
||||
else {
|
||||
uint16_t sum = parseHex(*(ast + 1)) * 16; // extract checksum
|
||||
sum += parseHex(*(ast + 2));
|
||||
char *p = nmea; // check checksum
|
||||
for (char *p1 = p + 1; p1 < ast; p1++)
|
||||
sum ^= *p1;
|
||||
if (sum != 0)
|
||||
return false; // bad checksum :(
|
||||
else
|
||||
thisCheck += NMEA_HAS_CHECKSUM;
|
||||
}
|
||||
// extract source of variable length
|
||||
char *p = nmea + 1;
|
||||
const char *src = tokenOnList(p, sources);
|
||||
if (src) {
|
||||
strcpy(thisSource, src);
|
||||
thisCheck += NMEA_HAS_SOURCE;
|
||||
} else
|
||||
return false;
|
||||
p += strlen(src);
|
||||
// extract sentence id and check if parsed
|
||||
const char *snc = tokenOnList(p, sentences_parsed);
|
||||
if (snc) {
|
||||
strcpy(thisSentence, snc);
|
||||
thisCheck += NMEA_HAS_SENTENCE_P + NMEA_HAS_SENTENCE;
|
||||
} else { // check if known
|
||||
snc = tokenOnList(p, sentences_known);
|
||||
if (snc) {
|
||||
strcpy(thisSentence, snc);
|
||||
thisCheck += NMEA_HAS_SENTENCE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // passed all the tests
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check if a token at the start of a string is on a list.
|
||||
@param token Pointer to the string
|
||||
@param list A list of strings, with the final entry starting "ZZ"
|
||||
@return Pointer to the found token, or NULL if it fails
|
||||
*/
|
||||
/**************************************************************************/
|
||||
const char *Adafruit_GPS::tokenOnList(char *token, const char **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
|
||||
// test for a match on the sentence name
|
||||
if (!strncmp((const char *)list[i], (const char *)token, strlen(list[i])))
|
||||
return list[i];
|
||||
i++;
|
||||
}
|
||||
return NULL; // couldn't find a match
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a string token from pointer p to the next comma, asterisk
|
||||
or end of string.
|
||||
@param buff Pointer to the buffer to store the string in
|
||||
@param p Pointer into a string
|
||||
@param n Max permitted size of string including terminating 0
|
||||
@return Pointer to the string buffer
|
||||
*/
|
||||
/**************************************************************************/
|
||||
char *Adafruit_GPS::parseStr(char *buff, char *p, int n) {
|
||||
char *e = strchr(p, ',');
|
||||
int len = 0;
|
||||
if (e) {
|
||||
len = min(e - p, n - 1);
|
||||
strncpy(buff, p, len); // copy up to the comma
|
||||
buff[len] = 0;
|
||||
} else {
|
||||
e = strchr(p, '*');
|
||||
if (e) {
|
||||
len = min(e - p, n - 1);
|
||||
strncpy(buff, p, len); // or up to the *
|
||||
buff[e - p] = 0;
|
||||
} else {
|
||||
len = min((int)strlen(p), n - 1);
|
||||
strncpy(buff, p, len); // or to the end or max capacity
|
||||
}
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the field empty, or should we try conversion? Won't work
|
||||
|
|
@ -151,32 +40,6 @@ char *Adafruit_GPS::parseStr(char *buff, char *p, int n) {
|
|||
@param pStart Pointer to the location of the token in the NMEA string
|
||||
@return true if empty field, false if something there
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::isEmpty(char *pStart) {
|
||||
if (',' != *pStart && '*' != *pStart && pStart != NULL)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for time
|
||||
@param p Pointer to the location of the token in the NMEA string
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_GPS::parseTime(char *p) {
|
||||
// get time
|
||||
uint32_t time = atol(p);
|
||||
hour = time / 10000;
|
||||
minute = (time % 10000) / 100;
|
||||
seconds = (time % 100);
|
||||
|
||||
p = strchr(p, '.') + 1;
|
||||
milliseconds = atoi(p);
|
||||
lastTime = sentTime;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for latitude angle
|
||||
|
|
@ -275,24 +138,6 @@ bool Adafruit_GPS::parseLonDir(char *p) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for whether there is a fix
|
||||
@param p Pointer to the location of the token in the NMEA string
|
||||
@return True if we parsed it, false if it has invalid data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::parseFix(char *p) {
|
||||
if (p[0] == 'A') {
|
||||
fix = true;
|
||||
lastFix = sentTime;
|
||||
} else if (p[0] == 'V')
|
||||
fix = false;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Time in seconds since the last position fix was obtained. Will
|
||||
|
|
@ -682,28 +527,6 @@ char *Adafruit_GPS::lastNMEA(void) {
|
|||
return (char *)lastline;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a hex character and return the appropriate decimal value
|
||||
@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
|
||||
*/
|
||||
/**************************************************************************/
|
||||
// read a Hex value and return the decimal equivalent
|
||||
uint8_t Adafruit_GPS::parseHex(char c) {
|
||||
if (c < '0')
|
||||
return 0;
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
if (c < 'A')
|
||||
return 0;
|
||||
if (c <= 'F')
|
||||
return (c - 'A') + 10;
|
||||
// if (c > 'F')
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Wait for a specified sentence from the device
|
||||
|
|
|
|||
|
|
@ -100,14 +100,10 @@ public:
|
|||
|
||||
void pause(bool b);
|
||||
|
||||
uint8_t parseHex(char c);
|
||||
|
||||
char read(void);
|
||||
size_t write(uint8_t);
|
||||
size_t available(void);
|
||||
|
||||
bool check(char *nmea);
|
||||
bool parse(char *);
|
||||
nmea_float_t secondsSinceFix();
|
||||
nmea_float_t secondsSinceTime();
|
||||
nmea_float_t secondsSinceDate();
|
||||
|
|
@ -116,6 +112,12 @@ public:
|
|||
bool wakeup(void);
|
||||
bool standby(void);
|
||||
|
||||
// NMEA_parse.cpp
|
||||
bool parse(char *);
|
||||
bool check(char *nmea);
|
||||
bool onList(char *nmea, const char **list);
|
||||
uint8_t parseHex(char c);
|
||||
|
||||
// NMEA_build.cpp
|
||||
#ifdef NMEA_EXTENSIONS
|
||||
char *build(char *nmea, const char *thisSource, const char *thisSentence,
|
||||
|
|
@ -234,17 +236,22 @@ public:
|
|||
#endif // NMEA_EXTENSIONS
|
||||
|
||||
private:
|
||||
const char *tokenOnList(char *token, const char **list);
|
||||
char *parseStr(char *buff, char *p, int n);
|
||||
bool isEmpty(char *pStart);
|
||||
void parseTime(char *);
|
||||
void parseLat(char *);
|
||||
bool parseLatDir(char *);
|
||||
void parseLon(char *);
|
||||
bool parseLonDir(char *);
|
||||
// NMEA_data.cpp
|
||||
void data_init();
|
||||
// NMEA_parse.cpp
|
||||
const char *tokenOnList(char *token, const char **list);
|
||||
bool parseCoord(char *p, nmea_float_t *angleDegrees = NULL,
|
||||
nmea_float_t *angle = NULL, int32_t *angle_fixed = NULL,
|
||||
char *dir = NULL);
|
||||
char *parseStr(char *buff, char *p, int n);
|
||||
bool parseTime(char *);
|
||||
bool parseFix(char *);
|
||||
bool isEmpty(char *pStart);
|
||||
|
||||
// used by check() for validity tests, room for future expansion
|
||||
const char *sources[6] = {"II", "WI", "GP", "GN",
|
||||
"P", "ZZZ"}; ///< valid source ids
|
||||
|
|
|
|||
|
|
@ -32,112 +32,102 @@
|
|||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a NMEA string
|
||||
@brief Parse a standard NMEA string and update the relevant variables.
|
||||
Sentences start with a $, then a two character source identifier, then a
|
||||
three character sentence identifier 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, including proprietary sentences
|
||||
that start with P, like the $PMTK commands to the GPS modules. See the
|
||||
build() function and http://fort21.ru/download/NMEAdescription.pdf for
|
||||
sentence descriptions.
|
||||
|
||||
Encapsulated data sentences are supported by NMEA-183, and start with !
|
||||
instead of $. https://gpsd.gitlab.io/gpsd/AIVDM.html provides details
|
||||
about encapsulated data sentences used in AIS.
|
||||
|
||||
parse() permits, but does not require Carriage Return and Line Feed at the
|
||||
end of sentences. The end of the sentence is recognized by the * for the
|
||||
checksum. parse() will not recognize a sentence without a valid checksum.
|
||||
|
||||
NMEA_EXTENSIONS must be defined in order to parse more than basic
|
||||
GPS module sentences.
|
||||
|
||||
@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 successfully parsed, false if fails check or parsing
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool 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.
|
||||
p = strchr(p, ',') + 1; // Skip to char after the next comma, then check.
|
||||
|
||||
if (!strcmp(thisSentence, "GGA")) {
|
||||
// found GGA
|
||||
// get time
|
||||
// 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
|
||||
// Adafruit from Actisense NGW-1 from SH CP150C
|
||||
parseTime(p);
|
||||
|
||||
// parse out latitude
|
||||
p = strchr(p, ',') + 1; // parse time with specialized function
|
||||
// parse out both latitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &latitudeDegrees, &latitude, &latitude_fixed, &lat))
|
||||
newDataValue(NMEA_LAT, latitudeDegrees);
|
||||
p = strchr(p, ',') + 1;
|
||||
parseLat(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!parseLatDir(p))
|
||||
return false;
|
||||
|
||||
// parse out longitude
|
||||
// parse out both longitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &longitudeDegrees, &longitude, &longitude_fixed, &lon))
|
||||
newDataValue(NMEA_LON, longitudeDegrees);
|
||||
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 (!isEmpty(p)) { // if it's a , (or a * at end of sentence) the value is
|
||||
// not included
|
||||
fixquality = atoi(p); // needs additional processing
|
||||
if (fixquality > 0) {
|
||||
fix = true;
|
||||
lastFix = sentTime;
|
||||
} else
|
||||
fix = false;
|
||||
}
|
||||
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
p = strchr(p, ',') + 1; // then move on to the next
|
||||
// Most can just be parsed with atoi() or atof(), then move on to the next.
|
||||
if (!isEmpty(p))
|
||||
satellites = atoi(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
HDOP = atof(p);
|
||||
}
|
||||
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDOP, HDOP = atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
if (!isEmpty(p))
|
||||
altitude = atof(p);
|
||||
}
|
||||
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
geoidheight = atof(p);
|
||||
}
|
||||
}
|
||||
p = strchr(p, ',') + 1; // skip the units
|
||||
if (!isEmpty(p))
|
||||
geoidheight = atof(p); // skip the rest
|
||||
|
||||
else if (!strcmp(thisSentence, "RMC")) {
|
||||
// found RMC
|
||||
// get time
|
||||
} else if (!strcmp(thisSentence, "RMC")) { //*****************************RMC
|
||||
// in Adafruit from Actisense NGW-1 from SH CP150C
|
||||
parseTime(p);
|
||||
|
||||
// fix or no fix
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!parseFix(p))
|
||||
return false;
|
||||
|
||||
// parse out latitude
|
||||
parseFix(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
parseLat(p);
|
||||
// parse out both latitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &latitudeDegrees, &latitude, &latitude_fixed, &lat))
|
||||
newDataValue(NMEA_LAT, latitudeDegrees);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!parseLatDir(p))
|
||||
return false;
|
||||
|
||||
// parse out longitude
|
||||
p = strchr(p, ',') + 1;
|
||||
parseLon(p);
|
||||
// parse out both longitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &longitudeDegrees, &longitude, &longitude_fixed, &lon))
|
||||
newDataValue(NMEA_LON, longitudeDegrees);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!parseLonDir(p))
|
||||
return false;
|
||||
|
||||
// speed
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
speed = atof(p);
|
||||
}
|
||||
|
||||
// angle
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_SOG, speed = atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
angle = atof(p);
|
||||
}
|
||||
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_COG, angle = atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
uint32_t fulldate = atof(p);
|
||||
|
|
@ -145,66 +135,264 @@ bool Adafruit_GPS::parse(char *nmea) {
|
|||
month = (fulldate % 10000) / 100;
|
||||
year = (fulldate % 100);
|
||||
lastDate = sentTime;
|
||||
}
|
||||
}
|
||||
} // skip the rest
|
||||
|
||||
else if (!strcmp(thisSentence, "GLL")) {
|
||||
// found GLL
|
||||
// parse out latitude
|
||||
parseLat(p);
|
||||
} else if (!strcmp(thisSentence, "GLL")) { //*****************************GLL
|
||||
// in Adafruit from Actisense NGW-1 from SH CP150C
|
||||
// parse out both latitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &latitudeDegrees, &latitude, &latitude_fixed, &lat))
|
||||
newDataValue(NMEA_LAT, latitudeDegrees);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!parseLatDir(p))
|
||||
return false;
|
||||
|
||||
// parse out longitude
|
||||
p = strchr(p, ',') + 1;
|
||||
parseLon(p);
|
||||
// parse out both longitude and direction, then go to next field, or fail
|
||||
if (parseCoord(p, &longitudeDegrees, &longitude, &longitude_fixed, &lon))
|
||||
newDataValue(NMEA_LON, longitudeDegrees);
|
||||
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;
|
||||
}
|
||||
parseFix(p); // skip the rest
|
||||
|
||||
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)) {
|
||||
} else if (!strcmp(thisSentence, "GSA")) { //*****************************GSA
|
||||
// in Adafruit from Actisense NGW-1
|
||||
p = strchr(p, ',') + 1; // skip selection mode
|
||||
if (!isEmpty(p))
|
||||
fixquality_3d = atoi(p);
|
||||
}
|
||||
p = strchr(p, ',') + 1;
|
||||
// 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)) {
|
||||
if (!isEmpty(p))
|
||||
PDOP = atof(p);
|
||||
}
|
||||
p = strchr(p, ',') + 1;
|
||||
// parse out HDOP, we also parse this from the GGA sentence. Chipset should
|
||||
// report the same for both
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDOP, HDOP = atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
HDOP = atof(p);
|
||||
if (!isEmpty(p))
|
||||
VDOP = atof(p); // last before checksum
|
||||
|
||||
}
|
||||
// parse out VDOP
|
||||
#ifdef NMEA_EXTENSIONS // Sentences not required for basic GPS functionality
|
||||
else if (!strcmp(thisSentence, "APB")) { //*******************************APB
|
||||
// from Actisense NGW-1 from SH CP150C
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "DBT")) { //*****************************DBT
|
||||
// from Actisense NGW-1
|
||||
// feet, metres, fathoms below transducer coerced to water depth from
|
||||
// surface in metres
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_DEPTH, atof(p) * 0.3048 + depthToTransducer);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p)) {
|
||||
VDOP = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_DEPTH, atof(p) + depthToTransducer);
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_DEPTH, atof(p) * 6 * 0.3048 + depthToTransducer);
|
||||
|
||||
} else if (!strcmp(thisSentence, "DPT")) { //*****************************DPT
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "GSV")) { //*****************************GSV
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "HDG")) { //*****************************HDG
|
||||
// from Actisense NGW-1 from SH CP150C
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "HDM")) { //*****************************HDM
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDG, atof(p)); // skip the rest
|
||||
|
||||
} else if (!strcmp(thisSentence, "HDT")) { //*****************************HDT
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDT, atof(p)); // skip the rest
|
||||
|
||||
} else if (!strcmp(thisSentence, "MDA")) { //*****************************MDA
|
||||
// from Actisense NGW-1
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_BAROMETER, atof(p) * 3386.39);
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_BAROMETER, atof(p) * 100000);
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
nmea_float_t T = 100000.;
|
||||
char u = 'C';
|
||||
if (!isEmpty(p))
|
||||
T = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
u = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (u != 'C') {
|
||||
T = (T - 32) / 1.8;
|
||||
u = 'C';
|
||||
} // coerce to C
|
||||
if (T < 1000)
|
||||
newDataValue(NMEA_TEMPERATURE_AIR, T);
|
||||
T = 100000.;
|
||||
u = 'C';
|
||||
if (!isEmpty(p))
|
||||
T = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
u = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (u != 'C') {
|
||||
T = (T - 32) / 1.8;
|
||||
u = 'C';
|
||||
}
|
||||
if (T < 1000)
|
||||
newDataValue(NMEA_TEMPERATURE_WATER, T);
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HUMIDITY, atof(p)); // skip the rest
|
||||
|
||||
} else if (!strcmp(thisSentence, "MTW")) { //*****************************MTW
|
||||
nmea_float_t T = 100000.;
|
||||
char u = 'C';
|
||||
if (!isEmpty(p))
|
||||
T = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
u = *p; // last before checksum
|
||||
if (u != 'C') {
|
||||
T = (T - 32) / 1.8;
|
||||
u = 'C';
|
||||
}
|
||||
if (T < 1000)
|
||||
newDataValue(NMEA_TEMPERATURE_WATER, T);
|
||||
|
||||
} else if (!strcmp(thisSentence, "MWD")) { //*****************************MWD
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "MWV")) { //*****************************MWV
|
||||
// from Actisense NGW-1
|
||||
nmea_float_t ang = 100000.;
|
||||
char ref = 'T';
|
||||
if (!isEmpty(p))
|
||||
ang = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
ref = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
nmea_float_t spd = 100000.;
|
||||
if (!isEmpty(p))
|
||||
spd = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
char units = 'N';
|
||||
if (!isEmpty(p))
|
||||
units = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
char stat = 'A';
|
||||
if (!isEmpty(p))
|
||||
stat = *p; // last before checksum
|
||||
if (units == 'K') {
|
||||
spd /= 1.6;
|
||||
units = 'M';
|
||||
}
|
||||
if (units == 'M') {
|
||||
spd *= 5280. / 6000.;
|
||||
units = 'N';
|
||||
}
|
||||
if (ang > 180.)
|
||||
ang -= 360.;
|
||||
if (ref == 'R') {
|
||||
if (ang < 1000. && stat == 'A')
|
||||
newDataValue(NMEA_AWA, ang);
|
||||
if (spd < 1000. && stat == 'A')
|
||||
newDataValue(NMEA_AWS, spd);
|
||||
} else {
|
||||
if (ang < 1000. && stat == 'A')
|
||||
newDataValue(NMEA_TWA, ang);
|
||||
if (spd < 1000. && stat == 'A')
|
||||
newDataValue(NMEA_TWS, spd);
|
||||
}
|
||||
|
||||
#ifdef NMEA_EXTENSIONS // Sentences not required for basic GPS functionality
|
||||
else if (!strcmp(thisSentence, "TXT")) { //*******************************TXT
|
||||
} else if (!strcmp(thisSentence, "RMB")) { //*****************************RMB
|
||||
// from Actisense NGW-1 from SH CP150C
|
||||
p = strchr(p, ',') + 1; // skip status
|
||||
nmea_float_t xte = 100000.;
|
||||
char xteDir = 'X';
|
||||
if (!isEmpty(p))
|
||||
xte = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
xteDir = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (xte < 10000. && xteDir != 'X') {
|
||||
if (xteDir == 'L')
|
||||
xte *= -1.;
|
||||
newDataValue(NMEA_XTE, xte);
|
||||
}
|
||||
if (!isEmpty(p))
|
||||
parseStr(toID, p, NMEA_MAX_WP_ID);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
parseStr(fromID, p, NMEA_MAX_WP_ID);
|
||||
p = strchr(p, ',') + 1;
|
||||
nmea_float_t latitudeWP =
|
||||
0; // All the same position data for the next way point
|
||||
nmea_float_t longitudeWP = 0;
|
||||
int32_t latitude_fixedWP = 0;
|
||||
int32_t longitude_fixedWP = 0;
|
||||
nmea_float_t latitudeDegreesWP = 0;
|
||||
nmea_float_t longitudeDegreesWP = 0;
|
||||
char latWP = 'N';
|
||||
char lonWP = 'W';
|
||||
|
||||
// parse out both latitude and direction for WayPoint, then go to next
|
||||
// field, or fail
|
||||
if (!isEmpty(p)) {
|
||||
if (!parseCoord(p, &latitudeDegreesWP, &latitudeWP, &latitude_fixedWP,
|
||||
&latWP))
|
||||
return false;
|
||||
else
|
||||
newDataValue(NMEA_LATWP, latitudeDegreesWP);
|
||||
}
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
// parse out both longitude and direction for WayPoint, then go to next
|
||||
// field, or fail
|
||||
if (!isEmpty(p)) {
|
||||
if (!parseCoord(p, &longitudeDegreesWP, &longitudeWP, &longitude_fixedWP,
|
||||
&lonWP))
|
||||
return false;
|
||||
else
|
||||
newDataValue(NMEA_LONWP, longitudeDegreesWP);
|
||||
}
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_DISTWP, atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_COGWP, atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_VMGWP, atof(p)); // skip arrival flag
|
||||
|
||||
} else if (!strcmp(thisSentence, "ROT")) { //*****************************ROT
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "RPM")) { //*****************************RPM
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "RSA")) { //*****************************RSA
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "TXT")) { //*****************************TXT
|
||||
if (!isEmpty(p))
|
||||
txtTot = atoi(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
|
|
@ -216,12 +404,128 @@ bool Adafruit_GPS::parse(char *nmea) {
|
|||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
parseStr(txtTXT, p, 61); // copy the text to NMEA TXT max of 61 characters
|
||||
|
||||
} else if (!strcmp(thisSentence, "VDR")) { //*****************************VDR
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "VHW")) { //*****************************VHW
|
||||
// from Actisense NGW-1
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDT, atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_HDG, atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_VTW, atof(p)); // skip the other units
|
||||
|
||||
} else if (!strcmp(thisSentence, "VLW")) { //*****************************VLW
|
||||
// from Actisense NGW-1
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_LOG, atof(p));
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_LOGR, atof(p)); // skip the other units
|
||||
|
||||
} else if (!strcmp(thisSentence, "VPW")) { //*****************************VPW
|
||||
// knots, metres/s coerced to knots
|
||||
nmea_float_t vmg = 100000.;
|
||||
if (!isEmpty(p))
|
||||
vmg = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
vmg = atof(p) * 0.3048 * 3600. / 6000.; // skip units
|
||||
if (vmg < 1000.)
|
||||
newDataValue(NMEA_VMG, vmg);
|
||||
} else if (!strcmp(thisSentence, "VTG")) { //*****************************VTG
|
||||
// from Actisense NGW-1 from SH CP150C
|
||||
return false;
|
||||
|
||||
} else if (!strcmp(thisSentence, "VWR")) { //*****************************VWR
|
||||
// from Actisense NGW-1
|
||||
nmea_float_t ang = 1000.;
|
||||
if (!isEmpty(p))
|
||||
ang = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
char ref = ' ';
|
||||
if (!isEmpty(p))
|
||||
ref = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (ref == 'L')
|
||||
ang *= -1;
|
||||
if (ang < 1000.)
|
||||
newDataValue(NMEA_AWA, ang);
|
||||
nmea_float_t ws = 0.0;
|
||||
char units = 'X';
|
||||
if (!isEmpty(p))
|
||||
ws = atof(p);
|
||||
p = strchr(p, ',') + 1; // knots
|
||||
if (!isEmpty(p))
|
||||
units = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
ws = atof(p);
|
||||
p = strchr(p, ',') + 1; // meters / second
|
||||
if (!isEmpty(p))
|
||||
units = *p;
|
||||
p = strchr(p, ',') + 1; // M
|
||||
if (!isEmpty(p))
|
||||
ws = atof(p);
|
||||
p = strchr(p, ',') + 1; // kilometers / hour can be converted back to knots
|
||||
if (!isEmpty(p))
|
||||
units = *p; // last before checksum
|
||||
if (units == 'M') {
|
||||
ws *= 3.6;
|
||||
units = 'K';
|
||||
} // convert m/s to km/h
|
||||
if (units == 'K') {
|
||||
ws /= 1.6;
|
||||
units = 'M';
|
||||
} // convert km/h to miles / h
|
||||
if (units == 'M') {
|
||||
ws *= 5280. / 6000.;
|
||||
units = 'N';
|
||||
} // convert miles / hr to knots
|
||||
if (units == 'N')
|
||||
newDataValue(NMEA_AWS, ws); // store the final result
|
||||
|
||||
} else if (!strcmp(thisSentence, "WCV")) { //*****************************WCV
|
||||
// from SH CP150C
|
||||
if (!isEmpty(p))
|
||||
newDataValue(NMEA_VMGWP, atof(p)); // skip the rest
|
||||
|
||||
} else if (!strcmp(thisSentence, "XTE")) { //*****************************XTE
|
||||
// from Actisense NGW-1 from SH CP150C
|
||||
p = strchr(p, ',') + 1; // skip status 1
|
||||
p = strchr(p, ',') + 1; // skip status 2
|
||||
nmea_float_t xte = 100000.;
|
||||
char xteDir = 'X';
|
||||
if (!isEmpty(p))
|
||||
xte = atof(p);
|
||||
p = strchr(p, ',') + 1;
|
||||
if (!isEmpty(p))
|
||||
xteDir = *p;
|
||||
p = strchr(p, ',') + 1;
|
||||
if (xte < 10000. && xteDir != 'X') {
|
||||
if (xteDir == 'L')
|
||||
xte *= -1.;
|
||||
newDataValue(NMEA_XTE, xte);
|
||||
} // skip units
|
||||
|
||||
} else if (!strcmp(thisSentence, "ZDA")) { //*****************************ZDA
|
||||
// from Actisense NGW-1
|
||||
return false;
|
||||
}
|
||||
#endif // NMEA_EXTENSIONS
|
||||
|
||||
// we dont parse the remaining, yet!
|
||||
else
|
||||
return false;
|
||||
else {
|
||||
return false; // didn't find the required sentence definition
|
||||
}
|
||||
|
||||
// Record the successful parsing of where the last data came from and when
|
||||
strcpy(lastSource, thisSource);
|
||||
|
|
@ -229,3 +533,298 @@ bool Adafruit_GPS::parse(char *nmea) {
|
|||
lastUpdate = millis();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check an NMEA string for basic format, valid source ID and valid
|
||||
and valid sentence ID. Update the values of thisCheck, thisSource and
|
||||
thisSentence.
|
||||
@param nmea Pointer to the NMEA string
|
||||
@return True if well formed, false if it has problems
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean Adafruit_GPS::check(char *nmea) {
|
||||
thisCheck = 0; // new check
|
||||
if (*nmea != '$' && *nmea != '!')
|
||||
return false; // doesn't start with $ or !
|
||||
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 *
|
||||
while (*ast)
|
||||
ast++; // go to the end
|
||||
while (*ast != '*' && ast > nmea)
|
||||
ast--; // then back to * if it's there
|
||||
if (*ast != '*')
|
||||
return false; // there is no asterisk
|
||||
else {
|
||||
uint16_t sum = parseHex(*(ast + 1)) * 16; // extract checksum
|
||||
sum += parseHex(*(ast + 2));
|
||||
char *p = nmea; // check checksum
|
||||
for (char *p1 = p + 1; p1 < ast; p1++)
|
||||
sum ^= *p1;
|
||||
if (sum != 0)
|
||||
return false; // bad checksum :(
|
||||
else
|
||||
thisCheck += NMEA_HAS_CHECKSUM;
|
||||
}
|
||||
// extract source of variable length
|
||||
char *p = nmea + 1;
|
||||
const char *src = tokenOnList(p, sources);
|
||||
if (src) {
|
||||
strcpy(thisSource, src);
|
||||
thisCheck += NMEA_HAS_SOURCE;
|
||||
} else
|
||||
return false;
|
||||
p += strlen(src);
|
||||
// extract sentence id and check if parsed
|
||||
const char *snc = tokenOnList(p, sentences_parsed);
|
||||
if (snc) {
|
||||
strcpy(thisSentence, snc);
|
||||
thisCheck += NMEA_HAS_SENTENCE_P + NMEA_HAS_SENTENCE;
|
||||
} else { // check if known
|
||||
snc = tokenOnList(p, sentences_known);
|
||||
if (snc) {
|
||||
strcpy(thisSentence, snc);
|
||||
thisCheck += NMEA_HAS_SENTENCE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // passed all the tests
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check if a token at the start of a string is on a list.
|
||||
@param token Pointer to the string
|
||||
@param list A list of strings, with the final entry starting "ZZ"
|
||||
@return Pointer to the found token, or NULL if it fails
|
||||
*/
|
||||
/**************************************************************************/
|
||||
const char *Adafruit_GPS::tokenOnList(char *token, const char **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
|
||||
// test for a match on the sentence name
|
||||
if (!strncmp((const char *)list[i], (const char *)token, strlen(list[i])))
|
||||
return list[i];
|
||||
i++;
|
||||
}
|
||||
return NULL; // couldn't find a match
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Check if an NMEA string is valid and is on a list, perhaps to
|
||||
decide if it should be passed to a particular NMEA device.
|
||||
@param nmea Pointer to the NMEA string
|
||||
@param list A list of strings, with the final entry "ZZ"
|
||||
@return True if on the list, false if it fails check or is not on the list
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::onList(char *nmea, const char **list) {
|
||||
if (!check(nmea)) // sets thisSentence if valid
|
||||
return false; // not a valid sentence
|
||||
// stop at terminator with first two letters ZZ and don't crash without it
|
||||
for (int i = 0; strncmp(list[i], "ZZ", 2) && i < 1000; i++) {
|
||||
// test for a match on the sentence name
|
||||
if (!strcmp((const char *)list[i], (const char *)thisSentence))
|
||||
return true;
|
||||
}
|
||||
return false; // couldn't find a match
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for lat or lon angle and direction.
|
||||
Works for either DDMM.mmmm,N (latitude) or DDDMM.mmmm,W (longitude) format.
|
||||
Insensitive to number of decimal places present. Only fills the variables
|
||||
if it succeeds and the variable pointer is not NULL. This allows calling
|
||||
to fill only the variables of interest. Does rudimentary validation on
|
||||
angle range.
|
||||
|
||||
Supersedes private functions parseLat(), parseLon(), parseLatDir(),
|
||||
parseLonDir(), all previously called from parse().
|
||||
@param pStart Pointer to the location of the token in the NMEA string
|
||||
@param angle Pointer to the angle to fill with value in degrees/minutes as
|
||||
received from the GPS (DDDMM.MMMM), unsigned
|
||||
@param angle_fixed Pointer to the fix point version latitude in decimal
|
||||
degrees * 10000000, signed
|
||||
@param angleDegrees Pointer to the angle to fill with decimal degrees,
|
||||
signed. As actual double on SAMD, etc. resolution is better than the
|
||||
fixed point version.
|
||||
@param dir Pointer to character to fill the direction N/S/E/W
|
||||
@return true if successful, false if failed or no value
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::parseCoord(char *pStart, nmea_float_t *angleDegrees,
|
||||
nmea_float_t *angle, int32_t *angle_fixed,
|
||||
char *dir) {
|
||||
char *p = pStart;
|
||||
if (!isEmpty(p)) {
|
||||
// get the number in DDDMM.mmmm format and break into components
|
||||
char degreebuff[10];
|
||||
char *e = strchr(p, '.');
|
||||
if (e == NULL || e - p > 6)
|
||||
return false; // no decimal point in range
|
||||
strncpy(degreebuff, p, e - p); // get DDDMM
|
||||
long dddmm = atol(degreebuff);
|
||||
long degrees = (dddmm / 100); // truncate the minutes
|
||||
long minutes = dddmm - degrees * 100; // remove the degrees
|
||||
p = e; // start from the decimal point
|
||||
nmea_float_t decminutes = atof(e); // the fraction after the decimal point
|
||||
p = strchr(p, ',') + 1; // go to the next field
|
||||
|
||||
// get the NSEW direction as a character
|
||||
char nsew = 'X';
|
||||
if (!isEmpty(p))
|
||||
nsew = *p; // field is not empty
|
||||
else
|
||||
return false; // no direction provided
|
||||
|
||||
// set the various numerical formats to their values
|
||||
long fixed = degrees * 10000000 + (minutes * 10000000) / 60 +
|
||||
(decminutes * 10000000) / 60;
|
||||
nmea_float_t ang = degrees * 100 + minutes + decminutes;
|
||||
nmea_float_t deg = fixed / (nmea_float_t)10000000.;
|
||||
if (nsew == 'S' ||
|
||||
nsew == 'W') { // fixed and deg are signed, but DDDMM.mmmm is not
|
||||
fixed = -fixed;
|
||||
deg = -deg;
|
||||
}
|
||||
|
||||
// reject directions that are not NSEW
|
||||
if (nsew != 'N' && nsew != 'S' && nsew != 'E' && nsew != 'W')
|
||||
return false;
|
||||
|
||||
// reject angles that are out of range
|
||||
if (nsew == 'N' || nsew == 'S')
|
||||
if(abs(deg) > 90) return false;
|
||||
if(abs(deg) > 180) return false;
|
||||
|
||||
// store in locations passed as args
|
||||
if (angle != NULL)
|
||||
*angle = ang;
|
||||
if (angle_fixed != NULL)
|
||||
*angle_fixed = fixed;
|
||||
if (angleDegrees != NULL)
|
||||
*angleDegrees = deg;
|
||||
if (dir != NULL)
|
||||
*dir = nsew;
|
||||
} else
|
||||
return false; // no number
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a string token from pointer p to the next comma, asterisk
|
||||
or end of string.
|
||||
@param buff Pointer to the buffer to store the string in
|
||||
@param p Pointer into a string
|
||||
@param n Max permitted size of string including terminating 0
|
||||
@return Pointer to the string buffer
|
||||
*/
|
||||
/**************************************************************************/
|
||||
char *Adafruit_GPS::parseStr(char *buff, char *p, int n) {
|
||||
char *e = strchr(p, ',');
|
||||
int len = 0;
|
||||
if (e) {
|
||||
len = min(e - p, n - 1);
|
||||
strncpy(buff, p, len); // copy up to the comma
|
||||
buff[len] = 0;
|
||||
} else {
|
||||
e = strchr(p, '*');
|
||||
if (e) {
|
||||
len = min(e - p, n - 1);
|
||||
strncpy(buff, p, len); // or up to the *
|
||||
buff[e - p] = 0;
|
||||
} else {
|
||||
len = min((int)strlen(p), n - 1);
|
||||
strncpy(buff, p, len); // or to the end or max capacity
|
||||
}
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for time. Independent of number
|
||||
of decimal places after the '.'
|
||||
@param p Pointer to the location of the token in the NMEA string
|
||||
@return true if successful, false otherwise
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::parseTime(char *p) {
|
||||
if (!isEmpty(p)) { // get time
|
||||
uint32_t time = atol(p);
|
||||
hour = time / 10000;
|
||||
minute = (time % 10000) / 100;
|
||||
seconds = (time % 100);
|
||||
p = strchr(p, '.');
|
||||
milliseconds = atof(p) * 1000;
|
||||
lastTime = sentTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a part of an NMEA string for whether there is a fix
|
||||
@param p Pointer to the location of the token in the NMEA string
|
||||
@return True if we parsed it, false if it has invalid data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
boolean Adafruit_GPS::parseFix(char *p) {
|
||||
if (!isEmpty(p)) {
|
||||
if (p[0] == 'A') {
|
||||
fix = true;
|
||||
lastFix = sentTime;
|
||||
} else if (p[0] == 'V')
|
||||
fix = false;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Is the field empty, or should we try conversion? Won't work
|
||||
for a text field that starts with an asterisk or a comma, but that
|
||||
probably violates the NMEA-183 standard.
|
||||
@param pStart Pointer to the location of the token in the NMEA string
|
||||
@return true if empty field, false if something there
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_GPS::isEmpty(char *pStart) {
|
||||
if (',' != *pStart && '*' != *pStart && pStart != NULL)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Parse a hex character and return the appropriate decimal value
|
||||
@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
|
||||
*/
|
||||
/**************************************************************************/
|
||||
// read a Hex value and return the decimal equivalent
|
||||
uint8_t Adafruit_GPS::parseHex(char c) {
|
||||
if (c < '0')
|
||||
return 0;
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
if (c < 'A')
|
||||
return 0;
|
||||
if (c <= 'F')
|
||||
return (c - 'A') + 10;
|
||||
// if (c > 'F')
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue