diff --git a/src/Adafruit_GPS.h b/src/Adafruit_GPS.h index c8ecbac..d32948a 100644 --- a/src/Adafruit_GPS.h +++ b/src/Adafruit_GPS.h @@ -244,7 +244,7 @@ private: // NMEA_data.cpp void data_init(); // NMEA_parse.cpp - const char *tokenOnList(char *token, const char **list); + const char *tokenOnList(char *token, const char list[][4]); bool parseCoord(char *p, nmea_float_t *angleDegrees = NULL, nmea_float_t *angle = NULL, int32_t *angle_fixed = NULL, char *dir = NULL); @@ -254,23 +254,10 @@ private: bool parseAntenna(char *); bool isEmpty(char *pStart); - // used by check() for validity tests, room for future expansion - const char *sources[9] = {"II", "WI", "GP", "PG", "GL", - "GA", "GN", "P", "ZZZ"}; ///< valid source ids -#ifdef NMEA_EXTENSIONS - const char *sentences_parsed[21] = {"GGA", "GLL", "GSA", "RMC", "DBT", "HDM", - "HDT", "MDA", "MTW", "MWV", "RMB", "TOP", - "TXT", "VHW", "VLW", "VPW", "VWR", "WCV", - "XTE", "ZZZ"}; ///< parseable sentence ids - const char *sentences_known[15] = { - "APB", "DPT", "GSV", "HDG", "MWD", "ROT", - "RPM", "RSA", "VDR", "VTG", "ZDA", "ZZZ"}; ///< known, but not parseable -#else // make the lists short to save memory - const char *sentences_parsed[6] = {"GGA", "GLL", "GSA", "RMC", - "TOP", "ZZZ"}; ///< parseable sentence ids - const char *sentences_known[4] = {"DBT", "HDM", "HDT", - "ZZZ"}; ///< known, but not parseable -#endif + // Shared flash tables avoid RAM copies of both the IDs and their pointers. + static const char PROGMEM sources[][4]; ///< valid source ids + static const char PROGMEM sentences_parsed[][4]; ///< parseable sentence ids + static const char PROGMEM sentences_known[][4]; ///< known, but not parseable // Make all of these times far in the past by setting them near the middle of // the millis() range. Timing assumes that sentences are parsed promptly. diff --git a/src/NMEA_parse.cpp b/src/NMEA_parse.cpp index e9285b0..a984dba 100644 --- a/src/NMEA_parse.cpp +++ b/src/NMEA_parse.cpp @@ -21,6 +21,22 @@ /**************************************************************************/ #include + +const char PROGMEM Adafruit_GPS::sources[][4] = {"II", "WI", "GP", "PG", "GL", + "GA", "GN", "P", "ZZZ"}; +#ifdef NMEA_EXTENSIONS +const char PROGMEM Adafruit_GPS::sentences_parsed[][4] = { + "GGA", "GLL", "GSA", "RMC", "DBT", "HDM", "HDT", "MDA", "MTW", "MWV", + "RMB", "TOP", "TXT", "VHW", "VLW", "VPW", "VWR", "WCV", "XTE", "ZZZ"}; +const char PROGMEM Adafruit_GPS::sentences_known[][4] = { + "APB", "DPT", "GSV", "HDG", "MWD", "ROT", + "RPM", "RSA", "VDR", "VTG", "ZDA", "ZZZ"}; +#else // make the lists short to save flash on small boards +const char PROGMEM Adafruit_GPS::sentences_parsed[][4] = {"GGA", "GLL", "GSA", + "RMC", "TOP", "ZZZ"}; +const char PROGMEM Adafruit_GPS::sentences_known[][4] = {"DBT", "HDM", "HDT", + "ZZZ"}; +#endif #include /**************************************************************************/ @@ -648,20 +664,20 @@ bool Adafruit_GPS::check(char *nmea) { char *p = nmea + 1; const char *src = tokenOnList(p, sources); if (src) { - strcpy(thisSource, src); + strcpy_P(thisSource, src); thisCheck += NMEA_HAS_SOURCE; } else return false; - p += strlen(src); + p += strlen_P(src); // extract sentence id and check if parsed const char *snc = tokenOnList(p, sentences_parsed); if (snc) { - strcpy(thisSentence, snc); + strcpy_P(thisSentence, snc); thisCheck += NMEA_HAS_SENTENCE_P + NMEA_HAS_SENTENCE; } else { // check if known snc = tokenOnList(p, sentences_known); if (snc) { - strcpy(thisSentence, snc); + strcpy_P(thisSentence, snc); thisCheck += NMEA_HAS_SENTENCE; return false; // known but not parsed } else { @@ -676,18 +692,17 @@ bool Adafruit_GPS::check(char *nmea) { /*! @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 + @param list A table in program memory, with the final entry starting "ZZ" + @return Program-memory 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 +const char *Adafruit_GPS::tokenOnList(char *token, const char list[][4]) { + for (int i = 0; i < 1000; i++) { + if (pgm_read_byte(list[i]) == 'Z' && pgm_read_byte(list[i] + 1) == 'Z') + break; // stop at terminator // test for a match on the sentence name - if (!strncmp((const char *)list[i], (const char *)token, strlen(list[i]))) + if (!strncmp_P(token, list[i], strlen_P(list[i]))) return list[i]; - i++; } return NULL; // couldn't find a match }